Compare commits

..

1 Commits

Author SHA1 Message Date
(no author)
ea75c7d8c1 This commit was manufactured by cvs2svn to create tag
'release_0_7_0'.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/tags/release_0_7_0@1420 c046a42c-6fe2-441c-8c8c-71466251a162
2005-04-27 20:49:24 +00:00
1145 changed files with 70342 additions and 449084 deletions

21
.cvsignore Normal file
View File

@@ -0,0 +1,21 @@
arm-user
armeb-user
config-host.*
dyngen
i386
i386-softmmu
i386-user
ppc-softmmu
ppc-user
qemu-doc.html
qemu-tech.html
qemu.1
qemu.pod
qemu-img.1
qemu-img.pod
sparc-user
qemu-img
sparc-softmmu
x86_64-softmmu
sparc64-user
sparc64-softmmu

45
.gitignore vendored
View File

@@ -1,45 +0,0 @@
config-host.*
i386
*-softmmu
*-darwin-user
*-linux-user
*-bsd-user
libhw32
libhw64
qemu-doc.html
qemu-tech.html
qemu-doc.info
qemu-tech.info
qemu.1
qemu.pod
qemu-img.1
qemu-img.pod
qemu-img
qemu-nbd
qemu-nbd.8
qemu-nbd.pod
qemu-options.texi
qemu-img-cmds.texi
qemu-img-cmds.h
qemu-io
qemu-monitor.texi
.gdbinit
*.a
*.aux
*.cp
*.dvi
*.exe
*.fn
*.ky
*.log
*.pg
*.toc
*.tp
*.vr
*.d
*.o
.pc
patches
pc-bios/bios-pq/status
pc-bios/vgabios-pq/status
.stgit-*

View File

@@ -1,78 +0,0 @@
Qemu Coding Style
=================
1. Whitespace
Of course, the most important aspect in any coding style is whitespace.
Crusty old coders who have trouble spotting the glasses on their noses
can tell the difference between a tab and eight spaces from a distance
of approximately fifteen parsecs. Many a flamewar have been fought and
lost on this issue.
QEMU indents are four spaces. Tabs are never used, except in Makefiles
where they have been irreversibly coded into the syntax.
Spaces of course are superior to tabs because:
- You have just one way to specify whitespace, not two. Ambiguity breeds
mistakes.
- The confusion surrounding 'use tabs to indent, spaces to justify' is gone.
- Tab indents push your code to the right, making your screen seriously
unbalanced.
- Tabs will be rendered incorrectly on editors who are misconfigured not
to use tab stops of eight positions.
- Tabs are rendered badly in patches, causing off-by-one errors in almost
every line.
- It is the QEMU coding style.
Do not leave whitespace dangling off the ends of lines.
2. Line width
Lines are 80 characters; not longer.
Rationale:
- Some people like to tile their 24" screens with a 6x4 matrix of 80x24
xterms and use vi in all of them. The best way to punish them is to
let them keep doing it.
- Code and especially patches is much more readable if limited to a sane
line length. Eighty is traditional.
- It is the QEMU coding style.
3. Naming
Variables are lower_case_with_underscores; easy to type and read. Structured
type names are in CamelCase; harder to type but standing out. Scalar type
names are lower_case_with_underscores_ending_with_a_t, like the POSIX
uint64_t and family. Note that this last convention contradicts POSIX
and is therefore likely to be changed.
Typedefs are used to eliminate the redundant 'struct' keyword. It is the
QEMU coding style.
4. Block structure
Every indented statement is braced; even if the block contains just one
statement. The opening brace is on the line that contains the control
flow statement that introduces the new block; the closing brace is on the
same line as the else keyword, or on a line by itself if there is no else
keyword. Example:
if (a == 5) {
printf("a was 5.\n");
} else if (a == 6) {
printf("a was 6.\n");
} else {
printf("a was something else entirely.\n");
}
An exception is the opening brace for a function; for reasons of tradition
and clarity it comes on a line by itself:
void a_function(void)
{
do_something();
}
Rationale: a consistent (except for functions...) bracing style reduces
ambiguity and avoids needless churn when lines are added or removed.
Furthermore, it is the QEMU coding style.

18
COPYING
View File

@@ -1,8 +1,8 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
Copyright (C) 19yy <name of author>
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
@@ -303,16 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@@ -335,5 +335,5 @@ necessary. Here is a sample; alter the names:
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -2,7 +2,7 @@
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -485,7 +485,7 @@ convey the exclusion of warranty; and each file should have at least the
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.

348
Changelog
View File

@@ -1,337 +1,3 @@
Version 0.11.1
- fix I2C slave addressing (Juha Riihimäki)
- Revert "vga: do not resize the screen on hw_invalidate" (Aurelien Jarno)
- slirp: fix use-after-free (Mark McLoughlin)
- Fix sparc.ld (Blue Swirl)
- ELF codedump build failures (Laurent Desnogues)
- kvm: Move KVM mp_state accessors to i386-specific code (Hollis Blanchard)
- fix configure script with armv4l cpu (Laurent Desnogues)
- net: disable draining tap queue in one go (Mark McLoughlin)
- pcnet: Restart poll timer on pcnet_start (Jan Kiszka)
- Sparc32: Fix lance (Blue Swirl)
- mac99: fix segmentation fault on startup (Aurelien Jarno)
- usb-linux.c: fix buffer overflow (Jim Paris)
- ARM host: fix generated blocks linking (Laurent Desnogues)
- qemu serial: lost tx irqs (affecting FreeBSD's new uart(4) driver (Juergen Lock)
- exec-all.h: increase MAX_OP_PER_INSTR to 96 from 64 (Aurelien Jarno)
version 0.11.0
- fix rtc polling mode (Bernhard Kauer)
- qcow2: order concurrent aio requests (Kevin Wolf)
- qemu-io: port to win32 (Stefan Weil)
- alpha: fix extlh instruction (Vince Weaver)
- tcg: fix size of local variables in tcg_gen_bswap64_i64 (Stefan Weil)
- net: fix send ordering (Jan Kiszka)
- escc: fix IRQ routing (Aurelien Jarno)
- versatile: fix Linux task preemption (Aurelien Jarno)
- curses: reduce memory usage by 250MB (Aurelien Jarno)
version 0.11.0-rc2
- mips: fix conditional move off fp conditions codes (Nath Froyd)
- fix migration to obey -S (Paolo Bonzini)
- remove pc-0-10 machine type (Mark McLoughlin)
- vnc: fix copyrect screen corruption (Gerd Hoffman)
- fix vm state change handlers running order (Markus Armbruster)
- e1000: fix eerc and ics emulation (Bill Paul)
- fix sdl zooming with pl110 (Blue Swirl)
- sparc64: flush pending conditional evaluations (Igor Kovalenko)
- esp: fix interrupt register read (Blue Swirl)
- option rom makefile fixes (Paul Brook)
- fix sparse warnings (Blue Swirl)
- fix symfind (Laurent Desnogues)
- win32: fix default prefix (Stefan Weil)
- fix checksum writing in signboot (Alex Graf)
- fix sdl window resize (Stefano Stabellini)
- do not resize the screen on hw_invalidate (Stefano Stabellini)
- Add checks for -smbios option (Beth Kon)
- fix do_set_link (Luiz Capitulino)
- fix do_commit behavior (Luiz Capitulino)
- make windows notice media change (Gleb Natapov)
- check for PR_SET_NAME being defined (Nathan Froyd)
- fix migration for ide devices (Anthony Liguori)
- Use correct depth in vmware vga (Reimar Doffiner)
- support 32bpp cursors in sdl (Reimar Doffinger)
- fix device name completion for eject (Blue Swirl)
- make screendump use DisplayState properly (Stefano Stabellini)
- fix autostart with live migration (Avi Kivity)
- fix detached migration with exec (Chris Lalancette)
- fix segv when changing vnc password in sdl (Zach Amsden)
- fix vnc password clearing with stdio monitor (Zach Amsden)
- clean up VGA type selection (Zach Amsden)
- add missing linefeed in error message (Stefan Weil)
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.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)
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.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)
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:
- fix savevm/loadvm (Anthony Liguori)
- live migration: fix dirty tracking windows (Glauber Costa)
- live migration: improve error propogation (Glauber Costa)
- qcow2: fix image creation for > ~2TB images (Chris Wright)
- hotplug: fix error handling for if= parameter (Eduardo Habkost)
- qcow2: fix data corruption (Nolan Leake)
- virtio: fix guest oops with 2.6.25 kernels (Rusty Russell)
- SH4: add support for -kernel (Takashi Yoshii, Aurelien Jarno)
- hotplug: fix closing of char devices (Jan Kiszka)
- hotplug: remove incorrect check for device name (Eduardo Habkost)
- enable -k on win32 (Herve Poussineau)
- configure: use LANG=C for grep (Andreas Faerber)
- fix VGA regression (malc)
version 0.10.1:
- virtio-net: check right return size on sg list (Alex Williamson)
- Make qemu_announce_self handle holes (live migration after hotplug)
(Marcelo Tosatti)
- Revert r6804-r6808 (qcow2 allocation info). This series of changes added
a high cost to startup for large qcow2 images (Anthony Liguori)
- qemu-img: fix help message (Aurelien Jarno)
- Fix build for non-default installs of SDL (Anthony Liguori)
- Fix race condition in env->interrupt_request. When using TCG and a dynticks
host timer, this condition could cause TCG to get stuck in an infinite
loop (Aurelien Jarno)
- Fix reading encrypted hard disk passwords during early startup (Jan Kiszka)
- Fix encrypted disk reporting in 'info block' (Jan Kiszka)
- Fix console size with tiny displays (MusicPal) (Jan Kiszka)
- Improve error handling in bdrv_open2 (Jan Kiszka)
- Avoid leaking data in mux'ed character devices (Jan Kiszka)
- Fix initial character device reset (no banner in monitor) (Jan Kiszka)
- Fix cpuid KVM crash on i386 host (Lubomir Rintel)
- Fix SLES10sp2 installation by adding ISTAT1 register to LSI SCSI emulation
(Ryan Harper)
version 0.10.0:
- TCG support (No longer requires GCC 3.x)
- Kernel Virtual Machine acceleration support
- BSD userspace emulation
- Bluetooth emulation and host passthrough support
- GDB XML register description support
- Intel e1000 emulation
- HPET emulation
- VirtIO paravirtual device support
- Marvell 88w8618 / MusicPal emulation
- Nokia N-series tablet emulation / OMAP2 processor emulation
- PCI hotplug support
- Live migration and new save/restore formats
- Curses display support
- qemu-nbd utility to mount supported block formats
- Altivec support in PPC emulation and new firmware (OpenBIOS)
- Multiple VNC clients are now supported
- TLS encryption is now supported in VNC
- MIPS Magnum R4000 machine (Hervé Poussineau)
- Braille support (Samuel Thibault)
- Freecom MusicPal system emulation (Jan Kiszka)
- OMAP242x and Nokia N800, N810 machines (Andrzej Zaborowski)
- EsounD audio driver (Frederick Reeve)
- Gravis Ultrasound GF1 sound card (Tibor "TS" Schütz)
- Many, many, bug fixes and new features
version 0.9.1:
- TFTP booting from host directory (Anthony Liguori, Erwan Velu)
- Tap device emulation for Solaris (Sittichai Palanisong)
- Monitor multiplexing to several I/O channels (Jason Wessel)
- ds1225y nvram support (Herve Poussineau)
- CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau)
- Several Sparc fixes (Aurelien Jarno, Blue Swirl, Robert Reif)
- MIPS 64-bit FPU support (Thiemo Seufer)
- Xscale PDA emulation (Andrzej Zaborowski)
- ColdFire system emulation (Paul Brook)
- Improved SH4 support (Magnus Damm)
- MIPS64 support (Aurelien Jarno, Thiemo Seufer)
- Preliminary Alpha guest support (J. Mayer)
- Read-only support for Parallels disk images (Alex Beregszaszi)
- SVM (x86 virtualization) support (Alexander Graf)
- CRIS emulation (Edgar E. Iglesias)
- SPARC32PLUS execution support (Blue Swirl)
- MIPS mipssim pseudo machine (Thiemo Seufer)
- Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh)
- OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski)
- ARM v6, v7, NEON SIMD and SMP emulation (Paul Brook/CodeSourcery)
- Gumstix boards: connex and verdex emulation (Thorsten Zitterell)
- Intel mainstone II board emulation (Armin Kuster)
- VMware SVGA II graphics card support (Andrzej Zaborowski)
version 0.9.0:
- Support for relative paths in backing files for disk images
- Async file I/O API
- New qcow2 disk image format
- Support of multiple VM snapshots
- Linux: specific host CDROM and floppy support
- SMM support
- Moved PCI init, MP table init and ACPI table init to Bochs BIOS
- Support for MIPS32 Release 2 instruction set (Thiemo Seufer)
- MIPS Malta system emulation (Aurelien Jarno, Stefan Weil)
- Darwin userspace emulation (Pierre d'Herbemont)
- m68k user support (Paul Brook)
- several x86 and x86_64 emulation fixes
- Mouse relative offset VNC extension (Anthony Liguori)
- PXE boot support (Anthony Liguori)
- '-daemonize' option (Anthony Liguori)
version 0.8.2:
- ACPI support
- PC VGA BIOS fixes
- switch to OpenBios for SPARC targets (Blue Swirl)
- VNC server fixes
- MIPS FPU support (Marius Groeger)
- Solaris/SPARC host support (Juergen Keil)
- PPC breakpoints and single stepping (Jason Wessel)
- USB updates (Paul Brook)
- UDP/TCP/telnet character devices (Jason Wessel)
- Windows sparse file support (Frediano Ziglio)
- RTL8139 NIC TCP segmentation offloading (Igor Kovalenko)
- PCNET NIC support (Antony T Curtis)
- Support for variable frequency host CPUs
- Workaround for win32 SMP hosts
- Support for AMD Flash memories (Jocelyn Mayer)
- Audio capture to WAV files support (malc)
version 0.8.1:
- USB tablet support (Brad Campbell, Anthony Liguori)
- win32 host serial support (Kazu)
- PC speaker support (Joachim Henke)
- IDE LBA48 support (Jens Axboe)
- SSE3 support
- Solaris port (Juergen Keil)
- Preliminary SH4 target (Samuel Tardieu)
- VNC server (Anthony Liguori)
- slirp fixes (Ed Swierk et al.)
- USB fixes
- ARM Versatile Platform Baseboard emulation (Paul Brook)
version 0.8.0:
- ARM system emulation: Arm Integrator/CP board with an arm1026ej-s
cpu (Paul Brook)
- SMP support
- Mac OS X cocoa improvements (Mike Kronenberg)
- Mac OS X CoreAudio driver (Mike Kronenberg)
- DirectSound driver (malc)
- ALSA audio driver (malc)
- new audio options: '-soundhw' and '-audio-help' (malc)
- ES1370 PCI audio device (malc)
- Initial USB support
- Linux host serial port access
- Linux host low level parallel port access
- New network emulation code supporting VLANs.
- MIPS and MIPSel User Linux emulation
- MIPS fixes to boot Linux (Daniel Jacobowitz)
- NX bit support
- Initial SPARC SMP support (Blue Swirl)
- Major overhaul of the virtual FAT driver for read/write support
(Johannes Schindelin)
version 0.7.2:
- x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit)
- merge self modifying code handling in dirty ram page mecanism.
- MIPS fixes (Ralf Baechle)
- better user net performances
version 0.7.1:
- read-only Virtual FAT support (Johannes Schindelin)
- Windows 2000 install disk full hack (original idea from Vladimir
N. Oleynik)
- VMDK disk image creation (Filip Navara)
- SPARC64 progress (Blue Swirl)
- initial MIPS support (Jocelyn mayer)
- MIPS improvements (Ralf Baechle)
- 64 bit fixes in user networking (initial patch by Gwenole Beauchesne)
- IOAPIC support (Filip Navara)
version 0.7.0:
- better BIOS translation and HDD geometry auto-detection
@@ -363,7 +29,7 @@ version 0.6.1:
- Mac OS X port (Pierre d'Herbemont)
- Virtual console support
- Better monitor line edition
- New block device layer
- New block device layer
- New 'qcow' growable disk image support with AES encryption and
transparent decompression
- VMware 3 and 4 read-only disk image support (untested)
@@ -429,7 +95,7 @@ version 0.5.5:
- FDC fixes for Win98
version 0.5.4:
- qemu-fast fixes
- BIOS area protection fix (aka EMM386.EXE fix) (Mike Nordell)
- keyboard/mouse fix (Mike Nordell)
@@ -456,7 +122,7 @@ version 0.5.3:
- added accurate CR0.MP/ME/TS emulation
- fixed DMA memory write access (Win95 boot floppy fix)
- graphical x86 linux loader
- command line monitor
- command line monitor
- generic removable device support
- support of CD-ROM change
- multiple network interface support
@@ -494,7 +160,7 @@ version 0.5.2:
- eflags optimisation fix for string operations
version 0.5.1:
- float access fixes when using soft mmu
- PC emulation support on PowerPC
- A20 support
@@ -509,7 +175,7 @@ version 0.5.1:
- Major SPARC target fixes (dynamically linked programs begin to work)
version 0.5.0:
- full hardware level VGA emulation
- graphical display with SDL
- added PS/2 mouse and keyboard emulation
@@ -547,7 +213,7 @@ version 0.4.2:
- SMP kernels can at least be booted
version 0.4.1:
- more accurate timer support in vl.
- more reliable NE2000 probe in vl.
- added 2.5.66 kernel in vl-test.
@@ -633,7 +299,7 @@ version 0.1.3:
- added bound, cmpxchg8b, cpuid instructions
- added 16 bit addressing support/override for string operations
- poll() fix
version 0.1.2:
- compile fixes

22
LICENSE
View File

@@ -1,18 +1,12 @@
The following points clarify the QEMU license:
The following points clarify the QEMU licenses:
1) QEMU as a whole is released under the GNU General Public License
1) The QEMU virtual CPU core library (libqemu.a) and the QEMU PC
system emulator are released under the GNU Lesser General Public
License.
2) Parts of QEMU have specific licenses which are compatible with the
GNU General Public License. Hence each source file contains its own
licensing information.
2) The Linux user mode QEMU emulator is released under the GNU General
Public License.
In particular, the QEMU virtual CPU core library (libqemu.a) is
released under the GNU Lesser General Public License. Many hardware
device emulation sources are released under the BSD license.
3) QEMU is a trademark of Fabrice Bellard.
3) The Tiny Code Generator (TCG) is released under the BSD license
(see license headers in files).
4) QEMU is a trademark of Fabrice Bellard.
Fabrice Bellard.
Fabrice Bellard.

View File

@@ -1,86 +0,0 @@
QEMU Maintainers
================
Project leaders:
----------------
Fabrice Bellard
Paul Brook
CPU cores:
----------
x86 Fabrice Bellard
ARM Paul Brook
SPARC Blue Swirl
MIPS Thiemo Seufer
PowerPC ?
M68K Paul Brook
SH4 ?
CRIS Edgar E. Iglesias
Alpha ?
MicroBlaze Edgar E. Iglesias
Machines (sorted by CPU):
-------------------------
x86
pc.c Fabrice Bellard (new maintainer needed)
ARM
integratorcp.c Paul Brook
versatilepb.c Paul Brook
Real View Paul Brook
spitz.c Andrzej Zaborowski
palm.c Andrzej Zaborowski
nseries.c Andrzej Zaborowski
stellaris.c Paul Brook
gumstix.c Thorsten Zitterell
mainstone.c Armin Kuster
musicpal.c Jan Kiszka
SPARC
sun4u.c Blue Swirl
sun4m.c Blue Swirl
MIPS
mips_r4k.c Aurelien Jarno
mips_malta.c Aurelien Jarno
mips_jazz.c Hervé Poussineau
mips_mipssim.c Thiemo Seufer
PowerPC
ppc_prep.c ?
ppc_oldworld.c Fabrice Bellard
ppc_chrp.c Fabrice Bellard
ppc405_boards.c ?
M86K
mcf5208.c Paul Brook
an5206.c Paul Brook
dummy_m68k.c Paul Brook
SH4
shix.c ?
r2d.c Magnus Damm
CRIS
etraxfs.c Edgar E. Iglesias
axis_dev88.c Edgar E. Iglesias
Alpha
MicroBlaze
petalogix_s3adsp1800.c Edgar E. Iglesias
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 ?
USB layer ?
Block layer ?
Graphic layer ?
Audio device layer Vassili Karpov (malc)
Character device layer ?
Network device layer ?
GDB stub ?
Linux user ?
Darwin user ?
SLIRP ?

430
Makefile
View File

@@ -1,255 +1,51 @@
# Makefile for QEMU.
-include config-host.mak
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
else
config-host.mak:
@echo "Please call configure before running make!"
@exit 1
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
ifdef CONFIG_DARWIN
CFLAGS+= -mdynamic-no-pic
endif
.PHONY: all clean cscope distclean dvi html info install install-doc \
recurse-all speed tar tarbin test
VPATH=$(SRC_PATH):$(SRC_PATH)/hw
CPPFLAGS += -I. -I$(SRC_PATH) -MMD -MP -MT $@
CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
CPPFLAGS += -U_FORTIFY_SOURCE
LDFLAGS=-g
LIBS=
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
TOOLS=qemu-img$(EXESUF)
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
LDFLAGS+=-static
endif
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
all: dyngen$(EXESUF) $(TOOLS) $(DOCS)
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
ifdef CONFIG_KQEMU
ifdef CONFIG_WIN32
LIBS+=-lwinmm -lws2_32 -liphlpapi
endif
build-all: $(TOOLS) $(DOCS) 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_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
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
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)
#######################################################################
# 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
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
ifdef CONFIG_WIN32
block-nested-y += raw-win32.o
$(MAKE) -C kqemu -f Makefile.winnt
else
ifdef CONFIG_AIO
block-obj-y += posix-aio-compat.o
$(MAKE) -C kqemu
endif
block-nested-y += raw-posix.o
endif
block-nested-$(CONFIG_CURL) += curl.o
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
block-obj-y += $(addprefix block/, $(block-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
# system emulation, i.e. a single QEMU executable should support all
# CPUs and machines.
obj-y = $(block-obj-y)
obj-y += readline.o console.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
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
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 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 ssi.o
obj-$(CONFIG_BRLAPI) += baum.o
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
audio-obj-$(CONFIG_OSS) += ossaudio.o
audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
audio-obj-$(CONFIG_ALSA) += alsaaudio.o
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-$(AUDIO_PT_INT) += audio_pt_int.o
audio-obj-y += wavcapture.o
obj-y += $(addprefix audio/, $(audio-obj-y))
obj-y += keymaps.o
obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
obj-$(CONFIG_CURSES) += curses.o
obj-y += vnc.o acl.o d3des.o
obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
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
LIBS+=$(CURL_LIBS)
cocoa.o: cocoa.m
keymaps.o: keymaps.c keymaps.h
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: CFLAGS += $(SDL_CFLAGS)
acl.o: acl.h acl.c
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: CFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
vnc-tls.o: vnc-tls.c vnc.h
vnc-auth-vencrypt.o: vnc-auth-vencrypt.c vnc.h
vnc-auth-sasl.o: vnc-auth-sasl.c vnc.h
curses.o: curses.c keymaps.h curses_keys.h
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 tool-osdep.o $(block-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 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 $@")
dyngen$(EXESUF): dyngen.c
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
clean:
# avoid old build problems by removing potentially incorrect old files
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
rm -f qemu-img-cmds.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 *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~
$(MAKE) -C tests clean
for d in $(ALL_SUBDIRS) libhw32 libhw64; do \
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
ifdef CONFIG_KQEMU
$(MAKE) -C kqemu clean
endif
distclean: clean
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; do \
rm -f config-host.mak config-host.h
for d in $(TARGET_DIRS); do \
rm -rf $$d || exit 1 ; \
done
@@ -257,166 +53,80 @@ KEYMAPS=da en-gb et fr fr-ch is lt modifiers no pt-br sv \
ar de en-us fi fr-be hr it lv nl pl ru th \
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-ne2k_pci.bin pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin \
bamboo.dtb petalogix-s3adsp1800.dtb \
multiboot.bin
else
BLOBS=
endif
install-doc: $(DOCS)
$(INSTALL_DIR) "$(DESTDIR)$(docdir)"
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
install: all
mkdir -p "$(bindir)"
install -m 755 -s $(TOOLS) "$(bindir)"
mkdir -p "$(datadir)"
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \
pc-bios/vgabios-cirrus.bin \
pc-bios/ppc_rom.bin \
pc-bios/proll.elf \
pc-bios/linux_boot.bin "$(datadir)"
mkdir -p "$(docdir)"
install -m 644 qemu-doc.html qemu-tech.html "$(docdir)"
ifndef CONFIG_WIN32
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
mkdir -p "$(mandir)/man1"
install qemu.1 qemu-img.1 "$(mandir)/man1"
mkdir -p "$(datadir)/keymaps"
install -m 644 $(addprefix keymaps/,$(KEYMAPS)) "$(datadir)/keymaps"
endif
install: all $(if $(BUILD_DOCS),install-doc)
$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
ifneq ($(TOOLS),)
$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
endif
ifneq ($(BLOBS),)
$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
set -e; for x in $(BLOBS); do \
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
done
endif
$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
set -e; for x in $(KEYMAPS); do \
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
done
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
ifdef CONFIG_KQEMU
cd kqemu ; ./install.sh
endif
# various test targets
test speed: all
test speed test2: all
$(MAKE) -C tests $@
TAGS:
etags *.[ch] tests/*.[ch] block/*.[ch] hw/*.[ch]
cscope:
rm -f ./cscope.*
find . -name "*.[ch]" -print | sed 's,^\./,,' > ./cscope.files
cscope -b
TAGS:
etags *.[ch] tests/*.[ch]
# documentation
%.html: %.texi
$(call quiet-command,texi2html -I=. -monolithic -number $<," GEN $@")
texi2html -monolithic -number $<
%.info: %.texi
$(call quiet-command,makeinfo -I . $< -o $@," GEN $@")
qemu.1: qemu-doc.texi
./texi2pod.pl $< qemu.pod
pod2man --section=1 --center=" " --release=" " qemu.pod > $@
%.dvi: %.texi
$(call quiet-command,texi2dvi -I . $<," GEN $@")
qemu-img.1: qemu-img.texi
./texi2pod.pl $< qemu-img.pod
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
qemu-options.texi: $(SRC_PATH)/qemu-options.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
qemu-monitor.texi: $(SRC_PATH)/qemu-monitor.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu.pod && \
pod2man --section=1 --center=" " --release=" " qemu.pod > $@, \
" GEN $@")
qemu-img.1: qemu-img.texi qemu-img-cmds.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-img.pod && \
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@, \
" GEN $@")
qemu-nbd.8: qemu-nbd.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-nbd.pod && \
pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
" GEN $@")
info: qemu-doc.info qemu-tech.info
dvi: qemu-doc.dvi qemu-tech.dvi
html: qemu-doc.html qemu-tech.html
qemu-doc.dvi qemu-doc.html qemu-doc.info: qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-monitor.texi qemu-img-cmds.texi
VERSION ?= $(shell cat VERSION)
FILE = qemu-$(VERSION)
FILE=qemu-$(shell cat VERSION)
# tar release (use 'make -k tar' on a checkouted tree)
tar:
rm -rf /tmp/$(FILE)
cp -r . /tmp/$(FILE)
cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
rm -rf /tmp/$(FILE)
# generate a binary distribution
tarbin:
cd / && tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \
( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
$(bindir)/qemu \
$(bindir)/qemu-system-x86_64 \
$(bindir)/qemu-system-arm \
$(bindir)/qemu-system-cris \
$(bindir)/qemu-system-m68k \
$(bindir)/qemu-system-mips \
$(bindir)/qemu-system-mipsel \
$(bindir)/qemu-system-mips64 \
$(bindir)/qemu-system-mips64el \
$(bindir)/qemu-system-ppc \
$(bindir)/qemu-system-ppcemb \
$(bindir)/qemu-system-ppc64 \
$(bindir)/qemu-system-sh4 \
$(bindir)/qemu-system-sh4eb \
$(bindir)/qemu-system-sparc \
$(bindir)/qemu-system-x86_64 \
$(bindir)/qemu-i386 \
$(bindir)/qemu-x86_64 \
$(bindir)/qemu-alpha \
$(bindir)/qemu-arm \
$(bindir)/qemu-armeb \
$(bindir)/qemu-cris \
$(bindir)/qemu-m68k \
$(bindir)/qemu-mips \
$(bindir)/qemu-mipsel \
$(bindir)/qemu-ppc \
$(bindir)/qemu-ppc64 \
$(bindir)/qemu-ppc64abi32 \
$(bindir)/qemu-sh4 \
$(bindir)/qemu-sh4eb \
$(bindir)/qemu-sparc \
$(bindir)/qemu-sparc64 \
$(bindir)/qemu-sparc32plus \
$(bindir)/qemu-img \
$(bindir)/qemu-nbd \
$(bindir)/qemu-arm \
$(bindir)/qemu-sparc \
$(bindir)/qemu-ppc \
$(bindir)/qemu-img \
$(datadir)/bios.bin \
$(datadir)/vgabios.bin \
$(datadir)/vgabios-cirrus.bin \
$(datadir)/ppc_rom.bin \
$(datadir)/video.x \
$(datadir)/openbios-sparc32 \
$(datadir)/openbios-sparc64 \
$(datadir)/openbios-ppc \
$(datadir)/pxe-ne2k_pci.bin \
$(datadir)/pxe-rtl8139.bin \
$(datadir)/pxe-pcnet.bin \
$(datadir)/pxe-e1000.bin \
$(datadir)/proll.elf \
$(datadir)/linux_boot.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 \
$(mandir)/man1/qemu-img.1 \
$(mandir)/man8/qemu-nbd.8
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
# Include automatically generated dependency files
-include $(wildcard *.d audio/*.d slirp/*.d block/*.d)
ifneq ($(wildcard .depend),)
include .depend
endif

View File

@@ -1,38 +0,0 @@
# Makefile for qemu target independent devices.
include config.mak
include ../config-host.mak
include $(SRC_PATH)/rules.mak
.PHONY: all
VPATH=$(SRC_PATH):$(SRC_PATH)/hw
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 += virtio.o virtio-pci.o
obj-y += fw_cfg.o
obj-y += watchdog.o
obj-y += nand.o ecc.o
obj-y += m48t59.o escc.o
# SCSI layer
obj-y += lsi53c895a.o esp.o
obj-y += dma-helpers.o sysbus.o qdev-addr.o
all: $(HWLIB)
# Dummy command so that make thinks it has done something
@true
$(HWLIB): $(obj-y)
clean:
rm -f *.o *.d *.a *~
# Include automatically generated dependency files
-include $(wildcard *.d */*.d)

File diff suppressed because it is too large Load Diff

2
README
View File

@@ -1,3 +1,3 @@
Read the documentation in qemu-doc.html.
Fabrice Bellard.
Fabrice Bellard.

16
README.distrib Normal file
View File

@@ -0,0 +1,16 @@
Information about the various packages used to build the current qemu
x86 binary distribution:
* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
was used to get most of the binary packages.
* wine-20020411 tarball
./configure --prefix=/usr/local/wine-i386
All exe and libs were stripped. Some compile time tools and the
includes were deleted.
* ldconfig was launched to build the library links:
qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache

48
TODO
View File

@@ -1,37 +1,57 @@
General:
-------
- cycle counter for all archs
- cpu_interrupt() win32/SMP fix
short term:
----------
- debug option in 'configure' script + disable -fomit-frame-pointer
- Precise VGA timings for old games/demos (malc patch)
- merge PIC spurious interrupt patch
- merge Solaris patch
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
- config file (at least for windows/Mac OS X)
- commit message if execution of code in IO memory
- update doc: PCI infos.
- VNC patch + Synaptic patch.
- basic VGA optimizations
- better code fetch
- physical memory cache (reduce qemu-fast address space size to about 32 MB)
- better code fetch (different exception handling + CS.limit support)
- do not resize vga if invalid size.
- avoid looping if only exceptions
- cycle counter for all archs
- TLB code protection support for PPC
- see openMosix Doc
- disable SMC handling for ARM/SPARC/PPC (not finished)
- see undefined flags for BTx insn
- user/kernel PUSHL/POPL in helper.c
- keyboard output buffer filling timing emulation
- return UD exception if LOCK prefix incorrectly used
- test ldt limit < 7 ?
- tests for each target CPU
- fix CCOP optimisation
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
- fix arm fpu rounding (at least for float->integer conversions)
- SMP support
ppc specific:
------------
- TLB invalidate not needed if msr_pr changes
- SPR_ENCODE() not useful
- enable shift optimizations ?
linux-user specific:
-------------------
- remove threading support as it cannot work at this point
- improve IPC syscalls
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
issues, fix 16 bit uid issues)
- use kernel traps for unaligned accesses on ARM ?
lower priority:
--------------
- more friendly BIOS (logo)
- int15 ah=86: use better timing
- suppress shift_mem ops
- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret)
- optimize FPU operations (evaluate x87 stack pointer statically)
- add IPC syscalls
- use -msoft-float on ARM
- use kernel traps for unaligned accesses on ARM ?
- handle rare page fault cases (in particular if page fault in helpers or
in syscall emulation code).
- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
issues, fix 16 bit uid issues)
- use page_unprotect_range in every suitable syscall to handle all
cases of self modifying code.
- use gcc as a backend to generate better code (easy to do by using
op-i386.c operations as local inline functions).

View File

@@ -1 +1 @@
0.11.1
0.7.0

105
a.out.h
View File

@@ -25,9 +25,9 @@ extern "C" {
struct external_filehdr {
short f_magic; /* magic number */
short f_nscns; /* number of sections */
host_ulong f_timdat; /* time & date stamp */
host_ulong f_symptr; /* file pointer to symtab */
host_ulong f_nsyms; /* number of symtab entries */
unsigned long f_timdat; /* time & date stamp */
unsigned long f_symptr; /* file pointer to symtab */
unsigned long f_nsyms; /* number of symtab entries */
short f_opthdr; /* sizeof(optional hdr) */
short f_flags; /* flags */
};
@@ -72,12 +72,12 @@ typedef struct
{
unsigned short magic; /* type of file */
unsigned short vstamp; /* version stamp */
host_ulong tsize; /* text size in bytes, padded to FW bdry*/
host_ulong dsize; /* initialized data " " */
host_ulong bsize; /* uninitialized data " " */
host_ulong entry; /* entry pt. */
host_ulong text_start; /* base of text used for this file */
host_ulong data_start; /* base of data used for this file=
unsigned long tsize; /* text size in bytes, padded to FW bdry*/
unsigned long dsize; /* initialized data " " */
unsigned long bsize; /* uninitialized data " " */
unsigned long entry; /* entry pt. */
unsigned long text_start; /* base of text used for this file */
unsigned long data_start; /* base of data used for this file=
*/
}
AOUTHDR;
@@ -103,16 +103,16 @@ AOUTHDR;
struct external_scnhdr {
char s_name[8]; /* section name */
host_ulong s_paddr; /* physical address, offset
unsigned long s_paddr; /* physical address, offset
of last addr in scn */
host_ulong s_vaddr; /* virtual address */
host_ulong s_size; /* section size */
host_ulong s_scnptr; /* file ptr to raw data for section */
host_ulong s_relptr; /* file ptr to relocation */
host_ulong s_lnnoptr; /* file ptr to line numbers */
unsigned long s_vaddr; /* virtual address */
unsigned long s_size; /* section size */
unsigned long s_scnptr; /* file ptr to raw data for section */
unsigned long s_relptr; /* file ptr to relocation */
unsigned long s_lnnoptr; /* file ptr to line numbers */
unsigned short s_nreloc; /* number of relocation entries */
unsigned short s_nlnno; /* number of line number entries*/
host_ulong s_flags; /* flags */
unsigned long s_flags; /* flags */
};
#define SCNHDR struct external_scnhdr
@@ -136,8 +136,8 @@ struct external_scnhdr {
*/
struct external_lineno {
union {
host_ulong l_symndx; /* function name symbol index, iff l_lnno 0 */
host_ulong l_paddr; /* (physical) address of line number */
unsigned long l_symndx; /* function name symbol index, iff l_lnno 0 */
unsigned long l_paddr; /* (physical) address of line number */
} l_addr;
unsigned short l_lnno; /* line number */
};
@@ -156,11 +156,11 @@ struct __attribute__((packed)) external_syment
union {
char e_name[E_SYMNMLEN];
struct {
host_ulong e_zeroes;
host_ulong e_offset;
unsigned long e_zeroes;
unsigned long e_offset;
} e;
} e;
host_ulong e_value;
unsigned long e_value;
unsigned short e_scnum;
unsigned short e_type;
char e_sclass[1];
@@ -174,18 +174,18 @@ struct __attribute__((packed)) external_syment
union external_auxent {
struct {
host_ulong x_tagndx; /* str, un, or enum tag indx */
unsigned long x_tagndx; /* str, un, or enum tag indx */
union {
struct {
unsigned short x_lnno; /* declaration line number */
unsigned short x_size; /* str/union/array size */
} x_lnsz;
host_ulong x_fsize; /* size of function */
unsigned long x_fsize; /* size of function */
} x_misc;
union {
struct { /* if ISFCN, tag, or .bb */
host_ulong x_lnnoptr;/* ptr to fcn line # */
host_ulong x_endndx; /* entry ndx past block end */
unsigned long x_lnnoptr;/* ptr to fcn line # */
unsigned long x_endndx; /* entry ndx past block end */
} x_fcn;
struct { /* if ISARY, up to 4 dimen. */
char x_dimen[E_DIMNUM][2];
@@ -197,22 +197,22 @@ union external_auxent {
union {
char x_fname[E_FILNMLEN];
struct {
host_ulong x_zeroes;
host_ulong x_offset;
unsigned long x_zeroes;
unsigned long x_offset;
} x_n;
} x_file;
struct {
host_ulong x_scnlen; /* section length */
unsigned long x_scnlen; /* section length */
unsigned short x_nreloc; /* # relocation entries */
unsigned short x_nlinno; /* # line numbers */
host_ulong x_checksum; /* section COMDAT checksum */
unsigned long x_checksum; /* section COMDAT checksum */
unsigned short x_associated;/* COMDAT associated section index */
char x_comdat[1]; /* COMDAT selection number */
} x_scn;
struct {
host_ulong x_tvfill; /* tv fill value */
unsigned long x_tvfill; /* tv fill value */
unsigned short x_tvlen; /* length of .tv */
char x_tvran[2][2]; /* tv range */
} x_tv; /* info about .tv section (in auxent of symbol .tv)) */
@@ -344,7 +344,7 @@ struct external_PE_filehdr
unsigned short e_oemid; /* OEM identifier (for e_oeminfo), 0x0 */
unsigned short e_oeminfo; /* OEM information; e_oemid specific, 0x0 */
char e_res2[10][2]; /* Reserved words, all 0x0 */
host_ulong e_lfanew; /* File address of new exe header, 0x80 */
unsigned long e_lfanew; /* File address of new exe header, 0x80 */
char dos_message[16][4]; /* other stuff, always follow DOS header */
unsigned int nt_signature; /* required NT signature, 0x4550 */
@@ -352,9 +352,9 @@ struct external_PE_filehdr
unsigned short f_magic; /* magic number */
unsigned short f_nscns; /* number of sections */
host_ulong f_timdat; /* time & date stamp */
host_ulong f_symptr; /* file pointer to symtab */
host_ulong f_nsyms; /* number of symtab entries */
unsigned long f_timdat; /* time & date stamp */
unsigned long f_symptr; /* file pointer to symtab */
unsigned long f_nsyms; /* number of symtab entries */
unsigned short f_opthdr; /* sizeof(optional hdr) */
unsigned short f_flags; /* flags */
};
@@ -370,17 +370,17 @@ typedef struct
{
unsigned short magic; /* type of file */
unsigned short vstamp; /* version stamp */
host_ulong tsize; /* text size in bytes, padded to FW bdry*/
host_ulong dsize; /* initialized data " " */
host_ulong bsize; /* uninitialized data " " */
host_ulong entry; /* entry pt. */
host_ulong text_start; /* base of text used for this file */
host_ulong data_start; /* base of all data used for this file */
unsigned long tsize; /* text size in bytes, padded to FW bdry*/
unsigned long dsize; /* initialized data " " */
unsigned long bsize; /* uninitialized data " " */
unsigned long entry; /* entry pt. */
unsigned long text_start; /* base of text used for this file */
unsigned long data_start; /* base of all data used for this file */
/* NT extra fields; see internal.h for descriptions */
host_ulong ImageBase;
host_ulong SectionAlignment;
host_ulong FileAlignment;
unsigned long ImageBase;
unsigned long SectionAlignment;
unsigned long FileAlignment;
unsigned short MajorOperatingSystemVersion;
unsigned short MinorOperatingSystemVersion;
unsigned short MajorImageVersion;
@@ -388,17 +388,17 @@ typedef struct
unsigned short MajorSubsystemVersion;
unsigned short MinorSubsystemVersion;
char Reserved1[4];
host_ulong SizeOfImage;
host_ulong SizeOfHeaders;
host_ulong CheckSum;
unsigned long SizeOfImage;
unsigned long SizeOfHeaders;
unsigned long CheckSum;
unsigned short Subsystem;
unsigned short DllCharacteristics;
host_ulong SizeOfStackReserve;
host_ulong SizeOfStackCommit;
host_ulong SizeOfHeapReserve;
host_ulong SizeOfHeapCommit;
host_ulong LoaderFlags;
host_ulong NumberOfRvaAndSizes;
unsigned long SizeOfStackReserve;
unsigned long SizeOfStackCommit;
unsigned long SizeOfHeapReserve;
unsigned long SizeOfHeapCommit;
unsigned long LoaderFlags;
unsigned long NumberOfRvaAndSizes;
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
@@ -428,3 +428,4 @@ typedef struct
#endif
#endif /* _A_OUT_H_ */

185
acl.c
View File

@@ -1,185 +0,0 @@
/*
* QEMU access control list management
*
* Copyright (C) 2009 Red Hat, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "sysemu.h"
#include "acl.h"
#ifdef HAVE_FNMATCH_H
#include <fnmatch.h>
#endif
static unsigned int nacls = 0;
static qemu_acl **acls = NULL;
qemu_acl *qemu_acl_find(const char *aclname)
{
int i;
for (i = 0 ; i < nacls ; i++) {
if (strcmp(acls[i]->aclname, aclname) == 0)
return acls[i];
}
return NULL;
}
qemu_acl *qemu_acl_init(const char *aclname)
{
qemu_acl *acl;
acl = qemu_acl_find(aclname);
if (acl)
return acl;
acl = qemu_malloc(sizeof(*acl));
acl->aclname = qemu_strdup(aclname);
/* Deny by default, so there is no window of "open
* access" between QEMU starting, and the user setting
* up ACLs in the monitor */
acl->defaultDeny = 1;
acl->nentries = 0;
TAILQ_INIT(&acl->entries);
acls = qemu_realloc(acls, sizeof(*acls) * (nacls +1));
acls[nacls] = acl;
nacls++;
return acl;
}
int qemu_acl_party_is_allowed(qemu_acl *acl,
const char *party)
{
qemu_acl_entry *entry;
TAILQ_FOREACH(entry, &acl->entries, next) {
#ifdef HAVE_FNMATCH_H
if (fnmatch(entry->match, party, 0) == 0)
return entry->deny ? 0 : 1;
#else
/* No fnmatch, so fallback to exact string matching
* instead of allowing wildcards */
if (strcmp(entry->match, party) == 0)
return entry->deny ? 0 : 1;
#endif
}
return acl->defaultDeny ? 0 : 1;
}
void qemu_acl_reset(qemu_acl *acl)
{
qemu_acl_entry *entry;
/* Put back to deny by default, so there is no window
* of "open access" while the user re-initializes the
* access control list */
acl->defaultDeny = 1;
TAILQ_FOREACH(entry, &acl->entries, next) {
TAILQ_REMOVE(&acl->entries, entry, next);
free(entry->match);
free(entry);
}
acl->nentries = 0;
}
int qemu_acl_append(qemu_acl *acl,
int deny,
const char *match)
{
qemu_acl_entry *entry;
entry = qemu_malloc(sizeof(*entry));
entry->match = qemu_strdup(match);
entry->deny = deny;
TAILQ_INSERT_TAIL(&acl->entries, entry, next);
acl->nentries++;
return acl->nentries;
}
int qemu_acl_insert(qemu_acl *acl,
int deny,
const char *match,
int index)
{
qemu_acl_entry *entry;
qemu_acl_entry *tmp;
int i = 0;
if (index <= 0)
return -1;
if (index >= acl->nentries)
return qemu_acl_append(acl, deny, match);
entry = qemu_malloc(sizeof(*entry));
entry->match = qemu_strdup(match);
entry->deny = deny;
TAILQ_FOREACH(tmp, &acl->entries, next) {
i++;
if (i == index) {
TAILQ_INSERT_BEFORE(tmp, entry, next);
acl->nentries++;
break;
}
}
return i;
}
int qemu_acl_remove(qemu_acl *acl,
const char *match)
{
qemu_acl_entry *entry;
int i = 0;
TAILQ_FOREACH(entry, &acl->entries, next) {
i++;
if (strcmp(entry->match, match) == 0) {
TAILQ_REMOVE(&acl->entries, entry, next);
return i;
}
}
return -1;
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 8
* End:
*/

74
acl.h
View File

@@ -1,74 +0,0 @@
/*
* QEMU access control list management
*
* Copyright (C) 2009 Red Hat, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __QEMU_ACL_H__
#define __QEMU_ACL_H__
#include "sys-queue.h"
typedef struct qemu_acl_entry qemu_acl_entry;
typedef struct qemu_acl qemu_acl;
struct qemu_acl_entry {
char *match;
int deny;
TAILQ_ENTRY(qemu_acl_entry) next;
};
struct qemu_acl {
char *aclname;
unsigned int nentries;
TAILQ_HEAD(,qemu_acl_entry) entries;
int defaultDeny;
};
qemu_acl *qemu_acl_init(const char *aclname);
qemu_acl *qemu_acl_find(const char *aclname);
int qemu_acl_party_is_allowed(qemu_acl *acl,
const char *party);
void qemu_acl_reset(qemu_acl *acl);
int qemu_acl_append(qemu_acl *acl,
int deny,
const char *match);
int qemu_acl_insert(qemu_acl *acl,
int deny,
const char *match,
int index);
int qemu_acl_remove(qemu_acl *acl,
const char *match);
#endif /* __QEMU_ACL_H__ */
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 8
* End:
*/

17
aes.c
View File

@@ -1,5 +1,5 @@
/**
*
*
* aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project.
*/
/*
@@ -27,17 +27,20 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "qemu-common.h"
#include "vl.h"
#include "aes.h"
#ifndef NDEBUG
#define NDEBUG
#endif
#include <assert.h>
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
#define MAXKC (256/32)
#define MAXKB (256/8)
#define MAXNR 14
/* This controls loop-unrolling in aes_core.c */
#undef FULL_UNROLL
# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
@@ -1264,7 +1267,7 @@ void AES_decrypt(const unsigned char *in, unsigned char *out,
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
const unsigned long length, const AES_KEY *key,
unsigned char *ivec, const int enc)
unsigned char *ivec, const int enc)
{
unsigned long n;
@@ -1291,7 +1294,7 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
AES_encrypt(tmp, tmp, key);
memcpy(out, tmp, AES_BLOCK_SIZE);
memcpy(ivec, tmp, AES_BLOCK_SIZE);
}
}
} else {
while (len >= AES_BLOCK_SIZE) {
memcpy(tmp, in, AES_BLOCK_SIZE);
@@ -1309,6 +1312,6 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
for(n=0; n < len; ++n)
out[n] = tmp[n] ^ ivec[n];
memcpy(ivec, tmp, AES_BLOCK_SIZE);
}
}
}
}

198
aio.c
View File

@@ -1,198 +0,0 @@
/*
* QEMU aio implementation
*
* 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.
*
*/
#include "qemu-common.h"
#include "block.h"
#include "sys-queue.h"
#include "qemu_socket.h"
typedef struct AioHandler AioHandler;
/* The list of registered 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
* dispatching callbacks.
*/
static int walking_handlers;
struct AioHandler
{
int fd;
IOHandler *io_read;
IOHandler *io_write;
AioFlushHandler *io_flush;
int deleted;
void *opaque;
LIST_ENTRY(AioHandler) node;
};
static AioHandler *find_aio_handler(int fd)
{
AioHandler *node;
LIST_FOREACH(node, &aio_handlers, node) {
if (node->fd == fd)
if (!node->deleted)
return node;
}
return NULL;
}
int qemu_aio_set_fd_handler(int fd,
IOHandler *io_read,
IOHandler *io_write,
AioFlushHandler *io_flush,
void *opaque)
{
AioHandler *node;
node = find_aio_handler(fd);
/* Are we deleting the fd handler? */
if (!io_read && !io_write) {
if (node) {
/* If the lock is held, just mark the node as deleted */
if (walking_handlers)
node->deleted = 1;
else {
/* Otherwise, delete it for real. We can't just mark it as
* deleted because deleted nodes are only cleaned up after
* releasing the walking_handlers lock.
*/
LIST_REMOVE(node, node);
qemu_free(node);
}
}
} else {
if (node == NULL) {
/* Alloc and insert if it's not already there */
node = qemu_mallocz(sizeof(AioHandler));
node->fd = fd;
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->opaque = opaque;
}
qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
return 0;
}
void qemu_aio_flush(void)
{
AioHandler *node;
int ret;
do {
ret = 0;
/*
* If there are pending emulated aio start them now so flush
* will be able to return 1.
*/
qemu_aio_wait();
LIST_FOREACH(node, &aio_handlers, node) {
ret |= node->io_flush(node->opaque);
}
} while (qemu_bh_poll() || ret > 0);
}
void qemu_aio_wait(void)
{
int ret;
if (qemu_bh_poll())
return;
do {
AioHandler *node;
fd_set rdfds, wrfds;
int max_fd = -1;
walking_handlers = 1;
FD_ZERO(&rdfds);
FD_ZERO(&wrfds);
/* fill fd sets */
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.
*/
if (node->io_flush && node->io_flush(node->opaque) == 0)
continue;
if (!node->deleted && node->io_read) {
FD_SET(node->fd, &rdfds);
max_fd = MAX(max_fd, node->fd + 1);
}
if (!node->deleted && node->io_write) {
FD_SET(node->fd, &wrfds);
max_fd = MAX(max_fd, node->fd + 1);
}
}
walking_handlers = 0;
/* No AIO operations? Get us out of here */
if (max_fd == -1)
break;
/* wait until next event */
ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
if (ret == -1 && errno == EINTR)
continue;
/* if we have any readable fds, dispatch event */
if (ret > 0) {
walking_handlers = 1;
/* we have to walk very carefully in case
* qemu_aio_set_fd_handler is called while we're walking */
node = LIST_FIRST(&aio_handlers);
while (node) {
AioHandler *tmp;
if (!node->deleted &&
FD_ISSET(node->fd, &rdfds) &&
node->io_read) {
node->io_read(node->opaque);
}
if (!node->deleted &&
FD_ISSET(node->fd, &wrfds) &&
node->io_write) {
node->io_write(node->opaque);
}
tmp = node;
node = LIST_NEXT(node, node);
if (tmp->deleted) {
LIST_REMOVE(tmp, node);
qemu_free(tmp);
}
}
walking_handlers = 0;
}
} while (ret == 0);
}

View File

@@ -16,12 +16,16 @@ 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 file; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
along with this file; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include <stdio.h>
#include "dis-asm.h"
#define ATTRIBUTE_UNUSED __attribute__((unused))
#define _(x) x
/* The opcode table is an array of struct alpha_opcode. */
struct alpha_opcode
@@ -373,7 +377,7 @@ const struct alpha_operand alpha_operands[] =
/* The signed "23-bit" aligned displacement of Branch format insns */
#define BDISP (MDISP + 1)
{ 21, 0, BFD_RELOC_23_PCREL_S2,
{ 21, 0, BFD_RELOC_23_PCREL_S2,
AXP_OPERAND_RELATIVE, insert_bdisp, extract_bdisp },
/* The 26-bit PALcode function */

5101
arm-dis.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,468 +0,0 @@
/*
* Arm "Angel" semihosting syscalls
*
* Copyright (c) 2005, 2007 CodeSourcery.
* Written by Paul Brook.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "cpu.h"
#ifdef CONFIG_USER_ONLY
#include "qemu.h"
#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
#else
#include "qemu-common.h"
#include "sysemu.h"
#include "gdbstub.h"
#endif
#define SYS_OPEN 0x01
#define SYS_CLOSE 0x02
#define SYS_WRITEC 0x03
#define SYS_WRITE0 0x04
#define SYS_WRITE 0x05
#define SYS_READ 0x06
#define SYS_READC 0x07
#define SYS_ISTTY 0x09
#define SYS_SEEK 0x0a
#define SYS_FLEN 0x0c
#define SYS_TMPNAM 0x0d
#define SYS_REMOVE 0x0e
#define SYS_RENAME 0x0f
#define SYS_CLOCK 0x10
#define SYS_TIME 0x11
#define SYS_SYSTEM 0x12
#define SYS_ERRNO 0x13
#define SYS_GET_CMDLINE 0x15
#define SYS_HEAPINFO 0x16
#define SYS_EXIT 0x18
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define GDB_O_RDONLY 0x000
#define GDB_O_WRONLY 0x001
#define GDB_O_RDWR 0x002
#define GDB_O_APPEND 0x008
#define GDB_O_CREAT 0x200
#define GDB_O_TRUNC 0x400
#define GDB_O_BINARY 0
static int gdb_open_modeflags[12] = {
GDB_O_RDONLY,
GDB_O_RDONLY | GDB_O_BINARY,
GDB_O_RDWR,
GDB_O_RDWR | GDB_O_BINARY,
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
};
static int open_modeflags[12] = {
O_RDONLY,
O_RDONLY | O_BINARY,
O_RDWR,
O_RDWR | O_BINARY,
O_WRONLY | O_CREAT | O_TRUNC,
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
O_RDWR | O_CREAT | O_TRUNC,
O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
O_WRONLY | O_CREAT | O_APPEND,
O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
O_RDWR | O_CREAT | O_APPEND,
O_RDWR | O_CREAT | O_APPEND | O_BINARY
};
#ifdef CONFIG_USER_ONLY
static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
{
if (code == (uint32_t)-1)
ts->swi_errno = errno;
return code;
}
#else
static inline uint32_t set_swi_errno(CPUState *env, uint32_t code)
{
return code;
}
#include "softmmu-semi.h"
#endif
static target_ulong arm_semi_syscall_len;
#if !defined(CONFIG_USER_ONLY)
static target_ulong syscall_err;
#endif
static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
{
#ifdef CONFIG_USER_ONLY
TaskState *ts = env->opaque;
#endif
if (ret == (target_ulong)-1) {
#ifdef CONFIG_USER_ONLY
ts->swi_errno = err;
#else
syscall_err = err;
#endif
env->regs[0] = ret;
} else {
/* Fixup syscalls that use nonstardard return conventions. */
switch (env->regs[0]) {
case SYS_WRITE:
case SYS_READ:
env->regs[0] = arm_semi_syscall_len - ret;
break;
case SYS_SEEK:
env->regs[0] = 0;
break;
default:
env->regs[0] = ret;
break;
}
}
}
static void arm_semi_flen_cb(CPUState *env, target_ulong ret, target_ulong err)
{
/* The size is always stored in big-endian order, extract
the value. We assume the size always fit in 32 bits. */
uint32_t size;
cpu_memory_rw_debug(env, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
env->regs[0] = be32_to_cpu(size);
#ifdef CONFIG_USER_ONLY
((TaskState *)env->opaque)->swi_errno = err;
#else
syscall_err = err;
#endif
}
#define ARG(n) \
({ \
target_ulong __arg; \
/* FIXME - handle get_user() failure */ \
get_user_ual(__arg, args + (n) * 4); \
__arg; \
})
#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
uint32_t do_arm_semihosting(CPUState *env)
{
target_ulong args;
char * s;
int nr;
uint32_t ret;
uint32_t len;
#ifdef CONFIG_USER_ONLY
TaskState *ts = env->opaque;
#else
CPUState *ts = env;
#endif
nr = env->regs[0];
args = env->regs[1];
switch (nr) {
case SYS_OPEN:
if (!(s = lock_user_string(ARG(0))))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
if (ARG(1) >= 12)
return (uint32_t)-1;
if (strcmp(s, ":tt") == 0) {
if (ARG(1) < 4)
return STDIN_FILENO;
else
return STDOUT_FILENO;
}
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0),
(int)ARG(2)+1, gdb_open_modeflags[ARG(1)]);
return env->regs[0];
} else {
ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
}
unlock_user(s, ARG(0), 0);
return ret;
case SYS_CLOSE:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0));
return env->regs[0];
} else {
return set_swi_errno(ts, close(ARG(0)));
}
case SYS_WRITEC:
{
char c;
if (get_user_u8(c, args))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
/* Write to debug console. stderr is near enough. */
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
return env->regs[0];
} else {
return write(STDERR_FILENO, &c, 1);
}
}
case SYS_WRITE0:
if (!(s = lock_user_string(args)))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
len = strlen(s);
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
ret = env->regs[0];
} else {
ret = write(STDERR_FILENO, s, len);
}
unlock_user(s, args, 0);
return ret;
case SYS_WRITE:
len = ARG(2);
if (use_gdb_syscalls()) {
arm_semi_syscall_len = len;
gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len);
return env->regs[0];
} else {
if (!(s = lock_user(VERIFY_READ, ARG(1), len, 1)))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
ret = set_swi_errno(ts, write(ARG(0), s, len));
unlock_user(s, ARG(1), 0);
if (ret == (uint32_t)-1)
return -1;
return len - ret;
}
case SYS_READ:
len = ARG(2);
if (use_gdb_syscalls()) {
arm_semi_syscall_len = len;
gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len);
return env->regs[0];
} else {
if (!(s = lock_user(VERIFY_WRITE, ARG(1), len, 0)))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
do
ret = set_swi_errno(ts, read(ARG(0), s, len));
while (ret == -1 && errno == EINTR);
unlock_user(s, ARG(1), len);
if (ret == (uint32_t)-1)
return -1;
return len - ret;
}
case SYS_READC:
/* XXX: Read from debug cosole. Not implemented. */
return 0;
case SYS_ISTTY:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0));
return env->regs[0];
} else {
return isatty(ARG(0));
}
case SYS_SEEK:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", ARG(0), ARG(1));
return env->regs[0];
} else {
ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
if (ret == (uint32_t)-1)
return -1;
return 0;
}
case SYS_FLEN:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
ARG(0), env->regs[13]-64);
return env->regs[0];
} else {
struct stat buf;
ret = set_swi_errno(ts, fstat(ARG(0), &buf));
if (ret == (uint32_t)-1)
return -1;
return buf.st_size;
}
case SYS_TMPNAM:
/* XXX: Not implemented. */
return -1;
case SYS_REMOVE:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1);
ret = env->regs[0];
} else {
if (!(s = lock_user_string(ARG(0))))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
ret = set_swi_errno(ts, remove(s));
unlock_user(s, ARG(0), 0);
}
return ret;
case SYS_RENAME:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
ARG(0), (int)ARG(1)+1, ARG(2), (int)ARG(3)+1);
return env->regs[0];
} else {
char *s2;
s = lock_user_string(ARG(0));
s2 = lock_user_string(ARG(2));
if (!s || !s2)
/* FIXME - should this error code be -TARGET_EFAULT ? */
ret = (uint32_t)-1;
else
ret = set_swi_errno(ts, rename(s, s2));
if (s2)
unlock_user(s2, ARG(2), 0);
if (s)
unlock_user(s, ARG(0), 0);
return ret;
}
case SYS_CLOCK:
return clock() / (CLOCKS_PER_SEC / 100);
case SYS_TIME:
return set_swi_errno(ts, time(NULL));
case SYS_SYSTEM:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1);
return env->regs[0];
} else {
if (!(s = lock_user_string(ARG(0))))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
ret = set_swi_errno(ts, system(s));
unlock_user(s, ARG(0), 0);
return ret;
}
case SYS_ERRNO:
#ifdef CONFIG_USER_ONLY
return ts->swi_errno;
#else
return syscall_err;
#endif
case SYS_GET_CMDLINE:
#ifdef CONFIG_USER_ONLY
/* Build a commandline from the original argv. */
{
char **arg = ts->info->host_argv;
int len = ARG(1);
/* lock the buffer on the ARM side */
char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0);
if (!cmdline_buffer)
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
s = cmdline_buffer;
while (*arg && len > 2) {
int n = strlen(*arg);
if (s != cmdline_buffer) {
*(s++) = ' ';
len--;
}
if (n >= len)
n = len - 1;
memcpy(s, *arg, n);
s += n;
len -= n;
arg++;
}
/* Null terminate the string. */
*s = 0;
len = s - cmdline_buffer;
/* Unlock the buffer on the ARM side. */
unlock_user(cmdline_buffer, ARG(0), len);
/* Adjust the commandline length argument. */
SET_ARG(1, len);
/* Return success if commandline fit into buffer. */
return *arg ? -1 : 0;
}
#else
return -1;
#endif
case SYS_HEAPINFO:
{
uint32_t *ptr;
uint32_t limit;
#ifdef CONFIG_USER_ONLY
/* Some C libraries assume the heap immediately follows .bss, so
allocate it using sbrk. */
if (!ts->heap_limit) {
long ret;
ts->heap_base = do_brk(0);
limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
/* Try a big heap, and reduce the size if that fails. */
for (;;) {
ret = do_brk(limit);
if (ret != -1)
break;
limit = (ts->heap_base >> 1) + (limit >> 1);
}
ts->heap_limit = limit;
}
if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
ptr[0] = tswap32(ts->heap_base);
ptr[1] = tswap32(ts->heap_limit);
ptr[2] = tswap32(ts->stack_base);
ptr[3] = tswap32(0); /* Stack limit. */
unlock_user(ptr, ARG(0), 16);
#else
limit = ram_size;
if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
/* TODO: Make this use the limit of the loaded application. */
ptr[0] = tswap32(limit / 2);
ptr[1] = tswap32(limit);
ptr[2] = tswap32(limit); /* Stack base */
ptr[3] = tswap32(0); /* Stack limit. */
unlock_user(ptr, ARG(0), 16);
#endif
return 0;
}
case SYS_EXIT:
exit(0);
default:
fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
cpu_dump_state(env, stderr, fprintf, 0);
abort();
}
}

26
arm.ld
View File

@@ -53,43 +53,17 @@ SECTIONS
.fini : { *(.fini) } =0x47ff041f
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
__exidx_start = .;
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
__exidx_end = .;
.reginfo : { *(.reginfo) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(0x100000) + (. & (0x100000 - 1));
.data :
{
*(.gen_code)
*(.data)
*(.gnu.linkonce.d*)
CONSTRUCTORS
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.data1 : { *(.data1) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
*(.ctors)

View File

@@ -1,952 +0,0 @@
/*
* QEMU ALSA audio driver
*
* Copyright (c) 2005 Vassili Karpov (malc)
*
* 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 <alsa/asoundlib.h>
#include "qemu-common.h"
#include "audio.h"
#if QEMU_GNUC_PREREQ(4, 3)
#pragma GCC diagnostic ignored "-Waddress"
#endif
#define AUDIO_CAP "alsa"
#include "audio_int.h"
typedef struct ALSAVoiceOut {
HWVoiceOut hw;
void *pcm_buf;
snd_pcm_t *handle;
} ALSAVoiceOut;
typedef struct ALSAVoiceIn {
HWVoiceIn hw;
snd_pcm_t *handle;
void *pcm_buf;
} ALSAVoiceIn;
static struct {
int size_in_usec_in;
int size_in_usec_out;
const char *pcm_name_in;
const char *pcm_name_out;
unsigned int buffer_size_in;
unsigned int period_size_in;
unsigned int buffer_size_out;
unsigned int period_size_out;
unsigned int threshold;
int buffer_size_in_overridden;
int period_size_in_overridden;
int buffer_size_out_overridden;
int period_size_out_overridden;
int verbose;
} conf = {
.buffer_size_out = 1024,
.pcm_name_out = "default",
.pcm_name_in = "default",
};
struct alsa_params_req {
int freq;
snd_pcm_format_t fmt;
int nchannels;
int size_in_usec;
int override_mask;
unsigned int buffer_size;
unsigned int period_size;
};
struct alsa_params_obt {
int freq;
audfmt_e fmt;
int endianness;
int nchannels;
snd_pcm_uframes_t samples;
};
static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
}
static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
int err,
const char *typ,
const char *fmt,
...
)
{
va_list ap;
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
}
static void alsa_anal_close (snd_pcm_t **handlep)
{
int err = snd_pcm_close (*handlep);
if (err) {
alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
}
*handlep = NULL;
}
static int alsa_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
{
switch (fmt) {
case AUD_FMT_S8:
return SND_PCM_FORMAT_S8;
case AUD_FMT_U8:
return SND_PCM_FORMAT_U8;
case AUD_FMT_S16:
return SND_PCM_FORMAT_S16_LE;
case AUD_FMT_U16:
return SND_PCM_FORMAT_U16_LE;
case AUD_FMT_S32:
return SND_PCM_FORMAT_S32_LE;
case AUD_FMT_U32:
return SND_PCM_FORMAT_U32_LE;
default:
dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_AUDIO
abort ();
#endif
return SND_PCM_FORMAT_U8;
}
}
static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
int *endianness)
{
switch (alsafmt) {
case SND_PCM_FORMAT_S8:
*endianness = 0;
*fmt = AUD_FMT_S8;
break;
case SND_PCM_FORMAT_U8:
*endianness = 0;
*fmt = AUD_FMT_U8;
break;
case SND_PCM_FORMAT_S16_LE:
*endianness = 0;
*fmt = AUD_FMT_S16;
break;
case SND_PCM_FORMAT_U16_LE:
*endianness = 0;
*fmt = AUD_FMT_U16;
break;
case SND_PCM_FORMAT_S16_BE:
*endianness = 1;
*fmt = AUD_FMT_S16;
break;
case SND_PCM_FORMAT_U16_BE:
*endianness = 1;
*fmt = AUD_FMT_U16;
break;
case SND_PCM_FORMAT_S32_LE:
*endianness = 0;
*fmt = AUD_FMT_S32;
break;
case SND_PCM_FORMAT_U32_LE:
*endianness = 0;
*fmt = AUD_FMT_U32;
break;
case SND_PCM_FORMAT_S32_BE:
*endianness = 1;
*fmt = AUD_FMT_S32;
break;
case SND_PCM_FORMAT_U32_BE:
*endianness = 1;
*fmt = AUD_FMT_U32;
break;
default:
dolog ("Unrecognized audio format %d\n", alsafmt);
return -1;
}
return 0;
}
static void alsa_dump_info (struct alsa_params_req *req,
struct alsa_params_obt *obt)
{
dolog ("parameter | requested value | obtained value\n");
dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
dolog ("channels | %10d | %10d\n",
req->nchannels, obt->nchannels);
dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
dolog ("============================================\n");
dolog ("requested: buffer size %d period size %d\n",
req->buffer_size, req->period_size);
dolog ("obtained: samples %ld\n", obt->samples);
}
static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
{
int err;
snd_pcm_sw_params_t *sw_params;
snd_pcm_sw_params_alloca (&sw_params);
err = snd_pcm_sw_params_current (handle, sw_params);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to get current software parameters\n");
return;
}
err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to set software threshold to %ld\n",
threshold);
return;
}
err = snd_pcm_sw_params (handle, sw_params);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to set software parameters\n");
return;
}
}
static int alsa_open (int in, struct alsa_params_req *req,
struct alsa_params_obt *obt, snd_pcm_t **handlep)
{
snd_pcm_t *handle;
snd_pcm_hw_params_t *hw_params;
int err;
int size_in_usec;
unsigned int freq, nchannels;
const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
snd_pcm_uframes_t obt_buffer_size;
const char *typ = in ? "ADC" : "DAC";
snd_pcm_format_t obtfmt;
freq = req->freq;
nchannels = req->nchannels;
size_in_usec = req->size_in_usec;
snd_pcm_hw_params_alloca (&hw_params);
err = snd_pcm_open (
&handle,
pcm_name,
in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK
);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
return -1;
}
err = snd_pcm_hw_params_any (handle, hw_params);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
goto err;
}
err = snd_pcm_hw_params_set_access (
handle,
hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED
);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set access type\n");
goto err;
}
err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
if (err < 0 && conf.verbose) {
alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
}
err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
goto err;
}
err = snd_pcm_hw_params_set_channels_near (
handle,
hw_params,
&nchannels
);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
req->nchannels);
goto err;
}
if (nchannels != 1 && nchannels != 2) {
alsa_logerr2 (err, typ,
"Can not handle obtained number of channels %d\n",
nchannels);
goto err;
}
if (req->buffer_size) {
unsigned long obt;
if (size_in_usec) {
int dir = 0;
unsigned int btime = req->buffer_size;
err = snd_pcm_hw_params_set_buffer_time_near (
handle,
hw_params,
&btime,
&dir
);
obt = btime;
}
else {
snd_pcm_uframes_t bsize = req->buffer_size;
err = snd_pcm_hw_params_set_buffer_size_near (
handle,
hw_params,
&bsize
);
obt = bsize;
}
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
size_in_usec ? "time" : "size", req->buffer_size);
goto err;
}
if ((req->override_mask & 2) && (obt - req->buffer_size))
dolog ("Requested buffer %s %u was rejected, using %lu\n",
size_in_usec ? "time" : "size", req->buffer_size, obt);
}
if (req->period_size) {
unsigned long obt;
if (size_in_usec) {
int dir = 0;
unsigned int ptime = req->period_size;
err = snd_pcm_hw_params_set_period_time_near (
handle,
hw_params,
&ptime,
&dir
);
obt = ptime;
}
else {
int dir = 0;
snd_pcm_uframes_t psize = req->period_size;
err = snd_pcm_hw_params_set_period_size_near (
handle,
hw_params,
&psize,
&dir
);
obt = psize;
}
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
size_in_usec ? "time" : "size", req->period_size);
goto err;
}
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);
}
err = snd_pcm_hw_params (handle, hw_params);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
goto err;
}
err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to get buffer size\n");
goto err;
}
err = snd_pcm_hw_params_get_format (hw_params, &obtfmt);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to get format\n");
goto err;
}
if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
dolog ("Invalid format was returned %d\n", obtfmt);
goto err;
}
err = snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
goto err;
}
if (!in && conf.threshold) {
snd_pcm_uframes_t threshold;
int bytes_per_sec;
bytes_per_sec = freq << (nchannels == 2);
switch (obt->fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
break;
case AUD_FMT_S16:
case AUD_FMT_U16:
bytes_per_sec <<= 1;
break;
case AUD_FMT_S32:
case AUD_FMT_U32:
bytes_per_sec <<= 2;
break;
}
threshold = (conf.threshold * bytes_per_sec) / 1000;
alsa_set_threshold (handle, threshold);
}
obt->nchannels = nchannels;
obt->freq = freq;
obt->samples = obt_buffer_size;
*handlep = handle;
if (conf.verbose &&
(obt->fmt != req->fmt ||
obt->nchannels != req->nchannels ||
obt->freq != req->freq)) {
dolog ("Audio paramters for %s\n", typ);
alsa_dump_info (req, obt);
}
#ifdef DEBUG
alsa_dump_info (req, obt);
#endif
return 0;
err:
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;
avail = snd_pcm_avail_update (handle);
if (avail < 0) {
if (avail == -EPIPE) {
if (!alsa_recover (handle)) {
avail = snd_pcm_avail_update (handle);
}
}
if (avail < 0) {
alsa_logerr (avail,
"Could not obtain number of available frames\n");
return -1;
}
}
return avail;
}
static int alsa_run_out (HWVoiceOut *hw)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
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");
return 0;
}
decr = audio_MIN (live, avail);
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;
}
static void alsa_fini_out (HWVoiceOut *hw)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
ldebug ("alsa_fini\n");
alsa_anal_close (&alsa->handle);
if (alsa->pcm_buf) {
qemu_free (alsa->pcm_buf);
alsa->pcm_buf = NULL;
}
}
static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
struct alsa_params_req req;
struct alsa_params_obt obt;
snd_pcm_t *handle;
struct audsettings obt_as;
req.fmt = aud_to_alsafmt (as->fmt);
req.freq = as->freq;
req.nchannels = as->nchannels;
req.period_size = conf.period_size_out;
req.buffer_size = conf.buffer_size_out;
req.size_in_usec = conf.size_in_usec_out;
req.override_mask =
(conf.period_size_out_overridden ? 1 : 0) |
(conf.buffer_size_out_overridden ? 2 : 0);
if (alsa_open (0, &req, &obt, &handle)) {
return -1;
}
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = obt.fmt;
obt_as.endianness = obt.endianness;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
if (!alsa->pcm_buf) {
dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
alsa_anal_close (&handle);
return -1;
}
alsa->handle = handle;
return 0;
}
static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
{
int err;
if (pause) {
err = snd_pcm_drop (handle);
if (err < 0) {
alsa_logerr (err, "Could not stop %s\n", typ);
return -1;
}
}
else {
err = snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr (err, "Could not prepare handle for %s\n", typ);
return -1;
}
}
return 0;
}
static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
switch (cmd) {
case VOICE_ENABLE:
ldebug ("enabling voice\n");
return alsa_voice_ctl (alsa->handle, "playback", 0);
case VOICE_DISABLE:
ldebug ("disabling voice\n");
return alsa_voice_ctl (alsa->handle, "playback", 1);
}
return -1;
}
static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
struct alsa_params_req req;
struct alsa_params_obt obt;
snd_pcm_t *handle;
struct audsettings obt_as;
req.fmt = aud_to_alsafmt (as->fmt);
req.freq = as->freq;
req.nchannels = as->nchannels;
req.period_size = conf.period_size_in;
req.buffer_size = conf.buffer_size_in;
req.size_in_usec = conf.size_in_usec_in;
req.override_mask =
(conf.period_size_in_overridden ? 1 : 0) |
(conf.buffer_size_in_overridden ? 2 : 0);
if (alsa_open (1, &req, &obt, &handle)) {
return -1;
}
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = obt.fmt;
obt_as.endianness = obt.endianness;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!alsa->pcm_buf) {
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
alsa_anal_close (&handle);
return -1;
}
alsa->handle = handle;
return 0;
}
static void alsa_fini_in (HWVoiceIn *hw)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
alsa_anal_close (&alsa->handle);
if (alsa->pcm_buf) {
qemu_free (alsa->pcm_buf);
alsa->pcm_buf = NULL;
}
}
static int alsa_run_in (HWVoiceIn *hw)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
int hwshift = hw->info.shift;
int i;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
int decr;
struct {
int add;
int len;
} bufs[2] = {
{ hw->wpos, 0 },
{ 0, 0 }
};
snd_pcm_sframes_t avail;
snd_pcm_uframes_t read_samples = 0;
if (!dead) {
return 0;
}
avail = alsa_get_avail (alsa->handle);
if (avail < 0) {
dolog ("Could not get number of captured frames\n");
return 0;
}
if (!avail && (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {
avail = hw->samples;
}
decr = audio_MIN (dead, avail);
if (!decr) {
return 0;
}
if (hw->wpos + decr > hw->samples) {
bufs[0].len = (hw->samples - hw->wpos);
bufs[1].len = (decr - (hw->samples - hw->wpos));
}
else {
bufs[0].len = decr;
}
for (i = 0; i < 2; ++i) {
void *src;
struct st_sample *dst;
snd_pcm_sframes_t nread;
snd_pcm_uframes_t len;
len = bufs[i].len;
src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
dst = hw->conv_buf + bufs[i].add;
while (len) {
nread = snd_pcm_readi (alsa->handle, src, len);
if (nread <= 0) {
switch (nread) {
case 0:
if (conf.verbose) {
dolog ("Failed to read %ld frames (read zero)\n", len);
}
goto exit;
case -EPIPE:
if (alsa_recover (alsa->handle)) {
alsa_logerr (nread, "Failed to read %ld frames\n", len);
goto exit;
}
if (conf.verbose) {
dolog ("Recovering from capture xrun\n");
}
continue;
case -EAGAIN:
goto exit;
default:
alsa_logerr (
nread,
"Failed to read %ld frames from %p\n",
len,
src
);
goto exit;
}
}
hw->conv (dst, src, nread, &nominal_volume);
src = advance (src, nread << hwshift);
dst += nread;
read_samples += nread;
len -= nread;
}
}
exit:
hw->wpos = (hw->wpos + read_samples) % hw->samples;
return read_samples;
}
static int alsa_read (SWVoiceIn *sw, void *buf, int size)
{
return audio_pcm_sw_read (sw, buf, size);
}
static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
switch (cmd) {
case VOICE_ENABLE:
ldebug ("enabling voice\n");
return alsa_voice_ctl (alsa->handle, "capture", 0);
case VOICE_DISABLE:
ldebug ("disabling voice\n");
return alsa_voice_ctl (alsa->handle, "capture", 1);
}
return -1;
}
static void *alsa_audio_init (void)
{
return &conf;
}
static void alsa_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_option alsa_options[] = {
{"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 = {
alsa_init_out,
alsa_fini_out,
alsa_run_out,
alsa_write,
alsa_ctl_out,
alsa_init_in,
alsa_fini_in,
alsa_run_in,
alsa_read,
alsa_ctl_in
};
struct audio_driver alsa_audio_driver = {
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)
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2003-2005 Vassili Karpov (malc)
*
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* 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
@@ -24,122 +24,31 @@
#ifndef QEMU_AUDIO_H
#define QEMU_AUDIO_H
#include "config-host.h"
#include "sys-queue.h"
typedef void (*audio_callback_fn_t) (void *opaque, int avail);
#include "mixeng.h"
typedef enum {
AUD_FMT_U8,
AUD_FMT_S8,
AUD_FMT_U16,
AUD_FMT_S16,
AUD_FMT_U32,
AUD_FMT_S32
AUD_FMT_U8,
AUD_FMT_S8,
AUD_FMT_U16,
AUD_FMT_S16
} audfmt_e;
#ifdef WORDS_BIGENDIAN
#define AUDIO_HOST_ENDIANNESS 1
#else
#define AUDIO_HOST_ENDIANNESS 0
#endif
typedef struct SWVoice SWVoice;
struct audsettings {
int freq;
int nchannels;
audfmt_e fmt;
int endianness;
};
typedef enum {
AUD_CNOTIFY_ENABLE,
AUD_CNOTIFY_DISABLE
} audcnotification_e;
struct audio_capture_ops {
void (*notify) (void *opaque, audcnotification_e cmd);
void (*capture) (void *opaque, void *buf, int size);
void (*destroy) (void *opaque);
};
struct capture_ops {
void (*info) (void *opaque);
void (*destroy) (void *opaque);
};
typedef struct CaptureState {
void *opaque;
struct capture_ops ops;
LIST_ENTRY (CaptureState) entries;
} CaptureState;
typedef struct SWVoiceOut SWVoiceOut;
typedef struct CaptureVoiceOut CaptureVoiceOut;
typedef struct SWVoiceIn SWVoiceIn;
typedef struct QEMUSoundCard {
char *name;
LIST_ENTRY (QEMUSoundCard) entries;
} QEMUSoundCard;
typedef struct QEMUAudioTimeStamp {
uint64_t old_ts;
} QEMUAudioTimeStamp;
void AUD_vlog (const char *cap, const char *fmt, va_list ap);
void AUD_log (const char *cap, const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((__format__ (__printf__, 2, 3)))
#endif
;
void AUD_help (void);
void AUD_register_card (const char *name, QEMUSoundCard *card);
void AUD_remove_card (QEMUSoundCard *card);
CaptureVoiceOut *AUD_add_capture (
struct audsettings *as,
struct audio_capture_ops *ops,
void *opaque
);
void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
SWVoiceOut *AUD_open_out (
QEMUSoundCard *card,
SWVoiceOut *sw,
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
struct audsettings *settings
);
void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
int AUD_write (SWVoiceOut *sw, void *pcm_buf, int size);
int AUD_get_buffer_size_out (SWVoiceOut *sw);
void AUD_set_active_out (SWVoiceOut *sw, int on);
int AUD_is_active_out (SWVoiceOut *sw);
void AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol);
void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol);
SWVoiceIn *AUD_open_in (
QEMUSoundCard *card,
SWVoiceIn *sw,
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
struct audsettings *settings
);
void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size);
void AUD_set_active_in (SWVoiceIn *sw, int on);
int AUD_is_active_in (SWVoiceIn *sw);
void AUD_init_time_stamp_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts);
uint64_t AUD_get_elapsed_usec_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts);
SWVoice * AUD_open (SWVoice *sw, const char *name, int freq,
int nchannels, audfmt_e fmt);
void AUD_init (void);
void AUD_log (const char *cap, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));;
void AUD_close (SWVoice *sw);
int AUD_write (SWVoice *sw, void *pcm_buf, int size);
void AUD_adjust (SWVoice *sw, int leftover);
void AUD_reset (SWVoice *sw);
int AUD_get_free (SWVoice *sw);
int AUD_get_buffer_size (SWVoice *sw);
void AUD_run (void);
void AUD_enable (SWVoice *sw, int on);
int AUD_calc_elapsed (SWVoice *sw);
static inline void *advance (void *p, int incr)
{
@@ -148,26 +57,9 @@ static inline void *advance (void *p, int incr)
}
uint32_t popcount (uint32_t u);
uint32_t lsbindex (uint32_t u);
inline uint32_t lsbindex (uint32_t u);
#ifdef __GNUC__
#define audio_MIN(a, b) ( __extension__ ({ \
__typeof (a) ta = a; \
__typeof (b) tb = b; \
((ta)>(tb)?(tb):(ta)); \
}))
#define audio_MAX(a, b) ( __extension__ ({ \
__typeof (a) ta = a; \
__typeof (b) tb = b; \
((ta)<(tb)?(tb):(ta)); \
}))
#else
#define audio_MIN(a, b) ((a)>(b)?(b):(a))
#define audio_MAX(a, b) ((a)<(b)?(b):(a))
#endif
int wav_start_capture (CaptureState *s, const char *path, int freq,
int bits, int nchannels);
#endif /* audio.h */

View File

@@ -1,8 +1,8 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2003-2005 Vassili Karpov (malc)
*
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* 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
@@ -24,262 +24,140 @@
#ifndef QEMU_AUDIO_INT_H
#define QEMU_AUDIO_INT_H
#ifdef CONFIG_COREAUDIO
#define FLOAT_MIXENG
/* #define RECIPROCAL */
#endif
#include "mixeng.h"
#include "vl.h"
struct audio_pcm_ops;
struct pcm_ops;
typedef enum {
AUD_OPT_INT,
AUD_OPT_FMT,
AUD_OPT_STR,
AUD_OPT_BOOL
} audio_option_tag_e;
struct audio_option {
const char *name;
audio_option_tag_e tag;
void *valp;
const char *descr;
int *overriddenp;
int overridden;
};
struct audio_callback {
void *opaque;
audio_callback_fn_t fn;
};
struct audio_pcm_info {
int bits;
int sign;
int freq;
int nchannels;
int align;
int shift;
int bytes_per_second;
int swap_endianness;
};
typedef struct SWVoiceCap SWVoiceCap;
typedef struct HWVoiceOut {
typedef struct HWVoice {
int active;
int enabled;
int pending_disable;
struct audio_pcm_info info;
int valid;
int freq;
f_sample *clip;
audfmt_e fmt;
int nchannels;
int align;
int shift;
int rpos;
uint64_t ts_helper;
int bufsize;
struct st_sample *mix_buf;
int bytes_per_second;
st_sample_t *mix_buf;
int samples;
LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
struct audio_pcm_ops *pcm_ops;
LIST_ENTRY (HWVoiceOut) entries;
} HWVoiceOut;
int64_t old_ticks;
int nb_voices;
struct SWVoice **pvoice;
struct pcm_ops *pcm_ops;
} HWVoice;
typedef struct HWVoiceIn {
int enabled;
struct audio_pcm_info info;
extern struct pcm_ops no_pcm_ops;
extern struct audio_output_driver no_output_driver;
t_sample *conv;
extern struct pcm_ops oss_pcm_ops;
extern struct audio_output_driver oss_output_driver;
int wpos;
int total_samples_captured;
uint64_t ts_helper;
extern struct pcm_ops sdl_pcm_ops;
extern struct audio_output_driver sdl_output_driver;
struct st_sample *conv_buf;
extern struct pcm_ops wav_pcm_ops;
extern struct audio_output_driver wav_output_driver;
int samples;
LIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
struct audio_pcm_ops *pcm_ops;
LIST_ENTRY (HWVoiceIn) entries;
} HWVoiceIn;
extern struct pcm_ops fmod_pcm_ops;
extern struct audio_output_driver fmod_output_driver;
struct SWVoiceOut {
QEMUSoundCard *card;
struct audio_pcm_info info;
t_sample *conv;
int64_t ratio;
struct st_sample *buf;
void *rate;
int total_hw_samples_mixed;
int active;
int empty;
HWVoiceOut *hw;
char *name;
struct mixeng_volume vol;
struct audio_callback callback;
LIST_ENTRY (SWVoiceOut) entries;
};
struct SWVoiceIn {
QEMUSoundCard *card;
int active;
struct audio_pcm_info info;
int64_t ratio;
void *rate;
int total_hw_samples_acquired;
struct st_sample *buf;
f_sample *clip;
HWVoiceIn *hw;
char *name;
struct mixeng_volume vol;
struct audio_callback callback;
LIST_ENTRY (SWVoiceIn) entries;
};
struct audio_driver {
struct audio_output_driver {
const char *name;
const char *descr;
struct audio_option *options;
void *(*init) (void);
void (*fini) (void *);
struct audio_pcm_ops *pcm_ops;
struct pcm_ops *pcm_ops;
int can_be_default;
int max_voices_out;
int max_voices_in;
int voice_size_out;
int voice_size_in;
int max_voices;
int voice_size;
};
struct audio_pcm_ops {
int (*init_out)(HWVoiceOut *hw, struct audsettings *as);
void (*fini_out)(HWVoiceOut *hw);
int (*run_out) (HWVoiceOut *hw);
int (*write) (SWVoiceOut *sw, void *buf, int size);
int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
int (*init_in) (HWVoiceIn *hw, struct audsettings *as);
void (*fini_in) (HWVoiceIn *hw);
int (*run_in) (HWVoiceIn *hw);
int (*read) (SWVoiceIn *sw, void *buf, int size);
int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
};
struct capture_callback {
struct audio_capture_ops ops;
typedef struct AudioState {
int fixed_format;
int fixed_freq;
int fixed_channels;
int fixed_fmt;
int nb_hw_voices;
int64_t ticks_threshold;
int freq_threshold;
void *opaque;
LIST_ENTRY (capture_callback) entries;
struct audio_output_driver *drv;
} AudioState;
extern AudioState audio_state;
struct SWVoice {
int freq;
audfmt_e fmt;
int nchannels;
int shift;
int align;
t_sample *conv;
int left;
int pos;
int bytes_per_second;
int64_t ratio;
st_sample_t *buf;
void *rate;
int wpos;
int live;
int active;
int64_t old_ticks;
HWVoice *hw;
char *name;
};
struct CaptureVoiceOut {
HWVoiceOut hw;
void *buf;
LIST_HEAD (cb_listhead, capture_callback) cb_head;
LIST_ENTRY (CaptureVoiceOut) entries;
struct pcm_ops {
int (*init) (HWVoice *hw, int freq, int nchannels, audfmt_e fmt);
void (*fini) (HWVoice *hw);
void (*run) (HWVoice *hw);
int (*write) (SWVoice *sw, void *buf, int size);
int (*ctl) (HWVoice *hw, int cmd, ...);
};
struct SWVoiceCap {
SWVoiceOut sw;
CaptureVoiceOut *cap;
LIST_ENTRY (SWVoiceCap) entries;
};
void pcm_sw_free_resources (SWVoice *sw);
int pcm_sw_alloc_resources (SWVoice *sw);
void pcm_sw_fini (SWVoice *sw);
int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
int nchannels, audfmt_e fmt);
struct AudioState {
struct audio_driver *drv;
void *drv_opaque;
void pcm_hw_clear (HWVoice *hw, void *buf, int len);
HWVoice * pcm_hw_find_any (HWVoice *hw);
HWVoice * pcm_hw_find_any_active (HWVoice *hw);
HWVoice * pcm_hw_find_any_passive (HWVoice *hw);
HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq,
int nchannels, audfmt_e fmt);
HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt);
int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw);
int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw);
SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt);
QEMUTimer *ts;
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;
};
void pcm_hw_free_resources (HWVoice *hw);
int pcm_hw_alloc_resources (HWVoice *hw);
void pcm_hw_fini (HWVoice *hw);
void pcm_hw_gc (HWVoice *hw);
int pcm_hw_get_live (HWVoice *hw);
int pcm_hw_get_live2 (HWVoice *hw, int *nb_active);
void pcm_hw_dec_live (HWVoice *hw, int decr);
int pcm_hw_write (SWVoice *sw, void *buf, int len);
extern struct audio_driver no_audio_driver;
extern struct audio_driver oss_audio_driver;
extern struct audio_driver sdl_audio_driver;
extern struct audio_driver wav_audio_driver;
extern struct audio_driver fmod_audio_driver;
extern struct audio_driver alsa_audio_driver;
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 mixeng_volume nominal_volume;
int audio_get_conf_int (const char *key, int defval);
const char *audio_get_conf_str (const char *key, const char *defval);
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
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_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);
struct audio_output_driver;
#define VOICE_ENABLE 1
#define VOICE_DISABLE 2
static inline int audio_ring_dist (int dst, int src, int len)
{
return (dst >= src) ? (dst - src) : (len - src + dst);
}
#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
static void GCC_ATTR dolog (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
}
#ifdef DEBUG
static void GCC_ATTR ldebug (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
}
#else
#if defined NDEBUG && defined __GNUC__
#define ldebug(...)
#elif defined NDEBUG && defined _MSC_VER
#define ldebug __noop
#else
static void GCC_ATTR ldebug (const char *fmt, ...)
{
(void) fmt;
}
#endif
#endif
#undef GCC_ATTR
#define AUDIO_STRINGIFY_(n) #n
#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)
#if defined _MSC_VER || defined __GNUC__
#define AUDIO_FUNC __FUNCTION__
#else
#define AUDIO_FUNC __FILE__ ":" AUDIO_STRINGIFY (__LINE__)
#endif
#endif /* audio_int.h */

View File

@@ -1,149 +0,0 @@
#include "qemu-common.h"
#include "audio.h"
#define AUDIO_CAP "audio-pt"
#include "audio_int.h"
#include "audio_pt_int.h"
static void logerr (struct audio_pt *pt, int err, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (pt->drv, fmt, ap);
va_end (ap);
AUD_log (NULL, "\n");
AUD_log (pt->drv, "Reason: %s\n", strerror (err));
}
int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
void *opaque, const char *drv, const char *cap)
{
int err, err2;
const char *efunc;
p->drv = drv;
err = pthread_mutex_init (&p->mutex, NULL);
if (err) {
efunc = "pthread_mutex_init";
goto err0;
}
err = pthread_cond_init (&p->cond, NULL);
if (err) {
efunc = "pthread_cond_init";
goto err1;
}
err = pthread_create (&p->thread, NULL, func, opaque);
if (err) {
efunc = "pthread_create";
goto err2;
}
return 0;
err2:
err2 = pthread_cond_destroy (&p->cond);
if (err2) {
logerr (p, err2, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
}
err1:
err2 = pthread_mutex_destroy (&p->mutex);
if (err2) {
logerr (p, err2, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
}
err0:
logerr (p, err, "%s(%s): %s failed", cap, AUDIO_FUNC, efunc);
return -1;
}
int audio_pt_fini (struct audio_pt *p, const char *cap)
{
int err, ret = 0;
err = pthread_cond_destroy (&p->cond);
if (err) {
logerr (p, err, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
ret = -1;
}
err = pthread_mutex_destroy (&p->mutex);
if (err) {
logerr (p, err, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
ret = -1;
}
return ret;
}
int audio_pt_lock (struct audio_pt *p, const char *cap)
{
int err;
err = pthread_mutex_lock (&p->mutex);
if (err) {
logerr (p, err, "%s(%s): pthread_mutex_lock failed", cap, AUDIO_FUNC);
return -1;
}
return 0;
}
int audio_pt_unlock (struct audio_pt *p, const char *cap)
{
int err;
err = pthread_mutex_unlock (&p->mutex);
if (err) {
logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
return -1;
}
return 0;
}
int audio_pt_wait (struct audio_pt *p, const char *cap)
{
int err;
err = pthread_cond_wait (&p->cond, &p->mutex);
if (err) {
logerr (p, err, "%s(%s): pthread_cond_wait failed", cap, AUDIO_FUNC);
return -1;
}
return 0;
}
int audio_pt_unlock_and_signal (struct audio_pt *p, const char *cap)
{
int err;
err = pthread_mutex_unlock (&p->mutex);
if (err) {
logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
return -1;
}
err = pthread_cond_signal (&p->cond);
if (err) {
logerr (p, err, "%s(%s): pthread_cond_signal failed", cap, AUDIO_FUNC);
return -1;
}
return 0;
}
int audio_pt_join (struct audio_pt *p, void **arg, const char *cap)
{
int err;
void *ret;
err = pthread_join (p->thread, &ret);
if (err) {
logerr (p, err, "%s(%s): pthread_join failed", cap, AUDIO_FUNC);
return -1;
}
*arg = ret;
return 0;
}

View File

@@ -1,22 +0,0 @@
#ifndef QEMU_AUDIO_PT_INT_H
#define QEMU_AUDIO_PT_INT_H
#include <pthread.h>
struct audio_pt {
const char *drv;
pthread_t thread;
pthread_cond_t cond;
pthread_mutex_t mutex;
};
int audio_pt_init (struct audio_pt *, void *(*) (void *), void *,
const char *, const char *);
int audio_pt_fini (struct audio_pt *, const char *);
int audio_pt_lock (struct audio_pt *, const char *);
int audio_pt_unlock (struct audio_pt *, const char *);
int audio_pt_wait (struct audio_pt *, const char *);
int audio_pt_unlock_and_signal (struct audio_pt *, const char *);
int audio_pt_join (struct audio_pt *, void **, const char *);
#endif /* audio_pt_int.h */

View File

@@ -1,566 +0,0 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2005 Vassili Karpov (malc)
*
* 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.
*/
#ifdef DAC
#define NAME "playback"
#define HWBUF hw->mix_buf
#define TYPE out
#define HW HWVoiceOut
#define SW SWVoiceOut
#else
#define NAME "capture"
#define TYPE in
#define HW HWVoiceIn
#define SW SWVoiceIn
#define HWBUF hw->conv_buf
#endif
static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv)
{
AudioState *s = &glob_audio_state;
int max_voices = glue (drv->max_voices_, TYPE);
int voice_size = glue (drv->voice_size_, TYPE);
if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
if (!max_voices) {
#ifdef DAC
dolog ("Driver `%s' does not support " NAME "\n", drv->name);
#endif
}
else {
dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n",
drv->name,
glue (s->nb_hw_voices_, TYPE),
max_voices);
}
glue (s->nb_hw_voices_, TYPE) = max_voices;
}
if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) {
dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
drv->name, max_voices);
glue (s->nb_hw_voices_, TYPE) = 0;
}
if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) {
dolog ("drv=`%s' voice_size=%d max_voices=0\n",
drv->name, voice_size);
}
}
static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
{
if (HWBUF) {
qemu_free (HWBUF);
}
HWBUF = NULL;
}
static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
{
HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (struct st_sample));
if (!HWBUF) {
dolog ("Could not allocate " NAME " buffer (%d samples)\n",
hw->samples);
return -1;
}
return 0;
}
static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
{
if (sw->buf) {
qemu_free (sw->buf);
}
if (sw->rate) {
st_rate_stop (sw->rate);
}
sw->buf = NULL;
sw->rate = NULL;
}
static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
{
int samples;
#ifdef DAC
samples = sw->hw->samples;
#else
samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
#endif
sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample));
if (!sw->buf) {
dolog ("Could not allocate buffer for `%s' (%d samples)\n",
SW_NAME (sw), samples);
return -1;
}
#ifdef DAC
sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
#else
sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
#endif
if (!sw->rate) {
qemu_free (sw->buf);
sw->buf = NULL;
return -1;
}
return 0;
}
static int glue (audio_pcm_sw_init_, TYPE) (
SW *sw,
HW *hw,
const char *name,
struct audsettings *as
)
{
int err;
audio_pcm_init_info (&sw->info, as);
sw->hw = hw;
sw->active = 0;
#ifdef DAC
sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
sw->total_hw_samples_mixed = 0;
sw->empty = 1;
#else
sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
#endif
#ifdef DAC
sw->conv = mixeng_conv
#else
sw->clip = mixeng_clip
#endif
[sw->info.nchannels == 2]
[sw->info.sign]
[sw->info.swap_endianness]
[audio_bits_to_index (sw->info.bits)];
sw->name = qemu_strdup (name);
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
if (err) {
qemu_free (sw->name);
sw->name = NULL;
}
return err;
}
static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
{
glue (audio_pcm_sw_free_resources_, TYPE) (sw);
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
}
static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw)
{
LIST_INSERT_HEAD (&hw->sw_head, sw, entries);
}
static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
{
LIST_REMOVE (sw, entries);
}
static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
{
AudioState *s = &glob_audio_state;
HW *hw = *hwp;
if (!hw->sw_head.lh_first) {
#ifdef DAC
audio_detach_capture (hw);
#endif
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);
qemu_free (hw);
*hwp = NULL;
}
}
static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
{
AudioState *s = &glob_audio_state;
return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
}
static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
{
while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
if (hw->enabled) {
return hw;
}
}
return NULL;
}
static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
HW *hw,
struct audsettings *as
)
{
while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
if (audio_pcm_info_eq (&hw->info, as)) {
return hw;
}
}
return NULL;
}
static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
{
HW *hw;
AudioState *s = &glob_audio_state;
struct audio_driver *drv = s->drv;
if (!glue (s->nb_hw_voices_, TYPE)) {
return NULL;
}
if (audio_bug (AUDIO_FUNC, !drv)) {
dolog ("No host audio driver\n");
return NULL;
}
if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) {
dolog ("Host audio driver without pcm_ops\n");
return NULL;
}
hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE));
if (!hw) {
dolog ("Can not allocate voice `%s' size %d\n",
drv->name, glue (drv->voice_size_, TYPE));
return NULL;
}
hw->pcm_ops = drv->pcm_ops;
LIST_INIT (&hw->sw_head);
#ifdef DAC
LIST_INIT (&hw->cap_head);
#endif
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
goto err0;
}
if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) {
dolog ("hw->samples=%d\n", hw->samples);
goto err1;
}
#ifdef DAC
hw->clip = mixeng_clip
#else
hw->conv = mixeng_conv
#endif
[hw->info.nchannels == 2]
[hw->info.sign]
[hw->info.swap_endianness]
[audio_bits_to_index (hw->info.bits)];
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
goto err1;
}
LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
glue (s->nb_hw_voices_, TYPE) -= 1;
#ifdef DAC
audio_attach_capture (hw);
#endif
return hw;
err1:
glue (hw->pcm_ops->fini_, TYPE) (hw);
err0:
qemu_free (hw);
return NULL;
}
static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as)
{
HW *hw;
if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
if (hw) {
return hw;
}
}
hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, as);
if (hw) {
return hw;
}
hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
if (hw) {
return hw;
}
return glue (audio_pcm_hw_find_any_, TYPE) (NULL);
}
static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
const char *sw_name,
struct audsettings *as
)
{
SW *sw;
HW *hw;
struct audsettings hw_as;
if (glue (conf.fixed_, TYPE).enabled) {
hw_as = glue (conf.fixed_, TYPE).settings;
}
else {
hw_as = *as;
}
sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw));
if (!sw) {
dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
sw_name ? sw_name : "unknown", sizeof (*sw));
goto err1;
}
hw = glue (audio_pcm_hw_add_, TYPE) (&hw_as);
if (!hw) {
goto err2;
}
glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
goto err3;
}
return sw;
err3:
glue (audio_pcm_hw_del_sw_, TYPE) (sw);
glue (audio_pcm_hw_gc_, TYPE) (&hw);
err2:
qemu_free (sw);
err1:
return NULL;
}
static void glue (audio_close_, TYPE) (SW *sw)
{
glue (audio_pcm_sw_fini_, TYPE) (sw);
glue (audio_pcm_hw_del_sw_, TYPE) (sw);
glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
qemu_free (sw);
}
void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
{
if (sw) {
if (audio_bug (AUDIO_FUNC, !card)) {
dolog ("card=%p\n", card);
return;
}
glue (audio_close_, TYPE) (sw);
}
}
SW *glue (AUD_open_, TYPE) (
QEMUSoundCard *card,
SW *sw,
const char *name,
void *callback_opaque ,
audio_callback_fn_t callback_fn,
struct audsettings *as
)
{
AudioState *s = &glob_audio_state;
#ifdef DAC
int live = 0;
SW *old_sw = NULL;
#endif
ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
name, as->freq, as->nchannels, as->fmt);
if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) {
dolog ("card=%p name=%p callback_fn=%p as=%p\n",
card, name, callback_fn, as);
goto fail;
}
if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
audio_print_settings (as);
goto fail;
}
if (audio_bug (AUDIO_FUNC, !s->drv)) {
dolog ("Can not open `%s' (no host audio driver)\n", name);
goto fail;
}
if (sw && audio_pcm_info_eq (&sw->info, as)) {
return sw;
}
#ifdef DAC
if (conf.plive && sw && (!sw->active && !sw->empty)) {
live = sw->total_hw_samples_mixed;
#ifdef DEBUG_PLIVE
dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live);
dolog ("Old %s freq %d, bits %d, channels %d\n",
SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels);
dolog ("New %s freq %d, bits %d, channels %d\n",
name,
freq,
(fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8,
nchannels);
#endif
if (live) {
old_sw = sw;
old_sw->callback.fn = NULL;
sw = NULL;
}
}
#endif
if (!glue (conf.fixed_, TYPE).enabled && sw) {
glue (AUD_close_, TYPE) (card, sw);
sw = NULL;
}
if (sw) {
HW *hw = sw->hw;
if (!hw) {
dolog ("Internal logic error voice `%s' has no hardware store\n",
SW_NAME (sw));
goto fail;
}
glue (audio_pcm_sw_fini_, TYPE) (sw);
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
goto fail;
}
}
else {
sw = glue (audio_pcm_create_voice_pair_, TYPE) (name, as);
if (!sw) {
dolog ("Failed to create voice `%s'\n", name);
return NULL;
}
}
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;
#ifdef DEBUG_PLIVE
dolog ("Silence will be mixed %d\n", mixed);
#endif
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);
#endif
}
return sw;
fail:
glue (AUD_close_, TYPE) (card, sw);
return NULL;
}
int glue (AUD_is_active_, TYPE) (SW *sw)
{
return sw ? sw->active : 0;
}
void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
{
if (!sw) {
return;
}
ts->old_ts = sw->hw->ts_helper;
}
uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
{
uint64_t delta, cur_ts, old_ts;
if (!sw) {
return 0;
}
cur_ts = sw->hw->ts_helper;
old_ts = ts->old_ts;
/* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
if (cur_ts >= old_ts) {
delta = cur_ts - old_ts;
}
else {
delta = UINT64_MAX - old_ts + cur_ts;
}
if (!delta) {
return 0;
}
return (delta * sw->hw->info.freq) / 1000000;
}
#undef TYPE
#undef HW
#undef SW
#undef HWBUF
#undef NAME

View File

@@ -1,550 +0,0 @@
/*
* QEMU OS X CoreAudio audio driver
*
* Copyright (c) 2005 Mike Kronenberg
*
* 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 <CoreAudio/CoreAudio.h>
#include <string.h> /* strerror */
#include <pthread.h> /* pthread_X */
#include "qemu-common.h"
#include "audio.h"
#define AUDIO_CAP "coreaudio"
#include "audio_int.h"
struct {
int buffer_frames;
int nbuffers;
int isAtexit;
} conf = {
.buffer_frames = 512,
.nbuffers = 4,
.isAtexit = 0
};
typedef struct coreaudioVoiceOut {
HWVoiceOut hw;
pthread_mutex_t mutex;
int isAtexit;
AudioDeviceID outputDeviceID;
UInt32 audioDevicePropertyBufferFrameSize;
AudioStreamBasicDescription outputStreamBasicDescription;
int live;
int decr;
int rpos;
} coreaudioVoiceOut;
static void coreaudio_logstatus (OSStatus status)
{
char *str = "BUG";
switch(status) {
case kAudioHardwareNoError:
str = "kAudioHardwareNoError";
break;
case kAudioHardwareNotRunningError:
str = "kAudioHardwareNotRunningError";
break;
case kAudioHardwareUnspecifiedError:
str = "kAudioHardwareUnspecifiedError";
break;
case kAudioHardwareUnknownPropertyError:
str = "kAudioHardwareUnknownPropertyError";
break;
case kAudioHardwareBadPropertySizeError:
str = "kAudioHardwareBadPropertySizeError";
break;
case kAudioHardwareIllegalOperationError:
str = "kAudioHardwareIllegalOperationError";
break;
case kAudioHardwareBadDeviceError:
str = "kAudioHardwareBadDeviceError";
break;
case kAudioHardwareBadStreamError:
str = "kAudioHardwareBadStreamError";
break;
case kAudioHardwareUnsupportedOperationError:
str = "kAudioHardwareUnsupportedOperationError";
break;
case kAudioDeviceUnsupportedFormatError:
str = "kAudioDeviceUnsupportedFormatError";
break;
case kAudioDevicePermissionsError:
str = "kAudioDevicePermissionsError";
break;
default:
AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
return;
}
AUD_log (AUDIO_CAP, "Reason: %s\n", str);
}
static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
OSStatus status,
const char *fmt,
...
)
{
va_list ap;
va_start (ap, fmt);
AUD_log (AUDIO_CAP, fmt, ap);
va_end (ap);
coreaudio_logstatus (status);
}
static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
OSStatus status,
const char *typ,
const char *fmt,
...
)
{
va_list ap;
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
coreaudio_logstatus (status);
}
static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
{
OSStatus status;
UInt32 result = 0;
UInt32 propertySize = sizeof(outputDeviceID);
status = AudioDeviceGetProperty(
outputDeviceID, 0, 0,
kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
if (status != kAudioHardwareNoError) {
coreaudio_logerr(status,
"Could not determine whether Device is playing\n");
}
return result;
}
static void coreaudio_atexit (void)
{
conf.isAtexit = 1;
}
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
{
int err;
err = pthread_mutex_lock (&core->mutex);
if (err) {
dolog ("Could not lock voice for %s\nReason: %s\n",
fn_name, strerror (err));
return -1;
}
return 0;
}
static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
{
int err;
err = pthread_mutex_unlock (&core->mutex);
if (err) {
dolog ("Could not unlock voice for %s\nReason: %s\n",
fn_name, strerror (err));
return -1;
}
return 0;
}
static int coreaudio_run_out (HWVoiceOut *hw)
{
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,
live,
core->live);
}
decr = audio_MIN (core->decr, live);
core->decr -= decr;
core->live = live - decr;
hw->rpos = core->rpos;
coreaudio_unlock (core, "coreaudio_run_out");
return decr;
}
/* callback to feed audiooutput buffer */
static OSStatus audioDeviceIOProc(
AudioDeviceID inDevice,
const AudioTimeStamp* inNow,
const AudioBufferList* inInputData,
const AudioTimeStamp* inInputTime,
AudioBufferList* outOutputData,
const AudioTimeStamp* inOutputTime,
void* hwptr)
{
UInt32 frame, frameCount;
float *out = outOutputData->mBuffers[0].mData;
HWVoiceOut *hw = hwptr;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
int rpos, live;
struct st_sample *src;
#ifndef FLOAT_MIXENG
#ifdef RECIPROCAL
const float scale = 1.f / UINT_MAX;
#else
const float scale = UINT_MAX;
#endif
#endif
if (coreaudio_lock (core, "audioDeviceIOProc")) {
inInputTime = 0;
return 0;
}
frameCount = core->audioDevicePropertyBufferFrameSize;
live = core->live;
/* if there are not enough samples, set signal and return */
if (live < frameCount) {
inInputTime = 0;
coreaudio_unlock (core, "audioDeviceIOProc(empty)");
return 0;
}
rpos = core->rpos;
src = hw->mix_buf + rpos;
/* fill buffer */
for (frame = 0; frame < frameCount; frame++) {
#ifdef FLOAT_MIXENG
*out++ = src[frame].l; /* left channel */
*out++ = src[frame].r; /* right channel */
#else
#ifdef RECIPROCAL
*out++ = src[frame].l * scale; /* left channel */
*out++ = src[frame].r * scale; /* right channel */
#else
*out++ = src[frame].l / scale; /* left channel */
*out++ = src[frame].r / scale; /* right channel */
#endif
#endif
}
rpos = (rpos + frameCount) % hw->samples;
core->decr += frameCount;
core->rpos = rpos;
coreaudio_unlock (core, "audioDeviceIOProc");
return 0;
}
static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
{
OSStatus status;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
UInt32 propertySize;
int err;
const char *typ = "playback";
AudioValueRange frameRange;
/* create mutex */
err = pthread_mutex_init(&core->mutex, NULL);
if (err) {
dolog("Could not create mutex\nReason: %s\n", strerror (err));
return -1;
}
audio_pcm_init_info (&hw->info, as);
/* open default output device */
propertySize = sizeof(core->outputDeviceID);
status = AudioHardwareGetProperty(
kAudioHardwarePropertyDefaultOutputDevice,
&propertySize,
&core->outputDeviceID);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get default output Device\n");
return -1;
}
if (core->outputDeviceID == kAudioDeviceUnknown) {
dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
return -1;
}
/* get minimum and maximum buffer frame sizes */
propertySize = sizeof(frameRange);
status = AudioDeviceGetProperty(
core->outputDeviceID,
0,
0,
kAudioDevicePropertyBufferFrameSizeRange,
&propertySize,
&frameRange);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get device buffer frame range\n");
return -1;
}
if (frameRange.mMinimum > conf.buffer_frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
}
else if (frameRange.mMaximum < conf.buffer_frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
}
else {
core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
}
/* set Buffer Frame Size */
propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
status = AudioDeviceSetProperty(
core->outputDeviceID,
NULL,
0,
false,
kAudioDevicePropertyBufferFrameSize,
propertySize,
&core->audioDevicePropertyBufferFrameSize);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not set device buffer frame size %ld\n",
core->audioDevicePropertyBufferFrameSize);
return -1;
}
/* get Buffer Frame Size */
propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
status = AudioDeviceGetProperty(
core->outputDeviceID,
0,
false,
kAudioDevicePropertyBufferFrameSize,
&propertySize,
&core->audioDevicePropertyBufferFrameSize);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get device buffer frame size\n");
return -1;
}
hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
/* get StreamFormat */
propertySize = sizeof(core->outputStreamBasicDescription);
status = AudioDeviceGetProperty(
core->outputDeviceID,
0,
false,
kAudioDevicePropertyStreamFormat,
&propertySize,
&core->outputStreamBasicDescription);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get Device Stream properties\n");
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
/* set Samplerate */
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
propertySize = sizeof(core->outputStreamBasicDescription);
status = AudioDeviceSetProperty(
core->outputDeviceID,
0,
0,
0,
kAudioDevicePropertyStreamFormat,
propertySize,
&core->outputStreamBasicDescription);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
as->freq);
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
/* set Callback */
status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
/* start Playback */
if (!isPlaying(core->outputDeviceID)) {
status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not start playback\n");
AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
}
return 0;
}
static void coreaudio_fini_out (HWVoiceOut *hw)
{
OSStatus status;
int err;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
if (!conf.isAtexit) {
/* stop playback */
if (isPlaying(core->outputDeviceID)) {
status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr (status, "Could not stop playback\n");
}
}
/* remove callback */
status = AudioDeviceRemoveIOProc(core->outputDeviceID,
audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr (status, "Could not remove IOProc\n");
}
}
core->outputDeviceID = kAudioDeviceUnknown;
/* destroy mutex */
err = pthread_mutex_destroy(&core->mutex);
if (err) {
dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
}
}
static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
OSStatus status;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
switch (cmd) {
case VOICE_ENABLE:
/* start playback */
if (!isPlaying(core->outputDeviceID)) {
status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr (status, "Could not resume playback\n");
}
}
break;
case VOICE_DISABLE:
/* stop playback */
if (!conf.isAtexit) {
if (isPlaying(core->outputDeviceID)) {
status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr (status, "Could not pause playback\n");
}
}
}
break;
}
return 0;
}
static void *coreaudio_audio_init (void)
{
atexit(coreaudio_atexit);
return &coreaudio_audio_init;
}
static void coreaudio_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_option coreaudio_options[] = {
{"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 = {
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 = {
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

@@ -1,293 +0,0 @@
/*
* QEMU DirectSound audio driver header
*
* Copyright (c) 2005 Vassili Karpov (malc)
*
* 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.
*/
#ifdef DSBTYPE_IN
#define NAME "capture buffer"
#define NAME2 "DirectSoundCapture"
#define TYPE in
#define IFACE IDirectSoundCaptureBuffer
#define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
#define FIELD dsound_capture_buffer
#define FIELD2 dsound_capture
#else
#define NAME "playback buffer"
#define NAME2 "DirectSound"
#define TYPE out
#define IFACE IDirectSoundBuffer
#define BUFPTR LPDIRECTSOUNDBUFFER
#define FIELD dsound_buffer
#define FIELD2 dsound
#endif
static int glue (dsound_unlock_, TYPE) (
BUFPTR buf,
LPVOID p1,
LPVOID p2,
DWORD blen1,
DWORD blen2
)
{
HRESULT hr;
hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not unlock " NAME "\n");
return -1;
}
return 0;
}
static int glue (dsound_lock_, TYPE) (
BUFPTR buf,
struct audio_pcm_info *info,
DWORD pos,
DWORD len,
LPVOID *p1p,
LPVOID *p2p,
DWORD *blen1p,
DWORD *blen2p,
int entire
)
{
HRESULT hr;
int i;
LPVOID p1 = NULL, p2 = NULL;
DWORD blen1 = 0, blen2 = 0;
DWORD flag;
#ifdef DSBTYPE_IN
flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
#else
flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
#endif
for (i = 0; i < conf.lock_retries; ++i) {
hr = glue (IFACE, _Lock) (
buf,
pos,
len,
&p1,
&blen1,
&p2,
&blen2,
flag
);
if (FAILED (hr)) {
#ifndef DSBTYPE_IN
if (hr == DSERR_BUFFERLOST) {
if (glue (dsound_restore_, TYPE) (buf)) {
dsound_logerr (hr, "Could not lock " NAME "\n");
goto fail;
}
continue;
}
#endif
dsound_logerr (hr, "Could not lock " NAME "\n");
goto fail;
}
break;
}
if (i == conf.lock_retries) {
dolog ("%d attempts to lock " NAME " failed\n", i);
goto fail;
}
if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
dolog ("DirectSound returned misaligned buffer %ld %ld\n",
blen1, blen2);
glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
goto fail;
}
if (!p1 && blen1) {
dolog ("warning: !p1 && blen1=%ld\n", blen1);
blen1 = 0;
}
if (!p2 && blen2) {
dolog ("warning: !p2 && blen2=%ld\n", blen2);
blen2 = 0;
}
*p1p = p1;
*p2p = p2;
*blen1p = blen1;
*blen2p = blen2;
return 0;
fail:
*p1p = NULL - 1;
*p2p = NULL - 1;
*blen1p = -1;
*blen2p = -1;
return -1;
}
#ifdef DSBTYPE_IN
static void dsound_fini_in (HWVoiceIn *hw)
#else
static void dsound_fini_out (HWVoiceOut *hw)
#endif
{
HRESULT hr;
#ifdef DSBTYPE_IN
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
#else
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
#endif
if (ds->FIELD) {
hr = glue (IFACE, _Stop) (ds->FIELD);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not stop " NAME "\n");
}
hr = glue (IFACE, _Release) (ds->FIELD);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not release " NAME "\n");
}
ds->FIELD = NULL;
}
}
#ifdef DSBTYPE_IN
static int dsound_init_in (HWVoiceIn *hw, struct audsettings *as)
#else
static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
#endif
{
int err;
HRESULT hr;
dsound *s = &glob_dsound;
WAVEFORMATEX wfx;
struct audsettings obt_as;
#ifdef DSBTYPE_IN
const char *typ = "ADC";
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
DSCBUFFERDESC bd;
DSCBCAPS bc;
#else
const char *typ = "DAC";
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
DSBUFFERDESC bd;
DSBCAPS bc;
#endif
if (!s->FIELD2) {
dolog ("Attempt to initialize voice without " NAME2 " object\n");
return -1;
}
err = waveformat_from_audio_settings (&wfx, as);
if (err) {
return -1;
}
memset (&bd, 0, sizeof (bd));
bd.dwSize = sizeof (bd);
bd.lpwfxFormat = &wfx;
#ifdef DSBTYPE_IN
bd.dwBufferBytes = conf.bufsize_in;
hr = IDirectSoundCapture_CreateCaptureBuffer (
s->dsound_capture,
&bd,
&ds->dsound_capture_buffer,
NULL
);
#else
bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
bd.dwBufferBytes = conf.bufsize_out;
hr = IDirectSound_CreateSoundBuffer (
s->dsound,
&bd,
&ds->dsound_buffer,
NULL
);
#endif
if (FAILED (hr)) {
dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
return -1;
}
hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
if (FAILED (hr)) {
dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
goto fail0;
}
#ifdef DEBUG_DSOUND
dolog (NAME "\n");
print_wave_format (&wfx);
#endif
memset (&bc, 0, sizeof (bc));
bc.dwSize = sizeof (bc);
hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
if (FAILED (hr)) {
dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
goto fail0;
}
err = waveformat_to_audio_settings (&wfx, &obt_as);
if (err) {
goto fail0;
}
ds->first_time = 1;
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
if (bc.dwBufferBytes & hw->info.align) {
dolog (
"GetCaps returned misaligned buffer size %ld, alignment %d\n",
bc.dwBufferBytes, hw->info.align + 1
);
}
hw->samples = bc.dwBufferBytes >> hw->info.shift;
#ifdef DEBUG_DSOUND
dolog ("caps %ld, desc %ld\n",
bc.dwBufferBytes, bd.dwBufferBytes);
dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
#endif
return 0;
fail0:
glue (dsound_fini_, TYPE) (hw);
return -1;
}
#undef NAME
#undef NAME2
#undef TYPE
#undef IFACE
#undef BUFPTR
#undef FIELD
#undef FIELD2

File diff suppressed because it is too large Load Diff

View File

@@ -1,596 +0,0 @@
/*
* QEMU ESD audio driver
*
* Copyright (c) 2006 Frederick Reeve (brushed up by malc)
*
* 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 <esd.h>
#include "qemu-common.h"
#include "audio.h"
#include <signal.h>
#define AUDIO_CAP "esd"
#include "audio_int.h"
#include "audio_pt_int.h"
typedef struct {
HWVoiceOut hw;
int done;
int live;
int decr;
int rpos;
void *pcm_buf;
int fd;
struct audio_pt pt;
} ESDVoiceOut;
typedef struct {
HWVoiceIn hw;
int done;
int dead;
int incr;
int wpos;
void *pcm_buf;
int fd;
struct audio_pt pt;
} ESDVoiceIn;
static struct {
int samples;
int divisor;
char *dac_host;
char *adc_host;
} conf = {
1024,
2,
NULL,
NULL
};
static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
}
/* playback */
static void *qesd_thread_out (void *arg)
{
ESDVoiceOut *esd = arg;
HWVoiceOut *hw = &esd->hw;
int threshold;
threshold = conf.divisor ? hw->samples / conf.divisor : 0;
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
for (;;) {
int decr, to_mix, rpos;
for (;;) {
if (esd->done) {
goto exit;
}
if (esd->live > threshold) {
break;
}
if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
goto exit;
}
}
decr = to_mix = esd->live;
rpos = hw->rpos;
if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
while (to_mix) {
ssize_t written;
int chunk = audio_MIN (to_mix, hw->samples - rpos);
struct st_sample *src = hw->mix_buf + rpos;
hw->clip (esd->pcm_buf, src, chunk);
again:
written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
if (written == -1) {
if (errno == EINTR || errno == EAGAIN) {
goto again;
}
qesd_logerr (errno, "write failed\n");
return NULL;
}
if (written != chunk << 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);
}
to_mix -= wsamples;
rpos = (rpos + wsamples) % hw->samples;
break;
}
rpos = (rpos + chunk) % hw->samples;
to_mix -= chunk;
}
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
esd->rpos = rpos;
esd->live -= decr;
esd->decr += decr;
}
exit:
audio_pt_unlock (&esd->pt, AUDIO_FUNC);
return NULL;
}
static int qesd_run_out (HWVoiceOut *hw)
{
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;
hw->rpos = esd->rpos;
if (esd->live > 0) {
audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
}
else {
audio_pt_unlock (&esd->pt, AUDIO_FUNC);
}
return decr;
}
static int qesd_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
{
ESDVoiceOut *esd = (ESDVoiceOut *) hw;
struct audsettings obt_as = *as;
int esdfmt = ESD_STREAM | ESD_PLAY;
int err;
sigset_t set, old_set;
sigfillset (&set);
esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
switch (as->fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
esdfmt |= ESD_BITS8;
obt_as.fmt = AUD_FMT_U8;
break;
case AUD_FMT_S32:
case AUD_FMT_U32:
dolog ("Will use 16 instead of 32 bit samples\n");
case AUD_FMT_S16:
case AUD_FMT_U16:
deffmt:
esdfmt |= ESD_BITS16;
obt_as.fmt = AUD_FMT_S16;
break;
default:
dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
goto deffmt;
}
obt_as.endianness = AUDIO_HOST_ENDIANNESS;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.samples;
esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!esd->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
return -1;
}
esd->fd = -1;
err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
if (err) {
qesd_logerr (err, "pthread_sigmask failed\n");
goto fail1;
}
esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
if (esd->fd < 0) {
qesd_logerr (errno, "esd_play_stream failed\n");
goto fail2;
}
if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
goto fail3;
}
err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
if (err) {
qesd_logerr (err, "pthread_sigmask(restore) failed\n");
}
return 0;
fail3:
if (close (esd->fd)) {
qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
AUDIO_FUNC, esd->fd);
}
esd->fd = -1;
fail2:
err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
if (err) {
qesd_logerr (err, "pthread_sigmask(restore) failed\n");
}
fail1:
qemu_free (esd->pcm_buf);
esd->pcm_buf = NULL;
return -1;
}
static void qesd_fini_out (HWVoiceOut *hw)
{
void *ret;
ESDVoiceOut *esd = (ESDVoiceOut *) hw;
audio_pt_lock (&esd->pt, AUDIO_FUNC);
esd->done = 1;
audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
if (esd->fd >= 0) {
if (close (esd->fd)) {
qesd_logerr (errno, "failed to close esd socket\n");
}
esd->fd = -1;
}
audio_pt_fini (&esd->pt, AUDIO_FUNC);
qemu_free (esd->pcm_buf);
esd->pcm_buf = NULL;
}
static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
/* capture */
static void *qesd_thread_in (void *arg)
{
ESDVoiceIn *esd = arg;
HWVoiceIn *hw = &esd->hw;
int threshold;
threshold = conf.divisor ? hw->samples / conf.divisor : 0;
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
for (;;) {
int incr, to_grab, wpos;
for (;;) {
if (esd->done) {
goto exit;
}
if (esd->dead > threshold) {
break;
}
if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
goto exit;
}
}
incr = to_grab = esd->dead;
wpos = hw->wpos;
if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
while (to_grab) {
ssize_t nread;
int chunk = audio_MIN (to_grab, hw->samples - wpos);
void *buf = advance (esd->pcm_buf, wpos);
again:
nread = read (esd->fd, buf, chunk << hw->info.shift);
if (nread == -1) {
if (errno == EINTR || errno == EAGAIN) {
goto again;
}
qesd_logerr (errno, "read failed\n");
return NULL;
}
if (nread != chunk << hw->info.shift) {
int rsamples = nread >> hw->info.shift;
int rbytes = rsamples << hw->info.shift;
if (rbytes != nread) {
dolog ("warning: Misaligned write %d (requested %d), "
"alignment %d\n",
rbytes, nread, hw->info.align + 1);
}
to_grab -= rsamples;
wpos = (wpos + rsamples) % hw->samples;
break;
}
hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
&nominal_volume);
wpos = (wpos + chunk) % hw->samples;
to_grab -= chunk;
}
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
esd->wpos = wpos;
esd->dead -= incr;
esd->incr += incr;
}
exit:
audio_pt_unlock (&esd->pt, AUDIO_FUNC);
return NULL;
}
static int qesd_run_in (HWVoiceIn *hw)
{
int live, incr, dead;
ESDVoiceIn *esd = (ESDVoiceIn *) hw;
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return 0;
}
live = audio_pcm_hw_get_live_in (hw);
dead = hw->samples - live;
incr = audio_MIN (dead, esd->incr);
esd->incr -= incr;
esd->dead = dead - incr;
hw->wpos = esd->wpos;
if (esd->dead > 0) {
audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
}
else {
audio_pt_unlock (&esd->pt, AUDIO_FUNC);
}
return incr;
}
static int qesd_read (SWVoiceIn *sw, void *buf, int len)
{
return audio_pcm_sw_read (sw, buf, len);
}
static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
{
ESDVoiceIn *esd = (ESDVoiceIn *) hw;
struct audsettings obt_as = *as;
int esdfmt = ESD_STREAM | ESD_RECORD;
int err;
sigset_t set, old_set;
sigfillset (&set);
esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
switch (as->fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
esdfmt |= ESD_BITS8;
obt_as.fmt = AUD_FMT_U8;
break;
case AUD_FMT_S16:
case AUD_FMT_U16:
esdfmt |= ESD_BITS16;
obt_as.fmt = AUD_FMT_S16;
break;
case AUD_FMT_S32:
case AUD_FMT_U32:
dolog ("Will use 16 instead of 32 bit samples\n");
esdfmt |= ESD_BITS16;
obt_as.fmt = AUD_FMT_S16;
break;
}
obt_as.endianness = AUDIO_HOST_ENDIANNESS;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.samples;
esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!esd->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
return -1;
}
esd->fd = -1;
err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
if (err) {
qesd_logerr (err, "pthread_sigmask failed\n");
goto fail1;
}
esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
if (esd->fd < 0) {
qesd_logerr (errno, "esd_record_stream failed\n");
goto fail2;
}
if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
goto fail3;
}
err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
if (err) {
qesd_logerr (err, "pthread_sigmask(restore) failed\n");
}
return 0;
fail3:
if (close (esd->fd)) {
qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
AUDIO_FUNC, esd->fd);
}
esd->fd = -1;
fail2:
err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
if (err) {
qesd_logerr (err, "pthread_sigmask(restore) failed\n");
}
fail1:
qemu_free (esd->pcm_buf);
esd->pcm_buf = NULL;
return -1;
}
static void qesd_fini_in (HWVoiceIn *hw)
{
void *ret;
ESDVoiceIn *esd = (ESDVoiceIn *) hw;
audio_pt_lock (&esd->pt, AUDIO_FUNC);
esd->done = 1;
audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
if (esd->fd >= 0) {
if (close (esd->fd)) {
qesd_logerr (errno, "failed to close esd socket\n");
}
esd->fd = -1;
}
audio_pt_fini (&esd->pt, AUDIO_FUNC);
qemu_free (esd->pcm_buf);
esd->pcm_buf = NULL;
}
static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
/* common */
static void *qesd_audio_init (void)
{
return &conf;
}
static void qesd_audio_fini (void *opaque)
{
(void) opaque;
ldebug ("esd_fini");
}
struct audio_option qesd_options[] = {
{"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 = {
qesd_init_out,
qesd_fini_out,
qesd_run_out,
qesd_write,
qesd_ctl_out,
qesd_init_in,
qesd_fini_in,
qesd_run_in,
qesd_read,
qesd_ctl_in,
};
struct audio_driver esd_audio_driver = {
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

@@ -1,8 +1,8 @@
/*
* QEMU FMOD audio driver
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
*
* QEMU FMOD audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* 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
@@ -23,80 +23,55 @@
*/
#include <fmod.h>
#include <fmod_errors.h>
#include "qemu-common.h"
#include "audio.h"
#include "vl.h"
#define AUDIO_CAP "fmod"
#include "audio_int.h"
#include "audio/audio_int.h"
typedef struct FMODVoiceOut {
HWVoiceOut hw;
typedef struct FMODVoice {
HWVoice hw;
unsigned int old_pos;
FSOUND_SAMPLE *fmod_sample;
int channel;
} FMODVoiceOut;
} FMODVoice;
typedef struct FMODVoiceIn {
HWVoiceIn hw;
FSOUND_SAMPLE *fmod_sample;
} FMODVoiceIn;
#define dolog(...) AUD_log ("fmod", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_FMOD_DRV "QEMU_FMOD_DRV"
#define QC_FMOD_FREQ "QEMU_FMOD_FREQ"
#define QC_FMOD_SAMPLES "QEMU_FMOD_SAMPLES"
#define QC_FMOD_CHANNELS "QEMU_FMOD_CHANNELS"
#define QC_FMOD_BUFSIZE "QEMU_FMOD_BUFSIZE"
#define QC_FMOD_THRESHOLD "QEMU_FMOD_THRESHOLD"
static struct {
const char *drvname;
int nb_samples;
int freq;
int nb_channels;
int bufsize;
int threshold;
int broken_adc;
} conf = {
NULL,
2048 * 2,
2048,
44100,
2,
1,
0,
0,
0
128
};
static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt, ...)
#define errstr() FMOD_ErrorString (FSOUND_GetError ())
static int fmod_hw_write (SWVoice *sw, void *buf, int len)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n",
FMOD_ErrorString (FSOUND_GetError ()));
return pcm_hw_write (sw, buf, len);
}
static void GCC_FMT_ATTR (2, 3) fmod_logerr2 (
const char *typ,
const char *fmt,
...
)
static void fmod_clear_sample (FMODVoice *fmd)
{
va_list ap;
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n",
FMOD_ErrorString (FSOUND_GetError ()));
}
static int fmod_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static void fmod_clear_sample (FMODVoiceOut *fmd)
{
HWVoiceOut *hw = &fmd->hw;
HWVoice *hw = &fmd->hw;
int status;
void *p1 = 0, *p2 = 0;
unsigned int len1 = 0, len2 = 0;
@@ -104,7 +79,7 @@ static void fmod_clear_sample (FMODVoiceOut *fmd)
status = FSOUND_Sample_Lock (
fmd->fmod_sample,
0,
hw->samples << hw->info.shift,
hw->samples << hw->shift,
&p1,
&p2,
&len1,
@@ -112,86 +87,78 @@ static void fmod_clear_sample (FMODVoiceOut *fmd)
);
if (!status) {
fmod_logerr ("Failed to lock sample\n");
dolog ("Failed to lock sample\nReason: %s\n", errstr ());
return;
}
if ((len1 & hw->info.align) || (len2 & hw->info.align)) {
dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
len1, len2, hw->info.align + 1);
if ((len1 & hw->align) || (len2 & hw->align)) {
dolog ("Locking sample returned unaligned length %d, %d\n",
len1, len2);
goto fail;
}
if ((len1 + len2) - (hw->samples << hw->info.shift)) {
dolog ("Lock returned incomplete length %d, %d\n",
len1 + len2, hw->samples << hw->info.shift);
if (len1 + len2 != hw->samples << hw->shift) {
dolog ("Locking sample returned incomplete length %d, %d\n",
len1 + len2, hw->samples << hw->shift);
goto fail;
}
audio_pcm_info_clear_buf (&hw->info, p1, hw->samples);
pcm_hw_clear (hw, p1, hw->samples);
fail:
status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
if (!status) {
fmod_logerr ("Failed to unlock sample\n");
dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
}
}
static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
static int fmod_write_sample (HWVoice *hw, uint8_t *dst, st_sample_t *src,
int src_size, int src_pos, int dst_len)
{
int src_len1 = dst_len;
int src_len2 = 0;
int pos = hw->rpos + dst_len;
struct st_sample *src1 = hw->mix_buf + hw->rpos;
struct st_sample *src2 = NULL;
int src_len1 = dst_len, src_len2 = 0, pos = src_pos + dst_len;
st_sample_t *src1 = src + src_pos, *src2 = 0;
if (pos > hw->samples) {
src_len1 = hw->samples - hw->rpos;
src2 = hw->mix_buf;
if (src_pos + dst_len > src_size) {
src_len1 = src_size - src_pos;
src2 = src;
src_len2 = dst_len - src_len1;
pos = src_len2;
}
if (src_len1) {
hw->clip (dst, src1, src_len1);
memset (src1, 0, src_len1 * sizeof (st_sample_t));
advance (dst, src_len1);
}
if (src_len2) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
memset (src2, 0, src_len2 * sizeof (st_sample_t));
}
hw->rpos = pos % hw->samples;
return pos;
}
static int fmod_unlock_sample (FSOUND_SAMPLE *sample, void *p1, void *p2,
static int fmod_unlock_sample (FMODVoice *fmd, void *p1, void *p2,
unsigned int blen1, unsigned int blen2)
{
int status = FSOUND_Sample_Unlock (sample, p1, p2, blen1, blen2);
int status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, blen1, blen2);
if (!status) {
fmod_logerr ("Failed to unlock sample\n");
dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int fmod_lock_sample (
FSOUND_SAMPLE *sample,
struct audio_pcm_info *info,
int pos,
int len,
void **p1,
void **p2,
unsigned int *blen1,
unsigned int *blen2
)
static int fmod_lock_sample (FMODVoice *fmd, int pos, int len,
void **p1, void **p2,
unsigned int *blen1, unsigned int *blen2)
{
HWVoice *hw = &fmd->hw;
int status;
status = FSOUND_Sample_Lock (
sample,
pos << info->shift,
len << info->shift,
fmd->fmod_sample,
pos << hw->shift,
len << hw->shift,
p1,
p2,
blen1,
@@ -199,117 +166,89 @@ static int fmod_lock_sample (
);
if (!status) {
fmod_logerr ("Failed to lock sample\n");
dolog ("Failed to lock sample\nReason: %s\n", errstr ());
return -1;
}
if ((*blen1 & info->align) || (*blen2 & info->align)) {
dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
*blen1, *blen2, info->align + 1);
fmod_unlock_sample (sample, *p1, *p2, *blen1, *blen2);
*p1 = NULL - 1;
*p2 = NULL - 1;
*blen1 = ~0U;
*blen2 = ~0U;
if ((*blen1 & hw->align) || (*blen2 & hw->align)) {
dolog ("Locking sample returned unaligned length %d, %d\n",
*blen1, *blen2);
fmod_unlock_sample (fmd, *p1, *p2, *blen1, *blen2);
return -1;
}
if (!*p1 && *blen1) {
dolog ("warning: !p1 && blen1=%d\n", *blen1);
*blen1 = 0;
}
if (!p2 && *blen2) {
dolog ("warning: !p2 && blen2=%d\n", *blen2);
*blen2 = 0;
}
return 0;
}
static int fmod_run_out (HWVoiceOut *hw)
static void fmod_hw_run (HWVoice *hw)
{
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
int live, decr;
FMODVoice *fmd = (FMODVoice *) hw;
int rpos, live, decr;
void *p1 = 0, *p2 = 0;
unsigned int blen1 = 0, blen2 = 0;
unsigned int len1 = 0, len2 = 0;
int nb_live;
int nb_active;
live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
if (!live) {
return 0;
live = pcm_hw_get_live2 (hw, &nb_active);
if (live <= 0) {
return;
}
if (!hw->pending_disable
&& nb_live
&& (conf.threshold && live <= conf.threshold)) {
ldebug ("live=%d nb_live=%d\n", live, nb_live);
return 0;
&& nb_active
&& conf.threshold
&& live <= conf.threshold) {
ldebug ("live=%d nb_active=%d\n", live, nb_active);
return;
}
decr = live;
#if 1
if (fmd->channel >= 0) {
int len = decr;
int old_pos = fmd->old_pos;
int ppos = FSOUND_GetCurrentPosition (fmd->channel);
int pos2 = (fmd->old_pos + decr) % hw->samples;
int pos = FSOUND_GetCurrentPosition (fmd->channel);
if (ppos == old_pos || !ppos) {
return 0;
if (fmd->old_pos < pos && pos2 >= pos) {
decr = pos - fmd->old_pos - (pos2 == pos) - 1;
}
else if (fmd->old_pos > pos && pos2 >= pos && pos2 < fmd->old_pos) {
decr = (hw->samples - fmd->old_pos) + pos - (pos2 == pos) - 1;
}
/* ldebug ("pos=%d pos2=%d old=%d live=%d decr=%d\n", */
/* pos, pos2, fmd->old_pos, live, decr); */
}
#endif
if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
len = ppos - old_pos;
}
else {
if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->samples))) {
len = hw->samples - old_pos + ppos;
}
}
decr = len;
if (audio_bug (AUDIO_FUNC, decr < 0)) {
dolog ("decr=%d live=%d ppos=%d old_pos=%d len=%d\n",
decr, live, ppos, old_pos, len);
return 0;
}
if (decr <= 0) {
return;
}
if (!decr) {
return 0;
if (fmod_lock_sample (fmd, fmd->old_pos, decr, &p1, &p2, &blen1, &blen2)) {
return;
}
if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
fmd->old_pos, decr,
&p1, &p2,
&blen1, &blen2)) {
return 0;
}
len1 = blen1 >> hw->info.shift;
len2 = blen2 >> hw->info.shift;
len1 = blen1 >> hw->shift;
len2 = blen2 >> hw->shift;
ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
decr = len1 + len2;
rpos = hw->rpos;
if (p1 && len1) {
fmod_write_sample (hw, p1, len1);
if (len1) {
rpos = fmod_write_sample (hw, p1, hw->mix_buf, hw->samples, rpos, len1);
}
if (p2 && len2) {
fmod_write_sample (hw, p2, len2);
if (len2) {
rpos = fmod_write_sample (hw, p2, hw->mix_buf, hw->samples, rpos, len2);
}
fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
fmod_unlock_sample (fmd, p1, p2, blen1, blen2);
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos % hw->samples;
fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
return decr;
}
static int aud_to_fmodfmt (audfmt_e fmt, int stereo)
static int AUD_to_fmodfmt (audfmt_e fmt, int stereo)
{
int mode = FSOUND_LOOP_NORMAL;
@@ -331,19 +270,16 @@ static int aud_to_fmodfmt (audfmt_e fmt, int stereo)
break;
default:
dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_FMOD
abort ();
#endif
mode |= FSOUND_8BITS;
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
return mode;
}
static void fmod_fini_out (HWVoiceOut *hw)
static void fmod_hw_fini (HWVoice *hw)
{
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
FMODVoice *fmd = (FMODVoice *) hw;
if (fmd->fmod_sample) {
FSOUND_Sample_Free (fmd->fmod_sample);
@@ -355,164 +291,69 @@ static void fmod_fini_out (HWVoiceOut *hw)
}
}
static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
static int fmod_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
int bits16, mode, channel;
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
struct audsettings obt_as = *as;
FMODVoice *fmd = (FMODVoice *) hw;
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
mode = AUD_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
FSOUND_FREE, /* index */
conf.nb_samples, /* length */
mode, /* mode */
as->freq, /* freq */
freq, /* freq */
255, /* volume */
128, /* pan */
255 /* priority */
);
if (!fmd->fmod_sample) {
fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n");
dolog ("Failed to allocate FMOD sample\nReason: %s\n", errstr ());
return -1;
}
channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
if (channel < 0) {
fmod_logerr2 ("DAC", "Failed to start playing sound\n");
dolog ("Failed to start playing sound\nReason: %s\n", errstr ());
FSOUND_Sample_Free (fmd->fmod_sample);
return -1;
}
fmd->channel = channel;
/* FMOD always operates on little endian frames? */
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
hw->freq = freq;
hw->fmt = fmt;
hw->nchannels = nchannels;
bits16 = fmt == AUD_FMT_U16 || fmt == AUD_FMT_S16;
hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16;
return 0;
}
static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
static int fmod_hw_ctl (HWVoice *hw, int cmd, ...)
{
int status;
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
FMODVoice *fmd = (FMODVoice *) hw;
switch (cmd) {
case VOICE_ENABLE:
fmod_clear_sample (fmd);
status = FSOUND_SetPaused (fmd->channel, 0);
if (!status) {
fmod_logerr ("Failed to resume channel %d\n", fmd->channel);
dolog ("Failed to resume channel %d\nReason: %s\n",
fmd->channel, errstr ());
}
break;
case VOICE_DISABLE:
status = FSOUND_SetPaused (fmd->channel, 1);
if (!status) {
fmod_logerr ("Failed to pause channel %d\n", fmd->channel);
dolog ("Failed to pause channel %d\nReason: %s\n",
fmd->channel, errstr ());
}
break;
}
return 0;
}
static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
{
int bits16, mode;
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
struct audsettings obt_as = *as;
if (conf.broken_adc) {
return -1;
}
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
FSOUND_FREE, /* index */
conf.nb_samples, /* length */
mode, /* mode */
as->freq, /* freq */
255, /* volume */
128, /* pan */
255 /* priority */
);
if (!fmd->fmod_sample) {
fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
return -1;
}
/* FMOD always operates on little endian frames? */
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
return 0;
}
static void fmod_fini_in (HWVoiceIn *hw)
{
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
if (fmd->fmod_sample) {
FSOUND_Record_Stop ();
FSOUND_Sample_Free (fmd->fmod_sample);
fmd->fmod_sample = 0;
}
}
static int fmod_run_in (HWVoiceIn *hw)
{
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
int hwshift = hw->info.shift;
int live, dead, new_pos, len;
unsigned int blen1 = 0, blen2 = 0;
unsigned int len1, len2;
unsigned int decr;
void *p1, *p2;
live = audio_pcm_hw_get_live_in (hw);
dead = hw->samples - live;
if (!dead) {
return 0;
}
new_pos = FSOUND_Record_GetPosition ();
if (new_pos < 0) {
fmod_logerr ("Could not get recording position\n");
return 0;
}
len = audio_ring_dist (new_pos, hw->wpos, hw->samples);
if (!len) {
return 0;
}
len = audio_MIN (len, dead);
if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
hw->wpos, len,
&p1, &p2,
&blen1, &blen2)) {
return 0;
}
len1 = blen1 >> hwshift;
len2 = blen2 >> hwshift;
decr = len1 + len2;
if (p1 && blen1) {
hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
}
if (p2 && len2) {
hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
}
fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
hw->wpos = (hw->wpos + decr) % hw->samples;
return decr;
}
static struct {
const char *name;
int type;
@@ -537,16 +378,16 @@ static struct {
{"ps2", FSOUND_OUTPUT_PS2},
{"gcube", FSOUND_OUTPUT_GC},
#endif
{"none-realtime", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
{"nort", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
};
static void *fmod_audio_init (void)
{
size_t i;
int i;
double ver;
int status;
int output_type = -1;
const char *drv = conf.drvname;
const char *drv = audio_get_conf_str (QC_FMOD_DRV, NULL);
ver = FSOUND_GetVersion ();
if (ver < FMOD_VERSION) {
@@ -554,17 +395,9 @@ static void *fmod_audio_init (void)
return NULL;
}
#ifdef __linux__
if (ver < 3.75) {
dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
"ADC will be disabled.\n");
conf.broken_adc = 1;
}
#endif
if (drv) {
int found = 0;
for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
if (!strcmp (drv, drvtab[i].name)) {
output_type = drvtab[i].type;
found = 1;
@@ -572,115 +405,65 @@ static void *fmod_audio_init (void)
}
}
if (!found) {
dolog ("Unknown FMOD driver `%s'\n", drv);
dolog ("Valid drivers:\n");
for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
dolog (" %s\n", drvtab[i].name);
}
dolog ("Unknown FMOD output driver `%s'\n", drv);
}
}
if (output_type != -1) {
status = FSOUND_SetOutput (output_type);
if (!status) {
fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type);
dolog ("FSOUND_SetOutput(%d) failed\nReason: %s\n",
output_type, errstr ());
return NULL;
}
}
conf.freq = audio_get_conf_int (QC_FMOD_FREQ, conf.freq);
conf.nb_samples = audio_get_conf_int (QC_FMOD_SAMPLES, conf.nb_samples);
conf.nb_channels =
audio_get_conf_int (QC_FMOD_CHANNELS,
(audio_state.nb_hw_voices > 1
? audio_state.nb_hw_voices
: conf.nb_channels));
conf.bufsize = audio_get_conf_int (QC_FMOD_BUFSIZE, conf.bufsize);
conf.threshold = audio_get_conf_int (QC_FMOD_THRESHOLD, conf.threshold);
if (conf.bufsize) {
status = FSOUND_SetBufferSize (conf.bufsize);
if (!status) {
fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize);
dolog ("FSOUND_SetBufferSize (%d) failed\nReason: %s\n",
conf.bufsize, errstr ());
}
}
status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
if (!status) {
fmod_logerr ("FSOUND_Init failed\n");
dolog ("FSOUND_Init failed\nReason: %s\n", errstr ());
return NULL;
}
return &conf;
}
static int fmod_read (SWVoiceIn *sw, void *buf, int size)
{
return audio_pcm_sw_read (sw, buf, size);
}
static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
int status;
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
switch (cmd) {
case VOICE_ENABLE:
status = FSOUND_Record_StartSample (fmd->fmod_sample, 1);
if (!status) {
fmod_logerr ("Failed to start recording\n");
}
break;
case VOICE_DISABLE:
status = FSOUND_Record_Stop ();
if (!status) {
fmod_logerr ("Failed to stop recording\n");
}
break;
}
return 0;
}
static void fmod_audio_fini (void *opaque)
{
(void) opaque;
FSOUND_Close ();
}
static struct audio_option fmod_options[] = {
{"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}
struct pcm_ops fmod_pcm_ops = {
fmod_hw_init,
fmod_hw_fini,
fmod_hw_run,
fmod_hw_write,
fmod_hw_ctl
};
static struct audio_pcm_ops fmod_pcm_ops = {
fmod_init_out,
fmod_fini_out,
fmod_run_out,
fmod_write,
fmod_ctl_out,
fmod_init_in,
fmod_fini_in,
fmod_run_in,
fmod_read,
fmod_ctl_in
};
struct audio_driver fmod_audio_driver = {
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)
struct audio_output_driver fmod_output_driver = {
"fmod",
fmod_audio_init,
fmod_audio_fini,
&fmod_pcm_ops,
1,
INT_MAX,
sizeof (FMODVoice)
};

View File

@@ -1,7 +1,7 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
* Copyright (c) 2004 Vassili Karpov (malc)
* Copyright (c) 1998 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -22,233 +22,88 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "audio.h"
#include "vl.h"
//#define DEBUG_FP
#include "audio/mixeng.h"
#define AUDIO_CAP "mixeng"
#include "audio_int.h"
/* 8 bit */
#define ENDIAN_CONVERSION natural
#define ENDIAN_CONVERT(v) (v)
/* Signed 8 bit */
#define IN_T int8_t
#define IN_MIN SCHAR_MIN
#define IN_MAX SCHAR_MAX
#define IN_MIN CHAR_MIN
#define IN_MAX CHAR_MAX
#define SIGNED
#define SHIFT 8
#include "mixeng_template.h"
#undef SIGNED
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#undef SHIFT
/* Unsigned 8 bit */
#define IN_T uint8_t
#define IN_MIN 0
#define IN_MAX UCHAR_MAX
#define SHIFT 8
#include "mixeng_template.h"
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#undef SHIFT
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
/* Signed 16 bit */
#define IN_T int16_t
#define IN_MIN SHRT_MIN
#define IN_MAX SHRT_MAX
#define SIGNED
#define SHIFT 16
#define ENDIAN_CONVERSION natural
#define ENDIAN_CONVERT(v) (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#define ENDIAN_CONVERSION swap
#define ENDIAN_CONVERT(v) bswap16 (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#undef SIGNED
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#undef SHIFT
/* Unsigned 16 bit */
#define IN_T uint16_t
#define IN_MIN 0
#define IN_MAX USHRT_MAX
#define SHIFT 16
#define ENDIAN_CONVERSION natural
#define ENDIAN_CONVERT(v) (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#define ENDIAN_CONVERSION swap
#define ENDIAN_CONVERT(v) bswap16 (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#undef SHIFT
/* Signed 32 bit */
#define IN_T int32_t
#define IN_MIN INT32_MIN
#define IN_MAX INT32_MAX
#define SIGNED
#define SHIFT 32
#define ENDIAN_CONVERSION natural
#define ENDIAN_CONVERT(v) (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#define ENDIAN_CONVERSION swap
#define ENDIAN_CONVERT(v) bswap32 (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#undef SIGNED
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#undef SHIFT
/* Unsigned 16 bit */
#define IN_T uint32_t
#define IN_MIN 0
#define IN_MAX UINT32_MAX
#define SHIFT 32
#define ENDIAN_CONVERSION natural
#define ENDIAN_CONVERT(v) (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#define ENDIAN_CONVERSION swap
#define ENDIAN_CONVERT(v) bswap32 (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#undef SHIFT
t_sample *mixeng_conv[2][2][2][3] = {
t_sample *mixeng_conv[2][2][2] = {
{
{
{
conv_natural_uint8_t_to_mono,
conv_natural_uint16_t_to_mono,
conv_natural_uint32_t_to_mono
},
{
conv_natural_uint8_t_to_mono,
conv_swap_uint16_t_to_mono,
conv_swap_uint32_t_to_mono,
}
conv_uint8_t_to_mono,
conv_uint16_t_to_mono
},
{
{
conv_natural_int8_t_to_mono,
conv_natural_int16_t_to_mono,
conv_natural_int32_t_to_mono
},
{
conv_natural_int8_t_to_mono,
conv_swap_int16_t_to_mono,
conv_swap_int32_t_to_mono
}
conv_int8_t_to_mono,
conv_int16_t_to_mono
}
},
{
{
{
conv_natural_uint8_t_to_stereo,
conv_natural_uint16_t_to_stereo,
conv_natural_uint32_t_to_stereo
},
{
conv_natural_uint8_t_to_stereo,
conv_swap_uint16_t_to_stereo,
conv_swap_uint32_t_to_stereo
}
conv_uint8_t_to_stereo,
conv_uint16_t_to_stereo
},
{
{
conv_natural_int8_t_to_stereo,
conv_natural_int16_t_to_stereo,
conv_natural_int32_t_to_stereo
},
{
conv_natural_int8_t_to_stereo,
conv_swap_int16_t_to_stereo,
conv_swap_int32_t_to_stereo,
}
conv_int8_t_to_stereo,
conv_int16_t_to_stereo
}
}
};
f_sample *mixeng_clip[2][2][2][3] = {
f_sample *mixeng_clip[2][2][2] = {
{
{
{
clip_natural_uint8_t_from_mono,
clip_natural_uint16_t_from_mono,
clip_natural_uint32_t_from_mono
},
{
clip_natural_uint8_t_from_mono,
clip_swap_uint16_t_from_mono,
clip_swap_uint32_t_from_mono
}
clip_uint8_t_from_mono,
clip_uint16_t_from_mono
},
{
{
clip_natural_int8_t_from_mono,
clip_natural_int16_t_from_mono,
clip_natural_int32_t_from_mono
},
{
clip_natural_int8_t_from_mono,
clip_swap_int16_t_from_mono,
clip_swap_int32_t_from_mono
}
clip_int8_t_from_mono,
clip_int16_t_from_mono
}
},
{
{
{
clip_natural_uint8_t_from_stereo,
clip_natural_uint16_t_from_stereo,
clip_natural_uint32_t_from_stereo
},
{
clip_natural_uint8_t_from_stereo,
clip_swap_uint16_t_from_stereo,
clip_swap_uint32_t_from_stereo
}
clip_uint8_t_from_stereo,
clip_uint16_t_from_stereo
},
{
{
clip_natural_int8_t_from_stereo,
clip_natural_int16_t_from_stereo,
clip_natural_int32_t_from_stereo
},
{
clip_natural_int8_t_from_stereo,
clip_swap_int16_t_from_stereo,
clip_swap_int32_t_from_stereo
}
clip_int8_t_from_stereo,
clip_int16_t_from_stereo
}
}
};
@@ -261,9 +116,9 @@ f_sample *mixeng_clip[2][2][2][3] = {
* Contributors with a more efficient algorithm.]
*
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Lance Norskog And Sundry Contributors are not responsible for
* the consequences of using this software.
* any purpose. This copyright notice must be maintained.
* Lance Norskog And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
/*
@@ -286,29 +141,36 @@ f_sample *mixeng_clip[2][2][2][3] = {
*/
/* Private data */
struct rate {
typedef struct ratestuff {
uint64_t opos;
uint64_t opos_inc;
uint32_t ipos; /* position in the input stream (integer) */
struct st_sample ilast; /* last sample in the input stream */
};
st_sample_t ilast; /* last sample in the input stream */
} *rate_t;
/*
* Prepare processing.
*/
void *st_rate_start (int inrate, int outrate)
{
struct rate *rate = audio_calloc (AUDIO_FUNC, 1, sizeof (*rate));
rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff));
if (!rate) {
dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate));
return NULL;
exit (EXIT_FAILURE);
}
if (inrate == outrate) {
// exit (EXIT_FAILURE);
}
if (inrate >= 65535 || outrate >= 65535) {
// exit (EXIT_FAILURE);
}
rate->opos = 0;
/* increment */
rate->opos_inc = ((uint64_t) inrate << 32) / outrate;
rate->opos_inc = (inrate * ((int64_t) UINT_MAX)) / outrate;
rate->ipos = 0;
rate->ilast.l = 0;
@@ -316,20 +178,78 @@ void *st_rate_start (int inrate, int outrate)
return rate;
}
#define NAME st_rate_flow_mix
#define OP(a, b) a += b
#include "rate_template.h"
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
int *isamp, int *osamp)
{
rate_t rate = (rate_t) opaque;
st_sample_t *istart, *iend;
st_sample_t *ostart, *oend;
st_sample_t ilast, icur, out;
int64_t t;
#define NAME st_rate_flow
#define OP(a, b) a = b
#include "rate_template.h"
ilast = rate->ilast;
istart = ibuf;
iend = ibuf + *isamp;
ostart = obuf;
oend = obuf + *osamp;
if (rate->opos_inc == 1ULL << 32) {
int i, n = *isamp > *osamp ? *osamp : *isamp;
for (i = 0; i < n; i++) {
obuf[i].l += ibuf[i].r;
obuf[i].r += ibuf[i].r;
}
*isamp = n;
*osamp = n;
return;
}
while (obuf < oend) {
/* Safety catch to make sure we have input samples. */
if (ibuf >= iend)
break;
/* read as many input samples so that ipos > opos */
while (rate->ipos <= (rate->opos >> 32)) {
ilast = *ibuf++;
rate->ipos++;
/* See if we finished the input buffer yet */
if (ibuf >= iend) goto the_end;
}
icur = *ibuf;
/* interpolate */
t = rate->opos & 0xffffffff;
out.l = (ilast.l * (INT_MAX - t) + icur.l * t) / INT_MAX;
out.r = (ilast.r * (INT_MAX - t) + icur.r * t) / INT_MAX;
/* output sample & increment position */
#if 0
*obuf++ = out;
#else
obuf->l += out.l;
obuf->r += out.r;
obuf += 1;
#endif
rate->opos += rate->opos_inc;
}
the_end:
*isamp = ibuf - istart;
*osamp = obuf - ostart;
rate->ilast = ilast;
}
void st_rate_stop (void *opaque)
{
qemu_free (opaque);
}
void mixeng_clear (struct st_sample *buf, int len)
{
memset (buf, 0, len * sizeof (struct st_sample));
}

View File

@@ -1,8 +1,8 @@
/*
* QEMU Mixing engine header
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
*
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* 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
@@ -24,28 +24,16 @@
#ifndef QEMU_MIXENG_H
#define QEMU_MIXENG_H
#ifdef FLOAT_MIXENG
typedef float mixeng_real;
struct mixeng_volume { int mute; mixeng_real r; mixeng_real l; };
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; };
#endif
typedef void (t_sample) (void *dst, const void *src, int samples);
typedef void (f_sample) (void *dst, const void *src, int samples);
typedef struct { int64_t l; int64_t r; } st_sample_t;
typedef void (t_sample) (struct st_sample *dst, const void *src,
int samples, struct mixeng_volume *vol);
typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
extern t_sample *mixeng_conv[2][2][2][3];
extern f_sample *mixeng_clip[2][2][2][3];
extern t_sample *mixeng_conv[2][2][2];
extern f_sample *mixeng_clip[2][2][2];
void *st_rate_start (int inrate, int outrate);
void st_rate_flow (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
int *isamp, int *osamp);
void st_rate_flow_mix (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
int *isamp, int *osamp);
void st_rate_stop (void *opaque);
void mixeng_clear (struct st_sample *buf, int len);
#endif /* mixeng.h */

View File

@@ -1,8 +1,8 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
*
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* 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
@@ -27,151 +27,85 @@
* dec++'ified by Dscho
*/
#ifndef SIGNED
#define HALF (IN_MAX >> 1)
#endif
#ifdef CONFIG_MIXEMU
#ifdef FLOAT_MIXENG
#define VOL(a, b) ((a) * (b))
#ifdef SIGNED
#define HALFT IN_MAX
#define HALF IN_MAX
#else
#define VOL(a, b) ((a) * (b)) >> 32
#endif
#else
#define VOL(a, b) a
#define HALFT ((IN_MAX)>>1)
#define HALF HALFT
#endif
#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
#ifdef FLOAT_MIXENG
static mixeng_real inline glue (conv_, ET) (IN_T v)
static int64_t inline glue(conv_,IN_T) (IN_T v)
{
IN_T nv = ENDIAN_CONVERT (v);
#ifdef RECIPROCAL
#ifdef SIGNED
return nv * (1.f / (mixeng_real) (IN_MAX - IN_MIN));
return (INT_MAX*(int64_t)v)/HALF;
#else
return (nv - HALF) * (1.f / (mixeng_real) IN_MAX);
#endif
#else /* !RECIPROCAL */
#ifdef SIGNED
return nv / (mixeng_real) (IN_MAX - IN_MIN);
#else
return (nv - HALF) / (mixeng_real) IN_MAX;
#endif
return (INT_MAX*((int64_t)v-HALFT))/HALF;
#endif
}
static IN_T inline glue (clip_, ET) (mixeng_real v)
static IN_T inline glue(clip_,IN_T) (int64_t v)
{
if (v >= 0.5) {
if (v >= INT_MAX)
return IN_MAX;
}
else if (v < -0.5) {
else if (v < -INT_MAX)
return IN_MIN;
}
#ifdef SIGNED
return ENDIAN_CONVERT ((IN_T) (v * (IN_MAX - IN_MIN)));
return (IN_T) (v*HALF/INT_MAX);
#else
return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
return (IN_T) (v+INT_MAX/2)*HALF/INT_MAX;
#endif
}
#else /* !FLOAT_MIXENG */
static inline int64_t glue (conv_, ET) (IN_T v)
static void glue(glue(conv_,IN_T),_to_stereo) (void *dst, const void *src,
int samples)
{
IN_T nv = ENDIAN_CONVERT (v);
#ifdef SIGNED
return ((int64_t) nv) << (32 - SHIFT);
#else
return ((int64_t) nv - HALF) << (32 - SHIFT);
#endif
}
static inline IN_T glue (clip_, ET) (int64_t v)
{
if (v >= 0x7f000000) {
return IN_MAX;
}
else if (v < -2147483648LL) {
return IN_MIN;
}
#ifdef SIGNED
return ENDIAN_CONVERT ((IN_T) (v >> (32 - SHIFT)));
#else
return ENDIAN_CONVERT ((IN_T) ((v >> (32 - SHIFT)) + HALF));
#endif
}
#endif
static void glue (glue (conv_, ET), _to_stereo)
(struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
{
struct st_sample *out = dst;
st_sample_t *out = (st_sample_t *) dst;
IN_T *in = (IN_T *) src;
#ifdef CONFIG_MIXEMU
if (vol->mute) {
mixeng_clear (dst, samples);
return;
}
#else
(void) vol;
#endif
while (samples--) {
out->l = VOL (glue (conv_, ET) (*in++), vol->l);
out->r = VOL (glue (conv_, ET) (*in++), vol->r);
out->l = glue(conv_,IN_T) (*in++);
out->r = glue(conv_,IN_T) (*in++);
out += 1;
}
}
static void glue (glue (conv_, ET), _to_mono)
(struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
static void glue(glue(conv_,IN_T),_to_mono) (void *dst, const void *src,
int samples)
{
struct st_sample *out = dst;
st_sample_t *out = (st_sample_t *) dst;
IN_T *in = (IN_T *) src;
#ifdef CONFIG_MIXEMU
if (vol->mute) {
mixeng_clear (dst, samples);
return;
}
#else
(void) vol;
#endif
while (samples--) {
out->l = VOL (glue (conv_, ET) (in[0]), vol->l);
out->l = glue(conv_,IN_T) (in[0]);
out->r = out->l;
out += 1;
in += 1;
}
}
static void glue (glue (clip_, ET), _from_stereo)
(void *dst, const struct st_sample *src, int samples)
static void glue(glue(clip_,IN_T),_from_stereo) (void *dst, const void *src,
int samples)
{
const struct st_sample *in = src;
st_sample_t *in = (st_sample_t *) src;
IN_T *out = (IN_T *) dst;
while (samples--) {
*out++ = glue (clip_, ET) (in->l);
*out++ = glue (clip_, ET) (in->r);
*out++ = glue(clip_,IN_T) (in->l);
*out++ = glue(clip_,IN_T) (in->r);
in += 1;
}
}
static void glue (glue (clip_, ET), _from_mono)
(void *dst, const struct st_sample *src, int samples)
static void glue(glue(clip_,IN_T),_from_mono) (void *dst, const void *src,
int samples)
{
const struct st_sample *in = src;
st_sample_t *in = (st_sample_t *) src;
IN_T *out = (IN_T *) dst;
while (samples--) {
*out++ = glue (clip_, ET) (in->l + in->r);
*out++ = glue(clip_,IN_T) (in->l + in->r);
in += 1;
}
}
#undef ET
#undef HALF
#undef VOL
#undef HALFT

View File

@@ -1,8 +1,8 @@
/*
* QEMU Timer based audio emulation
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
*
* QEMU NULL audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* 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
@@ -21,114 +21,79 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "audio.h"
#include "qemu-timer.h"
#include "vl.h"
#define AUDIO_CAP "noaudio"
#include "audio_int.h"
#include "audio/audio_int.h"
typedef struct NoVoiceOut {
HWVoiceOut hw;
typedef struct NoVoice {
HWVoice hw;
int64_t old_ticks;
} NoVoiceOut;
} NoVoice;
typedef struct NoVoiceIn {
HWVoiceIn hw;
int64_t old_ticks;
} NoVoiceIn;
#define dolog(...) AUD_log ("noaudio", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
static int no_run_out (HWVoiceOut *hw)
static void no_hw_run (HWVoice *hw)
{
NoVoiceOut *no = (NoVoiceOut *) hw;
int live, decr, samples;
int64_t now;
int64_t ticks;
int64_t bytes;
NoVoice *no = (NoVoice *) hw;
int rpos, live, decr, samples;
st_sample_t *src;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
live = audio_pcm_hw_get_live_out (&no->hw);
if (!live) {
return 0;
}
if (bytes > INT_MAX)
samples = INT_MAX >> hw->shift;
else
samples = bytes >> hw->shift;
now = qemu_get_clock (vm_clock);
ticks = now - no->old_ticks;
bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
no->old_ticks = now;
decr = audio_MIN (live, samples);
hw->rpos = (hw->rpos + decr) % hw->samples;
return decr;
}
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);
static int no_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
memset (src, 0, convert_samples * sizeof (st_sample_t));
static int no_init_out (HWVoiceOut *hw, struct audsettings *as)
{
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
return 0;
}
static void no_fini_out (HWVoiceOut *hw)
{
(void) hw;
}
static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
static int no_init_in (HWVoiceIn *hw, struct audsettings *as)
{
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
return 0;
}
static void no_fini_in (HWVoiceIn *hw)
{
(void) hw;
}
static int no_run_in (HWVoiceIn *hw)
{
NoVoiceIn *no = (NoVoiceIn *) hw;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
int samples = 0;
if (dead) {
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
no->old_ticks = now;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
samples = audio_MIN (samples, dead);
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
return samples;
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
}
static int no_read (SWVoiceIn *sw, void *buf, int size)
static int no_hw_write (SWVoice *sw, void *buf, int len)
{
int samples = size >> sw->info.shift;
int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
int to_clear = audio_MIN (samples, total);
audio_pcm_info_clear_buf (&sw->info, buf, to_clear);
return to_clear;
return pcm_hw_write (sw, buf, len);
}
static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
static int no_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
hw->freq = freq;
hw->nchannels = nchannels;
hw->fmt = fmt;
hw->bufsize = 4096;
return 0;
}
static void no_hw_fini (HWVoice *hw)
{
(void) hw;
}
static int no_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
@@ -142,33 +107,22 @@ static void *no_audio_init (void)
static void no_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_pcm_ops no_pcm_ops = {
no_init_out,
no_fini_out,
no_run_out,
no_write,
no_ctl_out,
no_init_in,
no_fini_in,
no_run_in,
no_read,
no_ctl_in
struct pcm_ops no_pcm_ops = {
no_hw_init,
no_hw_fini,
no_hw_run,
no_hw_write,
no_hw_ctl
};
struct audio_driver no_audio_driver = {
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)
struct audio_output_driver no_output_driver = {
"none",
no_audio_init,
no_audio_fini,
&no_pcm_ops,
1,
1,
sizeof (NoVoice)
};

View File

@@ -1,8 +1,8 @@
/*
* QEMU OSS audio driver
*
* Copyright (c) 2003-2005 Vassili Karpov (malc)
*
* QEMU OSS audio output driver
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* 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
@@ -21,54 +21,49 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#ifdef __OpenBSD__
#include <soundcard.h>
#else
#include <sys/soundcard.h>
#endif
#include "qemu-common.h"
#include "audio.h"
#include <assert.h>
#include "vl.h"
#define AUDIO_CAP "oss"
#include "audio_int.h"
#include "audio/audio_int.h"
typedef struct OSSVoiceOut {
HWVoiceOut hw;
typedef struct OSSVoice {
HWVoice hw;
void *pcm_buf;
int fd;
int nfrags;
int fragsize;
int mmapped;
int old_optr;
} OSSVoiceOut;
} OSSVoice;
typedef struct OSSVoiceIn {
HWVoiceIn hw;
void *pcm_buf;
int fd;
int nfrags;
int fragsize;
int old_optr;
} OSSVoiceIn;
#define dolog(...) AUD_log ("oss", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS"
#define QC_OSS_MMAP "QEMU_OSS_MMAP"
#define QC_OSS_DEV "QEMU_OSS_DEV"
#define errstr() strerror (errno)
static struct {
int try_mmap;
int nfrags;
int fragsize;
const char *devpath_out;
const char *devpath_in;
int debug;
const char *dspname;
} conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.devpath_out = "/dev/dsp",
.devpath_in = "/dev/dsp",
.debug = 0
.dspname = "/dev/dsp"
};
struct oss_params {
@@ -79,141 +74,65 @@ struct oss_params {
int fragsize;
};
static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
static int oss_hw_write (SWVoice *sw, void *buf, int len)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
return pcm_hw_write (sw, buf, len);
}
static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
int err,
const char *typ,
const char *fmt,
...
)
{
va_list ap;
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
}
static void oss_anal_close (int *fdp)
{
int err = close (*fdp);
if (err) {
oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
}
*fdp = -1;
}
static int oss_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int aud_to_ossfmt (audfmt_e fmt)
static int AUD_to_ossfmt (audfmt_e fmt)
{
switch (fmt) {
case AUD_FMT_S8:
return AFMT_S8;
case AUD_FMT_U8:
return AFMT_U8;
case AUD_FMT_S16:
return AFMT_S16_LE;
case AUD_FMT_U16:
return AFMT_U16_LE;
case AUD_FMT_S8: return AFMT_S8;
case AUD_FMT_U8: return AFMT_U8;
case AUD_FMT_S16: return AFMT_S16_LE;
case AUD_FMT_U16: return AFMT_U16_LE;
default:
dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_AUDIO
abort ();
#endif
return AFMT_U8;
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
static int oss_to_audfmt (int fmt)
{
switch (ossfmt) {
case AFMT_S8:
*endianness = 0;
*fmt = AUD_FMT_S8;
break;
case AFMT_U8:
*endianness = 0;
*fmt = AUD_FMT_U8;
break;
case AFMT_S16_LE:
*endianness = 0;
*fmt = AUD_FMT_S16;
break;
case AFMT_U16_LE:
*endianness = 0;
*fmt = AUD_FMT_U16;
break;
case AFMT_S16_BE:
*endianness = 1;
*fmt = AUD_FMT_S16;
break;
case AFMT_U16_BE:
*endianness = 1;
*fmt = AUD_FMT_U16;
break;
switch (fmt) {
case AFMT_S8: return AUD_FMT_S8;
case AFMT_U8: return AUD_FMT_U8;
case AFMT_S16_LE: return AUD_FMT_S16;
case AFMT_U16_LE: return AUD_FMT_U16;
default:
dolog ("Unrecognized audio format %d\n", ossfmt);
return -1;
dolog ("Internal logic error: Unrecognized OSS audio format %d\n"
"Aborting\n",
fmt);
exit (EXIT_FAILURE);
}
return 0;
}
#if defined DEBUG_MISMATCHES || defined DEBUG
static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
#ifdef DEBUG_PCM
static void oss_dump_pcm_info (struct oss_params *req, struct oss_params *obt)
{
dolog ("parameter | requested value | obtained value\n");
dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
dolog ("channels | %10d | %10d\n",
req->nchannels, obt->nchannels);
dolog ("channels | %10d | %10d\n", req->nchannels, obt->nchannels);
dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags);
dolog ("fragsize | %10d | %10d\n",
req->fragsize, obt->fragsize);
dolog ("fragsize | %10d | %10d\n", req->fragsize, obt->fragsize);
}
#endif
static int oss_open (int in, struct oss_params *req,
struct oss_params *obt, int *pfd)
static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
{
int fd;
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";
const char *dspname = conf.dspname;
fd = open (dspname, (in ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
fd = open (dspname, O_RDWR | O_NONBLOCK);
if (-1 == fd) {
oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
"Reason:%s\n",
dspname,
errstr ());
return -1;
}
@@ -222,41 +141,52 @@ static int oss_open (int in, struct oss_params *req,
fmt = req->fmt;
if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
dolog ("Could not initialize audio hardware\n"
"Failed to set sample size\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
req->nchannels);
dolog ("Could not initialize audio hardware\n"
"Failed to set number of channels\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
dolog ("Could not initialize audio hardware\n"
"Failed to set frequency\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set non-blocking mode\n"
"Reason: %s\n",
errstr ());
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);
dolog ("Could not initialize audio hardware\n"
"Failed to set buffer length (%d, %d)\n"
"Reason:%s\n",
conf.nfrags, conf.fragsize,
errstr ());
goto err;
}
if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
oss_logerr2 (errno, typ, "Failed to get buffer length\n");
goto err;
}
if (!abinfo.fragstotal || !abinfo.fragsize) {
AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
abinfo.fragstotal, abinfo.fragsize, typ);
if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &abinfo)) {
dolog ("Could not initialize audio hardware\n"
"Failed to get buffer length\n"
"Reason:%s\n",
errstr ());
goto err;
}
@@ -267,98 +197,75 @@ static int oss_open (int in, struct oss_params *req,
obt->fragsize = abinfo.fragsize;
*pfd = fd;
#ifdef DEBUG_MISMATCHES
if ((req->fmt != obt->fmt) ||
(req->nchannels != obt->nchannels) ||
(req->freq != obt->freq) ||
(req->fragsize != obt->fragsize) ||
(req->nfrags != obt->nfrags)) {
#ifdef DEBUG_PCM
dolog ("Audio parameters mismatch\n");
oss_dump_info (req, obt);
}
oss_dump_pcm_info (req, obt);
#endif
}
#ifdef DEBUG
oss_dump_info (req, obt);
#ifdef DEBUG_PCM
oss_dump_pcm_info (req, obt);
#endif
return 0;
err:
oss_anal_close (&fd);
err:
close (fd);
return -1;
}
static int oss_run_out (HWVoiceOut *hw)
static void oss_hw_run (HWVoice *hw)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
OSSVoice *oss = (OSSVoice *) hw;
int err, rpos, live, decr;
int samples;
uint8_t *dst;
struct st_sample *src;
st_sample_t *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;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
if (oss->mmapped) {
int bytes;
err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
if (err < 0) {
oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
return 0;
dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ());
return;
}
if (cntinfo.ptr == oss->old_optr) {
if (abs (hw->samples - live) < 64) {
dolog ("warning: Overrun\n");
}
return 0;
if (abs (hw->samples - live) < 64)
dolog ("overrun\n");
return;
}
if (cntinfo.ptr > oss->old_optr) {
bytes = cntinfo.ptr - oss->old_optr;
}
else {
bytes = bufsize + cntinfo.ptr - oss->old_optr;
bytes = hw->bufsize + cntinfo.ptr - oss->old_optr;
}
decr = audio_MIN (bytes >> hw->info.shift, live);
decr = audio_MIN (bytes >> hw->shift, live);
}
else {
err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
if (err < 0) {
oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
return 0;
dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ());
return;
}
if (abinfo.bytes > bufsize) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
"please report your OS/audio hw to malc@pulsesoft.com\n",
abinfo.bytes, bufsize);
}
abinfo.bytes = bufsize;
}
if (abinfo.bytes < 0) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
abinfo.bytes, bufsize);
}
return 0;
}
decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
if (!decr) {
return 0;
}
decr = audio_MIN (abinfo.bytes >> hw->shift, live);
if (decr <= 0)
return;
}
samples = decr;
@@ -367,38 +274,33 @@ static int oss_run_out (HWVoiceOut *hw)
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);
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
dst = advance (oss->pcm_buf, rpos << hw->shift);
hw->clip (dst, src, convert_samples);
if (!oss->mmapped) {
int written;
written = write (oss->fd, dst, convert_samples << hw->info.shift);
written = write (oss->fd, dst, convert_samples << hw->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
);
dolog ("Failed to write audio\nReason: %s\n", errstr ());
continue;
}
if (written != convert_samples << hw->info.shift) {
int wsamples = written >> hw->info.shift;
int wbytes = wsamples << hw->info.shift;
if (written != convert_samples << hw->shift) {
int wsamples = written >> hw->shift;
int wbytes = wsamples << hw->shift;
if (wbytes != written) {
dolog ("warning: Misaligned write %d (requested %d), "
"alignment %d\n",
wbytes, written, hw->info.align + 1);
dolog ("Unaligned write %d, %d\n", wbytes, written);
}
decr -= wsamples;
memset (src, 0, wbytes);
decr -= samples;
rpos = (rpos + wsamples) % hw->samples;
break;
}
}
memset (src, 0, convert_samples * sizeof (st_sample_t));
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
@@ -407,24 +309,28 @@ static int oss_run_out (HWVoiceOut *hw)
oss->old_optr = cntinfo.ptr;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
return decr;
}
static void oss_fini_out (HWVoiceOut *hw)
static void oss_hw_fini (HWVoice *hw)
{
int err;
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
OSSVoice *oss = (OSSVoice *) hw;
ldebug ("oss_fini\n");
oss_anal_close (&oss->fd);
ldebug ("oss_hw_fini\n");
err = close (oss->fd);
if (err) {
dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ());
}
oss->fd = -1;
if (oss->pcm_buf) {
if (oss->mmapped) {
err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
err = munmap (oss->pcm_buf, hw->bufsize);
if (err) {
oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
oss->pcm_buf, hw->samples << hw->info.shift);
dolog ("Failed to unmap OSS buffer\nReason: %s\n",
errstr ());
}
}
else {
@@ -434,76 +340,48 @@ static void oss_fini_out (HWVoiceOut *hw)
}
}
static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
OSSVoice *oss = (OSSVoice *) hw;
struct oss_params req, obt;
int endianness;
int err;
int fd;
audfmt_e effective_fmt;
struct audsettings obt_as;
oss->fd = -1;
req.fmt = aud_to_ossfmt (as->fmt);
req.freq = as->freq;
req.nchannels = as->nchannels;
assert (!oss->fd);
req.fmt = AUD_to_ossfmt (fmt);
req.freq = freq;
req.nchannels = nchannels;
req.fragsize = conf.fragsize;
req.nfrags = conf.nfrags;
if (oss_open (0, &req, &obt, &fd)) {
if (oss_open (&req, &obt, &oss->fd))
return -1;
}
err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
if (err) {
oss_anal_close (&fd);
return -1;
}
hw->freq = obt.freq;
hw->fmt = oss_to_audfmt (obt.fmt);
hw->nchannels = obt.nchannels;
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (&hw->info, &obt_as);
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
if (obt.nfrags * obt.fragsize & hw->info.align) {
dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
obt.nfrags * obt.fragsize, hw->info.align + 1);
}
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
hw->bufsize = obt.nfrags * obt.fragsize;
oss->mmapped = 0;
if (conf.try_mmap) {
oss->pcm_buf = mmap (
NULL,
hw->samples << hw->info.shift,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0
);
oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE,
MAP_SHARED, oss->fd, 0);
if (oss->pcm_buf == MAP_FAILED) {
oss_logerr (errno, "Failed to map %d bytes of DAC\n",
hw->samples << hw->info.shift);
dolog ("Failed to mmap OSS device\nReason: %s\n",
errstr ());
} else {
int err;
int trig = 0;
if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
errstr ());
}
else {
trig = PCM_ENABLE_OUTPUT;
if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (
errno,
"SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
);
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
"Reason: %s\n", errstr ());
}
else {
oss->mmapped = 1;
@@ -511,55 +389,43 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
}
if (!oss->mmapped) {
err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
err = munmap (oss->pcm_buf, hw->bufsize);
if (err) {
oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
oss->pcm_buf, hw->samples << hw->info.shift);
dolog ("Failed to unmap OSS device\nReason: %s\n",
errstr ());
}
}
}
}
if (!oss->mmapped) {
oss->pcm_buf = audio_calloc (
AUDIO_FUNC,
hw->samples,
1 << hw->info.shift
);
oss->pcm_buf = qemu_mallocz (hw->bufsize);
if (!oss->pcm_buf) {
dolog (
"Could not allocate DAC buffer (%d samples, each %d bytes)\n",
hw->samples,
1 << hw->info.shift
);
oss_anal_close (&fd);
close (oss->fd);
oss->fd = -1;
return -1;
}
}
oss->fd = fd;
return 0;
}
static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
static int oss_hw_ctl (HWVoice *hw, int cmd, ...)
{
int trig;
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
OSSVoice *oss = (OSSVoice *) hw;
if (!oss->mmapped) {
if (!oss->mmapped)
return 0;
}
switch (cmd) {
case VOICE_ENABLE:
ldebug ("enabling voice\n");
audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
pcm_hw_clear (hw, 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"
);
dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
"Reason: %s\n", errstr ());
return -1;
}
break;
@@ -568,7 +434,8 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
ldebug ("disabling voice\n");
trig = 0;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
errstr ());
return -1;
}
break;
@@ -576,205 +443,33 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0;
}
static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
struct oss_params req, obt;
int endianness;
int err;
int fd;
audfmt_e effective_fmt;
struct audsettings obt_as;
oss->fd = -1;
req.fmt = aud_to_ossfmt (as->fmt);
req.freq = as->freq;
req.nchannels = as->nchannels;
req.fragsize = conf.fragsize;
req.nfrags = conf.nfrags;
if (oss_open (1, &req, &obt, &fd)) {
return -1;
}
err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
if (err) {
oss_anal_close (&fd);
return -1;
}
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (&hw->info, &obt_as);
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
if (obt.nfrags * obt.fragsize & hw->info.align) {
dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
obt.nfrags * obt.fragsize, hw->info.align + 1);
}
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!oss->pcm_buf) {
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
oss_anal_close (&fd);
return -1;
}
oss->fd = fd;
return 0;
}
static void oss_fini_in (HWVoiceIn *hw)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
oss_anal_close (&oss->fd);
if (oss->pcm_buf) {
qemu_free (oss->pcm_buf);
oss->pcm_buf = NULL;
}
}
static int oss_run_in (HWVoiceIn *hw)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
int hwshift = hw->info.shift;
int i;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
size_t read_samples = 0;
struct {
int add;
int len;
} bufs[2] = {
{ hw->wpos, 0 },
{ 0, 0 }
};
if (!dead) {
return 0;
}
if (hw->wpos + dead > hw->samples) {
bufs[0].len = (hw->samples - hw->wpos) << hwshift;
bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
}
else {
bufs[0].len = dead << hwshift;
}
for (i = 0; i < 2; ++i) {
ssize_t nread;
if (bufs[i].len) {
void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
nread = read (oss->fd, p, bufs[i].len);
if (nread > 0) {
if (nread & hw->info.align) {
dolog ("warning: Misaligned read %zd (requested %d), "
"alignment %d\n", nread, bufs[i].add << hwshift,
hw->info.align + 1);
}
read_samples += nread >> hwshift;
hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
&nominal_volume);
}
if (bufs[i].len - nread) {
if (nread == -1) {
switch (errno) {
case EINTR:
case EAGAIN:
break;
default:
oss_logerr (
errno,
"Failed to read %d bytes of audio (to %p)\n",
bufs[i].len, p
);
break;
}
}
break;
}
}
}
hw->wpos = (hw->wpos + read_samples) % hw->samples;
return read_samples;
}
static int oss_read (SWVoiceIn *sw, void *buf, int size)
{
return audio_pcm_sw_read (sw, buf, size);
}
static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
static void *oss_audio_init (void)
{
conf.fragsize = audio_get_conf_int (QC_OSS_FRAGSIZE, conf.fragsize);
conf.nfrags = audio_get_conf_int (QC_OSS_NFRAGS, conf.nfrags);
conf.try_mmap = audio_get_conf_int (QC_OSS_MMAP, conf.try_mmap);
conf.dspname = audio_get_conf_str (QC_OSS_DEV, conf.dspname);
return &conf;
}
static void oss_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_option oss_options[] = {
{"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}
struct pcm_ops oss_pcm_ops = {
oss_hw_init,
oss_hw_fini,
oss_hw_run,
oss_hw_write,
oss_hw_ctl
};
static struct audio_pcm_ops oss_pcm_ops = {
oss_init_out,
oss_fini_out,
oss_run_out,
oss_write,
oss_ctl_out,
oss_init_in,
oss_fini_in,
oss_run_in,
oss_read,
oss_ctl_in
};
struct audio_driver oss_audio_driver = {
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)
struct audio_output_driver oss_output_driver = {
"oss",
oss_audio_init,
oss_audio_fini,
&oss_pcm_ops,
1,
INT_MAX,
sizeof (OSSVoice)
};

View File

@@ -1,515 +0,0 @@
/* public domain */
#include "qemu-common.h"
#include "audio.h"
#include <pulse/simple.h>
#include <pulse/error.h>
#define AUDIO_CAP "pulseaudio"
#include "audio_int.h"
#include "audio_pt_int.h"
typedef struct {
HWVoiceOut hw;
int done;
int live;
int decr;
int rpos;
pa_simple *s;
void *pcm_buf;
struct audio_pt pt;
} PAVoiceOut;
typedef struct {
HWVoiceIn hw;
int done;
int dead;
int incr;
int wpos;
pa_simple *s;
void *pcm_buf;
struct audio_pt pt;
} PAVoiceIn;
static struct {
int samples;
int divisor;
char *server;
char *sink;
char *source;
} conf = {
1024,
2,
NULL,
NULL,
NULL
};
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
}
static void *qpa_thread_out (void *arg)
{
PAVoiceOut *pa = arg;
HWVoiceOut *hw = &pa->hw;
int threshold;
threshold = conf.divisor ? hw->samples / conf.divisor : 0;
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return NULL;
}
for (;;) {
int decr, to_mix, rpos;
for (;;) {
if (pa->done) {
goto exit;
}
if (pa->live > threshold) {
break;
}
if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
goto exit;
}
}
decr = to_mix = pa->live;
rpos = hw->rpos;
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
return NULL;
}
while (to_mix) {
int error;
int chunk = audio_MIN (to_mix, hw->samples - rpos);
struct st_sample *src = hw->mix_buf + rpos;
hw->clip (pa->pcm_buf, src, chunk);
if (pa_simple_write (pa->s, pa->pcm_buf,
chunk << hw->info.shift, &error) < 0) {
qpa_logerr (error, "pa_simple_write failed\n");
return NULL;
}
rpos = (rpos + chunk) % hw->samples;
to_mix -= chunk;
}
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return NULL;
}
pa->rpos = rpos;
pa->live -= decr;
pa->decr += decr;
}
exit:
audio_pt_unlock (&pa->pt, AUDIO_FUNC);
return NULL;
}
static int qpa_run_out (HWVoiceOut *hw)
{
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;
hw->rpos = pa->rpos;
if (pa->live > 0) {
audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
}
else {
audio_pt_unlock (&pa->pt, AUDIO_FUNC);
}
return decr;
}
static int qpa_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
/* capture */
static void *qpa_thread_in (void *arg)
{
PAVoiceIn *pa = arg;
HWVoiceIn *hw = &pa->hw;
int threshold;
threshold = conf.divisor ? hw->samples / conf.divisor : 0;
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return NULL;
}
for (;;) {
int incr, to_grab, wpos;
for (;;) {
if (pa->done) {
goto exit;
}
if (pa->dead > threshold) {
break;
}
if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
goto exit;
}
}
incr = to_grab = pa->dead;
wpos = hw->wpos;
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
return NULL;
}
while (to_grab) {
int error;
int chunk = audio_MIN (to_grab, hw->samples - wpos);
void *buf = advance (pa->pcm_buf, wpos);
if (pa_simple_read (pa->s, buf,
chunk << hw->info.shift, &error) < 0) {
qpa_logerr (error, "pa_simple_read failed\n");
return NULL;
}
hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume);
wpos = (wpos + chunk) % hw->samples;
to_grab -= chunk;
}
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return NULL;
}
pa->wpos = wpos;
pa->dead -= incr;
pa->incr += incr;
}
exit:
audio_pt_unlock (&pa->pt, AUDIO_FUNC);
return NULL;
}
static int qpa_run_in (HWVoiceIn *hw)
{
int live, incr, dead;
PAVoiceIn *pa = (PAVoiceIn *) hw;
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return 0;
}
live = audio_pcm_hw_get_live_in (hw);
dead = hw->samples - live;
incr = audio_MIN (dead, pa->incr);
pa->incr -= incr;
pa->dead = dead - incr;
hw->wpos = pa->wpos;
if (pa->dead > 0) {
audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
}
else {
audio_pt_unlock (&pa->pt, AUDIO_FUNC);
}
return incr;
}
static int qpa_read (SWVoiceIn *sw, void *buf, int len)
{
return audio_pcm_sw_read (sw, buf, len);
}
static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
{
int format;
switch (afmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
format = PA_SAMPLE_U8;
break;
case AUD_FMT_S16:
case AUD_FMT_U16:
format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
break;
case AUD_FMT_S32:
case AUD_FMT_U32:
format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
break;
default:
dolog ("Internal logic error: Bad audio format %d\n", afmt);
format = PA_SAMPLE_U8;
break;
}
return format;
}
static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
{
switch (fmt) {
case PA_SAMPLE_U8:
return AUD_FMT_U8;
case PA_SAMPLE_S16BE:
*endianness = 1;
return AUD_FMT_S16;
case PA_SAMPLE_S16LE:
*endianness = 0;
return AUD_FMT_S16;
case PA_SAMPLE_S32BE:
*endianness = 1;
return AUD_FMT_S32;
case PA_SAMPLE_S32LE:
*endianness = 0;
return AUD_FMT_S32;
default:
dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
return AUD_FMT_U8;
}
}
static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
{
int error;
static pa_sample_spec ss;
struct audsettings obt_as = *as;
PAVoiceOut *pa = (PAVoiceOut *) hw;
ss.format = audfmt_to_pa (as->fmt, as->endianness);
ss.channels = as->nchannels;
ss.rate = as->freq;
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
pa->s = pa_simple_new (
conf.server,
"qemu",
PA_STREAM_PLAYBACK,
conf.sink,
"pcm.playback",
&ss,
NULL, /* channel map */
NULL, /* buffering attributes */
&error
);
if (!pa->s) {
qpa_logerr (error, "pa_simple_new for playback failed\n");
goto fail1;
}
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.samples;
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!pa->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
goto fail2;
}
if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
goto fail3;
}
return 0;
fail3:
qemu_free (pa->pcm_buf);
pa->pcm_buf = NULL;
fail2:
pa_simple_free (pa->s);
pa->s = NULL;
fail1:
return -1;
}
static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
{
int error;
static pa_sample_spec ss;
struct audsettings obt_as = *as;
PAVoiceIn *pa = (PAVoiceIn *) hw;
ss.format = audfmt_to_pa (as->fmt, as->endianness);
ss.channels = as->nchannels;
ss.rate = as->freq;
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
pa->s = pa_simple_new (
conf.server,
"qemu",
PA_STREAM_RECORD,
conf.source,
"pcm.capture",
&ss,
NULL, /* channel map */
NULL, /* buffering attributes */
&error
);
if (!pa->s) {
qpa_logerr (error, "pa_simple_new for capture failed\n");
goto fail1;
}
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.samples;
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!pa->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
goto fail2;
}
if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
goto fail3;
}
return 0;
fail3:
qemu_free (pa->pcm_buf);
pa->pcm_buf = NULL;
fail2:
pa_simple_free (pa->s);
pa->s = NULL;
fail1:
return -1;
}
static void qpa_fini_out (HWVoiceOut *hw)
{
void *ret;
PAVoiceOut *pa = (PAVoiceOut *) hw;
audio_pt_lock (&pa->pt, AUDIO_FUNC);
pa->done = 1;
audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
if (pa->s) {
pa_simple_free (pa->s);
pa->s = NULL;
}
audio_pt_fini (&pa->pt, AUDIO_FUNC);
qemu_free (pa->pcm_buf);
pa->pcm_buf = NULL;
}
static void qpa_fini_in (HWVoiceIn *hw)
{
void *ret;
PAVoiceIn *pa = (PAVoiceIn *) hw;
audio_pt_lock (&pa->pt, AUDIO_FUNC);
pa->done = 1;
audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
if (pa->s) {
pa_simple_free (pa->s);
pa->s = NULL;
}
audio_pt_fini (&pa->pt, AUDIO_FUNC);
qemu_free (pa->pcm_buf);
pa->pcm_buf = NULL;
}
static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
/* common */
static void *qpa_audio_init (void)
{
return &conf;
}
static void qpa_audio_fini (void *opaque)
{
(void) opaque;
}
struct audio_option qpa_options[] = {
{"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 = {
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 = {
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

@@ -1,111 +0,0 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
* Copyright (c) 1998 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.
*/
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
int *isamp, int *osamp)
{
struct rate *rate = opaque;
struct st_sample *istart, *iend;
struct st_sample *ostart, *oend;
struct st_sample ilast, icur, out;
#ifdef FLOAT_MIXENG
mixeng_real t;
#else
int64_t t;
#endif
ilast = rate->ilast;
istart = ibuf;
iend = ibuf + *isamp;
ostart = obuf;
oend = obuf + *osamp;
if (rate->opos_inc == (1ULL + UINT_MAX)) {
int i, n = *isamp > *osamp ? *osamp : *isamp;
for (i = 0; i < n; i++) {
OP (obuf[i].l, ibuf[i].l);
OP (obuf[i].r, ibuf[i].r);
}
*isamp = n;
*osamp = n;
return;
}
while (obuf < oend) {
/* Safety catch to make sure we have input samples. */
if (ibuf >= iend) {
break;
}
/* read as many input samples so that ipos > opos */
while (rate->ipos <= (rate->opos >> 32)) {
ilast = *ibuf++;
rate->ipos++;
/* See if we finished the input buffer yet */
if (ibuf >= iend) {
goto the_end;
}
}
icur = *ibuf;
/* interpolate */
#ifdef FLOAT_MIXENG
#ifdef RECIPROCAL
t = (rate->opos & UINT_MAX) * (1.f / UINT_MAX);
#else
t = (rate->opos & UINT_MAX) / (mixeng_real) UINT_MAX;
#endif
out.l = (ilast.l * (1.0 - t)) + icur.l * t;
out.r = (ilast.r * (1.0 - t)) + icur.r * t;
#else
t = rate->opos & 0xffffffff;
out.l = (ilast.l * ((int64_t) UINT_MAX - t) + icur.l * t) >> 32;
out.r = (ilast.r * ((int64_t) UINT_MAX - t) + icur.r * t) >> 32;
#endif
/* output sample & increment position */
OP (obuf->l, out.l);
OP (obuf->r, out.r);
obuf += 1;
rate->opos += rate->opos_inc;
}
the_end:
*isamp = ibuf - istart;
*osamp = obuf - ostart;
rate->ilast = ilast;
}
#undef NAME
#undef OP

View File

@@ -1,8 +1,8 @@
/*
* QEMU SDL audio driver
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
*
* QEMU SDL audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* 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
@@ -23,27 +23,24 @@
*/
#include <SDL.h>
#include <SDL_thread.h>
#include "qemu-common.h"
#include "audio.h"
#include "vl.h"
#ifndef _WIN32
#ifdef __sun__
#define _POSIX_PTHREAD_SEMANTICS 1
#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
#include <pthread.h>
#endif
#include <signal.h>
#include "audio/audio_int.h"
typedef struct SDLVoice {
HWVoice hw;
} SDLVoice;
#define dolog(...) AUD_log ("sdl", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define AUDIO_CAP "sdl"
#include "audio_int.h"
#define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES"
typedef struct SDLVoiceOut {
HWVoiceOut hw;
int live;
int rpos;
int decr;
} SDLVoiceOut;
#define errstr() SDL_GetError ()
static struct {
int nb_samples;
@@ -51,7 +48,7 @@ static struct {
1024
};
static struct SDLAudioState {
struct SDLAudioState {
int exit;
SDL_mutex *mutex;
SDL_sem *sem;
@@ -59,159 +56,110 @@ static struct SDLAudioState {
} glob_sdl;
typedef struct SDLAudioState SDLAudioState;
static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
static void sdl_hw_run (HWVoice *hw)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ());
(void) hw;
}
static int sdl_lock (SDLAudioState *s, const char *forfn)
static int sdl_lock (SDLAudioState *s)
{
if (SDL_LockMutex (s->mutex)) {
sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_unlock (SDLAudioState *s, const char *forfn)
static int sdl_unlock (SDLAudioState *s)
{
if (SDL_UnlockMutex (s->mutex)) {
sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_post (SDLAudioState *s, const char *forfn)
static int sdl_post (SDLAudioState *s)
{
if (SDL_SemPost (s->sem)) {
sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
dolog ("SDL_SemPost failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_wait (SDLAudioState *s, const char *forfn)
static int sdl_wait (SDLAudioState *s)
{
if (SDL_SemWait (s->sem)) {
sdl_logerr ("SDL_SemWait for %s failed\n", forfn);
dolog ("SDL_SemWait failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
static int sdl_unlock_and_post (SDLAudioState *s)
{
if (sdl_unlock (s, forfn)) {
if (sdl_unlock (s))
return -1;
}
return sdl_post (s, forfn);
return sdl_post (s);
}
static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
static int sdl_hw_write (SWVoice *sw, void *buf, int len)
{
int ret;
SDLAudioState *s = &glob_sdl;
sdl_lock (s);
ret = pcm_hw_write (sw, buf, len);
sdl_unlock_and_post (s);
return ret;
}
static int AUD_to_sdlfmt (audfmt_e fmt, int *shift)
{
*shift = 0;
switch (fmt) {
case AUD_FMT_S8: return AUDIO_S8;
case AUD_FMT_U8: return AUDIO_U8;
case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB;
case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB;
default:
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int sdl_to_audfmt (int fmt)
{
switch (fmt) {
case AUD_FMT_S8:
*shift = 0;
return AUDIO_S8;
case AUD_FMT_U8:
*shift = 0;
return AUDIO_U8;
case AUD_FMT_S16:
*shift = 1;
return AUDIO_S16LSB;
case AUD_FMT_U16:
*shift = 1;
return AUDIO_U16LSB;
case AUDIO_S8: return AUD_FMT_S8;
case AUDIO_U8: return AUD_FMT_U8;
case AUDIO_S16LSB: return AUD_FMT_S16;
case AUDIO_U16LSB: return AUD_FMT_U16;
default:
dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_AUDIO
abort ();
#endif
return AUDIO_U8;
dolog ("Internal logic error: Unrecognized SDL audio format %d\n"
"Aborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
{
switch (sdlfmt) {
case AUDIO_S8:
*endianess = 0;
*fmt = AUD_FMT_S8;
break;
case AUDIO_U8:
*endianess = 0;
*fmt = AUD_FMT_U8;
break;
case AUDIO_S16LSB:
*endianess = 0;
*fmt = AUD_FMT_S16;
break;
case AUDIO_U16LSB:
*endianess = 0;
*fmt = AUD_FMT_U16;
break;
case AUDIO_S16MSB:
*endianess = 1;
*fmt = AUD_FMT_S16;
break;
case AUDIO_U16MSB:
*endianess = 1;
*fmt = AUD_FMT_U16;
break;
default:
dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
return -1;
}
return 0;
}
static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
{
int status;
#ifndef _WIN32
sigset_t new, old;
/* Make sure potential threads created by SDL don't hog signals. */
sigfillset (&new);
pthread_sigmask (SIG_BLOCK, &new, &old);
#endif
status = SDL_OpenAudio (req, obt);
if (status) {
sdl_logerr ("SDL_OpenAudio failed\n");
dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ());
}
#ifndef _WIN32
pthread_sigmask (SIG_SETMASK, &old, NULL);
#endif
return status;
}
static void sdl_close (SDLAudioState *s)
{
if (s->initialized) {
sdl_lock (s, "sdl_close");
sdl_lock (s);
s->exit = 1;
sdl_unlock_and_post (s, "sdl_close");
sdl_unlock_and_post (s);
SDL_PauseAudio (1);
SDL_CloseAudio ();
s->initialized = 0;
@@ -220,146 +168,90 @@ static void sdl_close (SDLAudioState *s)
static void sdl_callback (void *opaque, Uint8 *buf, int len)
{
SDLVoiceOut *sdl = opaque;
SDLVoice *sdl = opaque;
SDLAudioState *s = &glob_sdl;
HWVoiceOut *hw = &sdl->hw;
int samples = len >> hw->info.shift;
HWVoice *hw = &sdl->hw;
int samples = len >> hw->shift;
if (s->exit) {
return;
}
while (samples) {
int to_mix, decr;
int to_mix, live, decr;
/* dolog ("in callback samples=%d\n", samples); */
sdl_wait (s, "sdl_callback");
sdl_wait (s);
if (s->exit) {
return;
}
if (sdl_lock (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) {
sdl_lock (s);
live = pcm_hw_get_live (hw);
if (live <= 0)
goto again;
}
/* dolog ("in callback live=%d\n", live); */
to_mix = audio_MIN (samples, sdl->live);
to_mix = audio_MIN (samples, 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;
st_sample_t *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;
memset (src, 0, chunk * sizeof (st_sample_t));
hw->rpos = (hw->rpos + chunk) % hw->samples;
to_mix -= chunk;
buf += chunk << hw->info.shift;
buf += chunk << hw->shift;
}
samples -= decr;
sdl->live -= decr;
sdl->decr += decr;
pcm_hw_dec_live (hw, decr);
again:
if (sdl_unlock (s, "sdl_callback")) {
return;
}
sdl_unlock (s);
}
/* dolog ("done len=%d\n", len); */
}
static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
static void sdl_hw_fini (HWVoice *hw)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int sdl_run_out (HWVoiceOut *hw)
{
int decr, live;
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
SDLAudioState *s = &glob_sdl;
if (sdl_lock (s, "sdl_callback")) {
return 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_callback");
}
else {
sdl_unlock (s, "sdl_callback");
}
return decr;
}
static void sdl_fini_out (HWVoiceOut *hw)
{
(void) hw;
ldebug ("sdl_hw_fini %d fixed=%d\n",
glob_sdl.initialized, audio_state.fixed_format);
sdl_close (&glob_sdl);
}
static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
SDLVoice *sdl = (SDLVoice *) hw;
SDLAudioState *s = &glob_sdl;
SDL_AudioSpec req, obt;
int shift;
int endianess;
int err;
audfmt_e effective_fmt;
struct audsettings obt_as;
shift <<= as->nchannels == 2;
ldebug ("sdl_hw_init %d freq=%d fixed=%d\n",
s->initialized, freq, audio_state.fixed_format);
req.freq = as->freq;
req.format = aud_to_sdlfmt (as->fmt, &shift);
req.channels = as->nchannels;
if (nchannels != 2) {
dolog ("Bogus channel count %d\n", nchannels);
return -1;
}
req.freq = freq;
req.format = AUD_to_sdlfmt (fmt, &shift);
req.channels = nchannels;
req.samples = conf.nb_samples;
shift <<= nchannels == 2;
req.callback = sdl_callback;
req.userdata = sdl;
if (sdl_open (&req, &obt)) {
if (sdl_open (&req, &obt))
return -1;
}
err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
if (err) {
sdl_close (s);
return -1;
}
obt_as.freq = obt.freq;
obt_as.nchannels = obt.channels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianess;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
hw->freq = obt.freq;
hw->fmt = sdl_to_audfmt (obt.format);
hw->nchannels = obt.channels;
hw->bufsize = obt.samples << shift;
s->initialized = 1;
s->exit = 0;
@@ -367,7 +259,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
return 0;
}
static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
static int sdl_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
@@ -386,22 +278,24 @@ static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
static void *sdl_audio_init (void)
{
SDLAudioState *s = &glob_sdl;
conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples);
if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
sdl_logerr ("SDL failed to initialize audio subsystem\n");
dolog ("SDL failed to initialize audio subsystem\nReason: %s\n",
errstr ());
return NULL;
}
s->mutex = SDL_CreateMutex ();
if (!s->mutex) {
sdl_logerr ("Failed to create SDL mutex\n");
dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ());
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
}
s->sem = SDL_CreateSemaphore (0);
if (!s->sem) {
sdl_logerr ("Failed to create SDL semaphore\n");
dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ());
SDL_DestroyMutex (s->mutex);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
@@ -419,36 +313,20 @@ static void sdl_audio_fini (void *opaque)
SDL_QuitSubSystem (SDL_INIT_AUDIO);
}
static struct audio_option sdl_options[] = {
{"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
"Size of SDL buffer in samples", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
struct pcm_ops sdl_pcm_ops = {
sdl_hw_init,
sdl_hw_fini,
sdl_hw_run,
sdl_hw_write,
sdl_hw_ctl
};
static struct audio_pcm_ops sdl_pcm_ops = {
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 = {
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
struct audio_output_driver sdl_output_driver = {
"sdl",
sdl_audio_init,
sdl_audio_fini,
&sdl_pcm_ops,
1,
1,
sizeof (SDLVoice)
};

View File

@@ -1,8 +1,8 @@
/*
* QEMU WAV audio driver
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
*
* QEMU WAV audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* 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
@@ -21,55 +21,49 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw/hw.h"
#include "qemu-timer.h"
#include "audio.h"
#include "vl.h"
#define AUDIO_CAP "wav"
#include "audio_int.h"
#include "audio/audio_int.h"
typedef struct WAVVoiceOut {
HWVoiceOut hw;
typedef struct WAVVoice {
HWVoice hw;
QEMUFile *f;
int64_t old_ticks;
void *pcm_buf;
int total_samples;
} WAVVoiceOut;
} WAVVoice;
#define dolog(...) AUD_log ("wav", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
static struct {
struct audsettings settings;
const char *wav_path;
} conf = {
{
44100,
2,
AUD_FMT_S16,
0
},
"qemu.wav"
.wav_path = "qemu.wav"
};
static int wav_run_out (HWVoiceOut *hw)
static void wav_hw_run (HWVoice *hw)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
WAVVoice *wav = (WAVVoice *) hw;
int rpos, live, decr, samples;
uint8_t *dst;
struct st_sample *src;
st_sample_t *src;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - wav->old_ticks;
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
if (bytes > INT_MAX) {
samples = INT_MAX >> hw->info.shift;
}
else {
samples = bytes >> hw->info.shift;
}
if (bytes > INT_MAX)
samples = INT_MAX >> hw->shift;
else
samples = bytes >> hw->shift;
live = audio_pcm_hw_get_live_out (hw);
if (!live) {
return 0;
}
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
wav->old_ticks = now;
decr = audio_MIN (live, samples);
@@ -79,24 +73,25 @@ static int wav_run_out (HWVoiceOut *hw)
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 (wav->pcm_buf, rpos << hw->info.shift);
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
dst = advance (wav->pcm_buf, rpos << hw->shift);
hw->clip (dst, src, convert_samples);
qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
qemu_put_buffer (wav->f, dst, convert_samples << hw->shift);
memset (src, 0, convert_samples * sizeof (st_sample_t));
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
wav->total_samples += convert_samples;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
return decr;
}
static int wav_write_out (SWVoiceOut *sw, void *buf, int len)
static int wav_hw_write (SWVoice *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
return pcm_hw_write (sw, buf, len);
}
/* VICE code: Store number as little endian. */
@@ -109,59 +104,45 @@ static void le_store (uint8_t *buf, uint32_t val, int len)
}
}
static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
int bits16 = 0, stereo = 0;
WAVVoice *wav = (WAVVoice *) hw;
int bits16 = 0, stereo = audio_state.fixed_channels == 2;
uint8_t hdr[] = {
0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
};
struct audsettings wav_as = conf.settings;
(void) as;
stereo = wav_as.nchannels == 2;
switch (wav_as.fmt) {
switch (audio_state.fixed_fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
bits16 = 0;
break;
case AUD_FMT_S16:
case AUD_FMT_U16:
bits16 = 1;
break;
case AUD_FMT_S32:
case AUD_FMT_U32:
dolog ("WAVE files can not handle 32bit formats\n");
return -1;
}
hdr[34] = bits16 ? 0x10 : 0x08;
wav_as.endianness = 0;
audio_pcm_init_info (&hw->info, &wav_as);
hw->samples = 1024;
wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!wav->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
hw->freq = 44100;
hw->nchannels = stereo ? 2 : 1;
hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
hw->bufsize = 4096;
wav->pcm_buf = qemu_mallocz (hw->bufsize);
if (!wav->pcm_buf)
return -1;
}
le_store (hdr + 22, hw->info.nchannels, 2);
le_store (hdr + 24, hw->info.freq, 4);
le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
le_store (hdr + 22, hw->nchannels, 2);
le_store (hdr + 24, hw->freq, 4);
le_store (hdr + 28, hw->freq << (bits16 + stereo), 4);
le_store (hdr + 32, 1 << (bits16 + stereo), 2);
wav->f = qemu_fopen (conf.wav_path, "wb");
wav->f = fopen (conf.wav_path, "wb");
if (!wav->f) {
dolog ("Failed to open wave file `%s'\nReason: %s\n",
dolog ("failed to open wave file `%s'\nReason: %s\n",
conf.wav_path, strerror (errno));
qemu_free (wav->pcm_buf);
wav->pcm_buf = NULL;
@@ -172,17 +153,17 @@ static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
return 0;
}
static void wav_fini_out (HWVoiceOut *hw)
static void wav_hw_fini (HWVoice *hw)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
WAVVoice *wav = (WAVVoice *) hw;
int stereo = hw->nchannels == 2;
uint8_t rlen[4];
uint8_t dlen[4];
uint32_t datalen = wav->total_samples << hw->info.shift;
uint32_t rifflen = datalen + 36;
uint32_t rifflen = (wav->total_samples << stereo) + 36;
uint32_t datalen = wav->total_samples << stereo;
if (!wav->f) {
if (!wav->f || !hw->active)
return;
}
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
@@ -193,14 +174,14 @@ static void wav_fini_out (HWVoiceOut *hw)
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
qemu_fclose (wav->f);
fclose (wav->f);
wav->f = NULL;
qemu_free (wav->pcm_buf);
wav->pcm_buf = NULL;
}
static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
static int wav_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
@@ -214,50 +195,23 @@ static void *wav_audio_init (void)
static void wav_audio_fini (void *opaque)
{
(void) opaque;
ldebug ("wav_fini");
}
static struct audio_option wav_options[] = {
{"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}
struct pcm_ops wav_pcm_ops = {
wav_hw_init,
wav_hw_fini,
wav_hw_run,
wav_hw_write,
wav_hw_ctl
};
static struct audio_pcm_ops wav_pcm_ops = {
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 = {
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
struct audio_output_driver wav_output_driver = {
"wav",
wav_audio_init,
wav_audio_fini,
&wav_pcm_ops,
1,
1,
sizeof (WAVVoice)
};

View File

@@ -1,161 +0,0 @@
#include "hw/hw.h"
#include "monitor.h"
#include "audio.h"
typedef struct {
QEMUFile *f;
int bytes;
char *path;
int freq;
int bits;
int nchannels;
CaptureVoiceOut *cap;
} WAVState;
/* VICE code: Store number as little endian. */
static void le_store (uint8_t *buf, uint32_t val, int len)
{
int i;
for (i = 0; i < len; i++) {
buf[i] = (uint8_t) (val & 0xff);
val >>= 8;
}
}
static void wav_notify (void *opaque, audcnotification_e cmd)
{
(void) opaque;
(void) cmd;
}
static void wav_destroy (void *opaque)
{
WAVState *wav = opaque;
uint8_t rlen[4];
uint8_t dlen[4];
uint32_t datalen = wav->bytes;
uint32_t rifflen = datalen + 36;
if (wav->f) {
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
qemu_fseek (wav->f, 4, SEEK_SET);
qemu_put_buffer (wav->f, rlen, 4);
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
qemu_fclose (wav->f);
}
qemu_free (wav->path);
}
static void wav_capture (void *opaque, void *buf, int size)
{
WAVState *wav = opaque;
qemu_put_buffer (wav->f, buf, size);
wav->bytes += size;
}
static void wav_capture_destroy (void *opaque)
{
WAVState *wav = opaque;
AUD_del_capture (wav->cap, wav);
}
static void wav_capture_info (void *opaque)
{
WAVState *wav = opaque;
char *path = wav->path;
monitor_printf(cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
wav->freq, wav->bits, wav->nchannels,
path ? path : "<not available>", wav->bytes);
}
static struct capture_ops wav_capture_ops = {
.destroy = wav_capture_destroy,
.info = wav_capture_info
};
int wav_start_capture (CaptureState *s, const char *path, int freq,
int bits, int nchannels)
{
Monitor *mon = cur_mon;
WAVState *wav;
uint8_t hdr[] = {
0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
};
struct audsettings as;
struct audio_capture_ops ops;
int stereo, bits16, shift;
CaptureVoiceOut *cap;
if (bits != 8 && bits != 16) {
monitor_printf(mon, "incorrect bit count %d, must be 8 or 16\n", bits);
return -1;
}
if (nchannels != 1 && nchannels != 2) {
monitor_printf(mon, "incorrect channel count %d, must be 1 or 2\n",
nchannels);
return -1;
}
stereo = nchannels == 2;
bits16 = bits == 16;
as.freq = freq;
as.nchannels = 1 << stereo;
as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
as.endianness = 0;
ops.notify = wav_notify;
ops.capture = wav_capture;
ops.destroy = wav_destroy;
wav = qemu_mallocz (sizeof (*wav));
shift = bits16 + stereo;
hdr[34] = bits16 ? 0x10 : 0x08;
le_store (hdr + 22, as.nchannels, 2);
le_store (hdr + 24, freq, 4);
le_store (hdr + 28, freq << shift, 4);
le_store (hdr + 32, 1 << shift, 2);
wav->f = qemu_fopen (path, "wb");
if (!wav->f) {
monitor_printf(mon, "Failed to open wave file `%s'\nReason: %s\n",
path, strerror (errno));
qemu_free (wav);
return -1;
}
wav->path = qemu_strdup (path);
wav->bits = bits;
wav->nchannels = nchannels;
wav->freq = freq;
qemu_put_buffer (wav->f, hdr, sizeof (hdr));
cap = AUD_add_capture (&as, &ops, wav);
if (!cap) {
monitor_printf(mon, "Failed to add audio capture\n");
qemu_free (wav->path);
qemu_fclose (wav->f);
qemu_free (wav);
return -1;
}
wav->cap = cap;
s->opaque = wav;
s->ops = wav_capture_ops;
return 0;
}

View File

@@ -1,27 +0,0 @@
/*
* Balloon
*
* 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_BALLOON_H
#define _QEMU_BALLOON_H
#include "cpu-defs.h"
typedef ram_addr_t (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
void qemu_balloon(ram_addr_t target);
ram_addr_t qemu_balloon_status(void);
#endif

View File

@@ -1,9 +1,9 @@
/*
* Block driver for the various disk image formats used by Bochs
* Currently only for "growing" type in read-only mode
*
*
* Copyright (c) 2005 Alex Beregszaszi
*
*
* 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
@@ -22,15 +22,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "vl.h"
#include "block_int.h"
#include "module.h"
/**************************************************************/
#define HEADER_MAGIC "Bochs Virtual HD Image"
#define HEADER_VERSION 0x00020000
#define HEADER_V1 0x00010000
#define HEADER_VERSION 0x00010000
#define HEADER_SIZE 512
#define REDOLOG_TYPE "Redolog"
@@ -39,13 +37,13 @@
// not allocated: 0xffffffff
// always little-endian
struct bochs_header_v1 {
struct bochs_header {
char magic[32]; // "Bochs Virtual HD Image"
char type[16]; // "Redolog"
char subtype[16]; // "Undoable" / "Volatile" / "Growing"
uint32_t version;
uint32_t header; // size of header
union {
struct {
uint32_t catalog; // num of entries
@@ -58,35 +56,14 @@ struct bochs_header_v1 {
} extra;
};
// always little-endian
struct bochs_header {
char magic[32]; // "Bochs Virtual HD Image"
char type[16]; // "Redolog"
char subtype[16]; // "Undoable" / "Volatile" / "Growing"
uint32_t version;
uint32_t header; // size of header
union {
struct {
uint32_t catalog; // num of entries
uint32_t bitmap; // bitmap size
uint32_t extent; // extent size
uint32_t reserved; // for ???
uint64_t disk; // disk size
char padding[HEADER_SIZE - 64 - 8 - 24];
} redolog;
char padding[HEADER_SIZE - 64 - 8];
} extra;
};
typedef struct BDRVBochsState {
int fd;
uint32_t *catalog_bitmap;
int catalog_size;
int data_offset;
int bitmap_blocks;
int extent_blocks;
int extent_size;
@@ -95,36 +72,34 @@ typedef struct BDRVBochsState {
static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const struct bochs_header *bochs = (const void *)buf;
if (buf_size < HEADER_SIZE)
return 0;
if (!strcmp(bochs->magic, HEADER_MAGIC) &&
!strcmp(bochs->type, REDOLOG_TYPE) &&
!strcmp(bochs->subtype, GROWING_TYPE) &&
((le32_to_cpu(bochs->version) == HEADER_VERSION) ||
(le32_to_cpu(bochs->version) == HEADER_V1)))
(le32_to_cpu(bochs->version) == HEADER_VERSION))
return 100;
return 0;
}
static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
static int bochs_open(BlockDriverState *bs, const char *filename)
{
BDRVBochsState *s = bs->opaque;
int fd, i;
struct bochs_header bochs;
struct bochs_header_v1 header_v1;
fd = open(filename, O_RDWR | O_BINARY);
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY);
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
bs->read_only = 1; // no write support yet
s->fd = fd;
if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) {
@@ -134,22 +109,18 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
if (strcmp(bochs.magic, HEADER_MAGIC) ||
strcmp(bochs.type, REDOLOG_TYPE) ||
strcmp(bochs.subtype, GROWING_TYPE) ||
((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
(le32_to_cpu(bochs.version) != HEADER_V1))) {
(le32_to_cpu(bochs.version) != HEADER_VERSION)) {
goto fail;
}
if (le32_to_cpu(bochs.version) == HEADER_V1) {
memcpy(&header_v1, &bochs, sizeof(bochs));
bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
} else {
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
}
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
if (!s->catalog_bitmap)
goto fail;
if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
s->catalog_size * 4)
goto fail;
@@ -160,7 +131,7 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512;
s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512;
s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
return 0;
@@ -179,7 +150,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
// seek to sector
extent_index = offset / s->extent_size;
extent_offset = (offset % s->extent_size) / 512;
if (s->catalog_bitmap[extent_index] == 0xffffffff)
{
// fprintf(stderr, "page not allocated [%x - %x:%x]\n",
@@ -190,17 +161,17 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
(s->extent_blocks + s->bitmap_blocks));
block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
// fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n",
// sector_num, extent_index, extent_offset,
// le32_to_cpu(s->catalog_bitmap[extent_index]),
// bitmap_offset, block_offset);
// read in bitmap for current extent
lseek(s->fd, bitmap_offset + (extent_offset / 8), SEEK_SET);
read(s->fd, &bitmap_entry, 1);
if (!((bitmap_entry >> (extent_offset % 8)) & 1))
{
// fprintf(stderr, "sector (%x) in bitmap not allocated\n",
@@ -209,11 +180,11 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
}
lseek(s->fd, block_offset, SEEK_SET);
return 0;
}
static int bochs_read(BlockDriverState *bs, int64_t sector_num,
static int bochs_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVBochsState *s = bs->opaque;
@@ -242,18 +213,12 @@ static void bochs_close(BlockDriverState *bs)
close(s->fd);
}
static BlockDriver bdrv_bochs = {
.format_name = "bochs",
.instance_size = sizeof(BDRVBochsState),
.bdrv_probe = bochs_probe,
.bdrv_open = bochs_open,
.bdrv_read = bochs_read,
.bdrv_close = bochs_close,
BlockDriver bdrv_bochs = {
"bochs",
sizeof(BDRVBochsState),
bochs_probe,
bochs_open,
bochs_read,
NULL,
bochs_close,
};
static void bdrv_bochs_init(void)
{
bdrv_register(&bdrv_bochs);
}
block_init(bdrv_bochs_init);

View File

@@ -1,8 +1,8 @@
/*
* QEMU Block driver for CLOOP images
*
*
* Copyright (c) 2004 Johannes E. Schindelin
*
*
* 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
@@ -21,9 +21,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "vl.h"
#include "block_int.h"
#include "module.h"
#include <zlib.h>
typedef struct BDRVCloopState {
@@ -33,8 +32,8 @@ typedef struct BDRVCloopState {
uint64_t* offsets;
uint32_t sectors_per_block;
uint32_t current_block;
uint8_t *compressed_block;
uint8_t *uncompressed_block;
char* compressed_block;
char* uncompressed_block;
z_stream zstream;
} BDRVCloopState;
@@ -51,14 +50,14 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int cloop_open(BlockDriverState *bs, const char *filename, int flags)
static int cloop_open(BlockDriverState *bs, const char *filename)
{
BDRVCloopState *s = bs->opaque;
uint32_t offsets_size,max_compressed_block_size=1,i;
s->fd = open(filename, O_RDONLY | O_BINARY);
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (s->fd < 0)
return -errno;
return -1;
bs->read_only = 1;
/* read header */
@@ -76,7 +75,8 @@ cloop_close:
/* read offsets */
offsets_size=s->n_blocks*sizeof(uint64_t);
s->offsets=(uint64_t*)qemu_malloc(offsets_size);
if(!(s->offsets=(uint64_t*)malloc(offsets_size)))
goto cloop_close;
if(read(s->fd,s->offsets,offsets_size)<offsets_size)
goto cloop_close;
for(i=0;i<s->n_blocks;i++) {
@@ -89,12 +89,14 @@ cloop_close:
}
/* initialize zlib engine */
s->compressed_block = qemu_malloc(max_compressed_block_size+1);
s->uncompressed_block = qemu_malloc(s->block_size);
if(!(s->compressed_block=(char*)malloc(max_compressed_block_size+1)))
goto cloop_close;
if(!(s->uncompressed_block=(char*)malloc(s->block_size)))
goto cloop_close;
if(inflateInit(&s->zstream) != Z_OK)
goto cloop_close;
s->current_block=s->n_blocks;
s->sectors_per_block = s->block_size/512;
bs->total_sectors = s->n_blocks*s->sectors_per_block;
return 0;
@@ -105,12 +107,12 @@ static inline int cloop_read_block(BDRVCloopState *s,int block_num)
if(s->current_block != block_num) {
int ret;
uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
lseek(s->fd, s->offsets[block_num], SEEK_SET);
ret = read(s->fd, s->compressed_block, bytes);
if (ret != bytes)
if (ret != bytes)
return -1;
s->zstream.next_in = s->compressed_block;
s->zstream.avail_in = bytes;
s->zstream.next_out = s->uncompressed_block;
@@ -121,13 +123,13 @@ static inline int cloop_read_block(BDRVCloopState *s,int block_num)
ret = inflate(&s->zstream, Z_FINISH);
if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size)
return -1;
s->current_block = block_num;
}
return 0;
}
static int cloop_read(BlockDriverState *bs, int64_t sector_num,
static int cloop_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVCloopState *s = bs->opaque;
@@ -154,18 +156,14 @@ static void cloop_close(BlockDriverState *bs)
inflateEnd(&s->zstream);
}
static BlockDriver bdrv_cloop = {
.format_name = "cloop",
.instance_size = sizeof(BDRVCloopState),
.bdrv_probe = cloop_probe,
.bdrv_open = cloop_open,
.bdrv_read = cloop_read,
.bdrv_close = cloop_close,
BlockDriver bdrv_cloop = {
"cloop",
sizeof(BDRVCloopState),
cloop_probe,
cloop_open,
cloop_read,
NULL,
cloop_close,
};
static void bdrv_cloop_init(void)
{
bdrv_register(&bdrv_cloop);
}
block_init(bdrv_cloop_init);

View File

@@ -1,8 +1,8 @@
/*
* Block driver for the COW format
*
*
* Copyright (c) 2004 Fabrice Bellard
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
@@ -22,9 +22,8 @@
* THE SOFTWARE.
*/
#ifndef _WIN32
#include "qemu-common.h"
#include "vl.h"
#include "block_int.h"
#include "module.h"
#include <sys/mman.h>
/**************************************************************/
@@ -55,15 +54,14 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const struct cow_header_v2 *cow_header = (const void *)buf;
if (buf_size >= sizeof(struct cow_header_v2) &&
be32_to_cpu(cow_header->magic) == COW_MAGIC &&
be32_to_cpu(cow_header->version) == COW_VERSION)
if (be32_to_cpu(cow_header->magic) == COW_MAGIC &&
be32_to_cpu(cow_header->version) == COW_VERSION)
return 100;
else
return 0;
}
static int cow_open(BlockDriverState *bs, const char *filename, int flags)
static int cow_open(BlockDriverState *bs, const char *filename)
{
BDRVCowState *s = bs->opaque;
int fd;
@@ -86,20 +84,36 @@ static int cow_open(BlockDriverState *bs, const char *filename, int flags)
be32_to_cpu(cow_header.version) != COW_VERSION) {
goto fail;
}
/* cow image found */
size = be64_to_cpu(cow_header.size);
bs->total_sectors = size / 512;
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
cow_header.backing_file);
#if 0
if (cow_header.backing_file[0] != '\0') {
if (stat(cow_header.backing_file, &st) != 0) {
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
goto fail;
}
if (st.st_mtime != be32_to_cpu(cow_header.mtime)) {
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
goto fail;
}
fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
if (fd < 0)
goto fail;
bs->fd = fd;
}
#endif
/* mmap the bitmap */
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
s->cow_bitmap_addr = (void *)mmap(get_mmap_addr(s->cow_bitmap_size),
s->cow_bitmap_size,
PROT_READ | PROT_WRITE,
MAP_SHARED, s->fd, 0);
s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
s->cow_bitmap_size,
PROT_READ | PROT_WRITE,
MAP_SHARED, s->fd, 0);
if (s->cow_bitmap_addr == MAP_FAILED)
goto fail;
s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
@@ -144,35 +158,28 @@ static inline int is_changed(uint8_t *bitmap,
return changed;
}
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
BDRVCowState *s = bs->opaque;
return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
}
static int cow_read(BlockDriverState *bs, int64_t sector_num,
static int cow_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVCowState *s = bs->opaque;
int ret, n;
while (nb_sectors > 0) {
if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
if (ret != n * 512)
return -1;
} else {
if (bs->backing_hd) {
/* read from the base image */
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
if (ret < 0)
return -1;
} else {
memset(buf, 0, n * 512);
}
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
@@ -180,15 +187,15 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num,
return 0;
}
static int cow_write(BlockDriverState *bs, int64_t sector_num,
static int cow_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVCowState *s = bs->opaque;
int ret, i;
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
ret = write(s->fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512)
if (ret != nb_sectors * 512)
return -1;
for (i = 0; i < nb_sectors; i++)
cow_set_bit(s->cow_bitmap, sector_num + i);
@@ -198,29 +205,21 @@ static int cow_write(BlockDriverState *bs, int64_t sector_num,
static void cow_close(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
munmap((void *)s->cow_bitmap_addr, s->cow_bitmap_size);
munmap(s->cow_bitmap_addr, s->cow_bitmap_size);
close(s->fd);
}
static int cow_create(const char *filename, QEMUOptionParameter *options)
static int cow_create(const char *filename, int64_t image_sectors,
const char *image_filename, int flags)
{
int fd, cow_fd;
struct cow_header_v2 cow_header;
struct stat st;
int64_t image_sectors = 0;
const char *image_filename = NULL;
/* Read out options */
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
image_sectors = options->value.n / 512;
} else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
image_filename = options->value.s;
}
options++;
}
if (flags)
return -ENOTSUP;
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (cow_fd < 0)
return -1;
@@ -228,23 +227,18 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
cow_header.magic = cpu_to_be32(COW_MAGIC);
cow_header.version = cpu_to_be32(COW_VERSION);
if (image_filename) {
/* Note: if no file, we put a dummy mtime */
cow_header.mtime = cpu_to_be32(0);
fd = open(image_filename, O_RDONLY | O_BINARY);
if (fd < 0) {
close(cow_fd);
goto mtime_fail;
return -1;
}
if (fstat(fd, &st) != 0) {
close(fd);
goto mtime_fail;
return -1;
}
close(fd);
cow_header.mtime = cpu_to_be32(st.st_mtime);
mtime_fail:
pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
image_filename);
realpath(image_filename, cow_header.backing_file);
}
cow_header.sectorsize = cpu_to_be32(512);
cow_header.size = cpu_to_be64(image_sectors * 512);
@@ -255,45 +249,15 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
return 0;
}
static void cow_flush(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
fsync(s->fd);
}
static QEMUOptionParameter cow_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{
.name = BLOCK_OPT_BACKING_FILE,
.type = OPT_STRING,
.help = "File name of a base image"
},
{ NULL }
BlockDriver bdrv_cow = {
"cow",
sizeof(BDRVCowState),
cow_probe,
cow_open,
cow_read,
cow_write,
cow_close,
cow_create,
cow_is_allocated,
};
static BlockDriver bdrv_cow = {
.format_name = "cow",
.instance_size = sizeof(BDRVCowState),
.bdrv_probe = cow_probe,
.bdrv_open = cow_open,
.bdrv_read = cow_read,
.bdrv_write = cow_write,
.bdrv_close = cow_close,
.bdrv_create = cow_create,
.bdrv_flush = cow_flush,
.bdrv_is_allocated = cow_is_allocated,
.create_options = cow_create_options,
};
static void bdrv_cow_init(void)
{
bdrv_register(&bdrv_cow);
}
block_init(bdrv_cow_init);
#endif

View File

@@ -1,8 +1,8 @@
/*
* QEMU Block driver for DMG images
*
*
* Copyright (c) 2004 Johannes E. Schindelin
*
*
* 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
@@ -21,15 +21,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "vl.h"
#include "block_int.h"
#include "bswap.h"
#include "module.h"
#include <zlib.h>
typedef struct BDRVDMGState {
int fd;
/* each chunk contains a certain number of sectors,
* offsets[i] is the offset in the .dmg file,
* lengths[i] is the length of the compressed chunk,
@@ -45,8 +44,8 @@ typedef struct BDRVDMGState {
uint64_t* sectors;
uint64_t* sectorcounts;
uint32_t current_chunk;
uint8_t *compressed_chunk;
uint8_t *uncompressed_chunk;
char* compressed_chunk;
char* uncompressed_chunk;
z_stream zstream;
} BDRVDMGState;
@@ -74,27 +73,25 @@ static off_t read_uint32(int fd)
return be32_to_cpu(buffer);
}
static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
static int dmg_open(BlockDriverState *bs, const char *filename)
{
BDRVDMGState *s = bs->opaque;
off_t info_begin,info_end,last_in_offset,last_out_offset;
uint32_t count;
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
s->fd = open(filename, O_RDONLY | O_BINARY);
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (s->fd < 0)
return -errno;
return -1;
bs->read_only = 1;
s->n_chunks = 0;
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
/* read offset of info blocks */
if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
dmg_close:
close(s->fd);
/* open raw instead */
bs->drv=bdrv_find_format("raw");
return bs->drv->bdrv_open(bs, filename, flags);
return -1;
}
info_begin=read_off(s->fd);
if(info_begin==0)
@@ -126,11 +123,11 @@ dmg_close:
goto dmg_close;
chunk_count = (count-204)/40;
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
s->types = qemu_realloc(s->types, new_size/2);
s->offsets = qemu_realloc(s->offsets, new_size);
s->lengths = qemu_realloc(s->lengths, new_size);
s->sectors = qemu_realloc(s->sectors, new_size);
s->sectorcounts = qemu_realloc(s->sectorcounts, new_size);
s->types = realloc(s->types, new_size/2);
s->offsets = realloc(s->offsets, new_size);
s->lengths = realloc(s->lengths, new_size);
s->sectors = realloc(s->sectors, new_size);
s->sectorcounts = realloc(s->sectorcounts, new_size);
for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
s->types[i] = read_uint32(s->fd);
@@ -160,13 +157,15 @@ dmg_close:
}
/* initialize zlib engine */
s->compressed_chunk = qemu_malloc(max_compressed_size+1);
s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk);
if(!(s->compressed_chunk=(char*)malloc(max_compressed_size+1)))
goto dmg_close;
if(!(s->uncompressed_chunk=(char*)malloc(512*max_sectors_per_chunk)))
goto dmg_close;
if(inflateInit(&s->zstream) != Z_OK)
goto dmg_close;
s->current_chunk = s->n_chunks;
return 0;
}
@@ -226,7 +225,7 @@ static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num)
if (ret != s->lengths[chunk])
return -1;
s->zstream.next_in = s->compressed_chunk;
s->zstream.avail_in = s->lengths[chunk];
s->zstream.next_out = s->uncompressed_chunk;
@@ -252,7 +251,7 @@ static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num)
return 0;
}
static int dmg_read(BlockDriverState *bs, int64_t sector_num,
static int dmg_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVDMGState *s = bs->opaque;
@@ -284,18 +283,13 @@ static void dmg_close(BlockDriverState *bs)
inflateEnd(&s->zstream);
}
static BlockDriver bdrv_dmg = {
.format_name = "dmg",
.instance_size = sizeof(BDRVDMGState),
.bdrv_probe = dmg_probe,
.bdrv_open = dmg_open,
.bdrv_read = dmg_read,
.bdrv_close = dmg_close,
BlockDriver bdrv_dmg = {
"dmg",
sizeof(BDRVDMGState),
dmg_probe,
dmg_open,
dmg_read,
NULL,
dmg_close,
};
static void bdrv_dmg_init(void)
{
bdrv_register(&bdrv_dmg);
}
block_init(bdrv_dmg_init);

View File

@@ -1,8 +1,8 @@
/*
* Block driver for the QCOW format
*
* Copyright (c) 2004-2006 Fabrice Bellard
*
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
@@ -21,9 +21,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "vl.h"
#include "block_int.h"
#include "module.h"
#include <zlib.h>
#include "aes.h"
@@ -54,7 +53,7 @@ typedef struct QCowHeader {
#define L2_CACHE_SIZE 16
typedef struct BDRVQcowState {
BlockDriverState *hd;
int fd;
int cluster_bits;
int cluster_size;
int cluster_sectors;
@@ -82,24 +81,27 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const QCowHeader *cow_header = (const void *)buf;
if (buf_size >= sizeof(QCowHeader) &&
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
be32_to_cpu(cow_header->version) == QCOW_VERSION)
if (be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
be32_to_cpu(cow_header->version) == QCOW_VERSION)
return 100;
else
return 0;
}
static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
static int qcow_open(BlockDriverState *bs, const char *filename)
{
BDRVQcowState *s = bs->opaque;
int len, i, shift, ret;
int fd, len, i, shift;
QCowHeader header;
ret = bdrv_file_open(&s->hd, filename, flags);
if (ret < 0)
return ret;
if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
s->fd = fd;
if (read(fd, &header, sizeof(header)) != sizeof(header))
goto fail;
be32_to_cpus(&header.magic);
be32_to_cpus(&header.version);
@@ -109,7 +111,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
be64_to_cpus(&header.size);
be32_to_cpus(&header.crypt_method);
be64_to_cpus(&header.l1_table_offset);
if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
goto fail;
if (header.size <= 1 || header.cluster_bits < 9)
@@ -135,7 +137,8 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
if (!s->l1_table)
goto fail;
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
lseek(fd, s->l1_table_offset, SEEK_SET);
if (read(fd, 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++) {
@@ -152,13 +155,14 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
if (!s->cluster_data)
goto fail;
s->cluster_cache_offset = -1;
/* read the backing file name */
if (header.backing_file_offset != 0) {
len = header.backing_file_size;
if (len > 1023)
len = 1023;
if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
lseek(fd, header.backing_file_offset, SEEK_SET);
if (read(fd, bs->backing_file, len) != len)
goto fail;
bs->backing_file[len] = '\0';
}
@@ -169,7 +173,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
qemu_free(s->l2_cache);
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
bdrv_delete(s->hd);
close(fd);
return -1;
}
@@ -178,7 +182,7 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
BDRVQcowState *s = bs->opaque;
uint8_t keybuf[16];
int len, i;
memset(keybuf, 0, 16);
len = strlen(key);
if (len > 16)
@@ -232,7 +236,7 @@ static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
for(i = 0; i < nb_sectors; i++) {
ivec.ll[0] = cpu_to_le64(sector_num);
ivec.ll[1] = 0;
AES_cbc_encrypt(in_buf, out_buf, 512, key,
AES_cbc_encrypt(in_buf, out_buf, 512, key,
ivec.b, enc);
sector_num++;
in_buf += 512;
@@ -249,7 +253,7 @@ static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
*
* 2 to allocate a compressed cluster of size
* 'compressed_size'. 'compressed_size' must be > 0 and <
* cluster_size
* cluster_size
*
* return 0 if not allocated.
*/
@@ -263,7 +267,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
uint64_t l2_offset, *l2_table, cluster_offset, tmp;
uint32_t min_count;
int new_l2_table;
l1_index = offset >> (s->l2_bits + s->cluster_bits);
l2_offset = s->l1_table[l1_index];
new_l2_table = 0;
@@ -271,14 +275,14 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
if (!allocate)
return 0;
/* allocate a new l2 entry */
l2_offset = bdrv_getlength(s->hd);
l2_offset = lseek(s->fd, 0, SEEK_END);
/* round to cluster size */
l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
/* update the L1 entry */
s->l1_table[l1_index] = l2_offset;
tmp = cpu_to_be64(l2_offset);
if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
&tmp, sizeof(tmp)) != sizeof(tmp))
lseek(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
new_l2_table = 1;
}
@@ -304,13 +308,14 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
}
}
l2_table = s->l2_cache + (min_index << s->l2_bits);
lseek(s->fd, l2_offset, SEEK_SET);
if (new_l2_table) {
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return 0;
} else {
if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return 0;
}
@@ -319,7 +324,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
found:
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
cluster_offset = be64_to_cpu(l2_table[l2_index]);
if (!cluster_offset ||
if (!cluster_offset ||
((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
if (!allocate)
return 0;
@@ -331,55 +336,56 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
overwritten */
if (decompress_cluster(s, cluster_offset) < 0)
return 0;
cluster_offset = bdrv_getlength(s->hd);
cluster_offset = (cluster_offset + s->cluster_size - 1) &
cluster_offset = lseek(s->fd, 0, SEEK_END);
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
/* write the cluster content */
if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) !=
lseek(s->fd, cluster_offset, SEEK_SET);
if (write(s->fd, s->cluster_cache, s->cluster_size) !=
s->cluster_size)
return -1;
} else {
cluster_offset = bdrv_getlength(s->hd);
cluster_offset = lseek(s->fd, 0, SEEK_END);
if (allocate == 1) {
/* round to cluster size */
cluster_offset = (cluster_offset + s->cluster_size - 1) &
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
ftruncate(s->fd, cluster_offset + s->cluster_size);
/* if encrypted, we must initialize the cluster
content which won't be written */
if (s->crypt_method &&
if (s->crypt_method &&
(n_end - n_start) < s->cluster_sectors) {
uint64_t start_sect;
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
memset(s->cluster_data + 512, 0x00, 512);
memset(s->cluster_data + 512, 0xaa, 512);
for(i = 0; i < s->cluster_sectors; i++) {
if (i < n_start || i >= n_end) {
encrypt_sectors(s, start_sect + i,
s->cluster_data,
encrypt_sectors(s, start_sect + i,
s->cluster_data,
s->cluster_data + 512, 1, 1,
&s->aes_encrypt_key);
if (bdrv_pwrite(s->hd, cluster_offset + i * 512,
s->cluster_data, 512) != 512)
lseek(s->fd, cluster_offset + i * 512, SEEK_SET);
if (write(s->fd, s->cluster_data, 512) != 512)
return -1;
}
}
}
} else if (allocate == 2) {
cluster_offset |= QCOW_OFLAG_COMPRESSED |
} else {
cluster_offset |= QCOW_OFLAG_COMPRESSED |
(uint64_t)compressed_size << (63 - s->cluster_bits);
}
}
/* update L2 table */
tmp = cpu_to_be64(cluster_offset);
l2_table[l2_index] = tmp;
if (bdrv_pwrite(s->hd,
l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
lseek(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
}
return cluster_offset;
}
static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
BDRVQcowState *s = bs->opaque;
@@ -421,7 +427,7 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
inflateEnd(strm);
return 0;
}
static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
{
int ret, csize;
@@ -431,8 +437,9 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
if (s->cluster_cache_offset != coffset) {
csize = cluster_offset >> (63 - s->cluster_bits);
csize &= (s->cluster_size - 1);
ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize);
if (ret != csize)
lseek(s->fd, coffset, SEEK_SET);
ret = read(s->fd, s->cluster_data, csize);
if (ret != csize)
return -1;
if (decompress_buffer(s->cluster_cache, s->cluster_size,
s->cluster_data, csize) < 0) {
@@ -443,15 +450,13 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
return 0;
}
#if 0
static int qcow_read(BlockDriverState *bs, int64_t sector_num,
static int qcow_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVQcowState *s = bs->opaque;
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
index_in_cluster = sector_num & (s->cluster_sectors - 1);
@@ -459,24 +464,18 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
if (bs->backing_hd) {
/* read from the base image */
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
if (ret < 0)
return -1;
} else {
memset(buf, 0, 512 * n);
}
memset(buf, 0, 512 * n);
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
if (decompress_cluster(s, cluster_offset) < 0)
return -1;
memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
} else {
ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
if (ret != n * 512)
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
if (s->crypt_method) {
encrypt_sectors(s, sector_num, buf, buf, n, 0,
encrypt_sectors(s, sector_num, buf, buf, n, 0,
&s->aes_decrypt_key);
}
}
@@ -486,250 +485,40 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
}
return 0;
}
#endif
typedef struct QCowAIOCB {
BlockDriverAIOCB common;
int64_t sector_num;
QEMUIOVector *qiov;
uint8_t *buf;
void *orig_buf;
int nb_sectors;
int n;
uint64_t cluster_offset;
uint8_t *cluster_data;
struct iovec hd_iov;
QEMUIOVector hd_qiov;
BlockDriverAIOCB *hd_aiocb;
} QCowAIOCB;
static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
QCowAIOCB *acb = (QCowAIOCB *)blockacb;
if (acb->hd_aiocb)
bdrv_aio_cancel(acb->hd_aiocb);
qemu_aio_release(acb);
}
static AIOPool qcow_aio_pool = {
.aiocb_size = sizeof(QCowAIOCB),
.cancel = qcow_aio_cancel,
};
static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int is_write)
{
QCowAIOCB *acb;
acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
if (!acb)
return NULL;
acb->hd_aiocb = NULL;
acb->sector_num = sector_num;
acb->qiov = qiov;
if (qiov->niov > 1) {
acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
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 = 0;
acb->cluster_offset = 0;
return acb;
}
static void qcow_aio_read_cb(void *opaque, int ret)
{
QCowAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
BDRVQcowState *s = bs->opaque;
int index_in_cluster;
acb->hd_aiocb = NULL;
if (ret < 0)
goto done;
redo:
/* post process the read buffer */
if (!acb->cluster_offset) {
/* nothing to do */
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
/* nothing to do */
} else {
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
index_in_cluster,
index_in_cluster + n);
if (!cluster_offset)
return -1;
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
if (s->crypt_method) {
encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
acb->n, 0,
&s->aes_decrypt_key);
}
}
acb->nb_sectors -= acb->n;
acb->sector_num += acb->n;
acb->buf += acb->n * 512;
if (acb->nb_sectors == 0) {
/* request completed */
ret = 0;
goto done;
}
/* prepare next AIO request */
acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9,
0, 0, 0, 0);
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
acb->n = s->cluster_sectors - index_in_cluster;
if (acb->n > acb->nb_sectors)
acb->n = acb->nb_sectors;
if (!acb->cluster_offset) {
if (bs->backing_hd) {
/* read from the base image */
acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = acb->n * 512;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
&acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
if (acb->hd_aiocb == NULL)
goto done;
encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
&s->aes_encrypt_key);
ret = write(s->fd, s->cluster_data, n * 512);
} else {
/* Note: in this case, no need to wait */
memset(acb->buf, 0, 512 * acb->n);
goto redo;
ret = write(s->fd, buf, n * 512);
}
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
/* add AIO support for compressed blocks ? */
if (decompress_cluster(s, acb->cluster_offset) < 0)
goto done;
memcpy(acb->buf,
s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
goto redo;
} else {
if ((acb->cluster_offset & 511) != 0) {
ret = -EIO;
goto done;
}
acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = acb->n * 512;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_readv(s->hd,
(acb->cluster_offset >> 9) + index_in_cluster,
&acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
if (acb->hd_aiocb == NULL)
goto done;
if (ret != n * 512)
return -1;
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
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 *qcow_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
QCowAIOCB *acb;
acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb)
return NULL;
qcow_aio_read_cb(acb, 0);
return &acb->common;
}
static void qcow_aio_write_cb(void *opaque, int ret)
{
QCowAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
BDRVQcowState *s = bs->opaque;
int index_in_cluster;
uint64_t cluster_offset;
const uint8_t *src_buf;
acb->hd_aiocb = NULL;
if (ret < 0)
goto done;
acb->nb_sectors -= acb->n;
acb->sector_num += acb->n;
acb->buf += acb->n * 512;
if (acb->nb_sectors == 0) {
/* request completed */
ret = 0;
goto done;
}
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
acb->n = s->cluster_sectors - index_in_cluster;
if (acb->n > acb->nb_sectors)
acb->n = acb->nb_sectors;
cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0,
index_in_cluster,
index_in_cluster + acb->n);
if (!cluster_offset || (cluster_offset & 511) != 0) {
ret = -EIO;
goto done;
}
if (s->crypt_method) {
if (!acb->cluster_data) {
acb->cluster_data = qemu_mallocz(s->cluster_size);
if (!acb->cluster_data) {
ret = -ENOMEM;
goto done;
}
}
encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
acb->n, 1, &s->aes_encrypt_key);
src_buf = acb->cluster_data;
} else {
src_buf = acb->buf;
}
acb->hd_iov.iov_base = (void *)src_buf;
acb->hd_iov.iov_len = acb->n * 512;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_writev(s->hd,
(cluster_offset >> 9) + index_in_cluster,
&acb->hd_qiov, acb->n,
qcow_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 *qcow_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVQcowState *s = bs->opaque;
QCowAIOCB *acb;
s->cluster_cache_offset = -1; /* disable compressed cache */
acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
if (!acb)
return NULL;
qcow_aio_write_cb(acb, 0);
return &acb->common;
return 0;
}
static void qcow_close(BlockDriverState *bs)
@@ -739,31 +528,20 @@ static void qcow_close(BlockDriverState *bs)
qemu_free(s->l2_cache);
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
bdrv_delete(s->hd);
close(s->fd);
}
static int qcow_create(const char *filename, QEMUOptionParameter *options)
static int qcow_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
int fd, header_size, backing_filename_len, l1_size, i, shift;
QCowHeader header;
char backing_filename[1024];
uint64_t tmp;
int64_t total_size = 0;
const char *backing_file = NULL;
int flags = 0;
struct stat st;
/* Read out options */
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
total_size = options->value.n / 512;
} else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
backing_file = options->value.s;
} else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
}
options++;
}
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0)
return -1;
memset(&header, 0, sizeof(header));
@@ -773,15 +551,15 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
header_size = sizeof(header);
backing_filename_len = 0;
if (backing_file) {
if (strcmp(backing_file, "fat:")) {
header.backing_file_offset = cpu_to_be64(header_size);
backing_filename_len = strlen(backing_file);
header.backing_file_size = cpu_to_be32(backing_filename_len);
header_size += backing_filename_len;
} else {
/* special backing file for vvfat */
backing_file = NULL;
realpath(backing_file, backing_filename);
if (stat(backing_filename, &st) != 0) {
return -1;
}
header.mtime = cpu_to_be32(st.st_mtime);
header.backing_file_offset = cpu_to_be64(header_size);
backing_filename_len = strlen(backing_filename);
header.backing_file_size = cpu_to_be32(backing_filename_len);
header_size += backing_filename_len;
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
unmodifyed sectors */
header.l2_bits = 12; /* 32 KB L2 tables */
@@ -794,16 +572,16 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift;
header.l1_table_offset = cpu_to_be64(header_size);
if (flags & BLOCK_FLAG_ENCRYPT) {
if (flags) {
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
} else {
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
}
/* write all the data */
write(fd, &header, sizeof(header));
if (backing_file) {
write(fd, backing_file, backing_filename_len);
write(fd, backing_filename, backing_filename_len);
}
lseek(fd, header_size, SEEK_SET);
tmp = 0;
@@ -814,30 +592,18 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
return 0;
}
static int qcow_make_empty(BlockDriverState *bs)
int qcow_get_cluster_size(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
uint32_t l1_length = s->l1_size * sizeof(uint64_t);
int ret;
memset(s->l1_table, 0, l1_length);
if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
return -1;
ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
if (ret < 0)
return ret;
memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
return 0;
if (bs->drv != &bdrv_qcow)
return -1;
return s->cluster_size;
}
/* XXX: put compressed sectors first, then all the cluster aligned
tables to avoid losing bytes in alignment */
static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf)
{
BDRVQcowState *s = bs->opaque;
z_stream strm;
@@ -845,8 +611,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
uint8_t *out_buf;
uint64_t cluster_offset;
if (nb_sectors != s->cluster_sectors)
return -EINVAL;
if (bs->drv != &bdrv_qcow)
return -1;
out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
if (!out_buf)
@@ -855,7 +621,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
/* best compression, small window, no zlib header */
memset(&strm, 0, sizeof(strm));
ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, -12,
Z_DEFLATED, -12,
9, Z_DEFAULT_STRATEGY);
if (ret != 0) {
qemu_free(out_buf);
@@ -879,76 +645,33 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
/* could not compress: write normal cluster */
bdrv_write(bs, sector_num, buf, s->cluster_sectors);
qcow_write(bs, sector_num, buf, s->cluster_sectors);
} else {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
out_len, 0, 0);
cluster_offset &= s->cluster_offset_mask;
if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
lseek(s->fd, cluster_offset, SEEK_SET);
if (write(s->fd, out_buf, out_len) != out_len) {
qemu_free(out_buf);
return -1;
}
}
qemu_free(out_buf);
return 0;
}
static void qcow_flush(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
bdrv_flush(s->hd);
}
static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
BDRVQcowState *s = bs->opaque;
bdi->cluster_size = s->cluster_size;
return 0;
}
static QEMUOptionParameter qcow_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{
.name = BLOCK_OPT_BACKING_FILE,
.type = OPT_STRING,
.help = "File name of a base image"
},
{
.name = BLOCK_OPT_ENCRYPT,
.type = OPT_FLAG,
.help = "Encrypt the image"
},
{ NULL }
BlockDriver bdrv_qcow = {
"qcow",
sizeof(BDRVQcowState),
qcow_probe,
qcow_open,
qcow_read,
qcow_write,
qcow_close,
qcow_create,
qcow_is_allocated,
qcow_set_key,
};
static BlockDriver bdrv_qcow = {
.format_name = "qcow",
.instance_size = sizeof(BDRVQcowState),
.bdrv_probe = qcow_probe,
.bdrv_open = qcow_open,
.bdrv_close = qcow_close,
.bdrv_create = qcow_create,
.bdrv_flush = qcow_flush,
.bdrv_is_allocated = qcow_is_allocated,
.bdrv_set_key = qcow_set_key,
.bdrv_make_empty = qcow_make_empty,
.bdrv_aio_readv = qcow_aio_readv,
.bdrv_aio_writev = qcow_aio_writev,
.bdrv_write_compressed = qcow_write_compressed,
.bdrv_get_info = qcow_get_info,
.create_options = qcow_create_options,
};
static void bdrv_qcow_init(void)
{
bdrv_register(&bdrv_qcow);
}
block_init(bdrv_qcow_init);

336
block-vmdk.c Normal file
View File

@@ -0,0 +1,336 @@
/*
* Block driver for the VMDK format
*
* Copyright (c) 2004 Fabrice Bellard
* Copyright (c) 2005 Filip Navara
*
* 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 "vl.h"
#include "block_int.h"
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
typedef struct {
uint32_t version;
uint32_t flags;
uint32_t disk_sectors;
uint32_t granularity;
uint32_t l1dir_offset;
uint32_t l1dir_size;
uint32_t file_sectors;
uint32_t cylinders;
uint32_t heads;
uint32_t sectors_per_track;
} VMDK3Header;
typedef struct {
uint32_t version;
uint32_t flags;
int64_t capacity;
int64_t granularity;
int64_t desc_offset;
int64_t desc_size;
int32_t num_gtes_per_gte;
int64_t rgd_offset;
int64_t gd_offset;
int64_t grain_offset;
char filler[1];
char check_bytes[4];
} __attribute__((packed)) VMDK4Header;
#define L2_CACHE_SIZE 16
typedef struct BDRVVmdkState {
int fd;
int64_t l1_table_offset;
int64_t l1_backup_table_offset;
uint32_t *l1_table;
uint32_t *l1_backup_table;
unsigned int l1_size;
uint32_t l1_entry_sectors;
unsigned int l2_size;
uint32_t *l2_cache;
uint32_t l2_cache_offsets[L2_CACHE_SIZE];
uint32_t l2_cache_counts[L2_CACHE_SIZE];
unsigned int cluster_sectors;
} BDRVVmdkState;
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
{
uint32_t magic;
if (buf_size < 4)
return 0;
magic = be32_to_cpu(*(uint32_t *)buf);
if (magic == VMDK3_MAGIC ||
magic == VMDK4_MAGIC)
return 100;
else
return 0;
}
static int vmdk_open(BlockDriverState *bs, const char *filename)
{
BDRVVmdkState *s = bs->opaque;
int fd, i;
uint32_t magic;
int l1_size;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
bs->read_only = 1;
}
if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
goto fail;
magic = be32_to_cpu(magic);
if (magic == VMDK3_MAGIC) {
VMDK3Header header;
if (read(fd, &header, sizeof(header)) !=
sizeof(header))
goto fail;
s->cluster_sectors = le32_to_cpu(header.granularity);
s->l2_size = 1 << 9;
s->l1_size = 1 << 6;
bs->total_sectors = le32_to_cpu(header.disk_sectors);
s->l1_table_offset = le32_to_cpu(header.l1dir_offset) << 9;
s->l1_backup_table_offset = 0;
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
} else if (magic == VMDK4_MAGIC) {
VMDK4Header header;
if (read(fd, &header, sizeof(header)) != sizeof(header))
goto fail;
bs->total_sectors = le32_to_cpu(header.capacity);
s->cluster_sectors = le32_to_cpu(header.granularity);
s->l2_size = le32_to_cpu(header.num_gtes_per_gte);
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
if (s->l1_entry_sectors <= 0)
goto fail;
s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1)
/ s->l1_entry_sectors;
s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
} else {
goto fail;
}
/* read the L1 table */
l1_size = s->l1_size * sizeof(uint32_t);
s->l1_table = qemu_malloc(l1_size);
if (!s->l1_table)
goto fail;
if (lseek(fd, s->l1_table_offset, SEEK_SET) == -1)
goto fail;
if (read(fd, s->l1_table, l1_size) != l1_size)
goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_table[i]);
}
if (s->l1_backup_table_offset) {
s->l1_backup_table = qemu_malloc(l1_size);
if (!s->l1_backup_table)
goto fail;
if (lseek(fd, s->l1_backup_table_offset, SEEK_SET) == -1)
goto fail;
if (read(fd, s->l1_backup_table, l1_size) != l1_size)
goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_backup_table[i]);
}
}
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
if (!s->l2_cache)
goto fail;
s->fd = fd;
return 0;
fail:
qemu_free(s->l1_backup_table);
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
close(fd);
return -1;
}
static uint64_t get_cluster_offset(BlockDriverState *bs,
uint64_t offset, int allocate)
{
BDRVVmdkState *s = bs->opaque;
unsigned int l1_index, l2_offset, l2_index;
int min_index, i, j;
uint32_t min_count, *l2_table, tmp;
uint64_t cluster_offset;
l1_index = (offset >> 9) / s->l1_entry_sectors;
if (l1_index >= s->l1_size)
return 0;
l2_offset = s->l1_table[l1_index];
if (!l2_offset)
return 0;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (l2_offset == s->l2_cache_offsets[i]) {
/* increment the hit count */
if (++s->l2_cache_counts[i] == 0xffffffff) {
for(j = 0; j < L2_CACHE_SIZE; j++) {
s->l2_cache_counts[j] >>= 1;
}
}
l2_table = s->l2_cache + (i * s->l2_size);
goto found;
}
}
/* not found: load a new entry in the least used one */
min_index = 0;
min_count = 0xffffffff;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (s->l2_cache_counts[i] < min_count) {
min_count = s->l2_cache_counts[i];
min_index = i;
}
}
l2_table = s->l2_cache + (min_index * s->l2_size);
lseek(s->fd, (int64_t)l2_offset * 512, SEEK_SET);
if (read(s->fd, l2_table, s->l2_size * sizeof(uint32_t)) !=
s->l2_size * sizeof(uint32_t))
return 0;
s->l2_cache_offsets[min_index] = l2_offset;
s->l2_cache_counts[min_index] = 1;
found:
l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
cluster_offset = le32_to_cpu(l2_table[l2_index]);
if (!cluster_offset) {
if (!allocate)
return 0;
cluster_offset = lseek(s->fd, 0, SEEK_END);
ftruncate(s->fd, cluster_offset + (s->cluster_sectors << 9));
cluster_offset >>= 9;
/* update L2 table */
tmp = cpu_to_le32(cluster_offset);
l2_table[l2_index] = tmp;
lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
/* update backup L2 table */
if (s->l1_backup_table_offset != 0) {
l2_offset = s->l1_backup_table[l1_index];
lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
}
}
cluster_offset <<= 9;
return cluster_offset;
}
static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
BDRVVmdkState *s = bs->opaque;
int index_in_cluster, n;
uint64_t cluster_offset;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
index_in_cluster = sector_num % s->cluster_sectors;
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
*pnum = n;
return (cluster_offset != 0);
}
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
index_in_cluster = sector_num % s->cluster_sectors;
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
memset(buf, 0, 512 * n);
} else {
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1);
if (!cluster_offset)
return -1;
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = write(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static void vmdk_close(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
close(s->fd);
}
BlockDriver bdrv_vmdk = {
"vmdk",
sizeof(BDRVVmdkState),
vmdk_probe,
vmdk_open,
vmdk_read,
vmdk_write,
vmdk_close,
NULL, /* no create yet */
vmdk_is_allocated,
};

243
block-vpc.c Normal file
View File

@@ -0,0 +1,243 @@
/*
* Block driver for Conectix/Microsoft Virtual PC images
*
* Copyright (c) 2005 Alex Beregszaszi
*
* 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 "vl.h"
#include "block_int.h"
/**************************************************************/
#define HEADER_SIZE 512
//#define CACHE
// always big-endian
struct vpc_subheader {
char magic[8]; // "conectix" / "cxsparse"
union {
struct {
uint32_t unk1[2];
uint32_t unk2; // always zero?
uint32_t subheader_offset;
uint32_t unk3; // some size?
char creator[4]; // "vpc "
uint16_t major;
uint16_t minor;
char guest[4]; // "Wi2k"
uint32_t unk4[7];
uint8_t vnet_id[16]; // virtual network id, purpose unknown
// next 16 longs are used, but dunno the purpose
// next 6 longs unknown, following 7 long maybe a serial
char padding[HEADER_SIZE - 84];
} main;
struct {
uint32_t unk1[2]; // all bits set
uint32_t unk2; // always zero?
uint32_t pagetable_offset;
uint32_t unk3;
uint32_t pagetable_entries; // 32bit/entry
uint32_t pageentry_size; // 512*8*512
uint32_t nb_sectors;
char padding[HEADER_SIZE - 40];
} sparse;
char padding[HEADER_SIZE - 8];
} type;
};
typedef struct BDRVVPCState {
int fd;
int pagetable_entries;
uint32_t *pagetable;
uint32_t pageentry_size;
#ifdef CACHE
uint8_t *pageentry_u8;
uint32_t *pageentry_u32;
uint16_t *pageentry_u16;
uint64_t last_bitmap;
#endif
} BDRVVPCState;
static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
{
if (!strncmp(buf, "conectix", 8))
return 100;
return 0;
}
static int vpc_open(BlockDriverState *bs, const char *filename)
{
BDRVVPCState *s = bs->opaque;
int fd, i;
struct vpc_subheader header;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
bs->read_only = 1; // no write support yet
s->fd = fd;
if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
goto fail;
if (strncmp(header.magic, "conectix", 8))
goto fail;
lseek(s->fd, be32_to_cpu(header.type.main.subheader_offset), SEEK_SET);
if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
goto fail;
if (strncmp(header.magic, "cxsparse", 8))
goto fail;
bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) *
be32_to_cpu(header.type.sparse.pageentry_size)) / 512;
lseek(s->fd, be32_to_cpu(header.type.sparse.pagetable_offset), SEEK_SET);
s->pagetable_entries = be32_to_cpu(header.type.sparse.pagetable_entries);
s->pagetable = qemu_malloc(s->pagetable_entries * 4);
if (!s->pagetable)
goto fail;
if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
s->pagetable_entries * 4)
goto fail;
for (i = 0; i < s->pagetable_entries; i++)
be32_to_cpus(&s->pagetable[i]);
s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size);
#ifdef CACHE
s->pageentry_u8 = qemu_malloc(512);
if (!s->pageentry_u8)
goto fail;
s->pageentry_u32 = s->pageentry_u8;
s->pageentry_u16 = s->pageentry_u8;
s->last_pagetable = -1;
#endif
return 0;
fail:
close(fd);
return -1;
}
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
{
BDRVVPCState *s = bs->opaque;
uint64_t offset = sector_num * 512;
uint64_t bitmap_offset, block_offset;
uint32_t pagetable_index, pageentry_index;
pagetable_index = offset / s->pageentry_size;
pageentry_index = (offset % s->pageentry_size) / 512;
if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
return -1; // not allocated
bitmap_offset = 512 * s->pagetable[pagetable_index];
block_offset = bitmap_offset + 512 + (512 * pageentry_index);
// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n",
// sector_num, pagetable_index, pageentry_index,
// bitmap_offset, block_offset);
// disabled by reason
#if 0
#ifdef CACHE
if (bitmap_offset != s->last_bitmap)
{
lseek(s->fd, bitmap_offset, SEEK_SET);
s->last_bitmap = bitmap_offset;
// Scary! Bitmap is stored as big endian 32bit entries,
// while we used to look it up byte by byte
read(s->fd, s->pageentry_u8, 512);
for (i = 0; i < 128; i++)
be32_to_cpus(&s->pageentry_u32[i]);
}
if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
return -1;
#else
lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
read(s->fd, &bitmap_entry, 1);
if ((bitmap_entry >> (pageentry_index % 8)) & 1)
return -1; // not allocated
#endif
#endif
lseek(s->fd, block_offset, SEEK_SET);
return 0;
}
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVPCState *s = bs->opaque;
int ret;
while (nb_sectors > 0) {
if (!seek_to_sector(bs, sector_num))
{
ret = read(s->fd, buf, 512);
if (ret != 512)
return -1;
}
else
memset(buf, 0, 512);
nb_sectors--;
sector_num++;
buf += 512;
}
return 0;
}
static void vpc_close(BlockDriverState *bs)
{
BDRVVPCState *s = bs->opaque;
qemu_free(s->pagetable);
#ifdef CACHE
qemu_free(s->pageentry_u8);
#endif
close(s->fd);
}
BlockDriver bdrv_vpc = {
"vpc",
sizeof(BDRVVPCState),
vpc_probe,
vpc_open,
vpc_read,
NULL,
vpc_close,
};

1558
block.c

File diff suppressed because it is too large Load Diff

168
block.h
View File

@@ -1,168 +0,0 @@
#ifndef BLOCK_H
#define BLOCK_H
#include "qemu-aio.h"
#include "qemu-common.h"
#include "qemu-option.h"
/* block.c */
typedef struct BlockDriver BlockDriver;
typedef struct BlockDriverInfo {
/* in bytes, 0 if irrelevant */
int cluster_size;
/* offset at which the VM state can be saved (0 if not possible) */
int64_t vm_state_offset;
} BlockDriverInfo;
typedef struct QEMUSnapshotInfo {
char id_str[128]; /* unique snapshot id */
/* the following fields are informative. They are not needed for
the consistency of the snapshot */
char name[256]; /* user choosen name */
uint32_t vm_state_size; /* VM state info size */
uint32_t date_sec; /* UTC date of the snapshot */
uint32_t date_nsec;
uint64_t vm_clock_nsec; /* VM clock relative to boot */
} QEMUSnapshotInfo;
#define BDRV_O_RDONLY 0x0000
#define BDRV_O_RDWR 0x0002
#define BDRV_O_ACCESS 0x0003
#define BDRV_O_CREAT 0x0004 /* create an empty file */
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
#define BDRV_O_FILE 0x0010 /* open as a raw file (do not try to
use a disk image format on top of
it (default for
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_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB)
void bdrv_info(Monitor *mon);
void bdrv_info_stats(Monitor *mon);
void bdrv_init(void);
BlockDriver *bdrv_find_format(const char *format_name);
int bdrv_create(BlockDriver *drv, const char* filename,
QEMUOptionParameter *options);
int bdrv_create2(BlockDriver *drv,
const char *filename, int64_t size_in_sectors,
const char *backing_file, const char *backing_format,
int flags);
BlockDriverState *bdrv_new(const char *device_name);
void bdrv_delete(BlockDriverState *bs);
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
int bdrv_open(BlockDriverState *bs, const char *filename, int flags);
int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
BlockDriver *drv);
void bdrv_close(BlockDriverState *bs);
int bdrv_check(BlockDriverState *bs);
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
int bdrv_pread(BlockDriverState *bs, int64_t offset,
void *buf, int count);
int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
const void *buf, int count);
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
int64_t bdrv_getlength(BlockDriverState *bs);
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
int bdrv_commit(BlockDriverState *bs);
void bdrv_register(BlockDriver *bdrv);
/* async block I/O */
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
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);
void bdrv_aio_cancel(BlockDriverAIOCB *acb);
/* sg packet commands */
int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);
BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb, void *opaque);
/* Ensure contents are flushed to disk. */
void bdrv_flush(BlockDriverState *bs);
void bdrv_flush_all(void);
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
int *pnum);
#define BDRV_TYPE_HD 0
#define BDRV_TYPE_CDROM 1
#define BDRV_TYPE_FLOPPY 2
#define BIOS_ATA_TRANSLATION_AUTO 0
#define BIOS_ATA_TRANSLATION_NONE 1
#define BIOS_ATA_TRANSLATION_LBA 2
#define BIOS_ATA_TRANSLATION_LARGE 3
#define BIOS_ATA_TRANSLATION_RECHS 4
void bdrv_set_geometry_hint(BlockDriverState *bs,
int cyls, int heads, int secs);
void bdrv_set_type_hint(BlockDriverState *bs, int type);
void bdrv_set_translation_hint(BlockDriverState *bs, int translation);
void bdrv_get_geometry_hint(BlockDriverState *bs,
int *pcyls, int *pheads, int *psecs);
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_is_sg(BlockDriverState *bs);
int bdrv_is_inserted(BlockDriverState *bs);
int bdrv_media_changed(BlockDriverState *bs);
int bdrv_is_locked(BlockDriverState *bs);
void bdrv_set_locked(BlockDriverState *bs, int locked);
int bdrv_eject(BlockDriverState *bs, int eject_flag);
void bdrv_set_change_cb(BlockDriverState *bs,
void (*change_cb)(void *opaque), void *opaque);
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
BlockDriverState *bdrv_find(const char *name);
void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs),
void *opaque);
int bdrv_is_encrypted(BlockDriverState *bs);
int bdrv_key_required(BlockDriverState *bs);
int bdrv_set_key(BlockDriverState *bs, const char *key);
int bdrv_query_missing_keys(void);
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
void *opaque);
const char *bdrv_get_device_name(BlockDriverState *bs);
int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
void bdrv_get_backing_filename(BlockDriverState *bs,
char *filename, int filename_size);
int bdrv_snapshot_create(BlockDriverState *bs,
QEMUSnapshotInfo *sn_info);
int bdrv_snapshot_goto(BlockDriverState *bs,
const char *snapshot_id);
int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
int bdrv_snapshot_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info);
char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
char *get_human_readable_size(char *buf, int buf_size, int64_t size);
int path_is_absolute(const char *path);
void path_combine(char *dest, int dest_size,
const char *base_path,
const char *filename);
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
int64_t pos, int size);
int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
int64_t pos, int size);
#endif

View File

@@ -1,562 +0,0 @@
/*
* QEMU Block driver for CURL images
*
* Copyright (c) 2009 Alexander Graf <agraf@suse.de>
*
* 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 "block_int.h"
#include <curl/curl.h>
// #define DEBUG
// #define DEBUG_VERBOSE
#ifdef DEBUG_CURL
#define dprintf(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
#else
#define dprintf(fmt, ...) do { } while (0)
#endif
#define CURL_NUM_STATES 8
#define CURL_NUM_ACB 8
#define SECTOR_SIZE 512
#define READ_AHEAD_SIZE (256 * 1024)
#define FIND_RET_NONE 0
#define FIND_RET_OK 1
#define FIND_RET_WAIT 2
struct BDRVCURLState;
typedef struct CURLAIOCB {
BlockDriverAIOCB common;
QEMUIOVector *qiov;
size_t start;
size_t end;
} CURLAIOCB;
typedef struct CURLState
{
struct BDRVCURLState *s;
CURLAIOCB *acb[CURL_NUM_ACB];
CURL *curl;
char *orig_buf;
size_t buf_start;
size_t buf_off;
size_t buf_len;
char range[128];
char errmsg[CURL_ERROR_SIZE];
char in_use;
} CURLState;
typedef struct BDRVCURLState {
CURLM *multi;
size_t len;
CURLState states[CURL_NUM_STATES];
char *url;
size_t readahead_size;
} BDRVCURLState;
static void curl_clean_state(CURLState *s);
static void curl_multi_do(void *arg);
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
void *s, void *sp)
{
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, s);
break;
case CURL_POLL_OUT:
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, s);
break;
case CURL_POLL_REMOVE:
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL);
break;
}
return 0;
}
static size_t curl_size_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
{
CURLState *s = ((CURLState*)opaque);
size_t realsize = size * nmemb;
long long fsize;
if(sscanf(ptr, "Content-Length: %lld", &fsize) == 1)
s->s->len = fsize;
return realsize;
}
static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
{
CURLState *s = ((CURLState*)opaque);
size_t realsize = size * nmemb;
int i;
dprintf("CURL: Just reading %lld bytes\n", (unsigned long long)realsize);
if (!s || !s->orig_buf)
goto read_end;
memcpy(s->orig_buf + s->buf_off, ptr, realsize);
s->buf_off += realsize;
for(i=0; i<CURL_NUM_ACB; i++) {
CURLAIOCB *acb = s->acb[i];
if (!acb)
continue;
if ((s->buf_off >= acb->end)) {
qemu_iovec_from_buffer(acb->qiov, s->orig_buf + acb->start,
acb->end - acb->start);
acb->common.cb(acb->common.opaque, 0);
qemu_aio_release(acb);
s->acb[i] = NULL;
}
}
read_end:
return realsize;
}
static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
CURLAIOCB *acb)
{
int i;
size_t end = start + len;
for (i=0; i<CURL_NUM_STATES; i++) {
CURLState *state = &s->states[i];
size_t buf_end = (state->buf_start + state->buf_off);
size_t buf_fend = (state->buf_start + state->buf_len);
if (!state->orig_buf)
continue;
if (!state->buf_off)
continue;
// Does the existing buffer cover our section?
if ((start >= state->buf_start) &&
(start <= buf_end) &&
(end >= state->buf_start) &&
(end <= buf_end))
{
char *buf = state->orig_buf + (start - state->buf_start);
qemu_iovec_from_buffer(acb->qiov, buf, len);
acb->common.cb(acb->common.opaque, 0);
return FIND_RET_OK;
}
// Wait for unfinished chunks
if ((start >= state->buf_start) &&
(start <= buf_fend) &&
(end >= state->buf_start) &&
(end <= buf_fend))
{
int j;
acb->start = start - state->buf_start;
acb->end = acb->start + len;
for (j=0; j<CURL_NUM_ACB; j++) {
if (!state->acb[j]) {
state->acb[j] = acb;
return FIND_RET_WAIT;
}
}
}
}
return FIND_RET_NONE;
}
static void curl_multi_do(void *arg)
{
BDRVCURLState *s = (BDRVCURLState *)arg;
int running;
int r;
int msgs_in_queue;
if (!s->multi)
return;
do {
r = curl_multi_socket_all(s->multi, &running);
} while(r == CURLM_CALL_MULTI_PERFORM);
/* Try to find done transfers, so we can free the easy
* handle again. */
do {
CURLMsg *msg;
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
if (!msg)
break;
if (msg->msg == CURLMSG_NONE)
break;
switch (msg->msg) {
case CURLMSG_DONE:
{
CURLState *state = NULL;
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
curl_clean_state(state);
break;
}
default:
msgs_in_queue = 0;
break;
}
} while(msgs_in_queue);
}
static CURLState *curl_init_state(BDRVCURLState *s)
{
CURLState *state = NULL;
int i, j;
do {
for (i=0; i<CURL_NUM_STATES; i++) {
for (j=0; j<CURL_NUM_ACB; j++)
if (s->states[i].acb[j])
continue;
if (s->states[i].in_use)
continue;
state = &s->states[i];
state->in_use = 1;
break;
}
if (!state) {
usleep(100);
curl_multi_do(s);
}
} while(!state);
if (state->curl)
goto has_curl;
state->curl = curl_easy_init();
if (!state->curl)
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_WRITEDATA, (void *)state);
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
#ifdef DEBUG_VERBOSE
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
#endif
has_curl:
state->s = s;
return state;
}
static void curl_clean_state(CURLState *s)
{
if (s->s->multi)
curl_multi_remove_handle(s->s->multi, s->curl);
s->in_use = 0;
}
static int curl_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVCURLState *s = bs->opaque;
CURLState *state = NULL;
double d;
#define RA_OPTSTR ":readahead="
char *file;
char *ra;
const char *ra_val;
int parse_state = 0;
static int inited = 0;
file = strdup(filename);
s->readahead_size = READ_AHEAD_SIZE;
/* Parse a trailing ":readahead=#:" param, if present. */
ra = file + strlen(file) - 1;
while (ra >= file) {
if (parse_state == 0) {
if (*ra == ':')
parse_state++;
else
break;
} else if (parse_state == 1) {
if (*ra > '9' || *ra < '0') {
char *opt_start = ra - strlen(RA_OPTSTR) + 1;
if (opt_start > file &&
strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
ra_val = ra + 1;
ra -= strlen(RA_OPTSTR) - 1;
*ra = '\0';
s->readahead_size = atoi(ra_val);
break;
} else {
break;
}
}
}
ra--;
}
if ((s->readahead_size & 0x1ff) != 0) {
fprintf(stderr, "HTTP_READAHEAD_SIZE %Zd is not a multiple of 512\n",
s->readahead_size);
goto out_noclean;
}
if (!inited) {
curl_global_init(CURL_GLOBAL_ALL);
inited = 1;
}
dprintf("CURL: Opening %s\n", file);
s->url = file;
state = curl_init_state(s);
if (!state)
goto out_noclean;
// Get file size
curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1);
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)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_NOBODY, 0);
if (d)
s->len = (size_t)d;
else if(!s->len)
goto out;
dprintf("CURL: Size = %lld\n", (long long)s->len);
curl_clean_state(state);
curl_easy_cleanup(state->curl);
state->curl = NULL;
// Now we know the file exists and its size, so let's
// initialize the multi interface!
s->multi = curl_multi_init();
curl_multi_setopt( s->multi, CURLMOPT_SOCKETDATA, s);
curl_multi_setopt( s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb );
curl_multi_do(s);
return 0;
out:
fprintf(stderr, "CURL: Error opening file: %s\n", state->errmsg);
curl_easy_cleanup(state->curl);
state->curl = NULL;
out_noclean:
qemu_free(file);
return -EINVAL;
}
static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
{
// Do we have to implement canceling? Seems to work without...
}
static AIOPool curl_aio_pool = {
.aiocb_size = sizeof(CURLAIOCB),
.cancel = curl_aio_cancel,
};
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVCURLState *s = bs->opaque;
CURLAIOCB *acb;
size_t start = sector_num * SECTOR_SIZE;
size_t end;
CURLState *state;
acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
if (!acb)
return NULL;
acb->qiov = qiov;
// In case we have the requested data already (e.g. read-ahead),
// we can just call the callback and be done.
switch (curl_find_buf(s, start, nb_sectors * SECTOR_SIZE, acb)) {
case FIND_RET_OK:
qemu_aio_release(acb);
// fall through
case FIND_RET_WAIT:
return &acb->common;
default:
break;
}
// No cache found, so let's start a new request
state = curl_init_state(s);
if (!state)
return NULL;
acb->start = 0;
acb->end = (nb_sectors * SECTOR_SIZE);
state->buf_off = 0;
if (state->orig_buf)
qemu_free(state->orig_buf);
state->buf_start = start;
state->buf_len = acb->end + s->readahead_size;
end = MIN(start + state->buf_len, s->len) - 1;
state->orig_buf = qemu_malloc(state->buf_len);
state->acb[0] = acb;
snprintf(state->range, 127, "%lld-%lld", (long long)start, (long long)end);
dprintf("CURL (AIO): Reading %d at %lld (%s)\n", (nb_sectors * SECTOR_SIZE), start, state->range);
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
curl_multi_add_handle(s->multi, state->curl);
curl_multi_do(s);
return &acb->common;
}
static void curl_close(BlockDriverState *bs)
{
BDRVCURLState *s = bs->opaque;
int i;
dprintf("CURL: Close\n");
for (i=0; i<CURL_NUM_STATES; i++) {
if (s->states[i].in_use)
curl_clean_state(&s->states[i]);
if (s->states[i].curl) {
curl_easy_cleanup(s->states[i].curl);
s->states[i].curl = NULL;
}
if (s->states[i].orig_buf) {
qemu_free(s->states[i].orig_buf);
s->states[i].orig_buf = NULL;
}
}
if (s->multi)
curl_multi_cleanup(s->multi);
if (s->url)
free(s->url);
}
static int64_t curl_getlength(BlockDriverState *bs)
{
BDRVCURLState *s = bs->opaque;
return s->len;
}
static BlockDriver bdrv_http = {
.format_name = "http",
.protocol_name = "http",
.instance_size = sizeof(BDRVCURLState),
.bdrv_open = curl_open,
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
.bdrv_aio_readv = curl_aio_readv,
};
static BlockDriver bdrv_https = {
.format_name = "https",
.protocol_name = "https",
.instance_size = sizeof(BDRVCURLState),
.bdrv_open = curl_open,
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
.bdrv_aio_readv = curl_aio_readv,
};
static BlockDriver bdrv_ftp = {
.format_name = "ftp",
.protocol_name = "ftp",
.instance_size = sizeof(BDRVCURLState),
.bdrv_open = curl_open,
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
.bdrv_aio_readv = curl_aio_readv,
};
static BlockDriver bdrv_ftps = {
.format_name = "ftps",
.protocol_name = "ftps",
.instance_size = sizeof(BDRVCURLState),
.bdrv_open = curl_open,
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
.bdrv_aio_readv = curl_aio_readv,
};
static BlockDriver bdrv_tftp = {
.format_name = "tftp",
.protocol_name = "tftp",
.instance_size = sizeof(BDRVCURLState),
.bdrv_open = curl_open,
.bdrv_close = curl_close,
.bdrv_getlength = curl_getlength,
.bdrv_aio_readv = curl_aio_readv,
};
static void curl_block_init(void)
{
bdrv_register(&bdrv_http);
bdrv_register(&bdrv_https);
bdrv_register(&bdrv_ftp);
bdrv_register(&bdrv_ftps);
bdrv_register(&bdrv_tftp);
}
block_init(curl_block_init);

View File

@@ -1,196 +0,0 @@
/*
* QEMU Block driver for NBD
*
* Copyright (C) 2008 Bull S.A.S.
* Author: Laurent Vivier <Laurent.Vivier@bull.net>
*
* Some parts:
* Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
*
* 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 "nbd.h"
#include "module.h"
#include <sys/types.h>
#include <unistd.h>
typedef struct BDRVNBDState {
int sock;
off_t size;
size_t blocksize;
} BDRVNBDState;
static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
{
BDRVNBDState *s = bs->opaque;
const char *host;
const char *unixpath;
int sock;
off_t size;
size_t blocksize;
int ret;
if ((flags & BDRV_O_CREAT))
return -EINVAL;
if (!strstart(filename, "nbd:", &host))
return -EINVAL;
if (strstart(host, "unix:", &unixpath)) {
if (unixpath[0] != '/')
return -EINVAL;
sock = unix_socket_outgoing(unixpath);
} else {
uint16_t port;
char *p, *r;
char hostname[128];
pstrcpy(hostname, 128, host);
p = strchr(hostname, ':');
if (p == NULL)
return -EINVAL;
*p = '\0';
p++;
port = strtol(p, &r, 0);
if (r == p)
return -EINVAL;
sock = tcp_socket_outgoing(hostname, port);
}
if (sock == -1)
return -errno;
ret = nbd_receive_negotiate(sock, &size, &blocksize);
if (ret == -1)
return -errno;
s->sock = sock;
s->size = size;
s->blocksize = blocksize;
return 0;
}
static int nbd_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
request.type = NBD_CMD_READ;
request.handle = (uint64_t)(intptr_t)bs;
request.from = sector_num * 512;;
request.len = nb_sectors * 512;
if (nbd_send_request(s->sock, &request) == -1)
return -errno;
if (nbd_receive_reply(s->sock, &reply) == -1)
return -errno;
if (reply.error !=0)
return -reply.error;
if (reply.handle != request.handle)
return -EIO;
if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len)
return -EIO;
return 0;
}
static int nbd_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
request.type = NBD_CMD_WRITE;
request.handle = (uint64_t)(intptr_t)bs;
request.from = sector_num * 512;;
request.len = nb_sectors * 512;
if (nbd_send_request(s->sock, &request) == -1)
return -errno;
if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len)
return -EIO;
if (nbd_receive_reply(s->sock, &reply) == -1)
return -errno;
if (reply.error !=0)
return -reply.error;
if (reply.handle != request.handle)
return -EIO;
return 0;
}
static void nbd_close(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
request.type = NBD_CMD_DISC;
request.handle = (uint64_t)(intptr_t)bs;
request.from = 0;
request.len = 0;
nbd_send_request(s->sock, &request);
close(s->sock);
}
static int64_t nbd_getlength(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
return s->size;
}
static BlockDriver bdrv_nbd = {
.format_name = "nbd",
.instance_size = sizeof(BDRVNBDState),
.bdrv_open = nbd_open,
.bdrv_read = nbd_read,
.bdrv_write = nbd_write,
.bdrv_close = nbd_close,
.bdrv_getlength = nbd_getlength,
.protocol_name = "nbd",
};
static void bdrv_nbd_init(void)
{
bdrv_register(&bdrv_nbd);
}
block_init(bdrv_nbd_init);

View File

@@ -1,181 +0,0 @@
/*
* Block driver for Parallels disk image format
*
* Copyright (c) 2007 Alex Beregszaszi
*
* This code is based on comparing different disk images created by Parallels.
*
* 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 "block_int.h"
#include "module.h"
/**************************************************************/
#define HEADER_MAGIC "WithoutFreeSpace"
#define HEADER_VERSION 2
#define HEADER_SIZE 64
// always little-endian
struct parallels_header {
char magic[16]; // "WithoutFreeSpace"
uint32_t version;
uint32_t heads;
uint32_t cylinders;
uint32_t tracks;
uint32_t catalog_entries;
uint32_t nb_sectors;
char padding[24];
} __attribute__((packed));
typedef struct BDRVParallelsState {
int fd;
uint32_t *catalog_bitmap;
int catalog_size;
int tracks;
} BDRVParallelsState;
static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const struct parallels_header *ph = (const void *)buf;
if (buf_size < HEADER_SIZE)
return 0;
if (!memcmp(ph->magic, HEADER_MAGIC, 16) &&
(le32_to_cpu(ph->version) == HEADER_VERSION))
return 100;
return 0;
}
static int parallels_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVParallelsState *s = bs->opaque;
int fd, i;
struct parallels_header ph;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
bs->read_only = 1; // no write support yet
s->fd = fd;
if (read(fd, &ph, sizeof(ph)) != sizeof(ph))
goto fail;
if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
(le32_to_cpu(ph.version) != HEADER_VERSION)) {
goto fail;
}
bs->total_sectors = le32_to_cpu(ph.nb_sectors);
if (lseek(s->fd, 64, SEEK_SET) != 64)
goto fail;
s->tracks = le32_to_cpu(ph.tracks);
s->catalog_size = le32_to_cpu(ph.catalog_entries);
s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
s->catalog_size * 4)
goto fail;
for (i = 0; i < s->catalog_size; i++)
le32_to_cpus(&s->catalog_bitmap[i]);
return 0;
fail:
if (s->catalog_bitmap)
qemu_free(s->catalog_bitmap);
close(fd);
return -1;
}
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
{
BDRVParallelsState *s = bs->opaque;
uint32_t index, offset, position;
index = sector_num / s->tracks;
offset = sector_num % s->tracks;
// not allocated
if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0))
return -1;
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);
if (lseek(s->fd, position, SEEK_SET) != position)
return -1;
return 0;
}
static int parallels_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVParallelsState *s = bs->opaque;
while (nb_sectors > 0) {
if (!seek_to_sector(bs, sector_num)) {
if (read(s->fd, buf, 512) != 512)
return -1;
} else
memset(buf, 0, 512);
nb_sectors--;
sector_num++;
buf += 512;
}
return 0;
}
static void parallels_close(BlockDriverState *bs)
{
BDRVParallelsState *s = bs->opaque;
qemu_free(s->catalog_bitmap);
close(s->fd);
}
static BlockDriver bdrv_parallels = {
.format_name = "parallels",
.instance_size = sizeof(BDRVParallelsState),
.bdrv_probe = parallels_probe,
.bdrv_open = parallels_open,
.bdrv_read = parallels_read,
.bdrv_close = parallels_close,
};
static void bdrv_parallels_init(void)
{
bdrv_register(&bdrv_parallels);
}
block_init(bdrv_parallels_init);

View File

@@ -1,839 +0,0 @@
/*
* Block driver for the QCOW version 2 format
*
* Copyright (c) 2004-2006 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 <zlib.h>
#include "qemu-common.h"
#include "block_int.h"
#include "block/qcow2.h"
int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
{
BDRVQcowState *s = bs->opaque;
int new_l1_size, new_l1_size2, ret, i;
uint64_t *new_l1_table;
uint64_t new_l1_table_offset;
uint8_t data[12];
new_l1_size = s->l1_size;
if (min_size <= new_l1_size)
return 0;
while (min_size > new_l1_size) {
new_l1_size = (new_l1_size * 3 + 1) / 2;
}
#ifdef DEBUG_ALLOC2
printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
#endif
new_l1_size2 = sizeof(uint64_t) * new_l1_size;
new_l1_table = qemu_mallocz(align_offset(new_l1_size2, 512));
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
/* write new table (align to cluster) */
new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
for(i = 0; i < s->l1_size; i++)
new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
if (ret != new_l1_size2)
goto fail;
for(i = 0; i < s->l1_size; i++)
new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
/* set new table */
cpu_to_be32w((uint32_t*)data, new_l1_size);
cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,
sizeof(data)) != sizeof(data))
goto fail;
qemu_free(s->l1_table);
qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
s->l1_table_offset = new_l1_table_offset;
s->l1_table = new_l1_table;
s->l1_size = new_l1_size;
return 0;
fail:
qemu_free(s->l1_table);
return -EIO;
}
void qcow2_l2_cache_reset(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
}
static inline int l2_cache_new_entry(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
uint32_t min_count;
int min_index, i;
/* find a new entry in the least used one */
min_index = 0;
min_count = 0xffffffff;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (s->l2_cache_counts[i] < min_count) {
min_count = s->l2_cache_counts[i];
min_index = i;
}
}
return min_index;
}
/*
* seek_l2_table
*
* seek l2_offset in the l2_cache table
* if not found, return NULL,
* if found,
* increments the l2 cache hit count of the entry,
* if counter overflow, divide by two all counters
* return the pointer to the l2 cache entry
*
*/
static uint64_t *seek_l2_table(BDRVQcowState *s, uint64_t l2_offset)
{
int i, j;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (l2_offset == s->l2_cache_offsets[i]) {
/* increment the hit count */
if (++s->l2_cache_counts[i] == 0xffffffff) {
for(j = 0; j < L2_CACHE_SIZE; j++) {
s->l2_cache_counts[j] >>= 1;
}
}
return s->l2_cache + (i << s->l2_bits);
}
}
return NULL;
}
/*
* l2_load
*
* Loads a L2 table into memory. If the table is in the cache, the cache
* is used; otherwise the L2 table is loaded from the image file.
*
* Returns a pointer to the L2 table on success, or NULL if the read from
* the image file failed.
*/
static uint64_t *l2_load(BlockDriverState *bs, uint64_t l2_offset)
{
BDRVQcowState *s = bs->opaque;
int min_index;
uint64_t *l2_table;
/* seek if the table for the given offset is in the cache */
l2_table = seek_l2_table(s, l2_offset);
if (l2_table != NULL)
return l2_table;
/* not found: load a new entry in the least used one */
min_index = l2_cache_new_entry(bs);
l2_table = s->l2_cache + (min_index << s->l2_bits);
if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return NULL;
s->l2_cache_offsets[min_index] = l2_offset;
s->l2_cache_counts[min_index] = 1;
return l2_table;
}
/*
* Writes one sector of the L1 table to the disk (can't update single entries
* and we really don't want bdrv_pread to perform a read-modify-write)
*/
#define L1_ENTRIES_PER_SECTOR (512 / 8)
static int write_l1_entry(BDRVQcowState *s, int l1_index)
{
uint64_t buf[L1_ENTRIES_PER_SECTOR];
int l1_start_index;
int i;
l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) {
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
}
if (bdrv_pwrite(s->hd, s->l1_table_offset + 8 * l1_start_index,
buf, sizeof(buf)) != sizeof(buf))
{
return -1;
}
return 0;
}
/*
* l2_allocate
*
* Allocate a new l2 entry in the file. If l1_index points to an already
* used entry in the L2 table (i.e. we are doing a copy on write for the L2
* table) copy the contents of the old L2 table into the newly allocated one.
* Otherwise the new table is initialized with zeros.
*
*/
static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
{
BDRVQcowState *s = bs->opaque;
int min_index;
uint64_t old_l2_offset;
uint64_t *l2_table, l2_offset;
old_l2_offset = s->l1_table[l1_index];
/* allocate a new l2 entry */
l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
/* update the L1 entry */
s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
if (write_l1_entry(s, l1_index) < 0) {
return NULL;
}
/* allocate a new entry in the l2 cache */
min_index = l2_cache_new_entry(bs);
l2_table = s->l2_cache + (min_index << s->l2_bits);
if (old_l2_offset == 0) {
/* if there was no old l2 table, clear the new table */
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
} else {
/* if there was an old l2 table, read it from the disk */
if (bdrv_pread(s->hd, old_l2_offset,
l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return NULL;
}
/* write the l2 table to the file */
if (bdrv_pwrite(s->hd, l2_offset,
l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return NULL;
/* update the l2 cache entry */
s->l2_cache_offsets[min_index] = l2_offset;
s->l2_cache_counts[min_index] = 1;
return l2_table;
}
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
uint64_t *l2_table, uint64_t start, uint64_t mask)
{
int i;
uint64_t offset = be64_to_cpu(l2_table[0]) & ~mask;
if (!offset)
return 0;
for (i = start; i < start + nb_clusters; i++)
if (offset + i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
break;
return (i - start);
}
static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
{
int i = 0;
while(nb_clusters-- && l2_table[i] == 0)
i++;
return i;
}
/* The crypt function is compatible with the linux cryptoloop
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
supported */
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, int enc,
const AES_KEY *key)
{
union {
uint64_t ll[2];
uint8_t b[16];
} ivec;
int i;
for(i = 0; i < nb_sectors; i++) {
ivec.ll[0] = cpu_to_le64(sector_num);
ivec.ll[1] = 0;
AES_cbc_encrypt(in_buf, out_buf, 512, key,
ivec.b, enc);
sector_num++;
in_buf += 512;
out_buf += 512;
}
}
int qcow2_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
int nb_sectors)
{
BDRVQcowState *s = bs->opaque;
int ret, index_in_cluster, n, n1;
uint64_t cluster_offset;
while (nb_sectors > 0) {
n = nb_sectors;
cluster_offset = qcow2_get_cluster_offset(bs, sector_num << 9, &n);
index_in_cluster = sector_num & (s->cluster_sectors - 1);
if (!cluster_offset) {
if (bs->backing_hd) {
/* read from the base image */
n1 = qcow2_backing_read1(bs->backing_hd, sector_num, buf, n);
if (n1 > 0) {
ret = bdrv_read(bs->backing_hd, sector_num, buf, n1);
if (ret < 0)
return -1;
}
} else {
memset(buf, 0, 512 * n);
}
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
if (qcow2_decompress_cluster(s, cluster_offset) < 0)
return -1;
memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
} else {
ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
if (ret != n * 512)
return -1;
if (s->crypt_method) {
qcow2_encrypt_sectors(s, sector_num, buf, buf, n, 0,
&s->aes_decrypt_key);
}
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
uint64_t cluster_offset, int n_start, int n_end)
{
BDRVQcowState *s = bs->opaque;
int n, ret;
n = n_end - n_start;
if (n <= 0)
return 0;
ret = qcow2_read(bs, start_sect + n_start, s->cluster_data, n);
if (ret < 0)
return ret;
if (s->crypt_method) {
qcow2_encrypt_sectors(s, start_sect + n_start,
s->cluster_data,
s->cluster_data, n, 1,
&s->aes_encrypt_key);
}
ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start,
s->cluster_data, n);
if (ret < 0)
return ret;
return 0;
}
/*
* get_cluster_offset
*
* For a given offset of the disk image, return cluster offset in
* qcow2 file.
*
* on entry, *num is the number of contiguous clusters we'd like to
* access following offset.
*
* on exit, *num is the number of contiguous clusters we can read.
*
* Return 1, if the offset is found
* Return 0, otherwise.
*
*/
uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num)
{
BDRVQcowState *s = bs->opaque;
int l1_index, l2_index;
uint64_t l2_offset, *l2_table, cluster_offset;
int l1_bits, c;
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;
l1_bits = s->l2_bits + s->cluster_bits;
/* compute how many bytes there are between the offset and
* the end of the l1 entry
*/
nb_available = (1 << l1_bits) - (offset & ((1 << l1_bits) - 1));
/* compute the number of available sectors */
nb_available = (nb_available >> 9) + index_in_cluster;
if (nb_needed > nb_available) {
nb_needed = nb_available;
}
cluster_offset = 0;
/* seek the the l2 offset in the l1 table */
l1_index = offset >> l1_bits;
if (l1_index >= s->l1_size)
goto out;
l2_offset = s->l1_table[l1_index];
/* seek the l2 table of the given l2 offset */
if (!l2_offset)
goto out;
/* load the l2 table in memory */
l2_offset &= ~QCOW_OFLAG_COPIED;
l2_table = l2_load(bs, l2_offset);
if (l2_table == NULL)
return 0;
/* find the cluster offset for the given disk offset */
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
cluster_offset = be64_to_cpu(l2_table[l2_index]);
nb_clusters = size_to_clusters(s, nb_needed << 9);
if (!cluster_offset) {
/* how many empty clusters ? */
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
} else {
/* how many allocated clusters ? */
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
}
nb_available = (c * s->cluster_sectors);
out:
if (nb_available > nb_needed)
nb_available = nb_needed;
*num = nb_available - index_in_cluster;
return cluster_offset & ~QCOW_OFLAG_COPIED;
}
/*
* get_cluster_table
*
* for a given disk offset, load (and allocate if needed)
* the l2 table.
*
* the l2 table offset in the qcow2 file and the cluster index
* in the l2 table are given to the caller.
*
*/
static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
uint64_t **new_l2_table,
uint64_t *new_l2_offset,
int *new_l2_index)
{
BDRVQcowState *s = bs->opaque;
int l1_index, l2_index, ret;
uint64_t l2_offset, *l2_table;
/* seek the the l2 offset in the l1 table */
l1_index = offset >> (s->l2_bits + s->cluster_bits);
if (l1_index >= s->l1_size) {
ret = qcow2_grow_l1_table(bs, l1_index + 1);
if (ret < 0)
return 0;
}
l2_offset = s->l1_table[l1_index];
/* seek the l2 table of the given l2 offset */
if (l2_offset & QCOW_OFLAG_COPIED) {
/* load the l2 table in memory */
l2_offset &= ~QCOW_OFLAG_COPIED;
l2_table = l2_load(bs, l2_offset);
if (l2_table == NULL)
return 0;
} else {
if (l2_offset)
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
l2_table = l2_allocate(bs, l1_index);
if (l2_table == NULL)
return 0;
l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
}
/* find the cluster offset for the given disk offset */
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
*new_l2_table = l2_table;
*new_l2_offset = l2_offset;
*new_l2_index = l2_index;
return 1;
}
/*
* alloc_compressed_cluster_offset
*
* For a given offset of the disk image, return cluster offset in
* qcow2 file.
*
* If the offset is not found, allocate a new compressed cluster.
*
* Return the cluster offset if successful,
* Return 0, otherwise.
*
*/
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
uint64_t offset,
int compressed_size)
{
BDRVQcowState *s = bs->opaque;
int l2_index, ret;
uint64_t l2_offset, *l2_table, cluster_offset;
int nb_csectors;
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
if (ret == 0)
return 0;
cluster_offset = be64_to_cpu(l2_table[l2_index]);
if (cluster_offset & QCOW_OFLAG_COPIED)
return cluster_offset & ~QCOW_OFLAG_COPIED;
if (cluster_offset)
qcow2_free_any_clusters(bs, cluster_offset, 1);
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
(cluster_offset >> 9);
cluster_offset |= QCOW_OFLAG_COMPRESSED |
((uint64_t)nb_csectors << s->csize_shift);
/* update L2 table */
/* compressed clusters never have the copied flag */
l2_table[l2_index] = cpu_to_be64(cluster_offset);
if (bdrv_pwrite(s->hd,
l2_offset + l2_index * sizeof(uint64_t),
l2_table + l2_index,
sizeof(uint64_t)) != sizeof(uint64_t))
return 0;
return cluster_offset;
}
/*
* Write L2 table updates to disk, writing whole sectors to avoid a
* read-modify-write in bdrv_pwrite
*/
#define L2_ENTRIES_PER_SECTOR (512 / 8)
static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table,
uint64_t l2_offset, int l2_index, int num)
{
int l2_start_index = l2_index & ~(L1_ENTRIES_PER_SECTOR - 1);
int start_offset = (8 * l2_index) & ~511;
int end_offset = (8 * (l2_index + num) + 511) & ~511;
size_t len = end_offset - start_offset;
if (bdrv_pwrite(s->hd, l2_offset + start_offset, &l2_table[l2_start_index],
len) != len)
{
return -1;
}
return 0;
}
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
QCowL2Meta *m)
{
BDRVQcowState *s = bs->opaque;
int i, j = 0, l2_index, ret;
uint64_t *old_cluster, start_sect, l2_offset, *l2_table;
if (m->nb_clusters == 0)
return 0;
old_cluster = qemu_malloc(m->nb_clusters * sizeof(uint64_t));
/* copy content of unmodified sectors */
start_sect = (m->offset & ~(s->cluster_size - 1)) >> 9;
if (m->n_start) {
ret = copy_sectors(bs, start_sect, cluster_offset, 0, m->n_start);
if (ret < 0)
goto err;
}
if (m->nb_available & (s->cluster_sectors - 1)) {
uint64_t end = m->nb_available & ~(uint64_t)(s->cluster_sectors - 1);
ret = copy_sectors(bs, start_sect + end, cluster_offset + (end << 9),
m->nb_available - end, s->cluster_sectors);
if (ret < 0)
goto err;
}
ret = -EIO;
/* update L2 table */
if (!get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index))
goto err;
for (i = 0; i < m->nb_clusters; i++) {
/* if two concurrent writes happen to the same unallocated cluster
* each write allocates separate cluster and writes data concurrently.
* The first one to complete updates l2 table with pointer to its
* cluster the second one has to do RMW (which is done above by
* copy_sectors()), update l2 table with its cluster pointer and free
* old cluster. This is what this loop does */
if(l2_table[l2_index + i] != 0)
old_cluster[j++] = l2_table[l2_index + i];
l2_table[l2_index + i] = cpu_to_be64((cluster_offset +
(i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
}
if (write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters) < 0) {
ret = -1;
goto err;
}
for (i = 0; i < j; i++)
qcow2_free_any_clusters(bs,
be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1);
ret = 0;
err:
qemu_free(old_cluster);
return ret;
}
/*
* alloc_cluster_offset
*
* For a given offset of the disk image, return cluster offset in
* qcow2 file.
*
* If the offset is not found, allocate a new cluster.
*
* Return the cluster offset if successful,
* Return 0, otherwise.
*
*/
uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
uint64_t offset,
int n_start, int n_end,
int *num, QCowL2Meta *m)
{
BDRVQcowState *s = bs->opaque;
int l2_index, ret;
uint64_t l2_offset, *l2_table, cluster_offset;
int nb_clusters, i = 0;
QCowL2Meta *old_alloc;
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
if (ret == 0)
return 0;
nb_clusters = size_to_clusters(s, n_end << 9);
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
cluster_offset = be64_to_cpu(l2_table[l2_index]);
/* We keep all QCOW_OFLAG_COPIED clusters */
if (cluster_offset & QCOW_OFLAG_COPIED) {
nb_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0, 0);
cluster_offset &= ~QCOW_OFLAG_COPIED;
m->nb_clusters = 0;
goto out;
}
/* for the moment, multiple compressed clusters are not managed */
if (cluster_offset & QCOW_OFLAG_COMPRESSED)
nb_clusters = 1;
/* how many available clusters ? */
while (i < nb_clusters) {
i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
&l2_table[l2_index], i, 0);
if(be64_to_cpu(l2_table[l2_index + i]))
break;
i += count_contiguous_free_clusters(nb_clusters - i,
&l2_table[l2_index + i]);
cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
if ((cluster_offset & QCOW_OFLAG_COPIED) ||
(cluster_offset & QCOW_OFLAG_COMPRESSED))
break;
}
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.
*/
LIST_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();
}
LIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight);
/* allocate a new cluster */
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
/* save info needed for meta data update */
m->offset = offset;
m->n_start = n_start;
m->nb_clusters = nb_clusters;
out:
m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
*num = m->nb_available - n_start;
return cluster_offset;
}
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
const uint8_t *buf, int buf_size)
{
z_stream strm1, *strm = &strm1;
int ret, out_len;
memset(strm, 0, sizeof(*strm));
strm->next_in = (uint8_t *)buf;
strm->avail_in = buf_size;
strm->next_out = out_buf;
strm->avail_out = out_buf_size;
ret = inflateInit2(strm, -12);
if (ret != Z_OK)
return -1;
ret = inflate(strm, Z_FINISH);
out_len = strm->next_out - out_buf;
if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
out_len != out_buf_size) {
inflateEnd(strm);
return -1;
}
inflateEnd(strm);
return 0;
}
int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
{
int ret, csize, nb_csectors, sector_offset;
uint64_t coffset;
coffset = cluster_offset & s->cluster_offset_mask;
if (s->cluster_cache_offset != coffset) {
nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
sector_offset = coffset & 511;
csize = nb_csectors * 512 - sector_offset;
ret = bdrv_read(s->hd, coffset >> 9, s->cluster_data, nb_csectors);
if (ret < 0) {
return -1;
}
if (decompress_buffer(s->cluster_cache, s->cluster_size,
s->cluster_data + sector_offset, csize) < 0) {
return -1;
}
s->cluster_cache_offset = coffset;
}
return 0;
}

View File

@@ -1,894 +0,0 @@
/*
* Block driver for the QCOW version 2 format
*
* Copyright (c) 2004-2006 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 "block_int.h"
#include "block/qcow2.h"
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
static int update_refcount(BlockDriverState *bs,
int64_t offset, int64_t length,
int addend);
static int cache_refcount_updates = 0;
static int write_refcount_block(BDRVQcowState *s)
{
size_t size = s->cluster_size;
if (s->refcount_block_cache_offset == 0) {
return 0;
}
if (bdrv_pwrite(s->hd, s->refcount_block_cache_offset,
s->refcount_block_cache, size) != size)
{
return -EIO;
}
return 0;
}
/*********************************************************/
/* refcount handling */
int qcow2_refcount_init(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
int ret, refcount_table_size2, i;
s->refcount_block_cache = qemu_malloc(s->cluster_size);
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
s->refcount_table = qemu_malloc(refcount_table_size2);
if (s->refcount_table_size > 0) {
ret = bdrv_pread(s->hd, s->refcount_table_offset,
s->refcount_table, refcount_table_size2);
if (ret != refcount_table_size2)
goto fail;
for(i = 0; i < s->refcount_table_size; i++)
be64_to_cpus(&s->refcount_table[i]);
}
return 0;
fail:
return -ENOMEM;
}
void qcow2_refcount_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
qemu_free(s->refcount_block_cache);
qemu_free(s->refcount_table);
}
static int load_refcount_block(BlockDriverState *bs,
int64_t refcount_block_offset)
{
BDRVQcowState *s = bs->opaque;
int ret;
if (cache_refcount_updates) {
write_refcount_block(s);
}
ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache,
s->cluster_size);
if (ret != s->cluster_size)
return -EIO;
s->refcount_block_cache_offset = refcount_block_offset;
return 0;
}
static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
{
BDRVQcowState *s = bs->opaque;
int refcount_table_index, block_index;
int64_t refcount_block_offset;
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
if (refcount_table_index >= s->refcount_table_size)
return 0;
refcount_block_offset = s->refcount_table[refcount_table_index];
if (!refcount_block_offset)
return 0;
if (refcount_block_offset != s->refcount_block_cache_offset) {
/* better than nothing: return allocated if read error */
if (load_refcount_block(bs, refcount_block_offset) < 0)
return 1;
}
block_index = cluster_index &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
return be16_to_cpu(s->refcount_block_cache[block_index]);
}
static int grow_refcount_table(BlockDriverState *bs, int min_size)
{
BDRVQcowState *s = bs->opaque;
int new_table_size, new_table_size2, refcount_table_clusters, i, ret;
uint64_t *new_table;
int64_t table_offset;
uint8_t data[12];
int old_table_size;
int64_t old_table_offset;
if (min_size <= s->refcount_table_size)
return 0;
/* compute new table size */
refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
for(;;) {
if (refcount_table_clusters == 0) {
refcount_table_clusters = 1;
} else {
refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
}
new_table_size = refcount_table_clusters << (s->cluster_bits - 3);
if (min_size <= new_table_size)
break;
}
#ifdef DEBUG_ALLOC2
printf("grow_refcount_table from %d to %d\n",
s->refcount_table_size,
new_table_size);
#endif
new_table_size2 = new_table_size * sizeof(uint64_t);
new_table = qemu_mallocz(new_table_size2);
memcpy(new_table, s->refcount_table,
s->refcount_table_size * sizeof(uint64_t));
for(i = 0; i < s->refcount_table_size; i++)
cpu_to_be64s(&new_table[i]);
/* Note: we cannot update the refcount now to avoid recursion */
table_offset = alloc_clusters_noref(bs, new_table_size2);
ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2);
if (ret != new_table_size2)
goto fail;
for(i = 0; i < s->refcount_table_size; i++)
be64_to_cpus(&new_table[i]);
cpu_to_be64w((uint64_t*)data, table_offset);
cpu_to_be32w((uint32_t*)(data + 8), refcount_table_clusters);
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
data, sizeof(data)) != sizeof(data))
goto fail;
qemu_free(s->refcount_table);
old_table_offset = s->refcount_table_offset;
old_table_size = s->refcount_table_size;
s->refcount_table = new_table;
s->refcount_table_size = new_table_size;
s->refcount_table_offset = table_offset;
update_refcount(bs, table_offset, new_table_size2, 1);
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;
}
static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
{
BDRVQcowState *s = bs->opaque;
int64_t offset, refcount_block_offset;
int ret, refcount_table_index;
uint64_t data64;
int cache = cache_refcount_updates;
/* Find L1 index and grow refcount table if needed */
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
if (refcount_table_index >= s->refcount_table_size) {
ret = grow_refcount_table(bs, refcount_table_index + 1);
if (ret < 0)
return ret;
}
/* Load or allocate the refcount block */
refcount_block_offset = s->refcount_table[refcount_table_index];
if (!refcount_block_offset) {
if (cache_refcount_updates) {
write_refcount_block(s);
cache_refcount_updates = 0;
}
/* create a new refcount block */
/* Note: we cannot update the refcount now to avoid recursion */
offset = alloc_clusters_noref(bs, s->cluster_size);
memset(s->refcount_block_cache, 0, s->cluster_size);
ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size);
if (ret != s->cluster_size)
return -EINVAL;
s->refcount_table[refcount_table_index] = offset;
data64 = cpu_to_be64(offset);
ret = bdrv_pwrite(s->hd, s->refcount_table_offset +
refcount_table_index * sizeof(uint64_t),
&data64, sizeof(data64));
if (ret != sizeof(data64))
return -EINVAL;
refcount_block_offset = offset;
s->refcount_block_cache_offset = offset;
update_refcount(bs, offset, s->cluster_size, 1);
cache_refcount_updates = cache;
} else {
if (refcount_block_offset != s->refcount_block_cache_offset) {
if (load_refcount_block(bs, refcount_block_offset) < 0)
return -EIO;
}
}
return refcount_block_offset;
}
#define REFCOUNTS_PER_SECTOR (512 >> REFCOUNT_SHIFT)
static int write_refcount_block_entries(BDRVQcowState *s,
int64_t refcount_block_offset, int first_index, int last_index)
{
size_t size;
if (cache_refcount_updates) {
return 0;
}
first_index &= ~(REFCOUNTS_PER_SECTOR - 1);
last_index = (last_index + REFCOUNTS_PER_SECTOR)
& ~(REFCOUNTS_PER_SECTOR - 1);
size = (last_index - first_index) << REFCOUNT_SHIFT;
if (bdrv_pwrite(s->hd,
refcount_block_offset + (first_index << REFCOUNT_SHIFT),
&s->refcount_block_cache[first_index], size) != size)
{
return -EIO;
}
return 0;
}
/* XXX: cache several refcount block clusters ? */
static int update_refcount(BlockDriverState *bs,
int64_t offset, int64_t length,
int addend)
{
BDRVQcowState *s = bs->opaque;
int64_t start, last, cluster_offset;
int64_t refcount_block_offset = 0;
int64_t table_index = -1, old_table_index;
int first_index = -1, last_index = -1;
#ifdef DEBUG_ALLOC2
printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",
offset, length, addend);
#endif
if (length <= 0)
return -EINVAL;
start = offset & ~(s->cluster_size - 1);
last = (offset + length - 1) & ~(s->cluster_size - 1);
for(cluster_offset = start; cluster_offset <= last;
cluster_offset += s->cluster_size)
{
int block_index, refcount;
int64_t cluster_index = cluster_offset >> s->cluster_bits;
/* Only write refcount block to disk when we are done with it */
old_table_index = table_index;
table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
if ((old_table_index >= 0) && (table_index != old_table_index)) {
if (write_refcount_block_entries(s, refcount_block_offset,
first_index, last_index) < 0)
{
return -EIO;
}
first_index = -1;
last_index = -1;
}
/* Load the refcount block and allocate it if needed */
refcount_block_offset = alloc_refcount_block(bs, cluster_index);
if (refcount_block_offset < 0) {
return refcount_block_offset;
}
/* we can update the count and save it */
block_index = cluster_index &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
if (first_index == -1 || block_index < first_index) {
first_index = block_index;
}
if (block_index > last_index) {
last_index = block_index;
}
refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
refcount += addend;
if (refcount < 0 || refcount > 0xffff)
return -EINVAL;
if (refcount == 0 && cluster_index < s->free_cluster_index) {
s->free_cluster_index = cluster_index;
}
s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
}
/* Write last changed block to disk */
if (refcount_block_offset != 0) {
if (write_refcount_block_entries(s, refcount_block_offset,
first_index, last_index) < 0)
{
return -EIO;
}
}
return 0;
}
/* addend must be 1 or -1 */
static int update_cluster_refcount(BlockDriverState *bs,
int64_t cluster_index,
int addend)
{
BDRVQcowState *s = bs->opaque;
int ret;
ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend);
if (ret < 0) {
return ret;
}
return get_refcount(bs, cluster_index);
}
/*********************************************************/
/* cluster allocation functions */
/* return < 0 if error */
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
{
BDRVQcowState *s = bs->opaque;
int i, nb_clusters;
nb_clusters = size_to_clusters(s, size);
retry:
for(i = 0; i < nb_clusters; i++) {
int64_t i = s->free_cluster_index++;
if (get_refcount(bs, i) != 0)
goto retry;
}
#ifdef DEBUG_ALLOC2
printf("alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
size,
(s->free_cluster_index - nb_clusters) << s->cluster_bits);
#endif
return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
}
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
{
int64_t offset;
offset = alloc_clusters_noref(bs, size);
update_refcount(bs, offset, size, 1);
return offset;
}
/* only used to allocate compressed sectors. We try to allocate
contiguous sectors. size must be <= cluster_size */
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
{
BDRVQcowState *s = bs->opaque;
int64_t offset, cluster_offset;
int free_in_cluster;
assert(size > 0 && size <= s->cluster_size);
if (s->free_byte_offset == 0) {
s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size);
}
redo:
free_in_cluster = s->cluster_size -
(s->free_byte_offset & (s->cluster_size - 1));
if (size <= free_in_cluster) {
/* enough space in current cluster */
offset = s->free_byte_offset;
s->free_byte_offset += size;
free_in_cluster -= size;
if (free_in_cluster == 0)
s->free_byte_offset = 0;
if ((offset & (s->cluster_size - 1)) != 0)
update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
} else {
offset = qcow2_alloc_clusters(bs, s->cluster_size);
cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
if ((cluster_offset + s->cluster_size) == offset) {
/* we are lucky: contiguous data */
offset = s->free_byte_offset;
update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
s->free_byte_offset += size;
} else {
s->free_byte_offset = offset;
goto redo;
}
}
return offset;
}
void qcow2_free_clusters(BlockDriverState *bs,
int64_t offset, int64_t size)
{
update_refcount(bs, offset, size, -1);
}
/*
* free_any_clusters
*
* free clusters according to its type: compressed or not
*
*/
void qcow2_free_any_clusters(BlockDriverState *bs,
uint64_t cluster_offset, int nb_clusters)
{
BDRVQcowState *s = bs->opaque;
/* free the cluster */
if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
int nb_csectors;
nb_csectors = ((cluster_offset >> s->csize_shift) &
s->csize_mask) + 1;
qcow2_free_clusters(bs,
(cluster_offset & s->cluster_offset_mask) & ~511,
nb_csectors * 512);
return;
}
qcow2_free_clusters(bs, cluster_offset, nb_clusters << s->cluster_bits);
return;
}
/*********************************************************/
/* snapshots and image creation */
void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset,
int64_t size)
{
int refcount;
int64_t start, last, cluster_offset;
uint16_t *p;
start = offset & ~(s->cluster_size - 1);
last = (offset + size - 1) & ~(s->cluster_size - 1);
for(cluster_offset = start; cluster_offset <= last;
cluster_offset += s->cluster_size) {
p = &s->refcount_block[cluster_offset >> s->cluster_bits];
refcount = be16_to_cpu(*p);
refcount++;
*p = cpu_to_be16(refcount);
}
}
/* update the refcounts of snapshots and the copied flag */
int qcow2_update_snapshot_refcount(BlockDriverState *bs,
int64_t l1_table_offset, int l1_size, int addend)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
int64_t old_offset, old_l2_offset;
int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount;
qcow2_l2_cache_reset(bs);
cache_refcount_updates = 1;
l2_table = NULL;
l1_table = NULL;
l1_size2 = l1_size * sizeof(uint64_t);
l1_allocated = 0;
if (l1_table_offset != s->l1_table_offset) {
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)
goto fail;
for(i = 0;i < l1_size; i++)
be64_to_cpus(&l1_table[i]);
} else {
assert(l1_size == s->l1_size);
l1_table = s->l1_table;
l1_allocated = 0;
}
l2_size = s->l2_size * sizeof(uint64_t);
l2_table = qemu_malloc(l2_size);
l1_modified = 0;
for(i = 0; i < l1_size; i++) {
l2_offset = l1_table[i];
if (l2_offset) {
old_l2_offset = l2_offset;
l2_offset &= ~QCOW_OFLAG_COPIED;
l2_modified = 0;
if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
goto fail;
for(j = 0; j < s->l2_size; j++) {
offset = be64_to_cpu(l2_table[j]);
if (offset != 0) {
old_offset = offset;
offset &= ~QCOW_OFLAG_COPIED;
if (offset & QCOW_OFLAG_COMPRESSED) {
nb_csectors = ((offset >> s->csize_shift) &
s->csize_mask) + 1;
if (addend != 0)
update_refcount(bs, (offset & s->cluster_offset_mask) & ~511,
nb_csectors * 512, addend);
/* compressed clusters are never modified */
refcount = 2;
} else {
if (addend != 0) {
refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend);
} else {
refcount = get_refcount(bs, offset >> s->cluster_bits);
}
}
if (refcount == 1) {
offset |= QCOW_OFLAG_COPIED;
}
if (offset != old_offset) {
l2_table[j] = cpu_to_be64(offset);
l2_modified = 1;
}
}
}
if (l2_modified) {
if (bdrv_pwrite(s->hd,
l2_offset, l2_table, l2_size) != l2_size)
goto fail;
}
if (addend != 0) {
refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend);
} else {
refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
}
if (refcount == 1) {
l2_offset |= QCOW_OFLAG_COPIED;
}
if (l2_offset != old_l2_offset) {
l1_table[i] = l2_offset;
l1_modified = 1;
}
}
}
if (l1_modified) {
for(i = 0; i < l1_size; i++)
cpu_to_be64s(&l1_table[i]);
if (bdrv_pwrite(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]);
}
if (l1_allocated)
qemu_free(l1_table);
qemu_free(l2_table);
cache_refcount_updates = 0;
write_refcount_block(s);
return 0;
fail:
if (l1_allocated)
qemu_free(l1_table);
qemu_free(l2_table);
cache_refcount_updates = 0;
write_refcount_block(s);
return -EIO;
}
/*********************************************************/
/* refcount checking functions */
/*
* Increases the refcount for a range of clusters in a given refcount table.
* This is used to construct a temporary refcount table out of L1 and L2 tables
* which can be compared the the refcount table saved in the image.
*
* Returns the number of errors in the image that were found
*/
static int inc_refcounts(BlockDriverState *bs,
uint16_t *refcount_table,
int refcount_table_size,
int64_t offset, int64_t size)
{
BDRVQcowState *s = bs->opaque;
int64_t start, last, cluster_offset;
int k;
int errors = 0;
if (size <= 0)
return 0;
start = offset & ~(s->cluster_size - 1);
last = (offset + size - 1) & ~(s->cluster_size - 1);
for(cluster_offset = start; cluster_offset <= last;
cluster_offset += s->cluster_size) {
k = cluster_offset >> s->cluster_bits;
if (k < 0 || k >= refcount_table_size) {
fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
cluster_offset);
errors++;
} else {
if (++refcount_table[k] == 0) {
fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64
"\n", cluster_offset);
errors++;
}
}
}
return errors;
}
/*
* Increases the refcount in the given refcount table for the all clusters
* referenced in the L2 table. While doing so, performs some checks on L2
* entries.
*
* Returns the number of errors found by the checks or -errno if an internal
* error occurred.
*/
static int check_refcounts_l2(BlockDriverState *bs,
uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset,
int check_copied)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l2_table, offset;
int i, l2_size, nb_csectors, refcount;
int errors = 0;
/* Read L2 table from disk */
l2_size = s->l2_size * sizeof(uint64_t);
l2_table = qemu_malloc(l2_size);
if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
goto fail;
/* Do the actual checks */
for(i = 0; i < s->l2_size; i++) {
offset = be64_to_cpu(l2_table[i]);
if (offset != 0) {
if (offset & QCOW_OFLAG_COMPRESSED) {
/* Compressed clusters don't have QCOW_OFLAG_COPIED */
if (offset & QCOW_OFLAG_COPIED) {
fprintf(stderr, "ERROR: cluster %" PRId64 ": "
"copied flag must never be set for compressed "
"clusters\n", offset >> s->cluster_bits);
offset &= ~QCOW_OFLAG_COPIED;
errors++;
}
/* Mark cluster as used */
nb_csectors = ((offset >> s->csize_shift) &
s->csize_mask) + 1;
offset &= s->cluster_offset_mask;
errors += inc_refcounts(bs, refcount_table,
refcount_table_size,
offset & ~511, nb_csectors * 512);
} else {
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
if (check_copied) {
uint64_t entry = offset;
offset &= ~QCOW_OFLAG_COPIED;
refcount = get_refcount(bs, offset >> s->cluster_bits);
if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) {
fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
PRIx64 " refcount=%d\n", entry, refcount);
errors++;
}
}
/* Mark cluster as used */
offset &= ~QCOW_OFLAG_COPIED;
errors += inc_refcounts(bs, refcount_table,
refcount_table_size,
offset, s->cluster_size);
/* Correct offsets are cluster aligned */
if (offset & (s->cluster_size - 1)) {
fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
"properly aligned; L2 entry corrupted.\n", offset);
errors++;
}
}
}
}
qemu_free(l2_table);
return errors;
fail:
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
qemu_free(l2_table);
return -EIO;
}
/*
* Increases the refcount for the L1 table, its L2 tables and all referenced
* clusters in the given refcount table. While doing so, performs some checks
* on L1 and L2 entries.
*
* Returns the number of errors found by the checks or -errno if an internal
* error occurred.
*/
static int check_refcounts_l1(BlockDriverState *bs,
uint16_t *refcount_table,
int refcount_table_size,
int64_t l1_table_offset, int l1_size,
int check_copied)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l1_table, l2_offset, l1_size2;
int i, refcount, ret;
int errors = 0;
l1_size2 = l1_size * sizeof(uint64_t);
/* Mark L1 table as used */
errors += inc_refcounts(bs, refcount_table, refcount_table_size,
l1_table_offset, l1_size2);
/* Read L1 table entries from disk */
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++) {
l2_offset = l1_table[i];
if (l2_offset) {
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
if (check_copied) {
refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED)
>> s->cluster_bits);
if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64
" refcount=%d\n", l2_offset, refcount);
errors++;
}
}
/* Mark L2 table as used */
l2_offset &= ~QCOW_OFLAG_COPIED;
errors += inc_refcounts(bs, refcount_table,
refcount_table_size,
l2_offset,
s->cluster_size);
/* L2 tables are cluster aligned */
if (l2_offset & (s->cluster_size - 1)) {
fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
"cluster aligned; L1 entry corrupted\n", l2_offset);
errors++;
}
/* Process and check L2 entries */
ret = check_refcounts_l2(bs, refcount_table, refcount_table_size,
l2_offset, check_copied);
if (ret < 0) {
goto fail;
}
errors += ret;
}
}
qemu_free(l1_table);
return errors;
fail:
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
qemu_free(l1_table);
return -EIO;
}
/*
* Checks an image for refcount consistency.
*
* Returns 0 if no errors are found, the number of errors in case the image is
* detected as corrupted, and -errno when an internal error occured.
*/
int qcow2_check_refcounts(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
int64_t size;
int nb_clusters, refcount1, refcount2, i;
QCowSnapshot *sn;
uint16_t *refcount_table;
int ret, errors = 0;
size = bdrv_getlength(s->hd);
nb_clusters = size_to_clusters(s, size);
refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
/* header */
errors += inc_refcounts(bs, refcount_table, nb_clusters,
0, s->cluster_size);
/* current L1 table */
ret = check_refcounts_l1(bs, refcount_table, nb_clusters,
s->l1_table_offset, s->l1_size, 1);
if (ret < 0) {
return ret;
}
errors += ret;
/* snapshots */
for(i = 0; i < s->nb_snapshots; i++) {
sn = s->snapshots + i;
check_refcounts_l1(bs, refcount_table, nb_clusters,
sn->l1_table_offset, sn->l1_size, 0);
}
errors += inc_refcounts(bs, refcount_table, nb_clusters,
s->snapshots_offset, s->snapshots_size);
/* refcount data */
errors += inc_refcounts(bs, refcount_table, nb_clusters,
s->refcount_table_offset,
s->refcount_table_size * sizeof(uint64_t));
for(i = 0; i < s->refcount_table_size; i++) {
int64_t offset;
offset = s->refcount_table[i];
if (offset != 0) {
errors += inc_refcounts(bs, refcount_table, nb_clusters,
offset, s->cluster_size);
}
}
/* compare ref counts */
for(i = 0; i < nb_clusters; i++) {
refcount1 = get_refcount(bs, i);
refcount2 = refcount_table[i];
if (refcount1 != refcount2) {
fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n",
i, refcount1, refcount2);
errors++;
}
}
qemu_free(refcount_table);
return errors;
}

View File

@@ -1,405 +0,0 @@
/*
* Block driver for the QCOW version 2 format
*
* Copyright (c) 2004-2006 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 "block_int.h"
#include "block/qcow2.h"
typedef struct __attribute__((packed)) QCowSnapshotHeader {
/* header is 8 byte aligned */
uint64_t l1_table_offset;
uint32_t l1_size;
uint16_t id_str_size;
uint16_t name_size;
uint32_t date_sec;
uint32_t date_nsec;
uint64_t vm_clock_nsec;
uint32_t vm_state_size;
uint32_t extra_data_size; /* for extension */
/* extra data follows */
/* id_str follows */
/* name follows */
} QCowSnapshotHeader;
void qcow2_free_snapshots(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
int i;
for(i = 0; i < s->nb_snapshots; i++) {
qemu_free(s->snapshots[i].name);
qemu_free(s->snapshots[i].id_str);
}
qemu_free(s->snapshots);
s->snapshots = NULL;
s->nb_snapshots = 0;
}
int qcow2_read_snapshots(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
QCowSnapshotHeader h;
QCowSnapshot *sn;
int i, id_str_size, name_size;
int64_t offset;
uint32_t extra_data_size;
if (!s->nb_snapshots) {
s->snapshots = NULL;
s->snapshots_size = 0;
return 0;
}
offset = s->snapshots_offset;
s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
for(i = 0; i < s->nb_snapshots; i++) {
offset = align_offset(offset, 8);
if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
goto fail;
offset += sizeof(h);
sn = s->snapshots + i;
sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
sn->l1_size = be32_to_cpu(h.l1_size);
sn->vm_state_size = be32_to_cpu(h.vm_state_size);
sn->date_sec = be32_to_cpu(h.date_sec);
sn->date_nsec = be32_to_cpu(h.date_nsec);
sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
extra_data_size = be32_to_cpu(h.extra_data_size);
id_str_size = be16_to_cpu(h.id_str_size);
name_size = be16_to_cpu(h.name_size);
offset += extra_data_size;
sn->id_str = qemu_malloc(id_str_size + 1);
if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
goto fail;
offset += id_str_size;
sn->id_str[id_str_size] = '\0';
sn->name = qemu_malloc(name_size + 1);
if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
goto fail;
offset += name_size;
sn->name[name_size] = '\0';
}
s->snapshots_size = offset - s->snapshots_offset;
return 0;
fail:
qcow2_free_snapshots(bs);
return -1;
}
/* add at the end of the file a new list of snapshots */
static int qcow_write_snapshots(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
QCowSnapshot *sn;
QCowSnapshotHeader h;
int i, name_size, id_str_size, snapshots_size;
uint64_t data64;
uint32_t data32;
int64_t offset, snapshots_offset;
/* compute the size of the snapshots */
offset = 0;
for(i = 0; i < s->nb_snapshots; i++) {
sn = s->snapshots + i;
offset = align_offset(offset, 8);
offset += sizeof(h);
offset += strlen(sn->id_str);
offset += strlen(sn->name);
}
snapshots_size = offset;
snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
offset = snapshots_offset;
for(i = 0; i < s->nb_snapshots; i++) {
sn = s->snapshots + i;
memset(&h, 0, sizeof(h));
h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
h.l1_size = cpu_to_be32(sn->l1_size);
h.vm_state_size = cpu_to_be32(sn->vm_state_size);
h.date_sec = cpu_to_be32(sn->date_sec);
h.date_nsec = cpu_to_be32(sn->date_nsec);
h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
id_str_size = strlen(sn->id_str);
name_size = strlen(sn->name);
h.id_str_size = cpu_to_be16(id_str_size);
h.name_size = cpu_to_be16(name_size);
offset = align_offset(offset, 8);
if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
goto fail;
offset += sizeof(h);
if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
goto fail;
offset += id_str_size;
if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
goto fail;
offset += name_size;
}
/* update the various header fields */
data64 = cpu_to_be64(snapshots_offset);
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
&data64, sizeof(data64)) != sizeof(data64))
goto fail;
data32 = cpu_to_be32(s->nb_snapshots);
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
&data32, sizeof(data32)) != sizeof(data32))
goto fail;
/* free the old snapshot table */
qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
s->snapshots_offset = snapshots_offset;
s->snapshots_size = snapshots_size;
return 0;
fail:
return -1;
}
static void find_new_snapshot_id(BlockDriverState *bs,
char *id_str, int id_str_size)
{
BDRVQcowState *s = bs->opaque;
QCowSnapshot *sn;
int i, id, id_max = 0;
for(i = 0; i < s->nb_snapshots; i++) {
sn = s->snapshots + i;
id = strtoul(sn->id_str, NULL, 10);
if (id > id_max)
id_max = id;
}
snprintf(id_str, id_str_size, "%d", id_max + 1);
}
static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
{
BDRVQcowState *s = bs->opaque;
int i;
for(i = 0; i < s->nb_snapshots; i++) {
if (!strcmp(s->snapshots[i].id_str, id_str))
return i;
}
return -1;
}
static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
{
BDRVQcowState *s = bs->opaque;
int i, ret;
ret = find_snapshot_by_id(bs, name);
if (ret >= 0)
return ret;
for(i = 0; i < s->nb_snapshots; i++) {
if (!strcmp(s->snapshots[i].name, name))
return i;
}
return -1;
}
/* if no id is provided, a new one is constructed */
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
{
BDRVQcowState *s = bs->opaque;
QCowSnapshot *snapshots1, sn1, *sn = &sn1;
int i, ret;
uint64_t *l1_table = NULL;
memset(sn, 0, sizeof(*sn));
if (sn_info->id_str[0] == '\0') {
/* compute a new id */
find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
}
/* check that the ID is unique */
if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
return -ENOENT;
sn->id_str = qemu_strdup(sn_info->id_str);
if (!sn->id_str)
goto fail;
sn->name = qemu_strdup(sn_info->name);
if (!sn->name)
goto fail;
sn->vm_state_size = sn_info->vm_state_size;
sn->date_sec = sn_info->date_sec;
sn->date_nsec = sn_info->date_nsec;
sn->vm_clock_nsec = sn_info->vm_clock_nsec;
ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
if (ret < 0)
goto fail;
/* create the L1 table of the snapshot */
sn->l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
sn->l1_size = s->l1_size;
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]);
}
if (bdrv_pwrite(s->hd, sn->l1_table_offset,
l1_table, s->l1_size * sizeof(uint64_t)) !=
(s->l1_size * sizeof(uint64_t)))
goto fail;
qemu_free(l1_table);
l1_table = NULL;
snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
if (s->snapshots) {
memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
qemu_free(s->snapshots);
}
s->snapshots = snapshots1;
s->snapshots[s->nb_snapshots++] = *sn;
if (qcow_write_snapshots(bs) < 0)
goto fail;
#ifdef DEBUG_ALLOC
qcow2_check_refcounts(bs);
#endif
return 0;
fail:
qemu_free(sn->name);
qemu_free(l1_table);
return -1;
}
/* copy the snapshot 'snapshot_name' into the current disk image */
int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
{
BDRVQcowState *s = bs->opaque;
QCowSnapshot *sn;
int i, snapshot_index, l1_size2;
snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
if (snapshot_index < 0)
return -ENOENT;
sn = &s->snapshots[snapshot_index];
if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
goto fail;
if (qcow2_grow_l1_table(bs, sn->l1_size) < 0)
goto fail;
s->l1_size = sn->l1_size;
l1_size2 = s->l1_size * sizeof(uint64_t);
/* copy the snapshot l1 table to the current l1 table */
if (bdrv_pread(s->hd, sn->l1_table_offset,
s->l1_table, l1_size2) != l1_size2)
goto fail;
if (bdrv_pwrite(s->hd, s->l1_table_offset,
s->l1_table, l1_size2) != l1_size2)
goto fail;
for(i = 0;i < s->l1_size; i++) {
be64_to_cpus(&s->l1_table[i]);
}
if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
goto fail;
#ifdef DEBUG_ALLOC
qcow2_check_refcounts(bs);
#endif
return 0;
fail:
return -EIO;
}
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
{
BDRVQcowState *s = bs->opaque;
QCowSnapshot *sn;
int snapshot_index, ret;
snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
if (snapshot_index < 0)
return -ENOENT;
sn = &s->snapshots[snapshot_index];
ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
if (ret < 0)
return ret;
/* must update the copied flag on the current cluster offsets */
ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
if (ret < 0)
return ret;
qcow2_free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
qemu_free(sn->id_str);
qemu_free(sn->name);
memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
s->nb_snapshots--;
ret = qcow_write_snapshots(bs);
if (ret < 0) {
/* XXX: restore snapshot if error ? */
return ret;
}
#ifdef DEBUG_ALLOC
qcow2_check_refcounts(bs);
#endif
return 0;
}
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
{
BDRVQcowState *s = bs->opaque;
QEMUSnapshotInfo *sn_tab, *sn_info;
QCowSnapshot *sn;
int i;
if (!s->nb_snapshots) {
*psn_tab = NULL;
return s->nb_snapshots;
}
sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
for(i = 0; i < s->nb_snapshots; i++) {
sn_info = sn_tab + i;
sn = s->snapshots + i;
pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
sn->id_str);
pstrcpy(sn_info->name, sizeof(sn_info->name),
sn->name);
sn_info->vm_state_size = sn->vm_state_size;
sn_info->date_sec = sn->date_sec;
sn_info->date_nsec = sn->date_nsec;
sn_info->vm_clock_nsec = sn->vm_clock_nsec;
}
*psn_tab = sn_tab;
return s->nb_snapshots;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,217 +0,0 @@
/*
* Block driver for the QCOW version 2 format
*
* Copyright (c) 2004-2006 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_QCOW2_H
#define BLOCK_QCOW2_H
#include "aes.h"
//#define DEBUG_ALLOC
//#define DEBUG_ALLOC2
//#define DEBUG_EXT
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
#define QCOW_VERSION 2
#define QCOW_CRYPT_NONE 0
#define QCOW_CRYPT_AES 1
#define QCOW_MAX_CRYPT_CLUSTERS 32
/* indicate that the refcount of the referenced cluster is exactly one. */
#define QCOW_OFLAG_COPIED (1LL << 63)
/* indicate that the cluster is compressed (they never have the copied flag) */
#define QCOW_OFLAG_COMPRESSED (1LL << 62)
#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
#define MIN_CLUSTER_BITS 9
#define MAX_CLUSTER_BITS 16
#define L2_CACHE_SIZE 16
typedef struct QCowHeader {
uint32_t magic;
uint32_t version;
uint64_t backing_file_offset;
uint32_t backing_file_size;
uint32_t cluster_bits;
uint64_t size; /* in bytes */
uint32_t crypt_method;
uint32_t l1_size; /* XXX: save number of clusters instead ? */
uint64_t l1_table_offset;
uint64_t refcount_table_offset;
uint32_t refcount_table_clusters;
uint32_t nb_snapshots;
uint64_t snapshots_offset;
} QCowHeader;
typedef struct QCowSnapshot {
uint64_t l1_table_offset;
uint32_t l1_size;
char *id_str;
char *name;
uint32_t vm_state_size;
uint32_t date_sec;
uint32_t date_nsec;
uint64_t vm_clock_nsec;
} QCowSnapshot;
typedef struct BDRVQcowState {
BlockDriverState *hd;
int cluster_bits;
int cluster_size;
int cluster_sectors;
int l2_bits;
int l2_size;
int l1_size;
int l1_vm_state_index;
int csize_shift;
int csize_mask;
uint64_t cluster_offset_mask;
uint64_t l1_table_offset;
uint64_t *l1_table;
uint64_t *l2_cache;
uint64_t l2_cache_offsets[L2_CACHE_SIZE];
uint32_t l2_cache_counts[L2_CACHE_SIZE];
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset;
LIST_HEAD(QCowClusterAlloc, QCowL2Meta) cluster_allocs;
uint64_t *refcount_table;
uint64_t refcount_table_offset;
uint32_t refcount_table_size;
uint64_t refcount_block_cache_offset;
uint16_t *refcount_block_cache;
int64_t free_cluster_index;
int64_t free_byte_offset;
uint32_t crypt_method; /* current crypt method, 0 if no key yet */
uint32_t crypt_method_header;
AES_KEY aes_encrypt_key;
AES_KEY aes_decrypt_key;
uint64_t snapshots_offset;
int snapshots_size;
int nb_snapshots;
QCowSnapshot *snapshots;
} BDRVQcowState;
/* XXX: use std qcow open function ? */
typedef struct QCowCreateState {
int cluster_size;
int cluster_bits;
uint16_t *refcount_block;
uint64_t *refcount_table;
int64_t l1_table_offset;
int64_t refcount_table_offset;
int64_t refcount_block_offset;
} QCowCreateState;
struct QCowAIOCB;
/* XXX This could be private for qcow2-cluster.c */
typedef struct QCowL2Meta
{
uint64_t offset;
int n_start;
int nb_available;
int nb_clusters;
struct QCowL2Meta *depends_on;
LIST_HEAD(QCowAioDependencies, QCowAIOCB) dependent_requests;
LIST_ENTRY(QCowL2Meta) next_in_flight;
} QCowL2Meta;
static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
{
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
}
static inline int64_t align_offset(int64_t offset, int n)
{
offset = (offset + n - 1) & ~(n - 1);
return offset;
}
// FIXME Need qcow2_ prefix to global functions
/* qcow2.c functions */
int qcow2_backing_read1(BlockDriverState *bs,
int64_t sector_num, uint8_t *buf, int nb_sectors);
/* qcow2-refcount.c functions */
int qcow2_refcount_init(BlockDriverState *bs);
void qcow2_refcount_close(BlockDriverState *bs);
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size);
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
void qcow2_free_clusters(BlockDriverState *bs,
int64_t offset, int64_t size);
void qcow2_free_any_clusters(BlockDriverState *bs,
uint64_t cluster_offset, int nb_clusters);
void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset,
int64_t size);
int qcow2_update_snapshot_refcount(BlockDriverState *bs,
int64_t l1_table_offset, int l1_size, int addend);
int qcow2_check_refcounts(BlockDriverState *bs);
/* qcow2-cluster.c functions */
int qcow2_grow_l1_table(BlockDriverState *bs, int min_size);
void qcow2_l2_cache_reset(BlockDriverState *bs);
int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, int enc,
const AES_KEY *key);
uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num);
uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
uint64_t offset,
int n_start, int n_end,
int *num, QCowL2Meta *m);
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
uint64_t offset,
int compressed_size);
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
QCowL2Meta *m);
int qcow2_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
int nb_sectors);
/* qcow2-snapshot.c functions */
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
void qcow2_free_snapshots(BlockDriverState *bs);
int qcow2_read_snapshots(BlockDriverState *bs);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,419 +0,0 @@
/*
* Block driver for RAW files (win32)
*
* Copyright (c) 2006 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-timer.h"
#include "block_int.h"
#include "module.h"
#include <windows.h>
#include <winioctl.h>
#define FTYPE_FILE 0
#define FTYPE_CD 1
#define FTYPE_HARDDISK 2
typedef struct BDRVRawState {
HANDLE hfile;
int type;
char drive_path[16]; /* format: "d:\" */
} BDRVRawState;
int qemu_ftruncate64(int fd, int64_t length)
{
LARGE_INTEGER li;
LONG high;
HANDLE h;
BOOL res;
if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
return -1;
h = (HANDLE)_get_osfhandle(fd);
/* get current position, ftruncate do not change position */
li.HighPart = 0;
li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
return -1;
high = length >> 32;
if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
return -1;
res = SetEndOfFile(h);
/* back to old position */
SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
return res ? 0 : -1;
}
static int set_sparse(int fd)
{
DWORD returned;
return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
NULL, 0, NULL, 0, &returned, NULL);
}
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
int access_flags, create_flags;
DWORD overlapped;
s->type = FTYPE_FILE;
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
access_flags = GENERIC_READ | GENERIC_WRITE;
} else {
access_flags = GENERIC_READ;
}
if (flags & BDRV_O_CREAT) {
create_flags = CREATE_ALWAYS;
} else {
create_flags = OPEN_EXISTING;
}
overlapped = FILE_ATTRIBUTE_NORMAL;
if ((flags & BDRV_O_NOCACHE))
overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
else if (!(flags & BDRV_O_CACHE_WB))
overlapped |= FILE_FLAG_WRITE_THROUGH;
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
create_flags, overlapped, NULL);
if (s->hfile == INVALID_HANDLE_VALUE) {
int err = GetLastError();
if (err == ERROR_ACCESS_DENIED)
return -EACCES;
return -1;
}
return 0;
}
static int raw_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
OVERLAPPED ov;
DWORD ret_count;
int ret;
int64_t offset = sector_num * 512;
int count = nb_sectors * 512;
memset(&ov, 0, sizeof(ov));
ov.Offset = offset;
ov.OffsetHigh = offset >> 32;
ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
if (!ret)
return ret_count;
if (ret_count == count)
ret_count = 0;
return ret_count;
}
static int raw_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
OVERLAPPED ov;
DWORD ret_count;
int ret;
int64_t offset = sector_num * 512;
int count = nb_sectors * 512;
memset(&ov, 0, sizeof(ov));
ov.Offset = offset;
ov.OffsetHigh = offset >> 32;
ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
if (!ret)
return ret_count;
if (ret_count == count)
ret_count = 0;
return ret_count;
}
static void raw_flush(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
FlushFileBuffers(s->hfile);
}
static void raw_close(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
CloseHandle(s->hfile);
}
static int raw_truncate(BlockDriverState *bs, int64_t offset)
{
BDRVRawState *s = bs->opaque;
LONG low, high;
low = offset;
high = offset >> 32;
if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
return -EIO;
if (!SetEndOfFile(s->hfile))
return -EIO;
return 0;
}
static int64_t raw_getlength(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
LARGE_INTEGER l;
ULARGE_INTEGER available, total, total_free;
DISK_GEOMETRY_EX dg;
DWORD count;
BOOL status;
switch(s->type) {
case FTYPE_FILE:
l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart);
if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
return -EIO;
break;
case FTYPE_CD:
if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
return -EIO;
l.QuadPart = total.QuadPart;
break;
case FTYPE_HARDDISK:
status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
NULL, 0, &dg, sizeof(dg), &count, NULL);
if (status != 0) {
l = dg.DiskSize;
}
break;
default:
return -EIO;
}
return l.QuadPart;
}
static int raw_create(const char *filename, QEMUOptionParameter *options)
{
int fd;
int64_t total_size = 0;
/* Read out options */
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
total_size = options->value.n / 512;
}
options++;
}
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
if (fd < 0)
return -EIO;
set_sparse(fd);
ftruncate(fd, total_size * 512);
close(fd);
return 0;
}
static QEMUOptionParameter raw_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{ NULL }
};
static BlockDriver bdrv_raw = {
.format_name = "raw",
.instance_size = sizeof(BDRVRawState),
.bdrv_open = raw_open,
.bdrv_close = raw_close,
.bdrv_create = raw_create,
.bdrv_flush = raw_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
.create_options = raw_create_options,
};
/***********************************************/
/* host device */
static int find_cdrom(char *cdrom_name, int cdrom_name_size)
{
char drives[256], *pdrv = drives;
UINT type;
memset(drives, 0, sizeof(drives));
GetLogicalDriveStrings(sizeof(drives), drives);
while(pdrv[0] != '\0') {
type = GetDriveType(pdrv);
switch(type) {
case DRIVE_CDROM:
snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
return 0;
break;
}
pdrv += lstrlen(pdrv) + 1;
}
return -1;
}
static int find_device_type(BlockDriverState *bs, const char *filename)
{
BDRVRawState *s = bs->opaque;
UINT type;
const char *p;
if (strstart(filename, "\\\\.\\", &p) ||
strstart(filename, "//./", &p)) {
if (stristart(p, "PhysicalDrive", NULL))
return FTYPE_HARDDISK;
snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
type = GetDriveType(s->drive_path);
switch (type) {
case DRIVE_REMOVABLE:
case DRIVE_FIXED:
return FTYPE_HARDDISK;
case DRIVE_CDROM:
return FTYPE_CD;
default:
return FTYPE_FILE;
}
} else {
return FTYPE_FILE;
}
}
static int hdev_probe_device(const char *filename)
{
if (strstart(filename, "/dev/cdrom", NULL))
return 100;
if (is_windows_drive(filename))
return 100;
return 0;
}
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
int access_flags, create_flags;
DWORD overlapped;
char device_name[64];
if (strstart(filename, "/dev/cdrom", NULL)) {
if (find_cdrom(device_name, sizeof(device_name)) < 0)
return -ENOENT;
filename = device_name;
} else {
/* transform drive letters into device name */
if (((filename[0] >= 'a' && filename[0] <= 'z') ||
(filename[0] >= 'A' && filename[0] <= 'Z')) &&
filename[1] == ':' && filename[2] == '\0') {
snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
filename = device_name;
}
}
s->type = find_device_type(bs, filename);
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
access_flags = GENERIC_READ | GENERIC_WRITE;
} else {
access_flags = GENERIC_READ;
}
create_flags = OPEN_EXISTING;
overlapped = FILE_ATTRIBUTE_NORMAL;
if ((flags & BDRV_O_NOCACHE))
overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
else if (!(flags & BDRV_O_CACHE_WB))
overlapped |= FILE_FLAG_WRITE_THROUGH;
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
create_flags, overlapped, NULL);
if (s->hfile == INVALID_HANDLE_VALUE) {
int err = GetLastError();
if (err == ERROR_ACCESS_DENIED)
return -EACCES;
return -1;
}
return 0;
}
#if 0
/***********************************************/
/* removable device additional commands */
static int raw_is_inserted(BlockDriverState *bs)
{
return 1;
}
static int raw_media_changed(BlockDriverState *bs)
{
return -ENOTSUP;
}
static int raw_eject(BlockDriverState *bs, int eject_flag)
{
DWORD ret_count;
if (s->type == FTYPE_FILE)
return -ENOTSUP;
if (eject_flag) {
DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
NULL, 0, NULL, 0, &lpBytesReturned, NULL);
} else {
DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
NULL, 0, NULL, 0, &lpBytesReturned, NULL);
}
}
static int raw_set_locked(BlockDriverState *bs, int locked)
{
return -ENOTSUP;
}
#endif
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,
.bdrv_flush = raw_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
.bdrv_getlength = raw_getlength,
};
static void bdrv_raw_init(void)
{
bdrv_register(&bdrv_raw);
bdrv_register(&bdrv_host_device);
}
block_init(bdrv_raw_init);

View File

@@ -1,870 +0,0 @@
/*
* Block driver for the VMDK format
*
* Copyright (c) 2004 Fabrice Bellard
* Copyright (c) 2005 Filip Navara
*
* 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 "block_int.h"
#include "module.h"
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
typedef struct {
uint32_t version;
uint32_t flags;
uint32_t disk_sectors;
uint32_t granularity;
uint32_t l1dir_offset;
uint32_t l1dir_size;
uint32_t file_sectors;
uint32_t cylinders;
uint32_t heads;
uint32_t sectors_per_track;
} VMDK3Header;
typedef struct {
uint32_t version;
uint32_t flags;
int64_t capacity;
int64_t granularity;
int64_t desc_offset;
int64_t desc_size;
int32_t num_gtes_per_gte;
int64_t rgd_offset;
int64_t gd_offset;
int64_t grain_offset;
char filler[1];
char check_bytes[4];
} __attribute__((packed)) VMDK4Header;
#define L2_CACHE_SIZE 16
typedef struct BDRVVmdkState {
BlockDriverState *hd;
int64_t l1_table_offset;
int64_t l1_backup_table_offset;
uint32_t *l1_table;
uint32_t *l1_backup_table;
unsigned int l1_size;
uint32_t l1_entry_sectors;
unsigned int l2_size;
uint32_t *l2_cache;
uint32_t l2_cache_offsets[L2_CACHE_SIZE];
uint32_t l2_cache_counts[L2_CACHE_SIZE];
unsigned int cluster_sectors;
uint32_t parent_cid;
int is_parent;
} BDRVVmdkState;
typedef struct VmdkMetaData {
uint32_t offset;
unsigned int l1_index;
unsigned int l2_index;
unsigned int l2_offset;
int valid;
} VmdkMetaData;
typedef struct ActiveBDRVState{
BlockDriverState *hd; // active image handler
uint64_t cluster_offset; // current write offset
}ActiveBDRVState;
static ActiveBDRVState activeBDRV;
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
{
uint32_t magic;
if (buf_size < 4)
return 0;
magic = be32_to_cpu(*(uint32_t *)buf);
if (magic == VMDK3_MAGIC ||
magic == VMDK4_MAGIC)
return 100;
else
return 0;
}
#define CHECK_CID 1
#define SECTOR_SIZE 512
#define DESC_SIZE 20*SECTOR_SIZE // 20 sectors of 512 bytes each
#define HEADER_SIZE 512 // first sector of 512 bytes
static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
{
BDRVVmdkState *s = bs->opaque;
char desc[DESC_SIZE];
uint32_t cid;
const char *p_name, *cid_str;
size_t cid_str_size;
/* the descriptor offset = 0x200 */
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
return 0;
if (parent) {
cid_str = "parentCID";
cid_str_size = sizeof("parentCID");
} else {
cid_str = "CID";
cid_str_size = sizeof("CID");
}
if ((p_name = strstr(desc,cid_str)) != NULL) {
p_name += cid_str_size;
sscanf(p_name,"%x",&cid);
}
return cid;
}
static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
{
BDRVVmdkState *s = bs->opaque;
char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
char *p_name, *tmp_str;
/* the descriptor offset = 0x200 */
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
return -1;
tmp_str = strstr(desc,"parentCID");
pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str);
if ((p_name = strstr(desc,"CID")) != NULL) {
p_name += sizeof("CID");
snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid);
pstrcat(desc, sizeof(desc), tmp_desc);
}
if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
return -1;
return 0;
}
static int vmdk_is_cid_valid(BlockDriverState *bs)
{
#ifdef CHECK_CID
BDRVVmdkState *s = bs->opaque;
BlockDriverState *p_bs = bs->backing_hd;
uint32_t cur_pcid;
if (p_bs) {
cur_pcid = vmdk_read_cid(p_bs,0);
if (s->parent_cid != cur_pcid)
// CID not valid
return 0;
}
#endif
// CID valid
return 1;
}
static int vmdk_snapshot_create(const char *filename, const char *backing_file)
{
int snp_fd, p_fd;
uint32_t p_cid;
char *p_name, *gd_buf, *rgd_buf;
const char *real_filename, *temp_str;
VMDK4Header header;
uint32_t gde_entries, gd_size;
int64_t gd_offset, rgd_offset, capacity, gt_size;
char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE];
static const char desc_template[] =
"# Disk DescriptorFile\n"
"version=1\n"
"CID=%x\n"
"parentCID=%x\n"
"createType=\"monolithicSparse\"\n"
"parentFileNameHint=\"%s\"\n"
"\n"
"# Extent description\n"
"RW %u SPARSE \"%s\"\n"
"\n"
"# The Disk Data Base \n"
"#DDB\n"
"\n";
snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
if (snp_fd < 0)
return -1;
p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
if (p_fd < 0) {
close(snp_fd);
return -1;
}
/* read the header */
if (lseek(p_fd, 0x0, SEEK_SET) == -1)
goto fail;
if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE)
goto fail;
/* write the header */
if (lseek(snp_fd, 0x0, SEEK_SET) == -1)
goto fail;
if (write(snp_fd, hdr, HEADER_SIZE) == -1)
goto fail;
memset(&header, 0, sizeof(header));
memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC
ftruncate(snp_fd, header.grain_offset << 9);
/* the descriptor offset = 0x200 */
if (lseek(p_fd, 0x200, SEEK_SET) == -1)
goto fail;
if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE)
goto fail;
if ((p_name = strstr(p_desc,"CID")) != NULL) {
p_name += sizeof("CID");
sscanf(p_name,"%x",&p_cid);
}
real_filename = filename;
if ((temp_str = strrchr(real_filename, '\\')) != NULL)
real_filename = temp_str + 1;
if ((temp_str = strrchr(real_filename, '/')) != NULL)
real_filename = temp_str + 1;
if ((temp_str = strrchr(real_filename, ':')) != NULL)
real_filename = temp_str + 1;
snprintf(s_desc, sizeof(s_desc), desc_template, p_cid, p_cid, backing_file,
(uint32_t)header.capacity, real_filename);
/* write the descriptor */
if (lseek(snp_fd, 0x200, SEEK_SET) == -1)
goto fail;
if (write(snp_fd, s_desc, strlen(s_desc)) == -1)
goto fail;
gd_offset = header.gd_offset * SECTOR_SIZE; // offset of GD table
rgd_offset = header.rgd_offset * SECTOR_SIZE; // offset of RGD table
capacity = header.capacity * SECTOR_SIZE; // Extent size
/*
* Each GDE span 32M disk, means:
* 512 GTE per GT, each GTE points to grain
*/
gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE;
if (!gt_size)
goto fail;
gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde
gd_size = gde_entries * sizeof(uint32_t);
/* write RGD */
rgd_buf = qemu_malloc(gd_size);
if (lseek(p_fd, rgd_offset, SEEK_SET) == -1)
goto fail_rgd;
if (read(p_fd, rgd_buf, gd_size) != gd_size)
goto fail_rgd;
if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1)
goto fail_rgd;
if (write(snp_fd, rgd_buf, gd_size) == -1)
goto fail_rgd;
qemu_free(rgd_buf);
/* write GD */
gd_buf = qemu_malloc(gd_size);
if (lseek(p_fd, gd_offset, SEEK_SET) == -1)
goto fail_gd;
if (read(p_fd, gd_buf, gd_size) != gd_size)
goto fail_gd;
if (lseek(snp_fd, gd_offset, SEEK_SET) == -1)
goto fail_gd;
if (write(snp_fd, gd_buf, gd_size) == -1)
goto fail_gd;
qemu_free(gd_buf);
close(p_fd);
close(snp_fd);
return 0;
fail_gd:
qemu_free(gd_buf);
fail_rgd:
qemu_free(rgd_buf);
fail:
close(p_fd);
close(snp_fd);
return -1;
}
static void vmdk_parent_close(BlockDriverState *bs)
{
if (bs->backing_hd)
bdrv_close(bs->backing_hd);
}
static int parent_open = 0;
static int vmdk_parent_open(BlockDriverState *bs, const char * filename)
{
BDRVVmdkState *s = bs->opaque;
char *p_name;
char desc[DESC_SIZE];
char parent_img_name[1024];
/* the descriptor offset = 0x200 */
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
return -1;
if ((p_name = strstr(desc,"parentFileNameHint")) != NULL) {
char *end_name;
struct stat file_buf;
p_name += sizeof("parentFileNameHint") + 1;
if ((end_name = strchr(p_name,'\"')) == NULL)
return -1;
if ((end_name - p_name) > sizeof (bs->backing_file) - 1)
return -1;
pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
if (stat(bs->backing_file, &file_buf) != 0) {
path_combine(parent_img_name, sizeof(parent_img_name),
filename, bs->backing_file);
} else {
pstrcpy(parent_img_name, sizeof(parent_img_name),
bs->backing_file);
}
bs->backing_hd = bdrv_new("");
if (!bs->backing_hd) {
failure:
bdrv_close(s->hd);
return -1;
}
parent_open = 1;
if (bdrv_open(bs->backing_hd, parent_img_name, BDRV_O_RDONLY) < 0)
goto failure;
parent_open = 0;
}
return 0;
}
static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVVmdkState *s = bs->opaque;
uint32_t magic;
int l1_size, i, ret;
if (parent_open)
// Parent must be opened as RO.
flags = BDRV_O_RDONLY;
ret = bdrv_file_open(&s->hd, filename, flags);
if (ret < 0)
return ret;
if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic))
goto fail;
magic = be32_to_cpu(magic);
if (magic == VMDK3_MAGIC) {
VMDK3Header header;
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
goto fail;
s->cluster_sectors = le32_to_cpu(header.granularity);
s->l2_size = 1 << 9;
s->l1_size = 1 << 6;
bs->total_sectors = le32_to_cpu(header.disk_sectors);
s->l1_table_offset = le32_to_cpu(header.l1dir_offset) << 9;
s->l1_backup_table_offset = 0;
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
} else if (magic == VMDK4_MAGIC) {
VMDK4Header header;
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
goto fail;
bs->total_sectors = le64_to_cpu(header.capacity);
s->cluster_sectors = le64_to_cpu(header.granularity);
s->l2_size = le32_to_cpu(header.num_gtes_per_gte);
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
if (s->l1_entry_sectors <= 0)
goto fail;
s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1)
/ s->l1_entry_sectors;
s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
if (parent_open)
s->is_parent = 1;
else
s->is_parent = 0;
// try to open parent images, if exist
if (vmdk_parent_open(bs, filename) != 0)
goto fail;
// write the CID once after the image creation
s->parent_cid = vmdk_read_cid(bs,1);
} else {
goto fail;
}
/* read the L1 table */
l1_size = s->l1_size * sizeof(uint32_t);
s->l1_table = qemu_malloc(l1_size);
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_table[i]);
}
if (s->l1_backup_table_offset) {
s->l1_backup_table = qemu_malloc(l1_size);
if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size)
goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_backup_table[i]);
}
}
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
return 0;
fail:
qemu_free(s->l1_backup_table);
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
bdrv_delete(s->hd);
return -1;
}
static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
uint64_t offset, int allocate);
static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
uint64_t offset, int allocate)
{
uint64_t parent_cluster_offset;
BDRVVmdkState *s = bs->opaque;
uint8_t whole_grain[s->cluster_sectors*512]; // 128 sectors * 512 bytes each = grain size 64KB
// we will be here if it's first write on non-exist grain(cluster).
// try to read from parent image, if exist
if (bs->backing_hd) {
BDRVVmdkState *ps = bs->backing_hd->opaque;
if (!vmdk_is_cid_valid(bs))
return -1;
parent_cluster_offset = get_cluster_offset(bs->backing_hd, NULL,
offset, allocate);
if (parent_cluster_offset) {
BDRVVmdkState *act_s = activeBDRV.hd->opaque;
if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512)
return -1;
//Write grain only into the active image
if (bdrv_pwrite(act_s->hd, activeBDRV.cluster_offset << 9, whole_grain, sizeof(whole_grain)) != sizeof(whole_grain))
return -1;
}
}
return 0;
}
static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data)
{
BDRVVmdkState *s = bs->opaque;
/* update L2 table */
if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
&(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
return -1;
/* update backup L2 table */
if (s->l1_backup_table_offset != 0) {
m_data->l2_offset = s->l1_backup_table[m_data->l1_index];
if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
&(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
return -1;
}
return 0;
}
static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
uint64_t offset, int allocate)
{
BDRVVmdkState *s = bs->opaque;
unsigned int l1_index, l2_offset, l2_index;
int min_index, i, j;
uint32_t min_count, *l2_table, tmp = 0;
uint64_t cluster_offset;
if (m_data)
m_data->valid = 0;
l1_index = (offset >> 9) / s->l1_entry_sectors;
if (l1_index >= s->l1_size)
return 0;
l2_offset = s->l1_table[l1_index];
if (!l2_offset)
return 0;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (l2_offset == s->l2_cache_offsets[i]) {
/* increment the hit count */
if (++s->l2_cache_counts[i] == 0xffffffff) {
for(j = 0; j < L2_CACHE_SIZE; j++) {
s->l2_cache_counts[j] >>= 1;
}
}
l2_table = s->l2_cache + (i * s->l2_size);
goto found;
}
}
/* not found: load a new entry in the least used one */
min_index = 0;
min_count = 0xffffffff;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (s->l2_cache_counts[i] < min_count) {
min_count = s->l2_cache_counts[i];
min_index = i;
}
}
l2_table = s->l2_cache + (min_index * s->l2_size);
if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) !=
s->l2_size * sizeof(uint32_t))
return 0;
s->l2_cache_offsets[min_index] = l2_offset;
s->l2_cache_counts[min_index] = 1;
found:
l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
cluster_offset = le32_to_cpu(l2_table[l2_index]);
if (!cluster_offset) {
if (!allocate)
return 0;
// Avoid the L2 tables update for the images that have snapshots.
if (!s->is_parent) {
cluster_offset = bdrv_getlength(s->hd);
bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
cluster_offset >>= 9;
tmp = cpu_to_le32(cluster_offset);
l2_table[l2_index] = tmp;
// Save the active image state
activeBDRV.cluster_offset = cluster_offset;
activeBDRV.hd = bs;
}
/* First of all we write grain itself, to avoid race condition
* that may to corrupt the image.
* This problem may occur because of insufficient space on host disk
* or inappropriate VM shutdown.
*/
if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1)
return 0;
if (m_data) {
m_data->offset = tmp;
m_data->l1_index = l1_index;
m_data->l2_index = l2_index;
m_data->l2_offset = l2_offset;
m_data->valid = 1;
}
}
cluster_offset <<= 9;
return cluster_offset;
}
static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
BDRVVmdkState *s = bs->opaque;
int index_in_cluster, n;
uint64_t cluster_offset;
cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
index_in_cluster = sector_num % s->cluster_sectors;
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
*pnum = n;
return (cluster_offset != 0);
}
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
int index_in_cluster, n, ret;
uint64_t cluster_offset;
while (nb_sectors > 0) {
cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
index_in_cluster = sector_num % s->cluster_sectors;
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
// try to read from parent image, if exist
if (bs->backing_hd) {
if (!vmdk_is_cid_valid(bs))
return -1;
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
if (ret < 0)
return -1;
} else {
memset(buf, 0, 512 * n);
}
} else {
if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
return -1;
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
VmdkMetaData m_data;
int index_in_cluster, n;
uint64_t cluster_offset;
static int cid_update = 0;
if (sector_num > bs->total_sectors) {
fprintf(stderr,
"(VMDK) Wrong offset: sector_num=0x%" PRIx64
" total_sectors=0x%" PRIx64 "\n",
sector_num, bs->total_sectors);
return -1;
}
while (nb_sectors > 0) {
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
cluster_offset = get_cluster_offset(bs, &m_data, sector_num << 9, 1);
if (!cluster_offset)
return -1;
if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
return -1;
if (m_data.valid) {
/* update L2 tables */
if (vmdk_L2update(bs, &m_data) == -1)
return -1;
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
// update CID on the first write every time the virtual disk is opened
if (!cid_update) {
vmdk_write_cid(bs, time(NULL));
cid_update++;
}
}
return 0;
}
static int vmdk_create(const char *filename, QEMUOptionParameter *options)
{
int fd, i;
VMDK4Header header;
uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
static const char desc_template[] =
"# Disk DescriptorFile\n"
"version=1\n"
"CID=%x\n"
"parentCID=ffffffff\n"
"createType=\"monolithicSparse\"\n"
"\n"
"# Extent description\n"
"RW %" PRId64 " SPARSE \"%s\"\n"
"\n"
"# The Disk Data Base \n"
"#DDB\n"
"\n"
"ddb.virtualHWVersion = \"%d\"\n"
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
"ddb.geometry.heads = \"16\"\n"
"ddb.geometry.sectors = \"63\"\n"
"ddb.adapterType = \"ide\"\n";
char desc[1024];
const char *real_filename, *temp_str;
int64_t total_size = 0;
const char *backing_file = NULL;
int flags = 0;
// Read out options
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
total_size = options->value.n / 512;
} else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
backing_file = options->value.s;
} else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
flags |= options->value.n ? BLOCK_FLAG_COMPAT6: 0;
}
options++;
}
/* XXX: add support for backing file */
if (backing_file) {
return vmdk_snapshot_create(filename, backing_file);
}
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0)
return -1;
magic = cpu_to_be32(VMDK4_MAGIC);
memset(&header, 0, sizeof(header));
header.version = cpu_to_le32(1);
header.flags = cpu_to_le32(3); /* ?? */
header.capacity = cpu_to_le64(total_size);
header.granularity = cpu_to_le64(128);
header.num_gtes_per_gte = cpu_to_le32(512);
grains = (total_size + header.granularity - 1) / header.granularity;
gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
header.desc_offset = 1;
header.desc_size = 20;
header.rgd_offset = header.desc_offset + header.desc_size;
header.gd_offset = header.rgd_offset + gd_size + (gt_size * gt_count);
header.grain_offset =
((header.gd_offset + gd_size + (gt_size * gt_count) +
header.granularity - 1) / header.granularity) *
header.granularity;
header.desc_offset = cpu_to_le64(header.desc_offset);
header.desc_size = cpu_to_le64(header.desc_size);
header.rgd_offset = cpu_to_le64(header.rgd_offset);
header.gd_offset = cpu_to_le64(header.gd_offset);
header.grain_offset = cpu_to_le64(header.grain_offset);
header.check_bytes[0] = 0xa;
header.check_bytes[1] = 0x20;
header.check_bytes[2] = 0xd;
header.check_bytes[3] = 0xa;
/* write all the data */
write(fd, &magic, sizeof(magic));
write(fd, &header, sizeof(header));
ftruncate(fd, header.grain_offset << 9);
/* write grain directory */
lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
for (i = 0, tmp = header.rgd_offset + gd_size;
i < gt_count; i++, tmp += gt_size)
write(fd, &tmp, sizeof(tmp));
/* write backup grain directory */
lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
for (i = 0, tmp = header.gd_offset + gd_size;
i < gt_count; i++, tmp += gt_size)
write(fd, &tmp, sizeof(tmp));
/* compose the descriptor */
real_filename = filename;
if ((temp_str = strrchr(real_filename, '\\')) != NULL)
real_filename = temp_str + 1;
if ((temp_str = strrchr(real_filename, '/')) != NULL)
real_filename = temp_str + 1;
if ((temp_str = strrchr(real_filename, ':')) != NULL)
real_filename = temp_str + 1;
snprintf(desc, sizeof(desc), desc_template, (unsigned int)time(NULL),
total_size, real_filename,
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
total_size / (int64_t)(63 * 16));
/* write the descriptor */
lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
write(fd, desc, strlen(desc));
close(fd);
return 0;
}
static void vmdk_close(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
// try to close parent image, if exist
vmdk_parent_close(s->hd);
bdrv_delete(s->hd);
}
static void vmdk_flush(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
bdrv_flush(s->hd);
}
static QEMUOptionParameter vmdk_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{
.name = BLOCK_OPT_BACKING_FILE,
.type = OPT_STRING,
.help = "File name of a base image"
},
{
.name = BLOCK_OPT_COMPAT6,
.type = OPT_FLAG,
.help = "VMDK version 6 image"
},
{ NULL }
};
static BlockDriver bdrv_vmdk = {
.format_name = "vmdk",
.instance_size = sizeof(BDRVVmdkState),
.bdrv_probe = vmdk_probe,
.bdrv_open = vmdk_open,
.bdrv_read = vmdk_read,
.bdrv_write = vmdk_write,
.bdrv_close = vmdk_close,
.bdrv_create = vmdk_create,
.bdrv_flush = vmdk_flush,
.bdrv_is_allocated = vmdk_is_allocated,
.create_options = vmdk_create_options,
};
static void bdrv_vmdk_init(void)
{
bdrv_register(&bdrv_vmdk);
}
block_init(bdrv_vmdk_init);

View File

@@ -1,623 +0,0 @@
/*
* Block driver for Conectix/Microsoft Virtual PC images
*
* Copyright (c) 2005 Alex Beregszaszi
* Copyright (c) 2009 Kevin Wolf <kwolf@suse.de>
*
* 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 "block_int.h"
#include "module.h"
/**************************************************************/
#define HEADER_SIZE 512
//#define CACHE
enum vhd_type {
VHD_FIXED = 2,
VHD_DYNAMIC = 3,
VHD_DIFFERENCING = 4,
};
// Seconds since Jan 1, 2000 0:00:00 (UTC)
#define VHD_TIMESTAMP_BASE 946684800
// always big-endian
struct vhd_footer {
char creator[8]; // "conectix"
uint32_t features;
uint32_t version;
// Offset of next header structure, 0xFFFFFFFF if none
uint64_t data_offset;
// Seconds since Jan 1, 2000 0:00:00 (UTC)
uint32_t timestamp;
char creator_app[4]; // "vpc "
uint16_t major;
uint16_t minor;
char creator_os[4]; // "Wi2k"
uint64_t orig_size;
uint64_t size;
uint16_t cyls;
uint8_t heads;
uint8_t secs_per_cyl;
uint32_t type;
// Checksum of the Hard Disk Footer ("one's complement of the sum of all
// the bytes in the footer without the checksum field")
uint32_t checksum;
// UUID used to identify a parent hard disk (backing file)
uint8_t uuid[16];
uint8_t in_saved_state;
};
struct vhd_dyndisk_header {
char magic[8]; // "cxsparse"
// Offset of next header structure, 0xFFFFFFFF if none
uint64_t data_offset;
// Offset of the Block Allocation Table (BAT)
uint64_t table_offset;
uint32_t version;
uint32_t max_table_entries; // 32bit/entry
// 2 MB by default, must be a power of two
uint32_t block_size;
uint32_t checksum;
uint8_t parent_uuid[16];
uint32_t parent_timestamp;
uint32_t reserved;
// Backing file name (in UTF-16)
uint8_t parent_name[512];
struct {
uint32_t platform;
uint32_t data_space;
uint32_t data_length;
uint32_t reserved;
uint64_t data_offset;
} parent_locator[8];
};
typedef struct BDRVVPCState {
BlockDriverState *hd;
uint8_t footer_buf[HEADER_SIZE];
uint64_t free_data_block_offset;
int max_table_entries;
uint32_t *pagetable;
uint64_t bat_offset;
uint64_t last_bitmap_offset;
uint32_t block_size;
uint32_t bitmap_size;
#ifdef CACHE
uint8_t *pageentry_u8;
uint32_t *pageentry_u32;
uint16_t *pageentry_u16;
uint64_t last_bitmap;
#endif
} BDRVVPCState;
static uint32_t vpc_checksum(uint8_t* buf, size_t size)
{
uint32_t res = 0;
int i;
for (i = 0; i < size; i++)
res += buf[i];
return ~res;
}
static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
{
if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
return 100;
return 0;
}
static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVVPCState *s = bs->opaque;
int ret, i;
struct vhd_footer* footer;
struct vhd_dyndisk_header* dyndisk_header;
uint8_t buf[HEADER_SIZE];
uint32_t checksum;
ret = bdrv_file_open(&s->hd, filename, flags);
if (ret < 0)
return ret;
if (bdrv_pread(s->hd, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
goto fail;
footer = (struct vhd_footer*) s->footer_buf;
if (strncmp(footer->creator, "conectix", 8))
goto fail;
checksum = be32_to_cpu(footer->checksum);
footer->checksum = 0;
if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum)
fprintf(stderr, "block-vpc: The header checksum of '%s' is "
"incorrect.\n", filename);
// The visible size of a image in Virtual PC depends on the geometry
// rather than on the size stored in the footer (the size in the footer
// is too large usually)
bs->total_sectors = (int64_t)
be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
if (bdrv_pread(s->hd, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
!= HEADER_SIZE)
goto fail;
dyndisk_header = (struct vhd_dyndisk_header*) buf;
if (strncmp(dyndisk_header->magic, "cxsparse", 8))
goto fail;
s->block_size = be32_to_cpu(dyndisk_header->block_size);
s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
s->pagetable = qemu_malloc(s->max_table_entries * 4);
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
if (bdrv_pread(s->hd, s->bat_offset, s->pagetable,
s->max_table_entries * 4) != s->max_table_entries * 4)
goto fail;
s->free_data_block_offset =
(s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
for (i = 0; i < s->max_table_entries; i++) {
be32_to_cpus(&s->pagetable[i]);
if (s->pagetable[i] != 0xFFFFFFFF) {
int64_t next = (512 * (int64_t) s->pagetable[i]) +
s->bitmap_size + s->block_size;
if (next> s->free_data_block_offset)
s->free_data_block_offset = next;
}
}
s->last_bitmap_offset = (int64_t) -1;
#ifdef CACHE
s->pageentry_u8 = qemu_malloc(512);
s->pageentry_u32 = s->pageentry_u8;
s->pageentry_u16 = s->pageentry_u8;
s->last_pagetable = -1;
#endif
return 0;
fail:
bdrv_delete(s->hd);
return -1;
}
/*
* Returns the absolute byte offset of the given sector in the image file.
* If the sector is not allocated, -1 is returned instead.
*
* The parameter write must be 1 if the offset will be used for a write
* operation (the block bitmaps is updated then), 0 otherwise.
*/
static inline int64_t get_sector_offset(BlockDriverState *bs,
int64_t sector_num, int write)
{
BDRVVPCState *s = bs->opaque;
uint64_t offset = sector_num * 512;
uint64_t bitmap_offset, block_offset;
uint32_t pagetable_index, pageentry_index;
pagetable_index = offset / s->block_size;
pageentry_index = (offset % s->block_size) / 512;
if (pagetable_index >= s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
return -1; // not allocated
bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index];
block_offset = bitmap_offset + s->bitmap_size + (512 * pageentry_index);
// We must ensure that we don't write to any sectors which are marked as
// unused in the bitmap. We get away with setting all bits in the block
// bitmap each time we write to a new block. This might cause Virtual PC to
// miss sparse read optimization, but it's not a problem in terms of
// correctness.
if (write && (s->last_bitmap_offset != bitmap_offset)) {
uint8_t bitmap[s->bitmap_size];
s->last_bitmap_offset = bitmap_offset;
memset(bitmap, 0xff, s->bitmap_size);
bdrv_pwrite(s->hd, bitmap_offset, bitmap, s->bitmap_size);
}
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
// sector_num, pagetable_index, pageentry_index,
// bitmap_offset, block_offset);
// disabled by reason
#if 0
#ifdef CACHE
if (bitmap_offset != s->last_bitmap)
{
lseek(s->fd, bitmap_offset, SEEK_SET);
s->last_bitmap = bitmap_offset;
// Scary! Bitmap is stored as big endian 32bit entries,
// while we used to look it up byte by byte
read(s->fd, s->pageentry_u8, 512);
for (i = 0; i < 128; i++)
be32_to_cpus(&s->pageentry_u32[i]);
}
if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
return -1;
#else
lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
read(s->fd, &bitmap_entry, 1);
if ((bitmap_entry >> (pageentry_index % 8)) & 1)
return -1; // not allocated
#endif
#endif
return block_offset;
}
/*
* Writes the footer to the end of the image file. This is needed when the
* file grows as it overwrites the old footer
*
* Returns 0 on success and < 0 on error
*/
static int rewrite_footer(BlockDriverState* bs)
{
int ret;
BDRVVPCState *s = bs->opaque;
int64_t offset = s->free_data_block_offset;
ret = bdrv_pwrite(s->hd, offset, s->footer_buf, HEADER_SIZE);
if (ret < 0)
return ret;
return 0;
}
/*
* Allocates a new block. This involves writing a new footer and updating
* the Block Allocation Table to use the space at the old end of the image
* file (overwriting the old footer)
*
* Returns the sectors' offset in the image file on success and < 0 on error
*/
static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
{
BDRVVPCState *s = bs->opaque;
int64_t bat_offset;
uint32_t index, bat_value;
int ret;
uint8_t bitmap[s->bitmap_size];
// Check if sector_num is valid
if ((sector_num < 0) || (sector_num > bs->total_sectors))
return -1;
// Write entry into in-memory BAT
index = (sector_num * 512) / s->block_size;
if (s->pagetable[index] != 0xFFFFFFFF)
return -1;
s->pagetable[index] = s->free_data_block_offset / 512;
// Initialize the block's bitmap
memset(bitmap, 0xff, s->bitmap_size);
bdrv_pwrite(s->hd, s->free_data_block_offset, bitmap, s->bitmap_size);
// Write new footer (the old one will be overwritten)
s->free_data_block_offset += s->block_size + s->bitmap_size;
ret = rewrite_footer(bs);
if (ret < 0)
goto fail;
// Write BAT entry to disk
bat_offset = s->bat_offset + (4 * index);
bat_value = be32_to_cpu(s->pagetable[index]);
ret = bdrv_pwrite(s->hd, bat_offset, &bat_value, 4);
if (ret < 0)
goto fail;
return get_sector_offset(bs, sector_num, 0);
fail:
s->free_data_block_offset -= (s->block_size + s->bitmap_size);
return -1;
}
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVPCState *s = bs->opaque;
int ret;
int64_t offset;
while (nb_sectors > 0) {
offset = get_sector_offset(bs, sector_num, 0);
if (offset == -1) {
memset(buf, 0, 512);
} else {
ret = bdrv_pread(s->hd, offset, buf, 512);
if (ret != 512)
return -1;
}
nb_sectors--;
sector_num++;
buf += 512;
}
return 0;
}
static int vpc_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVVPCState *s = bs->opaque;
int64_t offset;
int ret;
while (nb_sectors > 0) {
offset = get_sector_offset(bs, sector_num, 1);
if (offset == -1) {
offset = alloc_block(bs, sector_num);
if (offset < 0)
return -1;
}
ret = bdrv_pwrite(s->hd, offset, buf, 512);
if (ret != 512)
return -1;
nb_sectors--;
sector_num++;
buf += 512;
}
return 0;
}
/*
* Calculates the number of cylinders, heads and sectors per cylinder
* based on a given number of sectors. This is the algorithm described
* in the VHD specification.
*
* Note that the geometry doesn't always exactly match total_sectors but
* may round it down.
*
* Returns 0 on success, -EFBIG if the size is larger than 127 GB
*/
static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
uint8_t* heads, uint8_t* secs_per_cyl)
{
uint32_t cyls_times_heads;
if (total_sectors > 65535 * 16 * 255)
return -EFBIG;
if (total_sectors > 65535 * 16 * 63) {
*secs_per_cyl = 255;
*heads = 16;
cyls_times_heads = total_sectors / *secs_per_cyl;
} else {
*secs_per_cyl = 17;
cyls_times_heads = total_sectors / *secs_per_cyl;
*heads = (cyls_times_heads + 1023) / 1024;
if (*heads < 4)
*heads = 4;
if (cyls_times_heads >= (*heads * 1024) || *heads > 16) {
*secs_per_cyl = 31;
*heads = 16;
cyls_times_heads = total_sectors / *secs_per_cyl;
}
if (cyls_times_heads >= (*heads * 1024)) {
*secs_per_cyl = 63;
*heads = 16;
cyls_times_heads = total_sectors / *secs_per_cyl;
}
}
// Note: Rounding up deviates from the Virtual PC behaviour
// However, we need this to avoid truncating images in qemu-img convert
*cyls = (cyls_times_heads + *heads - 1) / *heads;
return 0;
}
static int vpc_create(const char *filename, QEMUOptionParameter *options)
{
uint8_t buf[1024];
struct vhd_footer* footer = (struct vhd_footer*) buf;
struct vhd_dyndisk_header* dyndisk_header =
(struct vhd_dyndisk_header*) buf;
int fd, i;
uint16_t cyls;
uint8_t heads;
uint8_t secs_per_cyl;
size_t block_size, num_bat_entries;
int64_t total_sectors = 0;
// Read out options
while (options && options->name) {
if (!strcmp(options->name, "size")) {
total_sectors = options->value.n / 512;
}
options++;
}
// Create the file
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
if (fd < 0)
return -EIO;
// Calculate matching total_size and geometry
if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl))
return -EFBIG;
total_sectors = (int64_t) cyls * heads * secs_per_cyl;
// Prepare the Hard Disk Footer
memset(buf, 0, 1024);
strncpy(footer->creator, "conectix", 8);
// TODO Check if "qemu" creator_app is ok for VPC
strncpy(footer->creator_app, "qemu", 4);
strncpy(footer->creator_os, "Wi2k", 4);
footer->features = be32_to_cpu(0x02);
footer->version = be32_to_cpu(0x00010000);
footer->data_offset = be64_to_cpu(HEADER_SIZE);
footer->timestamp = be32_to_cpu(time(NULL) - VHD_TIMESTAMP_BASE);
// Version of Virtual PC 2007
footer->major = be16_to_cpu(0x0005);
footer->minor =be16_to_cpu(0x0003);
footer->orig_size = be64_to_cpu(total_sectors * 512);
footer->size = be64_to_cpu(total_sectors * 512);
footer->cyls = be16_to_cpu(cyls);
footer->heads = heads;
footer->secs_per_cyl = secs_per_cyl;
footer->type = be32_to_cpu(VHD_DYNAMIC);
// TODO uuid is missing
footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
// Write the footer (twice: at the beginning and at the end)
block_size = 0x200000;
num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
return -EIO;
if (lseek(fd, 1536 + ((num_bat_entries * 4 + 511) & ~511), SEEK_SET) < 0)
return -EIO;
if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
return -EIO;
// Write the initial BAT
if (lseek(fd, 3 * 512, SEEK_SET) < 0)
return -EIO;
memset(buf, 0xFF, 512);
for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++)
if (write(fd, buf, 512) != 512)
return -EIO;
// Prepare the Dynamic Disk Header
memset(buf, 0, 1024);
strncpy(dyndisk_header->magic, "cxsparse", 8);
dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFF);
dyndisk_header->table_offset = be64_to_cpu(3 * 512);
dyndisk_header->version = be32_to_cpu(0x00010000);
dyndisk_header->block_size = be32_to_cpu(block_size);
dyndisk_header->max_table_entries = be32_to_cpu(num_bat_entries);
dyndisk_header->checksum = be32_to_cpu(vpc_checksum(buf, 1024));
// Write the header
if (lseek(fd, 512, SEEK_SET) < 0)
return -EIO;
if (write(fd, buf, 1024) != 1024)
return -EIO;
close(fd);
return 0;
}
static void vpc_close(BlockDriverState *bs)
{
BDRVVPCState *s = bs->opaque;
qemu_free(s->pagetable);
#ifdef CACHE
qemu_free(s->pageentry_u8);
#endif
bdrv_delete(s->hd);
}
static QEMUOptionParameter vpc_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{ NULL }
};
static BlockDriver bdrv_vpc = {
.format_name = "vpc",
.instance_size = sizeof(BDRVVPCState),
.bdrv_probe = vpc_probe,
.bdrv_open = vpc_open,
.bdrv_read = vpc_read,
.bdrv_write = vpc_write,
.bdrv_close = vpc_close,
.bdrv_create = vpc_create,
.create_options = vpc_create_options,
};
static void bdrv_vpc_init(void)
{
bdrv_register(&bdrv_vpc);
}
block_init(bdrv_vpc_init);

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
/*
* QEMU System Emulator block driver
*
*
* Copyright (c) 2003 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
@@ -24,162 +24,54 @@
#ifndef BLOCK_INT_H
#define BLOCK_INT_H
#include "block.h"
#include "qemu-option.h"
#define BLOCK_FLAG_ENCRYPT 1
#define BLOCK_FLAG_COMPRESS 2
#define BLOCK_FLAG_COMPAT6 4
#define BLOCK_OPT_SIZE "size"
#define BLOCK_OPT_ENCRYPT "encryption"
#define BLOCK_OPT_COMPAT6 "compat6"
#define BLOCK_OPT_BACKING_FILE "backing_file"
#define BLOCK_OPT_BACKING_FMT "backing_fmt"
#define BLOCK_OPT_CLUSTER_SIZE "cluster_size"
typedef struct AIOPool {
void (*cancel)(BlockDriverAIOCB *acb);
int aiocb_size;
BlockDriverAIOCB *free_aiocb;
} AIOPool;
struct BlockDriver {
const char *format_name;
int instance_size;
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
int (*bdrv_probe_device)(const char *filename);
int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
int (*bdrv_open)(BlockDriverState *bs, const char *filename);
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
void (*bdrv_close)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
void (*bdrv_flush)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, int64_t total_sectors,
const char *backing_file, int flags);
int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
int (*bdrv_make_empty)(BlockDriverState *bs);
/* aio */
BlockDriverAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
BlockDriverAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
const char *protocol_name;
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
int64_t (*bdrv_getlength)(BlockDriverState *bs);
int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
int (*bdrv_snapshot_create)(BlockDriverState *bs,
QEMUSnapshotInfo *sn_info);
int (*bdrv_snapshot_goto)(BlockDriverState *bs,
const char *snapshot_id);
int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id);
int (*bdrv_snapshot_list)(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info);
int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
int (*bdrv_save_vmstate)(BlockDriverState *bs, const uint8_t *buf,
int64_t pos, int size);
int (*bdrv_load_vmstate)(BlockDriverState *bs, uint8_t *buf,
int64_t pos, int size);
/* removable device specific */
int (*bdrv_is_inserted)(BlockDriverState *bs);
int (*bdrv_media_changed)(BlockDriverState *bs);
int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
/* to control generic scsi devices */
int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf);
BlockDriverAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs,
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb, void *opaque);
/* List of options for creating images, terminated by name == NULL */
QEMUOptionParameter *create_options;
/* Returns number of errors in image, -errno for internal errors */
int (*bdrv_check)(BlockDriverState* bs);
struct BlockDriver *next;
};
struct BlockDriverState {
int64_t total_sectors; /* if we are reading a disk image, give its
size in sectors */
int64_t total_sectors;
int read_only; /* if true, the media is read only */
int inserted; /* if true, the media is present */
int removable; /* if true, the media can be removed */
int locked; /* if true, the media cannot temporarily be ejected */
int encrypted; /* if true, the media is encrypted */
int valid_key; /* if true, a valid encryption key has been set */
int sg; /* if true, the device is a /dev/sg* */
/* event callback when inserting/removing */
void (*change_cb)(void *opaque);
void *change_opaque;
BlockDriver *drv; /* NULL means no media */
BlockDriver *drv;
void *opaque;
int boot_sector_enabled;
uint8_t boot_sector_data[512];
char filename[1024];
char backing_file[1024]; /* if non zero, the image is a diff of
this file image */
char backing_format[16]; /* if non-zero and backing_file exists */
int is_temporary;
int media_changed;
BlockDriverState *backing_hd;
/* async read/write emulation */
void *sync_aiocb;
/* I/O stats (display with "info blockstats"). */
uint64_t rd_bytes;
uint64_t wr_bytes;
uint64_t rd_ops;
uint64_t wr_ops;
/* Whether the disk can expand beyond total_sectors */
int growable;
/* the memory alignment required for the buffers handled by this driver */
int buffer_alignment;
/* 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];
BlockDriverState *next;
void *private;
};
struct BlockDriverAIOCB {
AIOPool *pool;
BlockDriverState *bs;
BlockDriverCompletionFunc *cb;
void *opaque;
BlockDriverAIOCB *next;
};
void get_tmp_filename(char *filename, int size);
void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque);
void qemu_aio_release(void *p);
void *qemu_blockalign(BlockDriverState *bs, size_t size);
extern BlockDriverState *bdrv_first;
#ifdef _WIN32
int is_windows_drive(const char *filename);
#endif
#endif /* BLOCK_INT_H */

View File

@@ -1,121 +0,0 @@
/*-
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)mman.h 8.2 (Berkeley) 1/9/95
* $FreeBSD: src/sys/sys/mman.h,v 1.42 2008/03/28 04:29:27 ps Exp $
*/
#define TARGET_FREEBSD_MAP_RESERVED0080 0x0080 /* previously misimplemented MAP_INHERIT */
#define TARGET_FREEBSD_MAP_RESERVED0100 0x0100 /* previously unimplemented MAP_NOEXTEND */
#define TARGET_FREEBSD_MAP_STACK 0x0400 /* region grows down, like a stack */
#define TARGET_FREEBSD_MAP_NOSYNC 0x0800 /* page to but do not sync underlying file */
#define TARGET_FREEBSD_MAP_FLAGMASK 0x1ff7
/* $NetBSD: mman.h,v 1.42 2008/11/18 22:13:49 ad Exp $ */
/*-
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)mman.h 8.2 (Berkeley) 1/9/95
*/
#define TARGET_NETBSD_MAP_INHERIT 0x0080 /* region is retained after exec */
#define TARGET_NETBSD_MAP_TRYFIXED 0x0400 /* attempt hint address, even within break */
#define TARGET_NETBSD_MAP_WIRED 0x0800 /* mlock() mapping when it is established */
#define TARGET_NETBSD_MAP_STACK 0x2000 /* allocated from memory, swap space (stack) */
#define TARGET_NETBSD_MAP_FLAGMASK 0x3ff7
/* $OpenBSD: mman.h,v 1.18 2003/07/21 22:52:19 tedu Exp $ */
/* $NetBSD: mman.h,v 1.11 1995/03/26 20:24:23 jtc Exp $ */
/*-
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)mman.h 8.1 (Berkeley) 6/2/93
*/
#define TARGET_OPENBSD_MAP_INHERIT 0x0080 /* region is retained after exec */
#define TARGET_OPENBSD_MAP_NOEXTEND 0x0100 /* for MAP_FILE, don't change file size */
#define TARGET_OPENBSD_MAP_TRYFIXED 0x0400 /* attempt hint address, even within heap */
#define TARGET_OPENBSD_MAP_FLAGMASK 0x17f7
// XXX
#define TARGET_BSD_MAP_FLAGMASK 0x3ff7

View File

@@ -1,204 +0,0 @@
/* Code for loading BSD executables. Mostly linux kernel code. */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "qemu.h"
#define TARGET_NGROUPS 32
/* ??? This should really be somewhere else. */
abi_long memcpy_to_target(abi_ulong dest, const void *src,
unsigned long len)
{
void *host_ptr;
host_ptr = lock_user(VERIFY_WRITE, dest, len, 0);
if (!host_ptr)
return -TARGET_EFAULT;
memcpy(host_ptr, src, len);
unlock_user(host_ptr, dest, 1);
return 0;
}
static int in_group_p(gid_t g)
{
/* return TRUE if we're in the specified group, FALSE otherwise */
int ngroup;
int i;
gid_t grouplist[TARGET_NGROUPS];
ngroup = getgroups(TARGET_NGROUPS, grouplist);
for(i = 0; i < ngroup; i++) {
if(grouplist[i] == g) {
return 1;
}
}
return 0;
}
static int count(char ** vec)
{
int i;
for(i = 0; *vec; i++) {
vec++;
}
return(i);
}
static int prepare_binprm(struct linux_binprm *bprm)
{
struct stat st;
int mode;
int retval, id_change;
if(fstat(bprm->fd, &st) < 0) {
return(-errno);
}
mode = st.st_mode;
if(!S_ISREG(mode)) { /* Must be regular file */
return(-EACCES);
}
if(!(mode & 0111)) { /* Must have at least one execute bit set */
return(-EACCES);
}
bprm->e_uid = geteuid();
bprm->e_gid = getegid();
id_change = 0;
/* Set-uid? */
if(mode & S_ISUID) {
bprm->e_uid = st.st_uid;
if(bprm->e_uid != geteuid()) {
id_change = 1;
}
}
/* Set-gid? */
/*
* If setgid is set but no group execute bit then this
* is a candidate for mandatory locking, not a setgid
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
bprm->e_gid = st.st_gid;
if (!in_group_p(bprm->e_gid)) {
id_change = 1;
}
}
memset(bprm->buf, 0, sizeof(bprm->buf));
retval = lseek(bprm->fd, 0L, SEEK_SET);
if(retval >= 0) {
retval = read(bprm->fd, bprm->buf, 128);
}
if(retval < 0) {
perror("prepare_binprm");
exit(-1);
/* return(-errno); */
}
else {
return(retval);
}
}
/* Construct the envp and argv tables on the target stack. */
abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
abi_ulong stringp, int push_ptr)
{
int n = sizeof(abi_ulong);
abi_ulong envp;
abi_ulong argv;
sp -= (envc + 1) * n;
envp = sp;
sp -= (argc + 1) * n;
argv = sp;
if (push_ptr) {
/* FIXME - handle put_user() failures */
sp -= n;
put_user_ual(envp, sp);
sp -= n;
put_user_ual(argv, sp);
}
sp -= n;
/* FIXME - handle put_user() failures */
put_user_ual(argc, sp);
while (argc-- > 0) {
/* FIXME - handle put_user() failures */
put_user_ual(stringp, argv);
argv += n;
stringp += target_strlen(stringp) + 1;
}
/* FIXME - handle put_user() failures */
put_user_ual(0, argv);
while (envc-- > 0) {
/* FIXME - handle put_user() failures */
put_user_ual(stringp, envp);
envp += n;
stringp += target_strlen(stringp) + 1;
}
/* FIXME - handle put_user() failures */
put_user_ual(0, envp);
return sp;
}
int loader_exec(const char * filename, char ** argv, char ** envp,
struct target_pt_regs * regs, struct image_info *infop)
{
struct linux_binprm bprm;
int retval;
int i;
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;
retval = open(filename, O_RDONLY);
if (retval < 0)
return retval;
bprm.fd = retval;
bprm.filename = (char *)filename;
bprm.argc = count(argv);
bprm.argv = argv;
bprm.envc = count(envp);
bprm.envp = envp;
retval = prepare_binprm(&bprm);
infop->host_argv = argv;
if(retval>=0) {
if (bprm.buf[0] == 0x7f
&& bprm.buf[1] == 'E'
&& bprm.buf[2] == 'L'
&& bprm.buf[3] == 'F') {
retval = load_elf_binary(&bprm,regs,infop);
} else {
fprintf(stderr, "Unknown binary format\n");
return -1;
}
}
if(retval>=0) {
/* success. Initialize important registers */
do_init_thread(regs, infop);
return retval;
}
/* Something went wrong, return the inode and free the argument pages*/
for (i=0 ; i<MAX_ARG_PAGES ; i++) {
free(bprm.page[i]);
}
return(retval);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,149 +0,0 @@
/* $OpenBSD: errno.h,v 1.20 2007/09/03 14:37:52 millert Exp $ */
/* $NetBSD: errno.h,v 1.10 1996/01/20 01:33:53 jtc Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)errno.h 8.5 (Berkeley) 1/21/94
*/
#define TARGET_EPERM 1 /* Operation not permitted */
#define TARGET_ENOENT 2 /* No such file or directory */
#define TARGET_ESRCH 3 /* No such process */
#define TARGET_EINTR 4 /* Interrupted system call */
#define TARGET_EIO 5 /* Input/output error */
#define TARGET_ENXIO 6 /* Device not configured */
#define TARGET_E2BIG 7 /* Argument list too long */
#define TARGET_ENOEXEC 8 /* Exec format error */
#define TARGET_EBADF 9 /* Bad file descriptor */
#define TARGET_ECHILD 10 /* No child processes */
#define TARGET_EDEADLK 11 /* Resource deadlock avoided */
/* 11 was EAGAIN */
#define TARGET_ENOMEM 12 /* Cannot allocate memory */
#define TARGET_EACCES 13 /* Permission denied */
#define TARGET_EFAULT 14 /* Bad address */
#define TARGET_ENOTBLK 15 /* Block device required */
#define TARGET_EBUSY 16 /* Device busy */
#define TARGET_EEXIST 17 /* File exists */
#define TARGET_EXDEV 18 /* Cross-device link */
#define TARGET_ENODEV 19 /* Operation not supported by device */
#define TARGET_ENOTDIR 20 /* Not a directory */
#define TARGET_EISDIR 21 /* Is a directory */
#define TARGET_EINVAL 22 /* Invalid argument */
#define TARGET_ENFILE 23 /* Too many open files in system */
#define TARGET_EMFILE 24 /* Too many open files */
#define TARGET_ENOTTY 25 /* Inappropriate ioctl for device */
#define TARGET_ETXTBSY 26 /* Text file busy */
#define TARGET_EFBIG 27 /* File too large */
#define TARGET_ENOSPC 28 /* No space left on device */
#define TARGET_ESPIPE 29 /* Illegal seek */
#define TARGET_EROFS 30 /* Read-only file system */
#define TARGET_EMLINK 31 /* Too many links */
#define TARGET_EPIPE 32 /* Broken pipe */
/* math software */
#define TARGET_EDOM 33 /* Numerical argument out of domain */
#define TARGET_ERANGE 34 /* Result too large */
/* non-blocking and interrupt i/o */
#define TARGET_EAGAIN 35 /* Resource temporarily unavailable */
#define TARGET_EWOULDBLOCK EAGAIN /* Operation would block */
#define TARGET_EINPROGRESS 36 /* Operation now in progress */
#define TARGET_EALREADY 37 /* Operation already in progress */
/* ipc/network software -- argument errors */
#define TARGET_ENOTSOCK 38 /* Socket operation on non-socket */
#define TARGET_EDESTADDRREQ 39 /* Destination address required */
#define TARGET_EMSGSIZE 40 /* Message too long */
#define TARGET_EPROTOTYPE 41 /* Protocol wrong type for socket */
#define TARGET_ENOPROTOOPT 42 /* Protocol not available */
#define TARGET_EPROTONOSUPPORT 43 /* Protocol not supported */
#define TARGET_ESOCKTNOSUPPORT 44 /* Socket type not supported */
#define TARGET_EOPNOTSUPP 45 /* Operation not supported */
#define TARGET_EPFNOSUPPORT 46 /* Protocol family not supported */
#define TARGET_EAFNOSUPPORT 47 /* Address family not supported by protocol family */
#define TARGET_EADDRINUSE 48 /* Address already in use */
#define TARGET_EADDRNOTAVAIL 49 /* Can't assign requested address */
/* ipc/network software -- operational errors */
#define TARGET_ENETDOWN 50 /* Network is down */
#define TARGET_ENETUNREACH 51 /* Network is unreachable */
#define TARGET_ENETRESET 52 /* Network dropped connection on reset */
#define TARGET_ECONNABORTED 53 /* Software caused connection abort */
#define TARGET_ECONNRESET 54 /* Connection reset by peer */
#define TARGET_ENOBUFS 55 /* No buffer space available */
#define TARGET_EISCONN 56 /* Socket is already connected */
#define TARGET_ENOTCONN 57 /* Socket is not connected */
#define TARGET_ESHUTDOWN 58 /* Can't send after socket shutdown */
#define TARGET_ETOOMANYREFS 59 /* Too many references: can't splice */
#define TARGET_ETIMEDOUT 60 /* Operation timed out */
#define TARGET_ECONNREFUSED 61 /* Connection refused */
#define TARGET_ELOOP 62 /* Too many levels of symbolic links */
#define TARGET_ENAMETOOLONG 63 /* File name too long */
/* should be rearranged */
#define TARGET_EHOSTDOWN 64 /* Host is down */
#define TARGET_EHOSTUNREACH 65 /* No route to host */
#define TARGET_ENOTEMPTY 66 /* Directory not empty */
/* quotas & mush */
#define TARGET_EPROCLIM 67 /* Too many processes */
#define TARGET_EUSERS 68 /* Too many users */
#define TARGET_EDQUOT 69 /* Disk quota exceeded */
/* Network File System */
#define TARGET_ESTALE 70 /* Stale NFS file handle */
#define TARGET_EREMOTE 71 /* Too many levels of remote in path */
#define TARGET_EBADRPC 72 /* RPC struct is bad */
#define TARGET_ERPCMISMATCH 73 /* RPC version wrong */
#define TARGET_EPROGUNAVAIL 74 /* RPC prog. not avail */
#define TARGET_EPROGMISMATCH 75 /* Program version wrong */
#define TARGET_EPROCUNAVAIL 76 /* Bad procedure for program */
#define TARGET_ENOLCK 77 /* No locks available */
#define TARGET_ENOSYS 78 /* Function not implemented */
#define TARGET_EFTYPE 79 /* Inappropriate file type or format */
#define TARGET_EAUTH 80 /* Authentication error */
#define TARGET_ENEEDAUTH 81 /* Need authenticator */
#define TARGET_EIPSEC 82 /* IPsec processing failure */
#define TARGET_ENOATTR 83 /* Attribute not found */
#define TARGET_EILSEQ 84 /* Illegal byte sequence */
#define TARGET_ENOMEDIUM 85 /* No medium found */
#define TARGET_EMEDIUMTYPE 86 /* Wrong Medium Type */
#define TARGET_EOVERFLOW 87 /* Conversion overflow */
#define TARGET_ECANCELED 88 /* Operation canceled */
#define TARGET_EIDRM 89 /* Identifier removed */
#define TARGET_ENOMSG 90 /* No message of desired type */
#define TARGET_ELAST 90 /* Must be equal largest errno */

View File

@@ -1,170 +0,0 @@
{ TARGET_FREEBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR___semctl, "__semctl", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR___syscall, "__syscall", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL },
{ TARGET_FREEBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL },
{ TARGET_FREEBSD_NR_acct, "acct", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_adjtime, "adjtime", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_bind, "bind", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_break, "break", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_chdir, "chdir", "%s(\"%s\")", NULL, NULL },
{ TARGET_FREEBSD_NR_chflags, "chflags", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_chmod, "chmod", "%s(\"%s\",%#o)", NULL, NULL },
{ TARGET_FREEBSD_NR_chown, "chown", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_chroot, "chroot", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_clock_getres, "clock_getres", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_clock_gettime, "clock_gettime", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_clock_settime, "clock_settime", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_close, "close", "%s(%d)", NULL, NULL },
{ TARGET_FREEBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL },
{ TARGET_FREEBSD_NR_dup, "dup", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_dup2, "dup2", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_execve, "execve", NULL, print_execve, NULL },
{ TARGET_FREEBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL },
{ TARGET_FREEBSD_NR_fchdir, "fchdir", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_fchflags, "fchflags", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL },
{ TARGET_FREEBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL },
{ TARGET_FREEBSD_NR_fcntl, "fcntl", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_fhopen, "fhopen", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_fhstat, "fhstat", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_fhstatfs, "fhstatfs", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_flock, "flock", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_fork, "fork", "%s()", NULL, NULL },
{ TARGET_FREEBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%p)", NULL, NULL },
{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%p)", NULL, NULL },
{ TARGET_FREEBSD_NR_fsync, "fsync", NULL, NULL, NULL },
{ 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_getegid, "getegid", "%s()", NULL, NULL },
{ TARGET_FREEBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL },
{ TARGET_FREEBSD_NR_getfh, "getfh", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getfsstat, "getfsstat", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getgid, "getgid", "%s()", NULL, NULL },
{ TARGET_FREEBSD_NR_getgroups, "getgroups", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getitimer, "getitimer", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getlogin, "getlogin", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getpeername, "getpeername", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getpgid, "getpgid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getpgrp, "getpgrp", "%s()", NULL, NULL },
{ TARGET_FREEBSD_NR_getpid, "getpid", "%s()", NULL, NULL },
{ TARGET_FREEBSD_NR_getppid, "getppid", "%s()", NULL, NULL },
{ TARGET_FREEBSD_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL },
{ TARGET_FREEBSD_NR_getresgid, "getresgid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getresuid, "getresuid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getrlimit, "getrlimit", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getrusage, "getrusage", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getsid, "getsid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getsockname, "getsockname", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getuid, "getuid", "%s()", NULL, NULL },
{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL },
{ TARGET_FREEBSD_NR_kevent, "kevent", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_kill, "kill", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_kqueue, "kqueue", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_ktrace, "ktrace", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_lchown, "lchown", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL },
{ TARGET_FREEBSD_NR_listen, "listen", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_lseek, "lseek", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_lstat, "lstat", "%s(\"%s\",%p)", NULL, NULL },
{ TARGET_FREEBSD_NR_madvise, "madvise", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_mincore, "mincore", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_minherit, "minherit", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_mkdir, "mkdir", "%s(\"%s\",%#o)", NULL, NULL },
{ TARGET_FREEBSD_NR_mkfifo, "mkfifo", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_mknod, "mknod", "%s(\"%s\",%#o,%#x)", NULL, NULL },
{ TARGET_FREEBSD_NR_mlock, "mlock", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_mlockall, "mlockall", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_mmap, "mmap", NULL, NULL, print_syscall_ret_addr },
{ TARGET_FREEBSD_NR_mount, "mount", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_mprotect, "mprotect", "%s(%#x,%#x,%d)", NULL, NULL },
{ TARGET_FREEBSD_NR_msgctl, "msgctl", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_msgget, "msgget", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_msgrcv, "msgrcv", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_msgsnd, "msgsnd", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_msync, "msync", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_munlock, "munlock", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_munlockall, "munlockall", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_munmap, "munmap", "%s(%p,%d)", NULL, NULL },
{ TARGET_FREEBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL },
{ TARGET_FREEBSD_NR_pathconf, "pathconf", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_pipe, "pipe", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_poll, "poll", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_pread, "pread", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_preadv, "preadv", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_profil, "profil", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_ptrace, "ptrace", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_pwrite, "pwrite", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_pwritev, "pwritev", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_quotactl, "quotactl", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_read, "read", "%s(%d,%#x,%d)", NULL, NULL },
{ TARGET_FREEBSD_NR_readlink, "readlink", "%s(\"%s\",%p,%d)", NULL, NULL },
{ TARGET_FREEBSD_NR_readv, "readv", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_reboot, "reboot", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_recvfrom, "recvfrom", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_recvmsg, "recvmsg", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_rename, "rename", "%s(\"%s\",\"%s\")", NULL, NULL },
{ TARGET_FREEBSD_NR_revoke, "revoke", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_rfork, "rfork", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_rmdir, "rmdir", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_sbrk, "sbrk", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_select, "select", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_semget, "semget", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_semop, "semop", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_sendto, "sendto", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setegid, "setegid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_seteuid, "seteuid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setgid, "setgid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setgroups, "setgroups", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setitimer, "setitimer", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setlogin, "setlogin", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setpgid, "setpgid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setpriority, "setpriority", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setregid, "setregid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setresgid, "setresgid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setresuid, "setresuid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setreuid, "setreuid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setrlimit, "setrlimit", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setsid, "setsid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setsockopt, "setsockopt", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_settimeofday, "settimeofday", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_setuid, "setuid", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_shmat, "shmat", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_shmctl, "shmctl", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_shmdt, "shmdt", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_shmget, "shmget", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_shutdown, "shutdown", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_sigaction, "sigaction", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_sigaltstack, "sigaltstack", "%s(%p,%p)", NULL, NULL },
{ TARGET_FREEBSD_NR_sigpending, "sigpending", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_sigprocmask, "sigprocmask", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_sigreturn, "sigreturn", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_sigsuspend, "sigsuspend", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_socket, "socket", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_socketpair, "socketpair", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_sstk, "sstk", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_stat, "stat", "%s(\"%s\",%p)", NULL, NULL },
{ TARGET_FREEBSD_NR_statfs, "statfs", "%s(\"%s\",%p)", NULL, NULL },
{ TARGET_FREEBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL },
{ TARGET_FREEBSD_NR_sync, "sync", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_syscall, "syscall", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_truncate, "truncate", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL },
{ TARGET_FREEBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL },
{ TARGET_FREEBSD_NR_unmount, "unmount", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_utimes, "utimes", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_vfork, "vfork", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_wait4, "wait4", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_write, "write", "%s(%d,%#x,%d)", NULL, NULL },
{ TARGET_FREEBSD_NR_writev, "writev", "%s(%d,%p,%#x)", NULL, NULL },

View File

@@ -1,373 +0,0 @@
/*
* System call numbers.
*
* $FreeBSD: src/sys/sys/syscall.h,v 1.224 2008/08/24 21:23:08 rwatson Exp $
* created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson
*/
#define TARGET_FREEBSD_NR_syscall 0
#define TARGET_FREEBSD_NR_exit 1
#define TARGET_FREEBSD_NR_fork 2
#define TARGET_FREEBSD_NR_read 3
#define TARGET_FREEBSD_NR_write 4
#define TARGET_FREEBSD_NR_open 5
#define TARGET_FREEBSD_NR_close 6
#define TARGET_FREEBSD_NR_wait4 7
#define TARGET_FREEBSD_NR_link 9
#define TARGET_FREEBSD_NR_unlink 10
#define TARGET_FREEBSD_NR_chdir 12
#define TARGET_FREEBSD_NR_fchdir 13
#define TARGET_FREEBSD_NR_mknod 14
#define TARGET_FREEBSD_NR_chmod 15
#define TARGET_FREEBSD_NR_chown 16
#define TARGET_FREEBSD_NR_break 17
#define TARGET_FREEBSD_NR_freebsd4_getfsstat 18
#define TARGET_FREEBSD_NR_getpid 20
#define TARGET_FREEBSD_NR_mount 21
#define TARGET_FREEBSD_NR_unmount 22
#define TARGET_FREEBSD_NR_setuid 23
#define TARGET_FREEBSD_NR_getuid 24
#define TARGET_FREEBSD_NR_geteuid 25
#define TARGET_FREEBSD_NR_ptrace 26
#define TARGET_FREEBSD_NR_recvmsg 27
#define TARGET_FREEBSD_NR_sendmsg 28
#define TARGET_FREEBSD_NR_recvfrom 29
#define TARGET_FREEBSD_NR_accept 30
#define TARGET_FREEBSD_NR_getpeername 31
#define TARGET_FREEBSD_NR_getsockname 32
#define TARGET_FREEBSD_NR_access 33
#define TARGET_FREEBSD_NR_chflags 34
#define TARGET_FREEBSD_NR_fchflags 35
#define TARGET_FREEBSD_NR_sync 36
#define TARGET_FREEBSD_NR_kill 37
#define TARGET_FREEBSD_NR_getppid 39
#define TARGET_FREEBSD_NR_dup 41
#define TARGET_FREEBSD_NR_pipe 42
#define TARGET_FREEBSD_NR_getegid 43
#define TARGET_FREEBSD_NR_profil 44
#define TARGET_FREEBSD_NR_ktrace 45
#define TARGET_FREEBSD_NR_getgid 47
#define TARGET_FREEBSD_NR_getlogin 49
#define TARGET_FREEBSD_NR_setlogin 50
#define TARGET_FREEBSD_NR_acct 51
#define TARGET_FREEBSD_NR_sigaltstack 53
#define TARGET_FREEBSD_NR_ioctl 54
#define TARGET_FREEBSD_NR_reboot 55
#define TARGET_FREEBSD_NR_revoke 56
#define TARGET_FREEBSD_NR_symlink 57
#define TARGET_FREEBSD_NR_readlink 58
#define TARGET_FREEBSD_NR_execve 59
#define TARGET_FREEBSD_NR_umask 60
#define TARGET_FREEBSD_NR_chroot 61
#define TARGET_FREEBSD_NR_msync 65
#define TARGET_FREEBSD_NR_vfork 66
#define TARGET_FREEBSD_NR_sbrk 69
#define TARGET_FREEBSD_NR_sstk 70
#define TARGET_FREEBSD_NR_vadvise 72
#define TARGET_FREEBSD_NR_munmap 73
#define TARGET_FREEBSD_NR_mprotect 74
#define TARGET_FREEBSD_NR_madvise 75
#define TARGET_FREEBSD_NR_mincore 78
#define TARGET_FREEBSD_NR_getgroups 79
#define TARGET_FREEBSD_NR_setgroups 80
#define TARGET_FREEBSD_NR_getpgrp 81
#define TARGET_FREEBSD_NR_setpgid 82
#define TARGET_FREEBSD_NR_setitimer 83
#define TARGET_FREEBSD_NR_swapon 85
#define TARGET_FREEBSD_NR_getitimer 86
#define TARGET_FREEBSD_NR_getdtablesize 89
#define TARGET_FREEBSD_NR_dup2 90
#define TARGET_FREEBSD_NR_fcntl 92
#define TARGET_FREEBSD_NR_select 93
#define TARGET_FREEBSD_NR_fsync 95
#define TARGET_FREEBSD_NR_setpriority 96
#define TARGET_FREEBSD_NR_socket 97
#define TARGET_FREEBSD_NR_connect 98
#define TARGET_FREEBSD_NR_getpriority 100
#define TARGET_FREEBSD_NR_bind 104
#define TARGET_FREEBSD_NR_setsockopt 105
#define TARGET_FREEBSD_NR_listen 106
#define TARGET_FREEBSD_NR_gettimeofday 116
#define TARGET_FREEBSD_NR_getrusage 117
#define TARGET_FREEBSD_NR_getsockopt 118
#define TARGET_FREEBSD_NR_readv 120
#define TARGET_FREEBSD_NR_writev 121
#define TARGET_FREEBSD_NR_settimeofday 122
#define TARGET_FREEBSD_NR_fchown 123
#define TARGET_FREEBSD_NR_fchmod 124
#define TARGET_FREEBSD_NR_setreuid 126
#define TARGET_FREEBSD_NR_setregid 127
#define TARGET_FREEBSD_NR_rename 128
#define TARGET_FREEBSD_NR_flock 131
#define TARGET_FREEBSD_NR_mkfifo 132
#define TARGET_FREEBSD_NR_sendto 133
#define TARGET_FREEBSD_NR_shutdown 134
#define TARGET_FREEBSD_NR_socketpair 135
#define TARGET_FREEBSD_NR_mkdir 136
#define TARGET_FREEBSD_NR_rmdir 137
#define TARGET_FREEBSD_NR_utimes 138
#define TARGET_FREEBSD_NR_adjtime 140
#define TARGET_FREEBSD_NR_setsid 147
#define TARGET_FREEBSD_NR_quotactl 148
#define TARGET_FREEBSD_NR_nlm_syscall 154
#define TARGET_FREEBSD_NR_nfssvc 155
#define TARGET_FREEBSD_NR_freebsd4_statfs 157
#define TARGET_FREEBSD_NR_freebsd4_fstatfs 158
#define TARGET_FREEBSD_NR_lgetfh 160
#define TARGET_FREEBSD_NR_getfh 161
#define TARGET_FREEBSD_NR_getdomainname 162
#define TARGET_FREEBSD_NR_setdomainname 163
#define TARGET_FREEBSD_NR_uname 164
#define TARGET_FREEBSD_NR_sysarch 165
#define TARGET_FREEBSD_NR_rtprio 166
#define TARGET_FREEBSD_NR_semsys 169
#define TARGET_FREEBSD_NR_msgsys 170
#define TARGET_FREEBSD_NR_shmsys 171
#define TARGET_FREEBSD_NR_freebsd6_pread 173
#define TARGET_FREEBSD_NR_freebsd6_pwrite 174
#define TARGET_FREEBSD_NR_setfib 175
#define TARGET_FREEBSD_NR_ntp_adjtime 176
#define TARGET_FREEBSD_NR_setgid 181
#define TARGET_FREEBSD_NR_setegid 182
#define TARGET_FREEBSD_NR_seteuid 183
#define TARGET_FREEBSD_NR_stat 188
#define TARGET_FREEBSD_NR_fstat 189
#define TARGET_FREEBSD_NR_lstat 190
#define TARGET_FREEBSD_NR_pathconf 191
#define TARGET_FREEBSD_NR_fpathconf 192
#define TARGET_FREEBSD_NR_getrlimit 194
#define TARGET_FREEBSD_NR_setrlimit 195
#define TARGET_FREEBSD_NR_getdirentries 196
#define TARGET_FREEBSD_NR_freebsd6_mmap 197
#define TARGET_FREEBSD_NR___syscall 198
#define TARGET_FREEBSD_NR_freebsd6_lseek 199
#define TARGET_FREEBSD_NR_freebsd6_truncate 200
#define TARGET_FREEBSD_NR_freebsd6_ftruncate 201
#define TARGET_FREEBSD_NR___sysctl 202
#define TARGET_FREEBSD_NR_mlock 203
#define TARGET_FREEBSD_NR_munlock 204
#define TARGET_FREEBSD_NR_undelete 205
#define TARGET_FREEBSD_NR_futimes 206
#define TARGET_FREEBSD_NR_getpgid 207
#define TARGET_FREEBSD_NR_poll 209
#define TARGET_FREEBSD_NR___semctl 220
#define TARGET_FREEBSD_NR_semget 221
#define TARGET_FREEBSD_NR_semop 222
#define TARGET_FREEBSD_NR_msgctl 224
#define TARGET_FREEBSD_NR_msgget 225
#define TARGET_FREEBSD_NR_msgsnd 226
#define TARGET_FREEBSD_NR_msgrcv 227
#define TARGET_FREEBSD_NR_shmat 228
#define TARGET_FREEBSD_NR_shmctl 229
#define TARGET_FREEBSD_NR_shmdt 230
#define TARGET_FREEBSD_NR_shmget 231
#define TARGET_FREEBSD_NR_clock_gettime 232
#define TARGET_FREEBSD_NR_clock_settime 233
#define TARGET_FREEBSD_NR_clock_getres 234
#define TARGET_FREEBSD_NR_ktimer_create 235
#define TARGET_FREEBSD_NR_ktimer_delete 236
#define TARGET_FREEBSD_NR_ktimer_settime 237
#define TARGET_FREEBSD_NR_ktimer_gettime 238
#define TARGET_FREEBSD_NR_ktimer_getoverrun 239
#define TARGET_FREEBSD_NR_nanosleep 240
#define TARGET_FREEBSD_NR_ntp_gettime 248
#define TARGET_FREEBSD_NR_minherit 250
#define TARGET_FREEBSD_NR_rfork 251
#define TARGET_FREEBSD_NR_openbsd_poll 252
#define TARGET_FREEBSD_NR_issetugid 253
#define TARGET_FREEBSD_NR_lchown 254
#define TARGET_FREEBSD_NR_aio_read 255
#define TARGET_FREEBSD_NR_aio_write 256
#define TARGET_FREEBSD_NR_lio_listio 257
#define TARGET_FREEBSD_NR_getdents 272
#define TARGET_FREEBSD_NR_lchmod 274
#define TARGET_FREEBSD_NR_netbsd_lchown 275
#define TARGET_FREEBSD_NR_lutimes 276
#define TARGET_FREEBSD_NR_netbsd_msync 277
#define TARGET_FREEBSD_NR_nstat 278
#define TARGET_FREEBSD_NR_nfstat 279
#define TARGET_FREEBSD_NR_nlstat 280
#define TARGET_FREEBSD_NR_preadv 289
#define TARGET_FREEBSD_NR_pwritev 290
#define TARGET_FREEBSD_NR_freebsd4_fhstatfs 297
#define TARGET_FREEBSD_NR_fhopen 298
#define TARGET_FREEBSD_NR_fhstat 299
#define TARGET_FREEBSD_NR_modnext 300
#define TARGET_FREEBSD_NR_modstat 301
#define TARGET_FREEBSD_NR_modfnext 302
#define TARGET_FREEBSD_NR_modfind 303
#define TARGET_FREEBSD_NR_kldload 304
#define TARGET_FREEBSD_NR_kldunload 305
#define TARGET_FREEBSD_NR_kldfind 306
#define TARGET_FREEBSD_NR_kldnext 307
#define TARGET_FREEBSD_NR_kldstat 308
#define TARGET_FREEBSD_NR_kldfirstmod 309
#define TARGET_FREEBSD_NR_getsid 310
#define TARGET_FREEBSD_NR_setresuid 311
#define TARGET_FREEBSD_NR_setresgid 312
#define TARGET_FREEBSD_NR_aio_return 314
#define TARGET_FREEBSD_NR_aio_suspend 315
#define TARGET_FREEBSD_NR_aio_cancel 316
#define TARGET_FREEBSD_NR_aio_error 317
#define TARGET_FREEBSD_NR_oaio_read 318
#define TARGET_FREEBSD_NR_oaio_write 319
#define TARGET_FREEBSD_NR_olio_listio 320
#define TARGET_FREEBSD_NR_yield 321
#define TARGET_FREEBSD_NR_mlockall 324
#define TARGET_FREEBSD_NR_munlockall 325
#define TARGET_FREEBSD_NR___getcwd 326
#define TARGET_FREEBSD_NR_sched_setparam 327
#define TARGET_FREEBSD_NR_sched_getparam 328
#define TARGET_FREEBSD_NR_sched_setscheduler 329
#define TARGET_FREEBSD_NR_sched_getscheduler 330
#define TARGET_FREEBSD_NR_sched_yield 331
#define TARGET_FREEBSD_NR_sched_get_priority_max 332
#define TARGET_FREEBSD_NR_sched_get_priority_min 333
#define TARGET_FREEBSD_NR_sched_rr_get_interval 334
#define TARGET_FREEBSD_NR_utrace 335
#define TARGET_FREEBSD_NR_freebsd4_sendfile 336
#define TARGET_FREEBSD_NR_kldsym 337
#define TARGET_FREEBSD_NR_jail 338
#define TARGET_FREEBSD_NR_sigprocmask 340
#define TARGET_FREEBSD_NR_sigsuspend 341
#define TARGET_FREEBSD_NR_freebsd4_sigaction 342
#define TARGET_FREEBSD_NR_sigpending 343
#define TARGET_FREEBSD_NR_freebsd4_sigreturn 344
#define TARGET_FREEBSD_NR_sigtimedwait 345
#define TARGET_FREEBSD_NR_sigwaitinfo 346
#define TARGET_FREEBSD_NR___acl_get_file 347
#define TARGET_FREEBSD_NR___acl_set_file 348
#define TARGET_FREEBSD_NR___acl_get_fd 349
#define TARGET_FREEBSD_NR___acl_set_fd 350
#define TARGET_FREEBSD_NR___acl_delete_file 351
#define TARGET_FREEBSD_NR___acl_delete_fd 352
#define TARGET_FREEBSD_NR___acl_aclcheck_file 353
#define TARGET_FREEBSD_NR___acl_aclcheck_fd 354
#define TARGET_FREEBSD_NR_extattrctl 355
#define TARGET_FREEBSD_NR_extattr_set_file 356
#define TARGET_FREEBSD_NR_extattr_get_file 357
#define TARGET_FREEBSD_NR_extattr_delete_file 358
#define TARGET_FREEBSD_NR_aio_waitcomplete 359
#define TARGET_FREEBSD_NR_getresuid 360
#define TARGET_FREEBSD_NR_getresgid 361
#define TARGET_FREEBSD_NR_kqueue 362
#define TARGET_FREEBSD_NR_kevent 363
#define TARGET_FREEBSD_NR_extattr_set_fd 371
#define TARGET_FREEBSD_NR_extattr_get_fd 372
#define TARGET_FREEBSD_NR_extattr_delete_fd 373
#define TARGET_FREEBSD_NR___setugid 374
#define TARGET_FREEBSD_NR_nfsclnt 375
#define TARGET_FREEBSD_NR_eaccess 376
#define TARGET_FREEBSD_NR_nmount 378
#define TARGET_FREEBSD_NR___mac_get_proc 384
#define TARGET_FREEBSD_NR___mac_set_proc 385
#define TARGET_FREEBSD_NR___mac_get_fd 386
#define TARGET_FREEBSD_NR___mac_get_file 387
#define TARGET_FREEBSD_NR___mac_set_fd 388
#define TARGET_FREEBSD_NR___mac_set_file 389
#define TARGET_FREEBSD_NR_kenv 390
#define TARGET_FREEBSD_NR_lchflags 391
#define TARGET_FREEBSD_NR_uuidgen 392
#define TARGET_FREEBSD_NR_sendfile 393
#define TARGET_FREEBSD_NR_mac_syscall 394
#define TARGET_FREEBSD_NR_getfsstat 395
#define TARGET_FREEBSD_NR_statfs 396
#define TARGET_FREEBSD_NR_fstatfs 397
#define TARGET_FREEBSD_NR_fhstatfs 398
#define TARGET_FREEBSD_NR_ksem_close 400
#define TARGET_FREEBSD_NR_ksem_post 401
#define TARGET_FREEBSD_NR_ksem_wait 402
#define TARGET_FREEBSD_NR_ksem_trywait 403
#define TARGET_FREEBSD_NR_ksem_init 404
#define TARGET_FREEBSD_NR_ksem_open 405
#define TARGET_FREEBSD_NR_ksem_unlink 406
#define TARGET_FREEBSD_NR_ksem_getvalue 407
#define TARGET_FREEBSD_NR_ksem_destroy 408
#define TARGET_FREEBSD_NR___mac_get_pid 409
#define TARGET_FREEBSD_NR___mac_get_link 410
#define TARGET_FREEBSD_NR___mac_set_link 411
#define TARGET_FREEBSD_NR_extattr_set_link 412
#define TARGET_FREEBSD_NR_extattr_get_link 413
#define TARGET_FREEBSD_NR_extattr_delete_link 414
#define TARGET_FREEBSD_NR___mac_execve 415
#define TARGET_FREEBSD_NR_sigaction 416
#define TARGET_FREEBSD_NR_sigreturn 417
#define TARGET_FREEBSD_NR_getcontext 421
#define TARGET_FREEBSD_NR_setcontext 422
#define TARGET_FREEBSD_NR_swapcontext 423
#define TARGET_FREEBSD_NR_swapoff 424
#define TARGET_FREEBSD_NR___acl_get_link 425
#define TARGET_FREEBSD_NR___acl_set_link 426
#define TARGET_FREEBSD_NR___acl_delete_link 427
#define TARGET_FREEBSD_NR___acl_aclcheck_link 428
#define TARGET_FREEBSD_NR_sigwait 429
#define TARGET_FREEBSD_NR_thr_create 430
#define TARGET_FREEBSD_NR_thr_exit 431
#define TARGET_FREEBSD_NR_thr_self 432
#define TARGET_FREEBSD_NR_thr_kill 433
#define TARGET_FREEBSD_NR__umtx_lock 434
#define TARGET_FREEBSD_NR__umtx_unlock 435
#define TARGET_FREEBSD_NR_jail_attach 436
#define TARGET_FREEBSD_NR_extattr_list_fd 437
#define TARGET_FREEBSD_NR_extattr_list_file 438
#define TARGET_FREEBSD_NR_extattr_list_link 439
#define TARGET_FREEBSD_NR_ksem_timedwait 441
#define TARGET_FREEBSD_NR_thr_suspend 442
#define TARGET_FREEBSD_NR_thr_wake 443
#define TARGET_FREEBSD_NR_kldunloadf 444
#define TARGET_FREEBSD_NR_audit 445
#define TARGET_FREEBSD_NR_auditon 446
#define TARGET_FREEBSD_NR_getauid 447
#define TARGET_FREEBSD_NR_setauid 448
#define TARGET_FREEBSD_NR_getaudit 449
#define TARGET_FREEBSD_NR_setaudit 450
#define TARGET_FREEBSD_NR_getaudit_addr 451
#define TARGET_FREEBSD_NR_setaudit_addr 452
#define TARGET_FREEBSD_NR_auditctl 453
#define TARGET_FREEBSD_NR__umtx_op 454
#define TARGET_FREEBSD_NR_thr_new 455
#define TARGET_FREEBSD_NR_sigqueue 456
#define TARGET_FREEBSD_NR_kmq_open 457
#define TARGET_FREEBSD_NR_kmq_setattr 458
#define TARGET_FREEBSD_NR_kmq_timedreceive 459
#define TARGET_FREEBSD_NR_kmq_timedsend 460
#define TARGET_FREEBSD_NR_kmq_notify 461
#define TARGET_FREEBSD_NR_kmq_unlink 462
#define TARGET_FREEBSD_NR_abort2 463
#define TARGET_FREEBSD_NR_thr_set_name 464
#define TARGET_FREEBSD_NR_aio_fsync 465
#define TARGET_FREEBSD_NR_rtprio_thread 466
#define TARGET_FREEBSD_NR_sctp_peeloff 471
#define TARGET_FREEBSD_NR_sctp_generic_sendmsg 472
#define TARGET_FREEBSD_NR_sctp_generic_sendmsg_iov 473
#define TARGET_FREEBSD_NR_sctp_generic_recvmsg 474
#define TARGET_FREEBSD_NR_pread 475
#define TARGET_FREEBSD_NR_pwrite 476
#define TARGET_FREEBSD_NR_mmap 477
#define TARGET_FREEBSD_NR_lseek 478
#define TARGET_FREEBSD_NR_truncate 479
#define TARGET_FREEBSD_NR_ftruncate 480
#define TARGET_FREEBSD_NR_thr_kill2 481
#define TARGET_FREEBSD_NR_shm_open 482
#define TARGET_FREEBSD_NR_shm_unlink 483
#define TARGET_FREEBSD_NR_cpuset 484
#define TARGET_FREEBSD_NR_cpuset_setid 485
#define TARGET_FREEBSD_NR_cpuset_getid 486
#define TARGET_FREEBSD_NR_cpuset_getaffinity 487
#define TARGET_FREEBSD_NR_cpuset_setaffinity 488
#define TARGET_FREEBSD_NR_faccessat 489
#define TARGET_FREEBSD_NR_fchmodat 490
#define TARGET_FREEBSD_NR_fchownat 491
#define TARGET_FREEBSD_NR_fexecve 492
#define TARGET_FREEBSD_NR_fstatat 493
#define TARGET_FREEBSD_NR_futimesat 494
#define TARGET_FREEBSD_NR_linkat 495
#define TARGET_FREEBSD_NR_mkdirat 496
#define TARGET_FREEBSD_NR_mkfifoat 497
#define TARGET_FREEBSD_NR_mknodat 498
#define TARGET_FREEBSD_NR_openat 499
#define TARGET_FREEBSD_NR_readlinkat 500
#define TARGET_FREEBSD_NR_renameat 501
#define TARGET_FREEBSD_NR_symlinkat 502
#define TARGET_FREEBSD_NR_unlinkat 503
#define TARGET_FREEBSD_NR_posix_openpt 504

View File

@@ -1,147 +0,0 @@
/* default linux values for the selectors */
#define __USER_CS (0x23)
#define __USER_DS (0x2B)
struct target_pt_regs {
long ebx;
long ecx;
long edx;
long esi;
long edi;
long ebp;
long eax;
int xds;
int xes;
long orig_eax;
long eip;
int xcs;
long eflags;
long esp;
int xss;
};
/* ioctls */
#define TARGET_LDT_ENTRIES 8192
#define TARGET_LDT_ENTRY_SIZE 8
#define TARGET_GDT_ENTRIES 9
#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
#define TARGET_GDT_ENTRY_TLS_MIN 6
#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1)
struct target_modify_ldt_ldt_s {
unsigned int entry_number;
abi_ulong base_addr;
unsigned int limit;
unsigned int flags;
};
/* vm86 defines */
#define TARGET_BIOSSEG 0x0f000
#define TARGET_CPU_086 0
#define TARGET_CPU_186 1
#define TARGET_CPU_286 2
#define TARGET_CPU_386 3
#define TARGET_CPU_486 4
#define TARGET_CPU_586 5
#define TARGET_VM86_SIGNAL 0 /* return due to signal */
#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */
#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */
#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */
/*
* Additional return values when invoking new vm86()
*/
#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */
#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */
/*
* function codes when invoking new vm86()
*/
#define TARGET_VM86_PLUS_INSTALL_CHECK 0
#define TARGET_VM86_ENTER 1
#define TARGET_VM86_ENTER_NO_BYPASS 2
#define TARGET_VM86_REQUEST_IRQ 3
#define TARGET_VM86_FREE_IRQ 4
#define TARGET_VM86_GET_IRQ_BITS 5
#define TARGET_VM86_GET_AND_RESET_IRQ 6
/*
* This is the stack-layout seen by the user space program when we have
* done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout
* is 'kernel_vm86_regs' (see below).
*/
struct target_vm86_regs {
/*
* normal regs, with special meaning for the segment descriptors..
*/
abi_long ebx;
abi_long ecx;
abi_long edx;
abi_long esi;
abi_long edi;
abi_long ebp;
abi_long eax;
abi_long __null_ds;
abi_long __null_es;
abi_long __null_fs;
abi_long __null_gs;
abi_long orig_eax;
abi_long eip;
unsigned short cs, __csh;
abi_long eflags;
abi_long esp;
unsigned short ss, __ssh;
/*
* these are specific to v86 mode:
*/
unsigned short es, __esh;
unsigned short ds, __dsh;
unsigned short fs, __fsh;
unsigned short gs, __gsh;
};
struct target_revectored_struct {
abi_ulong __map[8]; /* 256 bits */
};
struct target_vm86_struct {
struct target_vm86_regs regs;
abi_ulong flags;
abi_ulong screen_bitmap;
abi_ulong cpu_type;
struct target_revectored_struct int_revectored;
struct target_revectored_struct int21_revectored;
};
/*
* flags masks
*/
#define TARGET_VM86_SCREEN_BITMAP 0x0001
struct target_vm86plus_info_struct {
abi_ulong flags;
#define TARGET_force_return_for_pic (1 << 0)
#define TARGET_vm86dbg_active (1 << 1) /* for debugger */
#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */
#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */
unsigned char vm86dbg_intxxtab[32]; /* for debugger */
};
struct target_vm86plus_struct {
struct target_vm86_regs regs;
abi_ulong flags;
abi_ulong screen_bitmap;
abi_ulong cpu_type;
struct target_revectored_struct int_revectored;
struct target_revectored_struct int21_revectored;
struct target_vm86plus_info_struct vm86plus;
};
#define UNAME_MACHINE "i386"

View File

@@ -1,20 +0,0 @@
#ifndef TARGET_SIGNAL_H
#define TARGET_SIGNAL_H
#include "cpu.h"
/* this struct defines a stack used during syscall handling */
typedef struct target_sigaltstack {
abi_ulong ss_sp;
abi_long ss_flags;
abi_ulong ss_size;
} target_stack_t;
static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
{
return state->regs[R_ESP];
}
#endif /* TARGET_SIGNAL_H */

View File

@@ -1,976 +0,0 @@
/*
* qemu user main
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <machine/trap.h>
#include <sys/types.h>
#include <sys/mman.h>
#include "qemu.h"
#include "qemu-common.h"
/* For tb_lock */
#include "exec-all.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
int singlestep;
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
extern char **environ;
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
by remapping the process stack directly at the right place */
unsigned long x86_stack_size = 512 * 1024;
void gemu_log(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
#if defined(TARGET_I386)
int cpu_get_pic_interrupt(CPUState *env)
{
return -1;
}
#endif
/* These are no-ops because we are not threadsafe. */
static inline void cpu_exec_start(CPUState *env)
{
}
static inline void cpu_exec_end(CPUState *env)
{
}
static inline void start_exclusive(void)
{
}
static inline void end_exclusive(void)
{
}
void fork_start(void)
{
}
void fork_end(int child)
{
if (child) {
gdbserver_fork(thread_env);
}
}
void cpu_list_lock(void)
{
}
void cpu_list_unlock(void)
{
}
#ifdef TARGET_I386
/***********************************************************/
/* CPUX86 core interface */
void cpu_smm_update(CPUState *env)
{
}
uint64_t cpu_get_tsc(CPUX86State *env)
{
return cpu_get_real_ticks();
}
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
int flags)
{
unsigned int e1, e2;
uint32_t *p;
e1 = (addr << 16) | (limit & 0xffff);
e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
e2 |= flags;
p = ptr;
p[0] = tswap32(e1);
p[1] = tswap32(e2);
}
static uint64_t *idt_table;
#ifdef TARGET_X86_64
static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
uint64_t addr, unsigned int sel)
{
uint32_t *p, e1, e2;
e1 = (addr & 0xffff) | (sel << 16);
e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
p = ptr;
p[0] = tswap32(e1);
p[1] = tswap32(e2);
p[2] = tswap32(addr >> 32);
p[3] = 0;
}
/* only dpl matters as we do only user space emulation */
static void set_idt(int n, unsigned int dpl)
{
set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
}
#else
static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
uint32_t addr, unsigned int sel)
{
uint32_t *p, e1, e2;
e1 = (addr & 0xffff) | (sel << 16);
e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
p = ptr;
p[0] = tswap32(e1);
p[1] = tswap32(e2);
}
/* only dpl matters as we do only user space emulation */
static void set_idt(int n, unsigned int dpl)
{
set_gate(idt_table + n, 0, dpl, 0, 0);
}
#endif
void cpu_loop(CPUX86State *env, enum BSDType bsd_type)
{
int trapnr;
abi_ulong pc;
//target_siginfo_t info;
for(;;) {
trapnr = cpu_x86_exec(env);
switch(trapnr) {
case 0x80:
/* syscall from int $0x80 */
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:
/* 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;
break;
#endif
#if 0
case EXCP0B_NOSEG:
case EXCP0C_STACK:
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
queue_signal(env, info.si_signo, &info);
break;
case EXCP0D_GPF:
/* XXX: potential problem if ABI32 */
#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_fault(env);
} else
#endif
{
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
queue_signal(env, info.si_signo, &info);
}
break;
case EXCP0E_PAGE:
info.si_signo = SIGSEGV;
info.si_errno = 0;
if (!(env->error_code & 1))
info.si_code = TARGET_SEGV_MAPERR;
else
info.si_code = TARGET_SEGV_ACCERR;
info._sifields._sigfault._addr = env->cr[2];
queue_signal(env, info.si_signo, &info);
break;
case EXCP00_DIVZ:
#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
} else
#endif
{
/* division by zero */
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_code = TARGET_FPE_INTDIV;
info._sifields._sigfault._addr = env->eip;
queue_signal(env, info.si_signo, &info);
}
break;
case EXCP01_DB:
case EXCP03_INT3:
#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
} else
#endif
{
info.si_signo = SIGTRAP;
info.si_errno = 0;
if (trapnr == EXCP01_DB) {
info.si_code = TARGET_TRAP_BRKPT;
info._sifields._sigfault._addr = env->eip;
} else {
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
}
queue_signal(env, info.si_signo, &info);
}
break;
case EXCP04_INTO:
case EXCP05_BOUND:
#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
} else
#endif
{
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
queue_signal(env, info.si_signo, &info);
}
break;
case EXCP06_ILLOP:
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->eip;
queue_signal(env, info.si_signo, &info);
break;
#endif
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
#if 0
case EXCP_DEBUG:
{
int sig;
sig = gdb_handlesig (env, TARGET_SIGTRAP);
if (sig)
{
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
queue_signal(env, info.si_signo, &info);
}
}
break;
#endif
default:
pc = env->segs[R_CS].base + env->eip;
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
(long)pc, trapnr);
abort();
}
process_pending_signals(env);
}
}
#endif
#ifdef TARGET_SPARC
#define SPARC64_STACK_BIAS 2047
//#define DEBUG_WIN
/* WARNING: dealing with register windows _is_ complicated. More info
can be found at http://www.sics.se/~psm/sparcstack.html */
static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
{
index = (index + cwp * 16) % (16 * env->nwindows);
/* wrap handling : if cwp is on the last window, then we use the
registers 'after' the end */
if (index < 8 && env->cwp == env->nwindows - 1)
index += 16 * env->nwindows;
return index;
}
/* save the register window 'cwp1' */
static inline void save_window_offset(CPUSPARCState *env, int cwp1)
{
unsigned int i;
abi_ulong sp_ptr;
sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
#ifdef TARGET_SPARC64
if (sp_ptr & 3)
sp_ptr += SPARC64_STACK_BIAS;
#endif
#if defined(DEBUG_WIN)
printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
sp_ptr, cwp1);
#endif
for(i = 0; i < 16; i++) {
/* FIXME - what to do if put_user() fails? */
put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
sp_ptr += sizeof(abi_ulong);
}
}
static void save_window(CPUSPARCState *env)
{
#ifndef TARGET_SPARC64
unsigned int new_wim;
new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
((1LL << env->nwindows) - 1);
save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
env->wim = new_wim;
#else
save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
env->cansave++;
env->canrestore--;
#endif
}
static void restore_window(CPUSPARCState *env)
{
#ifndef TARGET_SPARC64
unsigned int new_wim;
#endif
unsigned int i, cwp1;
abi_ulong sp_ptr;
#ifndef TARGET_SPARC64
new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
((1LL << env->nwindows) - 1);
#endif
/* restore the invalid window */
cwp1 = cpu_cwp_inc(env, env->cwp + 1);
sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
#ifdef TARGET_SPARC64
if (sp_ptr & 3)
sp_ptr += SPARC64_STACK_BIAS;
#endif
#if defined(DEBUG_WIN)
printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
sp_ptr, cwp1);
#endif
for(i = 0; i < 16; i++) {
/* FIXME - what to do if get_user() fails? */
get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
sp_ptr += sizeof(abi_ulong);
}
#ifdef TARGET_SPARC64
env->canrestore++;
if (env->cleanwin < env->nwindows - 1)
env->cleanwin++;
env->cansave--;
#else
env->wim = new_wim;
#endif
}
static void flush_windows(CPUSPARCState *env)
{
int offset, cwp1;
offset = 1;
for(;;) {
/* if restore would invoke restore_window(), then we can stop */
cwp1 = cpu_cwp_inc(env, env->cwp + offset);
#ifndef TARGET_SPARC64
if (env->wim & (1 << cwp1))
break;
#else
if (env->canrestore == 0)
break;
env->cansave++;
env->canrestore--;
#endif
save_window_offset(env, cwp1);
offset++;
}
cwp1 = cpu_cwp_inc(env, env->cwp + 1);
#ifndef TARGET_SPARC64
/* set wim so that restore will reload the registers */
env->wim = 1 << cwp1;
#endif
#if defined(DEBUG_WIN)
printf("flush_windows: nb=%d\n", offset - 1);
#endif
}
void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
{
int trapnr, ret, syscall_nr;
//target_siginfo_t info;
while (1) {
trapnr = cpu_sparc_exec (env);
switch (trapnr) {
#ifndef TARGET_SPARC64
case 0x80:
#else
case 0x100:
#endif
syscall_nr = env->gregs[1];
if (bsd_type == target_freebsd)
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]);
else if (bsd_type == target_netbsd)
ret = do_netbsd_syscall(env, syscall_nr,
env->regwptr[0], env->regwptr[1],
env->regwptr[2], env->regwptr[3],
env->regwptr[4], env->regwptr[5]);
else { //if (bsd_type == target_openbsd)
#if defined(TARGET_SPARC64)
syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
TARGET_OPENBSD_SYSCALL_G2RFLAG);
#endif
ret = do_openbsd_syscall(env, syscall_nr,
env->regwptr[0], env->regwptr[1],
env->regwptr[2], env->regwptr[3],
env->regwptr[4], env->regwptr[5]);
}
if ((unsigned int)ret >= (unsigned int)(-515)) {
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
env->xcc |= PSR_CARRY;
#else
env->psr |= PSR_CARRY;
#endif
} else {
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
env->xcc &= ~PSR_CARRY;
#else
env->psr &= ~PSR_CARRY;
#endif
}
env->regwptr[0] = ret;
/* next instruction */
#if defined(TARGET_SPARC64)
if (bsd_type == target_openbsd &&
env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
env->pc = env->gregs[2];
env->npc = env->pc + 4;
} else if (bsd_type == target_openbsd &&
env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
env->pc = env->gregs[7];
env->npc = env->pc + 4;
} else {
env->pc = env->npc;
env->npc = env->npc + 4;
}
#else
env->pc = env->npc;
env->npc = env->npc + 4;
#endif
break;
case 0x83: /* flush windows */
#ifdef TARGET_ABI32
case 0x103:
#endif
flush_windows(env);
/* next instruction */
env->pc = env->npc;
env->npc = env->npc + 4;
break;
#ifndef TARGET_SPARC64
case TT_WIN_OVF: /* window overflow */
save_window(env);
break;
case TT_WIN_UNF: /* window underflow */
restore_window(env);
break;
case TT_TFAULT:
case TT_DFAULT:
#if 0
{
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->mmuregs[4];
queue_signal(env, info.si_signo, &info);
}
#endif
break;
#else
case TT_SPILL: /* window overflow */
save_window(env);
break;
case TT_FILL: /* window underflow */
restore_window(env);
break;
case TT_TFAULT:
case TT_DFAULT:
#if 0
{
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
if (trapnr == TT_DFAULT)
info._sifields._sigfault._addr = env->dmmuregs[4];
else
info._sifields._sigfault._addr = env->tsptr->tpc;
//queue_signal(env, info.si_signo, &info);
}
#endif
break;
#endif
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
case EXCP_DEBUG:
{
int sig;
sig = gdb_handlesig (env, TARGET_SIGTRAP);
#if 0
if (sig)
{
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
//queue_signal(env, info.si_signo, &info);
}
#endif
}
break;
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(env, stderr, fprintf, 0);
exit (1);
}
process_pending_signals (env);
}
}
#endif
static void usage(void)
{
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
"usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
"BSD CPU emulator (compiled for %s emulation)\n"
"\n"
"Standard options:\n"
"-h print this help\n"
"-g port wait gdb connection to port\n"
"-L path set the elf interpreter prefix (default=%s)\n"
"-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"
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
"\n"
"Debug options:\n"
"-d options activate log (logfile=%s)\n"
"-p pagesize set the host page size to 'pagesize'\n"
"-singlestep always run in singlestep mode\n"
"-strace log system calls\n"
"\n"
"Environment variables:\n"
"QEMU_STRACE Print system calls and arguments similar to the\n"
" 'strace' program. Enable by setting to any value.\n"
,
TARGET_ARCH,
interp_prefix,
x86_stack_size,
DEBUG_LOGFILE);
exit(1);
}
THREAD CPUState *thread_env;
/* Assumes contents are already zeroed. */
void init_task_state(TaskState *ts)
{
int i;
ts->used = 1;
ts->first_free = ts->sigqueue_table;
for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
}
ts->sigqueue_table[i].next = NULL;
}
int main(int argc, char **argv)
{
const char *filename;
const char *cpu_model;
struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1;
TaskState ts1, *ts = &ts1;
CPUState *env;
int optind;
const char *r;
int gdbstub_port = 0;
int drop_ld_preload = 0, environ_count = 0;
char **target_environ, **wrk, **dst;
enum BSDType bsd_type = target_openbsd;
if (argc <= 1)
usage();
/* init debug */
cpu_set_log_filename(DEBUG_LOGFILE);
cpu_model = NULL;
optind = 1;
for(;;) {
if (optind >= argc)
break;
r = argv[optind];
if (r[0] != '-')
break;
optind++;
r++;
if (!strcmp(r, "-")) {
break;
} else if (!strcmp(r, "d")) {
int mask;
const CPULogItem *item;
if (optind >= argc)
break;
r = argv[optind++];
mask = cpu_str_to_log_mask(r);
if (!mask) {
printf("Log items (comma separated):\n");
for(item = cpu_log_items; item->mask != 0; item++) {
printf("%-10s %s\n", item->name, item->help);
}
exit(1);
}
cpu_set_log(mask);
} else if (!strcmp(r, "s")) {
r = argv[optind++];
x86_stack_size = strtol(r, (char **)&r, 0);
if (x86_stack_size <= 0)
usage();
if (*r == 'M')
x86_stack_size *= 1024 * 1024;
else if (*r == 'k' || *r == 'K')
x86_stack_size *= 1024;
} else if (!strcmp(r, "L")) {
interp_prefix = argv[optind++];
} else if (!strcmp(r, "p")) {
qemu_host_page_size = atoi(argv[optind++]);
if (qemu_host_page_size == 0 ||
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
fprintf(stderr, "page size must be a power of two\n");
exit(1);
}
} else if (!strcmp(r, "g")) {
gdbstub_port = atoi(argv[optind++]);
} else if (!strcmp(r, "r")) {
qemu_uname_release = argv[optind++];
} else if (!strcmp(r, "cpu")) {
cpu_model = argv[optind++];
if (strcmp(cpu_model, "?") == 0) {
/* XXX: implement xxx_cpu_list for targets that still miss it */
#if defined(cpu_list)
cpu_list(stdout, &fprintf);
#endif
exit(1);
}
} else if (!strcmp(r, "drop-ld-preload")) {
drop_ld_preload = 1;
} else if (!strcmp(r, "bsd")) {
if (!strcasecmp(argv[optind], "freebsd")) {
bsd_type = target_freebsd;
} else if (!strcasecmp(argv[optind], "netbsd")) {
bsd_type = target_netbsd;
} else if (!strcasecmp(argv[optind], "openbsd")) {
bsd_type = target_openbsd;
} else {
usage();
}
optind++;
} else if (!strcmp(r, "singlestep")) {
singlestep = 1;
} else if (!strcmp(r, "strace")) {
do_strace = 1;
} else
{
usage();
}
}
if (optind >= argc)
usage();
filename = argv[optind];
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
/* Zero out image_info */
memset(info, 0, sizeof(struct image_info));
/* Scan interp_prefix dir for replacement files. */
init_paths(interp_prefix);
if (cpu_model == NULL) {
#if defined(TARGET_I386)
#ifdef TARGET_X86_64
cpu_model = "qemu64";
#else
cpu_model = "qemu32";
#endif
#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
cpu_model = "TI UltraSparc II";
#else
cpu_model = "Fujitsu MB86904";
#endif
#else
cpu_model = "any";
#endif
}
cpu_exec_init_all(0);
/* NOTE: we need to init the CPU at this stage to get
qemu_host_page_size */
env = cpu_init(cpu_model);
if (!env) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
thread_env = env;
if (getenv("QEMU_STRACE")) {
do_strace = 1;
}
wrk = environ;
while (*(wrk++))
environ_count++;
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);
}
*dst = NULL; /* NULL terminate target_environ */
if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
printf("Error loading %s\n", filename);
_exit(1);
}
for (wrk = target_environ; *wrk; wrk++) {
free(*wrk);
}
free(target_environ);
if (qemu_log_enabled()) {
log_page_dump();
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
qemu_log("end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code);
qemu_log("start_code 0x" TARGET_ABI_FMT_lx "\n",
info->start_code);
qemu_log("start_data 0x" TARGET_ABI_FMT_lx "\n",
info->start_data);
qemu_log("end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data);
qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
info->start_stack);
qemu_log("brk 0x" TARGET_ABI_FMT_lx "\n", info->brk);
qemu_log("entry 0x" TARGET_ABI_FMT_lx "\n", info->entry);
}
target_set_brk(info->brk);
syscall_init();
signal_init();
/* build Task State */
memset(ts, 0, sizeof(TaskState));
init_task_state(ts);
ts->info = info;
env->opaque = ts;
#if defined(TARGET_I386)
cpu_x86_set_cpl(env, 3);
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
env->hflags |= HF_PE_MASK;
if (env->cpuid_features & CPUID_SSE) {
env->cr[4] |= CR4_OSFXSR_MASK;
env->hflags |= HF_OSFXSR_MASK;
}
#ifndef TARGET_ABI32
/* enable 64 bit mode if possible */
if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
exit(1);
}
env->cr[4] |= CR4_PAE_MASK;
env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
env->hflags |= HF_LMA_MASK;
#endif
/* flags setup : we activate the IRQs by default as in user mode */
env->eflags |= IF_MASK;
/* linux register setup */
#ifndef TARGET_ABI32
env->regs[R_EAX] = regs->rax;
env->regs[R_EBX] = regs->rbx;
env->regs[R_ECX] = regs->rcx;
env->regs[R_EDX] = regs->rdx;
env->regs[R_ESI] = regs->rsi;
env->regs[R_EDI] = regs->rdi;
env->regs[R_EBP] = regs->rbp;
env->regs[R_ESP] = regs->rsp;
env->eip = regs->rip;
#else
env->regs[R_EAX] = regs->eax;
env->regs[R_EBX] = regs->ebx;
env->regs[R_ECX] = regs->ecx;
env->regs[R_EDX] = regs->edx;
env->regs[R_ESI] = regs->esi;
env->regs[R_EDI] = regs->edi;
env->regs[R_EBP] = regs->ebp;
env->regs[R_ESP] = regs->esp;
env->eip = regs->eip;
#endif
/* linux interrupt setup */
#ifndef TARGET_ABI32
env->idt.limit = 511;
#else
env->idt.limit = 255;
#endif
env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
idt_table = g2h(env->idt.base);
set_idt(0, 0);
set_idt(1, 0);
set_idt(2, 0);
set_idt(3, 3);
set_idt(4, 3);
set_idt(5, 0);
set_idt(6, 0);
set_idt(7, 0);
set_idt(8, 0);
set_idt(9, 0);
set_idt(10, 0);
set_idt(11, 0);
set_idt(12, 0);
set_idt(13, 0);
set_idt(14, 0);
set_idt(15, 0);
set_idt(16, 0);
set_idt(17, 0);
set_idt(18, 0);
set_idt(19, 0);
set_idt(0x80, 3);
/* linux segment setup */
{
uint64_t *gdt_table;
env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
gdt_table = g2h(env->gdt.base);
#ifdef TARGET_ABI32
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
(3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
#else
/* 64 bit code segment */
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
DESC_L_MASK |
(3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
#endif
write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
(3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
}
cpu_x86_load_seg(env, R_CS, __USER_CS);
cpu_x86_load_seg(env, R_SS, __USER_DS);
#ifdef TARGET_ABI32
cpu_x86_load_seg(env, R_DS, __USER_DS);
cpu_x86_load_seg(env, R_ES, __USER_DS);
cpu_x86_load_seg(env, R_FS, __USER_DS);
cpu_x86_load_seg(env, R_GS, __USER_DS);
/* This hack makes Wine work... */
env->segs[R_FS].selector = 0;
#else
cpu_x86_load_seg(env, R_DS, 0);
cpu_x86_load_seg(env, R_ES, 0);
cpu_x86_load_seg(env, R_FS, 0);
cpu_x86_load_seg(env, R_GS, 0);
#endif
#elif defined(TARGET_SPARC)
{
int i;
env->pc = regs->pc;
env->npc = regs->npc;
env->y = regs->y;
for(i = 0; i < 8; i++)
env->gregs[i] = regs->u_regs[i];
for(i = 0; i < 8; i++)
env->regwptr[i] = regs->u_regs[i + 8];
}
#else
#error unsupported target CPU
#endif
if (gdbstub_port) {
gdbserver_start (gdbstub_port);
gdb_handlesig(env, 0);
}
cpu_loop(env, bsd_type);
/* never exits */
return 0;
}

View File

@@ -1,560 +0,0 @@
/*
* mmap support for qemu
*
* Copyright (c) 2003 - 2008 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include "qemu.h"
#include "qemu-common.h"
#include "bsd-mman.h"
//#define DEBUG_MMAP
#if defined(USE_NPTL)
pthread_mutex_t mmap_mutex;
static int __thread mmap_lock_count;
void mmap_lock(void)
{
if (mmap_lock_count++ == 0) {
pthread_mutex_lock(&mmap_mutex);
}
}
void mmap_unlock(void)
{
if (--mmap_lock_count == 0) {
pthread_mutex_unlock(&mmap_mutex);
}
}
/* Grab lock to make sure things are in a consistent state after fork(). */
void mmap_fork_start(void)
{
if (mmap_lock_count)
abort();
pthread_mutex_lock(&mmap_mutex);
}
void mmap_fork_end(int child)
{
if (child)
pthread_mutex_init(&mmap_mutex, NULL);
else
pthread_mutex_unlock(&mmap_mutex);
}
#else
/* We aren't threadsafe to start with, so no need to worry about locking. */
void mmap_lock(void)
{
}
void mmap_unlock(void)
{
}
#endif
void *qemu_vmalloc(size_t size)
{
void *p;
unsigned long addr;
mmap_lock();
/* Use map and mark the pages as used. */
p = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
addr = (unsigned long)p;
if (addr == (target_ulong) addr) {
/* Allocated region overlaps guest address space.
This may recurse. */
page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size),
PAGE_RESERVED);
}
mmap_unlock();
return p;
}
void *qemu_malloc(size_t size)
{
char * p;
size += 16;
p = qemu_vmalloc(size);
*(size_t *)p = size;
return p + 16;
}
/* We use map, which is always zero initialized. */
void * qemu_mallocz(size_t size)
{
return qemu_malloc(size);
}
void qemu_free(void *ptr)
{
/* FIXME: We should unmark the reserved pages here. However this gets
complicated when one target page spans multiple host pages, so we
don't bother. */
size_t *p;
p = (size_t *)((char *)ptr - 16);
munmap(p, *p);
}
void *qemu_realloc(void *ptr, size_t size)
{
size_t old_size, copy;
void *new_ptr;
if (!ptr)
return qemu_malloc(size);
old_size = *(size_t *)((char *)ptr - 16);
copy = old_size < size ? old_size : size;
new_ptr = qemu_malloc(size);
memcpy(new_ptr, ptr, copy);
qemu_free(ptr);
return new_ptr;
}
/* NOTE: all the constants are the HOST ones, but addresses are target. */
int target_mprotect(abi_ulong start, abi_ulong len, int prot)
{
abi_ulong end, host_start, host_end, addr;
int prot1, ret;
#ifdef DEBUG_MMAP
printf("mprotect: start=0x" TARGET_FMT_lx
" len=0x" TARGET_FMT_lx " prot=%c%c%c\n", start, len,
prot & PROT_READ ? 'r' : '-',
prot & PROT_WRITE ? 'w' : '-',
prot & PROT_EXEC ? 'x' : '-');
#endif
if ((start & ~TARGET_PAGE_MASK) != 0)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
if (end < start)
return -EINVAL;
prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
if (len == 0)
return 0;
mmap_lock();
host_start = start & qemu_host_page_mask;
host_end = HOST_PAGE_ALIGN(end);
if (start > host_start) {
/* handle host page containing start */
prot1 = prot;
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
if (host_end == host_start + qemu_host_page_size) {
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
end = host_end;
}
ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS);
if (ret != 0)
goto error;
host_start += qemu_host_page_size;
}
if (end < host_end) {
prot1 = prot;
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
prot1 & PAGE_BITS);
if (ret != 0)
goto error;
host_end -= qemu_host_page_size;
}
/* handle the pages in the middle */
if (host_start < host_end) {
ret = mprotect(g2h(host_start), host_end - host_start, prot);
if (ret != 0)
goto error;
}
page_set_flags(start, start + len, prot | PAGE_VALID);
mmap_unlock();
return 0;
error:
mmap_unlock();
return ret;
}
/* map an incomplete host page */
static int mmap_frag(abi_ulong real_start,
abi_ulong start, abi_ulong end,
int prot, int flags, int fd, abi_ulong offset)
{
abi_ulong real_end, addr;
void *host_start;
int prot1, prot_new;
real_end = real_start + qemu_host_page_size;
host_start = g2h(real_start);
/* get the protection of the target pages outside the mapping */
prot1 = 0;
for(addr = real_start; addr < real_end; addr++) {
if (addr < start || addr >= end)
prot1 |= page_get_flags(addr);
}
if (prot1 == 0) {
/* no page was there, so we allocate one */
void *p = mmap(host_start, qemu_host_page_size, prot,
flags | MAP_ANON, -1, 0);
if (p == MAP_FAILED)
return -1;
prot1 = prot;
}
prot1 &= PAGE_BITS;
prot_new = prot | prot1;
if (!(flags & MAP_ANON)) {
/* msync() won't work here, so we return an error if write is
possible while it is a shared mapping */
if ((flags & TARGET_BSD_MAP_FLAGMASK) == MAP_SHARED &&
(prot & PROT_WRITE))
return -EINVAL;
/* adjust protection to be able to read */
if (!(prot1 & PROT_WRITE))
mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
/* read the corresponding file data */
pread(fd, g2h(start), end - start, offset);
/* put final protection */
if (prot_new != (prot1 | PROT_WRITE))
mprotect(host_start, qemu_host_page_size, prot_new);
} else {
/* just update the protection */
if (prot_new != prot1) {
mprotect(host_start, qemu_host_page_size, prot_new);
}
}
return 0;
}
#if defined(__CYGWIN__)
/* Cygwin doesn't have a whole lot of address space. */
static abi_ulong mmap_next_start = 0x18000000;
#else
static abi_ulong mmap_next_start = 0x40000000;
#endif
unsigned long last_brk;
/* find a free memory area of size 'size'. The search starts at
'start'. If 'start' == 0, then a default start address is used.
Return -1 if error.
*/
/* page_init() marks pages used by the host as reserved to be sure not
to use them. */
static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
{
abi_ulong addr, addr1, addr_start;
int prot;
unsigned long new_brk;
new_brk = (unsigned long)sbrk(0);
if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) {
/* This is a hack to catch the host allocating memory with brk().
If it uses mmap then we loose.
FIXME: We really want to avoid the host allocating memory in
the first place, and maybe leave some slack to avoid switching
to mmap. */
page_set_flags(last_brk & TARGET_PAGE_MASK,
TARGET_PAGE_ALIGN(new_brk),
PAGE_RESERVED);
}
last_brk = new_brk;
size = HOST_PAGE_ALIGN(size);
start = start & qemu_host_page_mask;
addr = start;
if (addr == 0)
addr = mmap_next_start;
addr_start = addr;
for(;;) {
prot = 0;
for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr1);
}
if (prot == 0)
break;
addr += qemu_host_page_size;
/* we found nothing */
if (addr == addr_start)
return (abi_ulong)-1;
}
if (start == 0)
mmap_next_start = addr + size;
return addr;
}
/* NOTE: all the constants are the HOST ones */
abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
int flags, int fd, abi_ulong offset)
{
abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
unsigned long host_start;
mmap_lock();
#ifdef DEBUG_MMAP
{
printf("mmap: start=0x" TARGET_FMT_lx
" len=0x" TARGET_FMT_lx " prot=%c%c%c flags=",
start, len,
prot & PROT_READ ? 'r' : '-',
prot & PROT_WRITE ? 'w' : '-',
prot & PROT_EXEC ? 'x' : '-');
if (flags & MAP_FIXED)
printf("MAP_FIXED ");
if (flags & MAP_ANON)
printf("MAP_ANON ");
switch(flags & TARGET_BSD_MAP_FLAGMASK) {
case MAP_PRIVATE:
printf("MAP_PRIVATE ");
break;
case MAP_SHARED:
printf("MAP_SHARED ");
break;
default:
printf("[MAP_FLAGMASK=0x%x] ", flags & TARGET_BSD_MAP_FLAGMASK);
break;
}
printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset);
}
#endif
if (offset & ~TARGET_PAGE_MASK) {
errno = EINVAL;
goto fail;
}
len = TARGET_PAGE_ALIGN(len);
if (len == 0)
goto the_end;
real_start = start & qemu_host_page_mask;
if (!(flags & MAP_FIXED)) {
abi_ulong mmap_start;
void *p;
host_offset = offset & qemu_host_page_mask;
host_len = len + offset - host_offset;
host_len = HOST_PAGE_ALIGN(host_len);
mmap_start = mmap_find_vma(real_start, host_len);
if (mmap_start == (abi_ulong)-1) {
errno = ENOMEM;
goto fail;
}
/* Note: we prefer to control the mapping address. It is
especially important if qemu_host_page_size >
qemu_real_host_page_size */
p = mmap(g2h(mmap_start),
host_len, prot, flags | MAP_FIXED, fd, host_offset);
if (p == MAP_FAILED)
goto fail;
/* update start so that it points to the file position at 'offset' */
host_start = (unsigned long)p;
if (!(flags & MAP_ANON))
host_start += offset - host_offset;
start = h2g(host_start);
} else {
int flg;
target_ulong addr;
if (start & ~TARGET_PAGE_MASK) {
errno = EINVAL;
goto fail;
}
end = start + len;
real_end = HOST_PAGE_ALIGN(end);
for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) {
flg = page_get_flags(addr);
if (flg & PAGE_RESERVED) {
errno = ENXIO;
goto fail;
}
}
/* worst case: we cannot map the file because the offset is not
aligned, so we read it */
if (!(flags & MAP_ANON) &&
(offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
/* msync() won't work here, so we return an error if write is
possible while it is a shared mapping */
if ((flags & TARGET_BSD_MAP_FLAGMASK) == MAP_SHARED &&
(prot & PROT_WRITE)) {
errno = EINVAL;
goto fail;
}
retaddr = target_mmap(start, len, prot | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANON,
-1, 0);
if (retaddr == -1)
goto fail;
pread(fd, g2h(start), len, offset);
if (!(prot & PROT_WRITE)) {
ret = target_mprotect(start, len, prot);
if (ret != 0) {
start = ret;
goto the_end;
}
}
goto the_end;
}
/* handle the start of the mapping */
if (start > real_start) {
if (real_end == real_start + qemu_host_page_size) {
/* one single host page */
ret = mmap_frag(real_start, start, end,
prot, flags, fd, offset);
if (ret == -1)
goto fail;
goto the_end1;
}
ret = mmap_frag(real_start, start, real_start + qemu_host_page_size,
prot, flags, fd, offset);
if (ret == -1)
goto fail;
real_start += qemu_host_page_size;
}
/* handle the end of the mapping */
if (end < real_end) {
ret = mmap_frag(real_end - qemu_host_page_size,
real_end - qemu_host_page_size, real_end,
prot, flags, fd,
offset + real_end - qemu_host_page_size - start);
if (ret == -1)
goto fail;
real_end -= qemu_host_page_size;
}
/* map the middle (easier) */
if (real_start < real_end) {
void *p;
unsigned long offset1;
if (flags & MAP_ANON)
offset1 = 0;
else
offset1 = offset + real_start - start;
p = mmap(g2h(real_start), real_end - real_start,
prot, flags, fd, offset1);
if (p == MAP_FAILED)
goto fail;
}
}
the_end1:
page_set_flags(start, start + len, prot | PAGE_VALID);
the_end:
#ifdef DEBUG_MMAP
printf("ret=0x" TARGET_FMT_lx "\n", start);
page_dump(stdout);
printf("\n");
#endif
mmap_unlock();
return start;
fail:
mmap_unlock();
return -1;
}
int target_munmap(abi_ulong start, abi_ulong len)
{
abi_ulong end, real_start, real_end, addr;
int prot, ret;
#ifdef DEBUG_MMAP
printf("munmap: start=0x%lx len=0x%lx\n", start, len);
#endif
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
if (len == 0)
return -EINVAL;
mmap_lock();
end = start + len;
real_start = start & qemu_host_page_mask;
real_end = HOST_PAGE_ALIGN(end);
if (start > real_start) {
/* handle host page containing start */
prot = 0;
for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
if (real_end == real_start + qemu_host_page_size) {
for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
end = real_end;
}
if (prot != 0)
real_start += qemu_host_page_size;
}
if (end < real_end) {
prot = 0;
for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
if (prot != 0)
real_end -= qemu_host_page_size;
}
ret = 0;
/* unmap what we can */
if (real_start < real_end) {
ret = munmap(g2h(real_start), real_end - real_start);
}
if (ret == 0)
page_set_flags(start, start + len, 0);
mmap_unlock();
return ret;
}
int target_msync(abi_ulong start, abi_ulong len, int flags)
{
abi_ulong end;
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
if (end < start)
return -EINVAL;
if (end == start)
return 0;
start &= qemu_host_page_mask;
return msync(g2h(start), end - start, flags);
}

View File

@@ -1,145 +0,0 @@
{ TARGET_NETBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL },
{ TARGET_NETBSD_NR___syscall, "__syscall", NULL, NULL, NULL },
{ TARGET_NETBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL },
{ TARGET_NETBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL },
{ TARGET_NETBSD_NR_acct, "acct", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_adjtime, "adjtime", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_bind, "bind", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_break, "break", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_chdir, "chdir", "%s(\"%s\")", NULL, NULL },
{ TARGET_NETBSD_NR_chflags, "chflags", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_chmod, "chmod", "%s(\"%s\",%#o)", NULL, NULL },
{ TARGET_NETBSD_NR_chown, "chown", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_chroot, "chroot", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_clock_getres, "clock_getres", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_clock_gettime, "clock_gettime", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_clock_settime, "clock_settime", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_close, "close", "%s(%d)", NULL, NULL },
{ TARGET_NETBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL },
{ TARGET_NETBSD_NR_dup, "dup", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_dup2, "dup2", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_execve, "execve", NULL, print_execve, NULL },
{ TARGET_NETBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL },
{ TARGET_NETBSD_NR_fchdir, "fchdir", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_fchflags, "fchflags", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL },
{ TARGET_NETBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL },
{ TARGET_NETBSD_NR_fcntl, "fcntl", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_flock, "flock", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_fork, "fork", "%s()", NULL, NULL },
{ TARGET_NETBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_fsync, "fsync", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_futimes, "futimes", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
{ TARGET_NETBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL },
{ TARGET_NETBSD_NR_getgid, "getgid", "%s()", NULL, NULL },
{ TARGET_NETBSD_NR_getgroups, "getgroups", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_getitimer, "getitimer", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_getpeername, "getpeername", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_getpgid, "getpgid", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_getpgrp, "getpgrp", "%s()", NULL, NULL },
{ TARGET_NETBSD_NR_getpid, "getpid", "%s()", NULL, NULL },
{ TARGET_NETBSD_NR_getppid, "getppid", "%s()", NULL, NULL },
{ TARGET_NETBSD_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL },
{ TARGET_NETBSD_NR_getrlimit, "getrlimit", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_getrusage, "getrusage", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_getsid, "getsid", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_getsockname, "getsockname", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_getuid, "getuid", "%s()", NULL, NULL },
{ TARGET_NETBSD_NR_ioctl, "ioctl", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL },
{ TARGET_NETBSD_NR_kevent, "kevent", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_kill, "kill", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_kqueue, "kqueue", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_ktrace, "ktrace", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_lchown, "lchown", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_lfs_bmapv, "lfs_bmapv", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_lfs_markv, "lfs_markv", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_lfs_segclean, "lfs_segclean", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_lfs_segwait, "lfs_segwait", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL },
{ TARGET_NETBSD_NR_listen, "listen", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_lseek, "lseek", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_madvise, "madvise", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_mincore, "mincore", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_minherit, "minherit", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_mkdir, "mkdir", "%s(\"%s\",%#o)", NULL, NULL },
{ TARGET_NETBSD_NR_mkfifo, "mkfifo", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_mknod, "mknod", "%s(\"%s\",%#o,%#x)", NULL, NULL },
{ TARGET_NETBSD_NR_mlock, "mlock", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_mlockall, "mlockall", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_mmap, "mmap", NULL, NULL, print_syscall_ret_addr },
{ TARGET_NETBSD_NR_mprotect, "mprotect", "%s(%#x,%#x,%d)", NULL, NULL },
{ TARGET_NETBSD_NR_msgget, "msgget", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_msgrcv, "msgrcv", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_msgsnd, "msgsnd", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_munlock, "munlock", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_munlockall, "munlockall", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_munmap, "munmap", "%s(%p,%d)", NULL, NULL },
{ TARGET_NETBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL },
{ TARGET_NETBSD_NR_pathconf, "pathconf", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_pipe, "pipe", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_poll, "poll", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_pread, "pread", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_preadv, "preadv", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_profil, "profil", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_ptrace, "ptrace", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_pwrite, "pwrite", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_pwritev, "pwritev", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_quotactl, "quotactl", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_read, "read", "%s(%d,%#x,%d)", NULL, NULL },
{ TARGET_NETBSD_NR_readlink, "readlink", "%s(\"%s\",%p,%d)", NULL, NULL },
{ TARGET_NETBSD_NR_readv, "readv", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_reboot, "reboot", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_recvfrom, "recvfrom", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_recvmsg, "recvmsg", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_rename, "rename", "%s(\"%s\",\"%s\")", NULL, NULL },
{ TARGET_NETBSD_NR_revoke, "revoke", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_rmdir, "rmdir", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_sbrk, "sbrk", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_select, "select", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_semget, "semget", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_semop, "semop", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_sendto, "sendto", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setegid, "setegid", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_seteuid, "seteuid", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setgid, "setgid", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setgroups, "setgroups", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setitimer, "setitimer", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setpgid, "setpgid", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setpriority, "setpriority", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setregid, "setregid", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setreuid, "setreuid", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setrlimit, "setrlimit", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setsid, "setsid", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setsockopt, "setsockopt", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_settimeofday, "settimeofday", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_setuid, "setuid", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_shmat, "shmat", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_shmdt, "shmdt", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_shmget, "shmget", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_shutdown, "shutdown", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_socketpair, "socketpair", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_sstk, "sstk", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_swapctl, "swapctl", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL },
{ TARGET_NETBSD_NR_sync, "sync", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_sysarch, "sysarch", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_syscall, "syscall", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_truncate, "truncate", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL },
{ TARGET_NETBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL },
{ TARGET_NETBSD_NR_unmount, "unmount", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_utimes, "utimes", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_vfork, "vfork", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_wait4, "wait4", NULL, NULL, NULL },
{ TARGET_NETBSD_NR_write, "write", "%s(%d,%#x,%d)", NULL, NULL },
{ TARGET_NETBSD_NR_writev, "writev", "%s(%d,%p,%#x)", NULL, NULL },

View File

@@ -1,373 +0,0 @@
/* $NetBSD: syscall.h,v 1.215 2008/06/17 16:07:57 tsutsui Exp $ */
/*
* System call numbers.
*
* created from NetBSD: syscalls.master,v 1.204 2008/06/17 16:05:23 tsutsui Exp
*/
#define TARGET_NETBSD_NR_syscall 0
#define TARGET_NETBSD_NR_exit 1
#define TARGET_NETBSD_NR_fork 2
#define TARGET_NETBSD_NR_read 3
#define TARGET_NETBSD_NR_write 4
#define TARGET_NETBSD_NR_open 5
#define TARGET_NETBSD_NR_close 6
#define TARGET_NETBSD_NR_wait4 7
#define TARGET_NETBSD_NR_compat_43_ocreat 8
#define TARGET_NETBSD_NR_link 9
#define TARGET_NETBSD_NR_unlink 10
#define TARGET_NETBSD_NR_chdir 12
#define TARGET_NETBSD_NR_fchdir 13
#define TARGET_NETBSD_NR_mknod 14
#define TARGET_NETBSD_NR_chmod 15
#define TARGET_NETBSD_NR_chown 16
#define TARGET_NETBSD_NR_break 17
#define TARGET_NETBSD_NR_compat_20_getfsstat 18
#define TARGET_NETBSD_NR_compat_43_olseek 19
#define TARGET_NETBSD_NR_getpid 20
#define TARGET_NETBSD_NR_getpid 20
#define TARGET_NETBSD_NR_compat_40_mount 21
#define TARGET_NETBSD_NR_unmount 22
#define TARGET_NETBSD_NR_setuid 23
#define TARGET_NETBSD_NR_getuid 24
#define TARGET_NETBSD_NR_getuid 24
#define TARGET_NETBSD_NR_geteuid 25
#define TARGET_NETBSD_NR_ptrace 26
#define TARGET_NETBSD_NR_recvmsg 27
#define TARGET_NETBSD_NR_sendmsg 28
#define TARGET_NETBSD_NR_recvfrom 29
#define TARGET_NETBSD_NR_accept 30
#define TARGET_NETBSD_NR_getpeername 31
#define TARGET_NETBSD_NR_getsockname 32
#define TARGET_NETBSD_NR_access 33
#define TARGET_NETBSD_NR_chflags 34
#define TARGET_NETBSD_NR_fchflags 35
#define TARGET_NETBSD_NR_sync 36
#define TARGET_NETBSD_NR_kill 37
#define TARGET_NETBSD_NR_compat_43_stat43 38
#define TARGET_NETBSD_NR_getppid 39
#define TARGET_NETBSD_NR_compat_43_lstat43 40
#define TARGET_NETBSD_NR_dup 41
#define TARGET_NETBSD_NR_pipe 42
#define TARGET_NETBSD_NR_getegid 43
#define TARGET_NETBSD_NR_profil 44
#define TARGET_NETBSD_NR_ktrace 45
#define TARGET_NETBSD_NR_compat_13_sigaction13 46
#define TARGET_NETBSD_NR_getgid 47
#define TARGET_NETBSD_NR_getgid 47
#define TARGET_NETBSD_NR_compat_13_sigprocmask13 48
#define TARGET_NETBSD_NR___getlogin 49
#define TARGET_NETBSD_NR___setlogin 50
#define TARGET_NETBSD_NR_acct 51
#define TARGET_NETBSD_NR_compat_13_sigpending13 52
#define TARGET_NETBSD_NR_compat_13_sigaltstack13 53
#define TARGET_NETBSD_NR_ioctl 54
#define TARGET_NETBSD_NR_compat_12_oreboot 55
#define TARGET_NETBSD_NR_revoke 56
#define TARGET_NETBSD_NR_symlink 57
#define TARGET_NETBSD_NR_readlink 58
#define TARGET_NETBSD_NR_execve 59
#define TARGET_NETBSD_NR_umask 60
#define TARGET_NETBSD_NR_chroot 61
#define TARGET_NETBSD_NR_compat_43_fstat43 62
#define TARGET_NETBSD_NR_compat_43_ogetkerninfo 63
#define TARGET_NETBSD_NR_compat_43_ogetpagesize 64
#define TARGET_NETBSD_NR_compat_12_msync 65
#define TARGET_NETBSD_NR_vfork 66
#define TARGET_NETBSD_NR_sbrk 69
#define TARGET_NETBSD_NR_sstk 70
#define TARGET_NETBSD_NR_compat_43_ommap 71
#define TARGET_NETBSD_NR_vadvise 72
#define TARGET_NETBSD_NR_munmap 73
#define TARGET_NETBSD_NR_mprotect 74
#define TARGET_NETBSD_NR_madvise 75
#define TARGET_NETBSD_NR_mincore 78
#define TARGET_NETBSD_NR_getgroups 79
#define TARGET_NETBSD_NR_setgroups 80
#define TARGET_NETBSD_NR_getpgrp 81
#define TARGET_NETBSD_NR_setpgid 82
#define TARGET_NETBSD_NR_setitimer 83
#define TARGET_NETBSD_NR_compat_43_owait 84
#define TARGET_NETBSD_NR_compat_12_oswapon 85
#define TARGET_NETBSD_NR_getitimer 86
#define TARGET_NETBSD_NR_compat_43_ogethostname 87
#define TARGET_NETBSD_NR_compat_43_osethostname 88
#define TARGET_NETBSD_NR_compat_43_ogetdtablesize 89
#define TARGET_NETBSD_NR_dup2 90
#define TARGET_NETBSD_NR_fcntl 92
#define TARGET_NETBSD_NR_select 93
#define TARGET_NETBSD_NR_fsync 95
#define TARGET_NETBSD_NR_setpriority 96
#define TARGET_NETBSD_NR_compat_30_socket 97
#define TARGET_NETBSD_NR_connect 98
#define TARGET_NETBSD_NR_compat_43_oaccept 99
#define TARGET_NETBSD_NR_getpriority 100
#define TARGET_NETBSD_NR_compat_43_osend 101
#define TARGET_NETBSD_NR_compat_43_orecv 102
#define TARGET_NETBSD_NR_compat_13_sigreturn13 103
#define TARGET_NETBSD_NR_bind 104
#define TARGET_NETBSD_NR_setsockopt 105
#define TARGET_NETBSD_NR_listen 106
#define TARGET_NETBSD_NR_compat_43_osigvec 108
#define TARGET_NETBSD_NR_compat_43_osigblock 109
#define TARGET_NETBSD_NR_compat_43_osigsetmask 110
#define TARGET_NETBSD_NR_compat_13_sigsuspend13 111
#define TARGET_NETBSD_NR_compat_43_osigstack 112
#define TARGET_NETBSD_NR_compat_43_orecvmsg 113
#define TARGET_NETBSD_NR_compat_43_osendmsg 114
#define TARGET_NETBSD_NR_gettimeofday 116
#define TARGET_NETBSD_NR_getrusage 117
#define TARGET_NETBSD_NR_getsockopt 118
#define TARGET_NETBSD_NR_readv 120
#define TARGET_NETBSD_NR_writev 121
#define TARGET_NETBSD_NR_settimeofday 122
#define TARGET_NETBSD_NR_fchown 123
#define TARGET_NETBSD_NR_fchmod 124
#define TARGET_NETBSD_NR_compat_43_orecvfrom 125
#define TARGET_NETBSD_NR_setreuid 126
#define TARGET_NETBSD_NR_setregid 127
#define TARGET_NETBSD_NR_rename 128
#define TARGET_NETBSD_NR_compat_43_otruncate 129
#define TARGET_NETBSD_NR_compat_43_oftruncate 130
#define TARGET_NETBSD_NR_flock 131
#define TARGET_NETBSD_NR_mkfifo 132
#define TARGET_NETBSD_NR_sendto 133
#define TARGET_NETBSD_NR_shutdown 134
#define TARGET_NETBSD_NR_socketpair 135
#define TARGET_NETBSD_NR_mkdir 136
#define TARGET_NETBSD_NR_rmdir 137
#define TARGET_NETBSD_NR_utimes 138
#define TARGET_NETBSD_NR_adjtime 140
#define TARGET_NETBSD_NR_compat_43_ogetpeername 141
#define TARGET_NETBSD_NR_compat_43_ogethostid 142
#define TARGET_NETBSD_NR_compat_43_osethostid 143
#define TARGET_NETBSD_NR_compat_43_ogetrlimit 144
#define TARGET_NETBSD_NR_compat_43_osetrlimit 145
#define TARGET_NETBSD_NR_compat_43_okillpg 146
#define TARGET_NETBSD_NR_setsid 147
#define TARGET_NETBSD_NR_quotactl 148
#define TARGET_NETBSD_NR_compat_43_oquota 149
#define TARGET_NETBSD_NR_compat_43_ogetsockname 150
#define TARGET_NETBSD_NR_nfssvc 155
#define TARGET_NETBSD_NR_compat_43_ogetdirentries 156
#define TARGET_NETBSD_NR_compat_20_statfs 157
#define TARGET_NETBSD_NR_compat_20_fstatfs 158
#define TARGET_NETBSD_NR_compat_30_getfh 161
#define TARGET_NETBSD_NR_compat_09_ogetdomainname 162
#define TARGET_NETBSD_NR_compat_09_osetdomainname 163
#define TARGET_NETBSD_NR_compat_09_ouname 164
#define TARGET_NETBSD_NR_sysarch 165
#define TARGET_NETBSD_NR_compat_10_osemsys 169
#define TARGET_NETBSD_NR_compat_10_omsgsys 170
#define TARGET_NETBSD_NR_compat_10_oshmsys 171
#define TARGET_NETBSD_NR_pread 173
#define TARGET_NETBSD_NR_pwrite 174
#define TARGET_NETBSD_NR_compat_30_ntp_gettime 175
#define TARGET_NETBSD_NR_ntp_adjtime 176
#define TARGET_NETBSD_NR_setgid 181
#define TARGET_NETBSD_NR_setegid 182
#define TARGET_NETBSD_NR_seteuid 183
#define TARGET_NETBSD_NR_lfs_bmapv 184
#define TARGET_NETBSD_NR_lfs_markv 185
#define TARGET_NETBSD_NR_lfs_segclean 186
#define TARGET_NETBSD_NR_lfs_segwait 187
#define TARGET_NETBSD_NR_compat_12_stat12 188
#define TARGET_NETBSD_NR_compat_12_fstat12 189
#define TARGET_NETBSD_NR_compat_12_lstat12 190
#define TARGET_NETBSD_NR_pathconf 191
#define TARGET_NETBSD_NR_fpathconf 192
#define TARGET_NETBSD_NR_getrlimit 194
#define TARGET_NETBSD_NR_setrlimit 195
#define TARGET_NETBSD_NR_compat_12_getdirentries 196
#define TARGET_NETBSD_NR_mmap 197
#define TARGET_NETBSD_NR___syscall 198
#define TARGET_NETBSD_NR_lseek 199
#define TARGET_NETBSD_NR_truncate 200
#define TARGET_NETBSD_NR_ftruncate 201
#define TARGET_NETBSD_NR___sysctl 202
#define TARGET_NETBSD_NR_mlock 203
#define TARGET_NETBSD_NR_munlock 204
#define TARGET_NETBSD_NR_undelete 205
#define TARGET_NETBSD_NR_futimes 206
#define TARGET_NETBSD_NR_getpgid 207
#define TARGET_NETBSD_NR_reboot 208
#define TARGET_NETBSD_NR_poll 209
#define TARGET_NETBSD_NR_compat_14___semctl 220
#define TARGET_NETBSD_NR_semget 221
#define TARGET_NETBSD_NR_semop 222
#define TARGET_NETBSD_NR_semconfig 223
#define TARGET_NETBSD_NR_compat_14_msgctl 224
#define TARGET_NETBSD_NR_msgget 225
#define TARGET_NETBSD_NR_msgsnd 226
#define TARGET_NETBSD_NR_msgrcv 227
#define TARGET_NETBSD_NR_shmat 228
#define TARGET_NETBSD_NR_compat_14_shmctl 229
#define TARGET_NETBSD_NR_shmdt 230
#define TARGET_NETBSD_NR_shmget 231
#define TARGET_NETBSD_NR_clock_gettime 232
#define TARGET_NETBSD_NR_clock_settime 233
#define TARGET_NETBSD_NR_clock_getres 234
#define TARGET_NETBSD_NR_timer_create 235
#define TARGET_NETBSD_NR_timer_delete 236
#define TARGET_NETBSD_NR_timer_settime 237
#define TARGET_NETBSD_NR_timer_gettime 238
#define TARGET_NETBSD_NR_timer_getoverrun 239
#define TARGET_NETBSD_NR_nanosleep 240
#define TARGET_NETBSD_NR_fdatasync 241
#define TARGET_NETBSD_NR_mlockall 242
#define TARGET_NETBSD_NR_munlockall 243
#define TARGET_NETBSD_NR___sigtimedwait 244
#define TARGET_NETBSD_NR_modctl 246
#define TARGET_NETBSD_NR__ksem_init 247
#define TARGET_NETBSD_NR__ksem_open 248
#define TARGET_NETBSD_NR__ksem_unlink 249
#define TARGET_NETBSD_NR__ksem_close 250
#define TARGET_NETBSD_NR__ksem_post 251
#define TARGET_NETBSD_NR__ksem_wait 252
#define TARGET_NETBSD_NR__ksem_trywait 253
#define TARGET_NETBSD_NR__ksem_getvalue 254
#define TARGET_NETBSD_NR__ksem_destroy 255
#define TARGET_NETBSD_NR_mq_open 257
#define TARGET_NETBSD_NR_mq_close 258
#define TARGET_NETBSD_NR_mq_unlink 259
#define TARGET_NETBSD_NR_mq_getattr 260
#define TARGET_NETBSD_NR_mq_setattr 261
#define TARGET_NETBSD_NR_mq_notify 262
#define TARGET_NETBSD_NR_mq_send 263
#define TARGET_NETBSD_NR_mq_receive 264
#define TARGET_NETBSD_NR_mq_timedsend 265
#define TARGET_NETBSD_NR_mq_timedreceive 266
#define TARGET_NETBSD_NR___posix_rename 270
#define TARGET_NETBSD_NR_swapctl 271
#define TARGET_NETBSD_NR_compat_30_getdents 272
#define TARGET_NETBSD_NR_minherit 273
#define TARGET_NETBSD_NR_lchmod 274
#define TARGET_NETBSD_NR_lchown 275
#define TARGET_NETBSD_NR_lutimes 276
#define TARGET_NETBSD_NR___msync13 277
#define TARGET_NETBSD_NR_compat_30___stat13 278
#define TARGET_NETBSD_NR_compat_30___fstat13 279
#define TARGET_NETBSD_NR_compat_30___lstat13 280
#define TARGET_NETBSD_NR___sigaltstack14 281
#define TARGET_NETBSD_NR___vfork14 282
#define TARGET_NETBSD_NR___posix_chown 283
#define TARGET_NETBSD_NR___posix_fchown 284
#define TARGET_NETBSD_NR___posix_lchown 285
#define TARGET_NETBSD_NR_getsid 286
#define TARGET_NETBSD_NR___clone 287
#define TARGET_NETBSD_NR_fktrace 288
#define TARGET_NETBSD_NR_preadv 289
#define TARGET_NETBSD_NR_pwritev 290
#define TARGET_NETBSD_NR_compat_16___sigaction14 291
#define TARGET_NETBSD_NR___sigpending14 292
#define TARGET_NETBSD_NR___sigprocmask14 293
#define TARGET_NETBSD_NR___sigsuspend14 294
#define TARGET_NETBSD_NR_compat_16___sigreturn14 295
#define TARGET_NETBSD_NR___getcwd 296
#define TARGET_NETBSD_NR_fchroot 297
#define TARGET_NETBSD_NR_compat_30_fhopen 298
#define TARGET_NETBSD_NR_compat_30_fhstat 299
#define TARGET_NETBSD_NR_compat_20_fhstatfs 300
#define TARGET_NETBSD_NR_____semctl13 301
#define TARGET_NETBSD_NR___msgctl13 302
#define TARGET_NETBSD_NR___shmctl13 303
#define TARGET_NETBSD_NR_lchflags 304
#define TARGET_NETBSD_NR_issetugid 305
#define TARGET_NETBSD_NR_utrace 306
#define TARGET_NETBSD_NR_getcontext 307
#define TARGET_NETBSD_NR_setcontext 308
#define TARGET_NETBSD_NR__lwp_create 309
#define TARGET_NETBSD_NR__lwp_exit 310
#define TARGET_NETBSD_NR__lwp_self 311
#define TARGET_NETBSD_NR__lwp_wait 312
#define TARGET_NETBSD_NR__lwp_suspend 313
#define TARGET_NETBSD_NR__lwp_continue 314
#define TARGET_NETBSD_NR__lwp_wakeup 315
#define TARGET_NETBSD_NR__lwp_getprivate 316
#define TARGET_NETBSD_NR__lwp_setprivate 317
#define TARGET_NETBSD_NR__lwp_kill 318
#define TARGET_NETBSD_NR__lwp_detach 319
#define TARGET_NETBSD_NR__lwp_park 320
#define TARGET_NETBSD_NR__lwp_unpark 321
#define TARGET_NETBSD_NR__lwp_unpark_all 322
#define TARGET_NETBSD_NR__lwp_setname 323
#define TARGET_NETBSD_NR__lwp_getname 324
#define TARGET_NETBSD_NR__lwp_ctl 325
#define TARGET_NETBSD_NR_sa_register 330
#define TARGET_NETBSD_NR_sa_stacks 331
#define TARGET_NETBSD_NR_sa_enable 332
#define TARGET_NETBSD_NR_sa_setconcurrency 333
#define TARGET_NETBSD_NR_sa_yield 334
#define TARGET_NETBSD_NR_sa_preempt 335
#define TARGET_NETBSD_NR_sa_unblockyield 336
#define TARGET_NETBSD_NR___sigaction_sigtramp 340
#define TARGET_NETBSD_NR_pmc_get_info 341
#define TARGET_NETBSD_NR_pmc_control 342
#define TARGET_NETBSD_NR_rasctl 343
#define TARGET_NETBSD_NR_kqueue 344
#define TARGET_NETBSD_NR_kevent 345
#define TARGET_NETBSD_NR__sched_setparam 346
#define TARGET_NETBSD_NR__sched_getparam 347
#define TARGET_NETBSD_NR__sched_setaffinity 348
#define TARGET_NETBSD_NR__sched_getaffinity 349
#define TARGET_NETBSD_NR_sched_yield 350
#define TARGET_NETBSD_NR_fsync_range 354
#define TARGET_NETBSD_NR_uuidgen 355
#define TARGET_NETBSD_NR_getvfsstat 356
#define TARGET_NETBSD_NR_statvfs1 357
#define TARGET_NETBSD_NR_fstatvfs1 358
#define TARGET_NETBSD_NR_compat_30_fhstatvfs1 359
#define TARGET_NETBSD_NR_extattrctl 360
#define TARGET_NETBSD_NR_extattr_set_file 361
#define TARGET_NETBSD_NR_extattr_get_file 362
#define TARGET_NETBSD_NR_extattr_delete_file 363
#define TARGET_NETBSD_NR_extattr_set_fd 364
#define TARGET_NETBSD_NR_extattr_get_fd 365
#define TARGET_NETBSD_NR_extattr_delete_fd 366
#define TARGET_NETBSD_NR_extattr_set_link 367
#define TARGET_NETBSD_NR_extattr_get_link 368
#define TARGET_NETBSD_NR_extattr_delete_link 369
#define TARGET_NETBSD_NR_extattr_list_fd 370
#define TARGET_NETBSD_NR_extattr_list_file 371
#define TARGET_NETBSD_NR_extattr_list_link 372
#define TARGET_NETBSD_NR_pselect 373
#define TARGET_NETBSD_NR_pollts 374
#define TARGET_NETBSD_NR_setxattr 375
#define TARGET_NETBSD_NR_lsetxattr 376
#define TARGET_NETBSD_NR_fsetxattr 377
#define TARGET_NETBSD_NR_getxattr 378
#define TARGET_NETBSD_NR_lgetxattr 379
#define TARGET_NETBSD_NR_fgetxattr 380
#define TARGET_NETBSD_NR_listxattr 381
#define TARGET_NETBSD_NR_llistxattr 382
#define TARGET_NETBSD_NR_flistxattr 383
#define TARGET_NETBSD_NR_removexattr 384
#define TARGET_NETBSD_NR_lremovexattr 385
#define TARGET_NETBSD_NR_fremovexattr 386
#define TARGET_NETBSD_NR___stat30 387
#define TARGET_NETBSD_NR___fstat30 388
#define TARGET_NETBSD_NR___lstat30 389
#define TARGET_NETBSD_NR___getdents30 390
#define TARGET_NETBSD_NR_compat_30___fhstat30 392
#define TARGET_NETBSD_NR___ntp_gettime30 393
#define TARGET_NETBSD_NR___socket30 394
#define TARGET_NETBSD_NR___getfh30 395
#define TARGET_NETBSD_NR___fhopen40 396
#define TARGET_NETBSD_NR___fhstatvfs140 397
#define TARGET_NETBSD_NR___fhstat40 398
#define TARGET_NETBSD_NR_aio_cancel 399
#define TARGET_NETBSD_NR_aio_error 400
#define TARGET_NETBSD_NR_aio_fsync 401
#define TARGET_NETBSD_NR_aio_read 402
#define TARGET_NETBSD_NR_aio_return 403
#define TARGET_NETBSD_NR_aio_suspend 404
#define TARGET_NETBSD_NR_aio_write 405
#define TARGET_NETBSD_NR_lio_listio 406
#define TARGET_NETBSD_NR___mount50 410
#define TARGET_NETBSD_NR_mremap 411
#define TARGET_NETBSD_NR_pset_create 412
#define TARGET_NETBSD_NR_pset_destroy 413
#define TARGET_NETBSD_NR_pset_assign 414
#define TARGET_NETBSD_NR__pset_bind 415
#define TARGET_NETBSD_NR___posix_fadvise50 416

View File

@@ -1,187 +0,0 @@
{ TARGET_OPENBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR___semctl, "__semctl", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR___syscall, "__syscall", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL },
{ TARGET_OPENBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL },
{ TARGET_OPENBSD_NR_acct, "acct", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_adjfreq, "adjfreq", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_adjtime, "adjtime", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_bind, "bind", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_break, "break", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_chdir, "chdir", "%s(\"%s\")", NULL, NULL },
{ TARGET_OPENBSD_NR_chflags, "chflags", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_chmod, "chmod", "%s(\"%s\",%#o)", NULL, NULL },
{ TARGET_OPENBSD_NR_chown, "chown", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_chroot, "chroot", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_clock_getres, "clock_getres", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_clock_gettime, "clock_gettime", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_clock_settime, "clock_settime", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_close, "close", "%s(%d)", NULL, NULL },
{ TARGET_OPENBSD_NR_closefrom, "closefrom", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_connect, "connect", "%s(%d,%#x,%d)", NULL, NULL },
{ TARGET_OPENBSD_NR_dup, "dup", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_dup2, "dup2", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_execve, "execve", NULL, print_execve, NULL },
{ TARGET_OPENBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL },
{ TARGET_OPENBSD_NR_fchdir, "fchdir", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_fchflags, "fchflags", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL },
{ TARGET_OPENBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL },
{ TARGET_OPENBSD_NR_fcntl, "fcntl", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_fhopen, "fhopen", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_fhstat, "fhstat", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_fhstatfs, "fhstatfs", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_flock, "flock", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_fork, "fork", "%s()", NULL, NULL },
{ TARGET_OPENBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_fstat, "fstat", "%s(%d,%p)", NULL, NULL },
{ TARGET_OPENBSD_NR_fstatfs, "fstatfs", "%s(%d,%p)", NULL, NULL },
{ TARGET_OPENBSD_NR_fsync, "fsync", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_futimes, "futimes", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
{ TARGET_OPENBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL },
{ TARGET_OPENBSD_NR_getfh, "getfh", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getfsstat, "getfsstat", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getgid, "getgid", "%s()", NULL, NULL },
{ TARGET_OPENBSD_NR_getgroups, "getgroups", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getitimer, "getitimer", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getlogin, "getlogin", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getpeereid, "getpeereid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getpeername, "getpeername", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getpgid, "getpgid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getpgrp, "getpgrp", "%s()", NULL, NULL },
{ TARGET_OPENBSD_NR_getpid, "getpid", "%s()", NULL, NULL },
{ TARGET_OPENBSD_NR_getppid, "getppid", "%s()", NULL, NULL },
{ TARGET_OPENBSD_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL },
{ TARGET_OPENBSD_NR_getresgid, "getresgid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getresuid, "getresuid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getrlimit, "getrlimit", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getrusage, "getrusage", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getsid, "getsid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getsockname, "getsockname", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getthrid, "getthrid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_getuid, "getuid", "%s()", NULL, NULL },
{ TARGET_OPENBSD_NR_ioctl, "ioctl", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL },
{ TARGET_OPENBSD_NR_kevent, "kevent", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_kill, "kill", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_kqueue, "kqueue", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_ktrace, "ktrace", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_lchown, "lchown", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_lfs_bmapv, "lfs_bmapv", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_lfs_markv, "lfs_markv", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_lfs_segclean, "lfs_segclean", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_lfs_segwait, "lfs_segwait", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL },
{ TARGET_OPENBSD_NR_listen, "listen", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_lseek, "lseek", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_lstat, "lstat", "%s(\"%s\",%p)", NULL, NULL },
{ TARGET_OPENBSD_NR_madvise, "madvise", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_mincore, "mincore", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_minherit, "minherit", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_mkdir, "mkdir", "%s(\"%s\",%#o)", NULL, NULL },
{ TARGET_OPENBSD_NR_mkfifo, "mkfifo", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_mknod, "mknod", "%s(\"%s\",%#o,%#x)", NULL, NULL },
{ TARGET_OPENBSD_NR_mlock, "mlock", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_mlockall, "mlockall", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_mmap, "mmap", NULL, NULL, print_syscall_ret_addr },
{ TARGET_OPENBSD_NR_mount, "mount", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_mprotect, "mprotect", "%s(%#x,%#x,%d)", NULL, NULL },
{ TARGET_OPENBSD_NR_mquery, "mquery", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_msgctl, "msgctl", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_msgget, "msgget", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_msgrcv, "msgrcv", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_msgsnd, "msgsnd", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_msync, "msync", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_munlock, "munlock", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_munlockall, "munlockall", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_munmap, "munmap", "%s(%p,%d)", NULL, NULL },
{ TARGET_OPENBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL },
{ TARGET_OPENBSD_NR_opipe, "opipe", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_osigaltstack, "osigaltstack", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_pathconf, "pathconf", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_pipe, "pipe", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_poll, "poll", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_pread, "pread", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_preadv, "preadv", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_profil, "profil", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_ptrace, "ptrace", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_pwrite, "pwrite", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_pwritev, "pwritev", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_quotactl, "quotactl", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_read, "read", "%s(%d,%#x,%d)", NULL, NULL },
{ TARGET_OPENBSD_NR_readlink, "readlink", "%s(\"%s\",%p,%d)", NULL, NULL },
{ TARGET_OPENBSD_NR_readv, "readv", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_reboot, "reboot", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_recvfrom, "recvfrom", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_recvmsg, "recvmsg", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_rename, "rename", "%s(\"%s\",\"%s\")", NULL, NULL },
{ TARGET_OPENBSD_NR_revoke, "revoke", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_rfork, "rfork", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_rmdir, "rmdir", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_sbrk, "sbrk", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_select, "select", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_semget, "semget", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_semop, "semop", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_sendto, "sendto", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setegid, "setegid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_seteuid, "seteuid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setgid, "setgid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setgroups, "setgroups", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setitimer, "setitimer", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setlogin, "setlogin", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setpgid, "setpgid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setpriority, "setpriority", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setregid, "setregid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setresgid, "setresgid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setresuid, "setresuid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setreuid, "setreuid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setrlimit, "setrlimit", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setsid, "setsid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setsockopt, "setsockopt", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_settimeofday, "settimeofday", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_setuid, "setuid", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_shmat, "shmat", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_shmctl, "shmctl", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_shmdt, "shmdt", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_shmget, "shmget", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_shutdown, "shutdown", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_sigaction, "sigaction", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_sigaltstack, "sigaltstack", "%s(%p,%p)", NULL, NULL },
{ TARGET_OPENBSD_NR_sigpending, "sigpending", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_sigprocmask, "sigprocmask", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_sigreturn, "sigreturn", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_sigsuspend, "sigsuspend", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_socket, "socket", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_socketpair, "socketpair", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_sstk, "sstk", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_stat, "stat", "%s(\"%s\",%p)", NULL, NULL },
{ TARGET_OPENBSD_NR_statfs, "statfs", "%s(\"%s\",%p)", NULL, NULL },
{ TARGET_OPENBSD_NR_swapctl, "swapctl", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL },
{ TARGET_OPENBSD_NR_sync, "sync", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_sysarch, "sysarch", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_syscall, "syscall", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_threxit, "threxit", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_thrsigdivert, "thrsigdivert", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_thrsleep, "thrsleep", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_thrwakeup, "thrwakeup", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_truncate, "truncate", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL },
{ TARGET_OPENBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL },
{ TARGET_OPENBSD_NR_unmount, "unmount", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_utimes, "utimes", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_vfork, "vfork", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_wait4, "wait4", NULL, NULL, NULL },
{ TARGET_OPENBSD_NR_write, "write", "%s(%d,%#x,%d)", NULL, NULL },
{ TARGET_OPENBSD_NR_writev, "writev", "%s(%d,%p,%#x)", NULL, NULL },
{ TARGET_OPENBSD_NR_xfspioctl, "xfspioctl", NULL, NULL, NULL },

View File

@@ -1,225 +0,0 @@
/* $OpenBSD: syscall.h,v 1.101 2008/03/16 19:43:41 otto Exp $ */
/*
* System call numbers.
*
* created from; OpenBSD: syscalls.master,v 1.90 2008/03/16 19:42:57 otto Exp
*/
#define TARGET_OPENBSD_NR_syscall 0
#define TARGET_OPENBSD_NR_exit 1
#define TARGET_OPENBSD_NR_fork 2
#define TARGET_OPENBSD_NR_read 3
#define TARGET_OPENBSD_NR_write 4
#define TARGET_OPENBSD_NR_open 5
#define TARGET_OPENBSD_NR_close 6
#define TARGET_OPENBSD_NR_wait4 7
#define TARGET_OPENBSD_NR_link 9
#define TARGET_OPENBSD_NR_unlink 10
#define TARGET_OPENBSD_NR_chdir 12
#define TARGET_OPENBSD_NR_fchdir 13
#define TARGET_OPENBSD_NR_mknod 14
#define TARGET_OPENBSD_NR_chmod 15
#define TARGET_OPENBSD_NR_chown 16
#define TARGET_OPENBSD_NR_break 17
#define TARGET_OPENBSD_NR_getpid 20
#define TARGET_OPENBSD_NR_mount 21
#define TARGET_OPENBSD_NR_unmount 22
#define TARGET_OPENBSD_NR_setuid 23
#define TARGET_OPENBSD_NR_getuid 24
#define TARGET_OPENBSD_NR_geteuid 25
#define TARGET_OPENBSD_NR_ptrace 26
#define TARGET_OPENBSD_NR_recvmsg 27
#define TARGET_OPENBSD_NR_sendmsg 28
#define TARGET_OPENBSD_NR_recvfrom 29
#define TARGET_OPENBSD_NR_accept 30
#define TARGET_OPENBSD_NR_getpeername 31
#define TARGET_OPENBSD_NR_getsockname 32
#define TARGET_OPENBSD_NR_access 33
#define TARGET_OPENBSD_NR_chflags 34
#define TARGET_OPENBSD_NR_fchflags 35
#define TARGET_OPENBSD_NR_sync 36
#define TARGET_OPENBSD_NR_kill 37
#define TARGET_OPENBSD_NR_getppid 39
#define TARGET_OPENBSD_NR_dup 41
#define TARGET_OPENBSD_NR_opipe 42
#define TARGET_OPENBSD_NR_getegid 43
#define TARGET_OPENBSD_NR_profil 44
#define TARGET_OPENBSD_NR_ktrace 45
#define TARGET_OPENBSD_NR_sigaction 46
#define TARGET_OPENBSD_NR_getgid 47
#define TARGET_OPENBSD_NR_sigprocmask 48
#define TARGET_OPENBSD_NR_getlogin 49
#define TARGET_OPENBSD_NR_setlogin 50
#define TARGET_OPENBSD_NR_acct 51
#define TARGET_OPENBSD_NR_sigpending 52
#define TARGET_OPENBSD_NR_osigaltstack 53
#define TARGET_OPENBSD_NR_ioctl 54
#define TARGET_OPENBSD_NR_reboot 55
#define TARGET_OPENBSD_NR_revoke 56
#define TARGET_OPENBSD_NR_symlink 57
#define TARGET_OPENBSD_NR_readlink 58
#define TARGET_OPENBSD_NR_execve 59
#define TARGET_OPENBSD_NR_umask 60
#define TARGET_OPENBSD_NR_chroot 61
#define TARGET_OPENBSD_NR_vfork 66
#define TARGET_OPENBSD_NR_sbrk 69
#define TARGET_OPENBSD_NR_sstk 70
#define TARGET_OPENBSD_NR_munmap 73
#define TARGET_OPENBSD_NR_mprotect 74
#define TARGET_OPENBSD_NR_madvise 75
#define TARGET_OPENBSD_NR_mincore 78
#define TARGET_OPENBSD_NR_getgroups 79
#define TARGET_OPENBSD_NR_setgroups 80
#define TARGET_OPENBSD_NR_getpgrp 81
#define TARGET_OPENBSD_NR_setpgid 82
#define TARGET_OPENBSD_NR_setitimer 83
#define TARGET_OPENBSD_NR_getitimer 86
#define TARGET_OPENBSD_NR_dup2 90
#define TARGET_OPENBSD_NR_fcntl 92
#define TARGET_OPENBSD_NR_select 93
#define TARGET_OPENBSD_NR_fsync 95
#define TARGET_OPENBSD_NR_setpriority 96
#define TARGET_OPENBSD_NR_socket 97
#define TARGET_OPENBSD_NR_connect 98
#define TARGET_OPENBSD_NR_getpriority 100
#define TARGET_OPENBSD_NR_sigreturn 103
#define TARGET_OPENBSD_NR_bind 104
#define TARGET_OPENBSD_NR_setsockopt 105
#define TARGET_OPENBSD_NR_listen 106
#define TARGET_OPENBSD_NR_sigsuspend 111
#define TARGET_OPENBSD_NR_gettimeofday 116
#define TARGET_OPENBSD_NR_getrusage 117
#define TARGET_OPENBSD_NR_getsockopt 118
#define TARGET_OPENBSD_NR_readv 120
#define TARGET_OPENBSD_NR_writev 121
#define TARGET_OPENBSD_NR_settimeofday 122
#define TARGET_OPENBSD_NR_fchown 123
#define TARGET_OPENBSD_NR_fchmod 124
#define TARGET_OPENBSD_NR_setreuid 126
#define TARGET_OPENBSD_NR_setregid 127
#define TARGET_OPENBSD_NR_rename 128
#define TARGET_OPENBSD_NR_flock 131
#define TARGET_OPENBSD_NR_mkfifo 132
#define TARGET_OPENBSD_NR_sendto 133
#define TARGET_OPENBSD_NR_shutdown 134
#define TARGET_OPENBSD_NR_socketpair 135
#define TARGET_OPENBSD_NR_mkdir 136
#define TARGET_OPENBSD_NR_rmdir 137
#define TARGET_OPENBSD_NR_utimes 138
#define TARGET_OPENBSD_NR_adjtime 140
#define TARGET_OPENBSD_NR_setsid 147
#define TARGET_OPENBSD_NR_quotactl 148
#define TARGET_OPENBSD_NR_nfssvc 155
#define TARGET_OPENBSD_NR_getfh 161
#define TARGET_OPENBSD_NR_sysarch 165
#define TARGET_OPENBSD_NR_pread 173
#define TARGET_OPENBSD_NR_pwrite 174
#define TARGET_OPENBSD_NR_setgid 181
#define TARGET_OPENBSD_NR_setegid 182
#define TARGET_OPENBSD_NR_seteuid 183
#define TARGET_OPENBSD_NR_lfs_bmapv 184
#define TARGET_OPENBSD_NR_lfs_markv 185
#define TARGET_OPENBSD_NR_lfs_segclean 186
#define TARGET_OPENBSD_NR_lfs_segwait 187
#define TARGET_OPENBSD_NR_pathconf 191
#define TARGET_OPENBSD_NR_fpathconf 192
#define TARGET_OPENBSD_NR_swapctl 193
#define TARGET_OPENBSD_NR_getrlimit 194
#define TARGET_OPENBSD_NR_setrlimit 195
#define TARGET_OPENBSD_NR_getdirentries 196
#define TARGET_OPENBSD_NR_mmap 197
#define TARGET_OPENBSD_NR___syscall 198
#define TARGET_OPENBSD_NR_lseek 199
#define TARGET_OPENBSD_NR_truncate 200
#define TARGET_OPENBSD_NR_ftruncate 201
#define TARGET_OPENBSD_NR___sysctl 202
#define TARGET_OPENBSD_NR_mlock 203
#define TARGET_OPENBSD_NR_munlock 204
#define TARGET_OPENBSD_NR_futimes 206
#define TARGET_OPENBSD_NR_getpgid 207
#define TARGET_OPENBSD_NR_xfspioctl 208
#define TARGET_OPENBSD_NR_semget 221
#define TARGET_OPENBSD_NR_msgget 225
#define TARGET_OPENBSD_NR_msgsnd 226
#define TARGET_OPENBSD_NR_msgrcv 227
#define TARGET_OPENBSD_NR_shmat 228
#define TARGET_OPENBSD_NR_shmdt 230
#define TARGET_OPENBSD_NR_clock_gettime 232
#define TARGET_OPENBSD_NR_clock_settime 233
#define TARGET_OPENBSD_NR_clock_getres 234
#define TARGET_OPENBSD_NR_nanosleep 240
#define TARGET_OPENBSD_NR_minherit 250
#define TARGET_OPENBSD_NR_rfork 251
#define TARGET_OPENBSD_NR_poll 252
#define TARGET_OPENBSD_NR_issetugid 253
#define TARGET_OPENBSD_NR_lchown 254
#define TARGET_OPENBSD_NR_getsid 255
#define TARGET_OPENBSD_NR_msync 256
#define TARGET_OPENBSD_NR_pipe 263
#define TARGET_OPENBSD_NR_fhopen 264
#define TARGET_OPENBSD_NR_preadv 267
#define TARGET_OPENBSD_NR_pwritev 268
#define TARGET_OPENBSD_NR_kqueue 269
#define TARGET_OPENBSD_NR_kevent 270
#define TARGET_OPENBSD_NR_mlockall 271
#define TARGET_OPENBSD_NR_munlockall 272
#define TARGET_OPENBSD_NR_getpeereid 273
#define TARGET_OPENBSD_NR_getresuid 281
#define TARGET_OPENBSD_NR_setresuid 282
#define TARGET_OPENBSD_NR_getresgid 283
#define TARGET_OPENBSD_NR_setresgid 284
#define TARGET_OPENBSD_NR_mquery 286
#define TARGET_OPENBSD_NR_closefrom 287
#define TARGET_OPENBSD_NR_sigaltstack 288
#define TARGET_OPENBSD_NR_shmget 289
#define TARGET_OPENBSD_NR_semop 290
#define TARGET_OPENBSD_NR_stat 291
#define TARGET_OPENBSD_NR_fstat 292
#define TARGET_OPENBSD_NR_lstat 293
#define TARGET_OPENBSD_NR_fhstat 294
#define TARGET_OPENBSD_NR___semctl 295
#define TARGET_OPENBSD_NR_shmctl 296
#define TARGET_OPENBSD_NR_msgctl 297
#define TARGET_OPENBSD_NR_sched_yield 298
#define TARGET_OPENBSD_NR_getthrid 299
#define TARGET_OPENBSD_NR_thrsleep 300
#define TARGET_OPENBSD_NR_thrwakeup 301
#define TARGET_OPENBSD_NR_threxit 302
#define TARGET_OPENBSD_NR_thrsigdivert 303
#define TARGET_OPENBSD_NR___getcwd 304
#define TARGET_OPENBSD_NR_adjfreq 305
#define TARGET_OPENBSD_NR_getfsstat 306
#define TARGET_OPENBSD_NR_statfs 307
#define TARGET_OPENBSD_NR_fstatfs 308
#define TARGET_OPENBSD_NR_fhstatfs 309
/* syscall flags from machine/trap.h */
/* $OpenBSD: trap.h,v 1.4 2008/07/04 22:04:37 kettenis Exp $ */
/* $NetBSD: trap.h,v 1.4 1999/06/07 05:28:04 eeh Exp $ */
/*
* Copyright (c) 1996-1999 Eduardo Horvath
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#define TARGET_OPENBSD_SYSCALL_G2RFLAG 0x400 /* on success, return to %g2 rather than npc */
#define TARGET_OPENBSD_SYSCALL_G7RFLAG 0x800 /* use %g7 as above (deprecated) */

View File

@@ -1,163 +0,0 @@
/* Code to mangle pathnames into those matching a given prefix.
eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so");
The assumption is that this area does not change.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include "qemu.h"
#include "qemu-common.h"
struct pathelem
{
/* Name of this, eg. lib */
char *name;
/* Full path name, eg. /usr/gnemul/x86-linux/lib. */
char *pathname;
struct pathelem *parent;
/* Children */
unsigned int num_entries;
struct pathelem *entries[0];
};
static struct pathelem *base;
/* First N chars of S1 match S2, and S2 is N chars long. */
static int strneq(const char *s1, unsigned int n, const char *s2)
{
unsigned int i;
for (i = 0; i < n; i++)
if (s1[i] != s2[i])
return 0;
return s2[i] == 0;
}
static struct pathelem *add_entry(struct pathelem *root, const char *name);
static struct pathelem *new_entry(const char *root,
struct pathelem *parent,
const char *name)
{
struct pathelem *new = malloc(sizeof(*new));
new->name = strdup(name);
asprintf(&new->pathname, "%s/%s", root, name);
new->num_entries = 0;
return new;
}
#define streq(a,b) (strcmp((a), (b)) == 0)
static struct pathelem *add_dir_maybe(struct pathelem *path)
{
DIR *dir;
if ((dir = opendir(path->pathname)) != NULL) {
struct dirent *dirent;
while ((dirent = readdir(dir)) != NULL) {
if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
path = add_entry(path, dirent->d_name);
}
}
closedir(dir);
}
return path;
}
static struct pathelem *add_entry(struct pathelem *root, const char *name)
{
root->num_entries++;
root = realloc(root, sizeof(*root)
+ sizeof(root->entries[0])*root->num_entries);
root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
root->entries[root->num_entries-1]
= add_dir_maybe(root->entries[root->num_entries-1]);
return root;
}
/* This needs to be done after tree is stabilized (ie. no more reallocs!). */
static void set_parents(struct pathelem *child, struct pathelem *parent)
{
unsigned int i;
child->parent = parent;
for (i = 0; i < child->num_entries; i++)
set_parents(child->entries[i], child);
}
/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
static const char *
follow_path(const struct pathelem *cursor, const char *name)
{
unsigned int i, namelen;
name += strspn(name, "/");
namelen = strcspn(name, "/");
if (namelen == 0)
return cursor->pathname;
if (strneq(name, namelen, ".."))
return follow_path(cursor->parent, name + namelen);
if (strneq(name, namelen, "."))
return follow_path(cursor, name + namelen);
for (i = 0; i < cursor->num_entries; i++)
if (strneq(name, namelen, cursor->entries[i]->name))
return follow_path(cursor->entries[i], name + namelen);
/* Not found */
return NULL;
}
void init_paths(const char *prefix)
{
char pref_buf[PATH_MAX];
if (prefix[0] == '\0' ||
!strcmp(prefix, "/"))
return;
if (prefix[0] != '/') {
char *cwd = getcwd(NULL, 0);
size_t pref_buf_len = sizeof(pref_buf);
if (!cwd)
abort();
pstrcpy(pref_buf, sizeof(pref_buf), cwd);
pstrcat(pref_buf, pref_buf_len, "/");
pstrcat(pref_buf, pref_buf_len, prefix);
free(cwd);
} else
pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1);
base = new_entry("", NULL, pref_buf);
base = add_dir_maybe(base);
if (base->num_entries == 0) {
free (base);
base = NULL;
} else {
set_parents(base, base);
}
}
/* Look for path in emulation dir, otherwise return name. */
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[0] != '/')
return name;
return follow_path(base, name) ?: name;
}

View File

@@ -1,24 +0,0 @@
#ifndef QEMU_TYPES_H
#define QEMU_TYPES_H
#include "cpu.h"
#ifdef TARGET_ABI32
typedef uint32_t abi_ulong;
typedef int32_t abi_long;
#define TARGET_ABI_FMT_lx "%08x"
#define TARGET_ABI_FMT_ld "%d"
#define TARGET_ABI_FMT_lu "%u"
#define TARGET_ABI_BITS 32
#else
typedef target_ulong abi_ulong;
typedef target_long abi_long;
#define TARGET_ABI_FMT_lx TARGET_FMT_lx
#define TARGET_ABI_FMT_ld TARGET_FMT_ld
#define TARGET_ABI_FMT_lu TARGET_FMT_lu
#define TARGET_ABI_BITS TARGET_LONG_BITS
/* for consistency, define ABI32 too */
#if TARGET_ABI_BITS == 32
#define TARGET_ABI32 1
#endif
#endif
#endif

View File

@@ -1,392 +0,0 @@
#ifndef QEMU_H
#define QEMU_H
#include <signal.h>
#include <string.h>
#include "cpu.h"
#undef DEBUG_REMAP
#ifdef DEBUG_REMAP
#include <stdlib.h>
#endif /* DEBUG_REMAP */
#include "qemu-types.h"
enum BSDType {
target_freebsd,
target_netbsd,
target_openbsd,
};
#include "syscall_defs.h"
#include "syscall.h"
#include "target_signal.h"
#include "gdbstub.h"
#if defined(USE_NPTL)
#define THREAD __thread
#else
#define THREAD
#endif
/* This struct is used to hold certain information about the image.
* Basically, it replicates in user space what would be certain
* task_struct fields in the kernel
*/
struct image_info {
abi_ulong load_addr;
abi_ulong start_code;
abi_ulong end_code;
abi_ulong start_data;
abi_ulong end_data;
abi_ulong start_brk;
abi_ulong brk;
abi_ulong start_mmap;
abi_ulong mmap;
abi_ulong rss;
abi_ulong start_stack;
abi_ulong entry;
abi_ulong code_offset;
abi_ulong data_offset;
char **host_argv;
int personality;
};
#define MAX_SIGQUEUE_SIZE 1024
struct sigqueue {
struct sigqueue *next;
//target_siginfo_t info;
};
struct emulated_sigtable {
int pending; /* true if signal is pending */
struct sigqueue *first;
struct sigqueue info; /* in order to always have memory for the
first signal, we put it here */
};
/* NOTE: we force a big alignment so that the stack stored after is
aligned too */
typedef struct TaskState {
struct TaskState *next;
int used; /* non zero if used */
struct image_info *info;
struct emulated_sigtable sigtab[TARGET_NSIG];
struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
struct sigqueue *first_free; /* first free siginfo queue entry */
int signal_pending; /* non zero if a signal may be pending */
uint8_t stack[0];
} __attribute__((aligned(16))) TaskState;
void init_task_state(TaskState *ts);
extern const char *qemu_uname_release;
/* ??? See if we can avoid exposing so much of the loader internals. */
/*
* MAX_ARG_PAGES defines the number of pages allocated for arguments
* and envelope for the new program. 32 should suffice, this gives
* a maximum env+arg of 128kB w/4KB pages!
*/
#define MAX_ARG_PAGES 32
/*
* This structure is used to hold the arguments that are
* used when loading binaries.
*/
struct linux_binprm {
char buf[128];
void *page[MAX_ARG_PAGES];
abi_ulong p;
int fd;
int e_uid, e_gid;
int argc, envc;
char **argv;
char **envp;
char * filename; /* Name of binary */
};
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
abi_ulong stringp, int push_ptr);
int loader_exec(const char * filename, char ** argv, char ** envp,
struct target_pt_regs * regs, struct image_info *infop);
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info);
int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info);
abi_long memcpy_to_target(abi_ulong dest, const void *src,
unsigned long len);
void target_set_brk(abi_ulong new_brk);
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 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);
abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
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, 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);
void fork_end(int child);
#include "qemu-log.h"
/* strace.c */
void
print_freebsd_syscall(int num,
abi_long arg1, abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5, abi_long arg6);
void print_freebsd_syscall_ret(int num, abi_long ret);
void
print_netbsd_syscall(int num,
abi_long arg1, abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5, abi_long arg6);
void print_netbsd_syscall_ret(int num, abi_long ret);
void
print_openbsd_syscall(int num,
abi_long arg1, abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5, abi_long arg6);
void print_openbsd_syscall_ret(int num, abi_long ret);
extern int do_strace;
/* signal.c */
void process_pending_signals(CPUState *cpu_env);
void signal_init(void);
//int queue_signal(CPUState *env, int sig, target_siginfo_t *info);
//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
long do_sigreturn(CPUState *env);
long do_rt_sigreturn(CPUState *env);
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
/* mmap.c */
int target_mprotect(abi_ulong start, abi_ulong len, int prot);
abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
int flags, int fd, abi_ulong offset);
int target_munmap(abi_ulong start, abi_ulong len);
abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
abi_ulong new_size, unsigned long flags,
abi_ulong new_addr);
int target_msync(abi_ulong start, abi_ulong len, int flags);
extern unsigned long last_brk;
void mmap_lock(void);
void mmap_unlock(void);
void cpu_list_lock(void);
void cpu_list_unlock(void);
#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
#define VERIFY_WRITE 1 /* implies read access */
static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
{
return page_check_range((target_ulong)addr, size,
(type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0;
}
/* NOTE __get_user and __put_user use host pointers and don't check access. */
/* These are usually used to access struct data members once the
* struct has been locked - usually with lock_user_struct().
*/
#define __put_user(x, hptr)\
({\
int size = sizeof(*hptr);\
switch(size) {\
case 1:\
*(uint8_t *)(hptr) = (uint8_t)(typeof(*hptr))(x);\
break;\
case 2:\
*(uint16_t *)(hptr) = tswap16((typeof(*hptr))(x));\
break;\
case 4:\
*(uint32_t *)(hptr) = tswap32((typeof(*hptr))(x));\
break;\
case 8:\
*(uint64_t *)(hptr) = tswap64((typeof(*hptr))(x));\
break;\
default:\
abort();\
}\
0;\
})
#define __get_user(x, hptr) \
({\
int size = sizeof(*hptr);\
switch(size) {\
case 1:\
x = (typeof(*hptr))*(uint8_t *)(hptr);\
break;\
case 2:\
x = (typeof(*hptr))tswap16(*(uint16_t *)(hptr));\
break;\
case 4:\
x = (typeof(*hptr))tswap32(*(uint32_t *)(hptr));\
break;\
case 8:\
x = (typeof(*hptr))tswap64(*(uint64_t *)(hptr));\
break;\
default:\
/* avoid warning */\
x = 0;\
abort();\
}\
0;\
})
/* put_user()/get_user() take a guest address and check access */
/* These are usually used to access an atomic data type, such as an int,
* that has been passed by address. These internally perform locking
* and unlocking on the data type.
*/
#define put_user(x, gaddr, target_type) \
({ \
abi_ulong __gaddr = (gaddr); \
target_type *__hptr; \
abi_long __ret; \
if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \
__ret = __put_user((x), __hptr); \
unlock_user(__hptr, __gaddr, sizeof(target_type)); \
} else \
__ret = -TARGET_EFAULT; \
__ret; \
})
#define get_user(x, gaddr, target_type) \
({ \
abi_ulong __gaddr = (gaddr); \
target_type *__hptr; \
abi_long __ret; \
if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \
__ret = __get_user((x), __hptr); \
unlock_user(__hptr, __gaddr, 0); \
} else { \
/* avoid warning */ \
(x) = 0; \
__ret = -TARGET_EFAULT; \
} \
__ret; \
})
#define put_user_ual(x, gaddr) put_user((x), (gaddr), abi_ulong)
#define put_user_sal(x, gaddr) put_user((x), (gaddr), abi_long)
#define put_user_u64(x, gaddr) put_user((x), (gaddr), uint64_t)
#define put_user_s64(x, gaddr) put_user((x), (gaddr), int64_t)
#define put_user_u32(x, gaddr) put_user((x), (gaddr), uint32_t)
#define put_user_s32(x, gaddr) put_user((x), (gaddr), int32_t)
#define put_user_u16(x, gaddr) put_user((x), (gaddr), uint16_t)
#define put_user_s16(x, gaddr) put_user((x), (gaddr), int16_t)
#define put_user_u8(x, gaddr) put_user((x), (gaddr), uint8_t)
#define put_user_s8(x, gaddr) put_user((x), (gaddr), int8_t)
#define get_user_ual(x, gaddr) get_user((x), (gaddr), abi_ulong)
#define get_user_sal(x, gaddr) get_user((x), (gaddr), abi_long)
#define get_user_u64(x, gaddr) get_user((x), (gaddr), uint64_t)
#define get_user_s64(x, gaddr) get_user((x), (gaddr), int64_t)
#define get_user_u32(x, gaddr) get_user((x), (gaddr), uint32_t)
#define get_user_s32(x, gaddr) get_user((x), (gaddr), int32_t)
#define get_user_u16(x, gaddr) get_user((x), (gaddr), uint16_t)
#define get_user_s16(x, gaddr) get_user((x), (gaddr), int16_t)
#define get_user_u8(x, gaddr) get_user((x), (gaddr), uint8_t)
#define get_user_s8(x, gaddr) get_user((x), (gaddr), int8_t)
/* copy_from_user() and copy_to_user() are usually used to copy data
* buffers between the target and host. These internally perform
* locking/unlocking of the memory.
*/
abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
/* Functions for accessing guest memory. The tget and tput functions
read/write single values, byteswapping as neccessary. The lock_user
gets a pointer to a contiguous area of guest memory, but does not perform
and byteswapping. lock_user may return either a pointer to the guest
memory, or a temporary buffer. */
/* Lock an area of guest memory into the host. If copy is true then the
host area will have the same contents as the guest. */
static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
{
if (!access_ok(type, guest_addr, len))
return NULL;
#ifdef DEBUG_REMAP
{
void *addr;
addr = malloc(len);
if (copy)
memcpy(addr, g2h(guest_addr), len);
else
memset(addr, 0, len);
return addr;
}
#else
return g2h(guest_addr);
#endif
}
/* Unlock an area of guest memory. The first LEN bytes must be
flushed back to guest memory. host_ptr = NULL is explicitly
allowed and does nothing. */
static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
long len)
{
#ifdef DEBUG_REMAP
if (!host_ptr)
return;
if (host_ptr == g2h(guest_addr))
return;
if (len > 0)
memcpy(g2h(guest_addr), host_ptr, len);
free(host_ptr);
#endif
}
/* Return the length of a string in target memory or -TARGET_EFAULT if
access error. */
abi_long target_strlen(abi_ulong gaddr);
/* Like lock_user but for null terminated strings. */
static inline void *lock_user_string(abi_ulong guest_addr)
{
abi_long len;
len = target_strlen(guest_addr);
if (len < 0)
return NULL;
return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
}
/* Helper macros for locking/ulocking a target struct. */
#define lock_user_struct(type, host_ptr, guest_addr, copy) \
(host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy))
#define unlock_user_struct(host_ptr, guest_addr, copy) \
unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
#if defined(USE_NPTL)
#include <pthread.h>
#endif
#endif /* QEMU_H */

View File

@@ -1,38 +0,0 @@
/*
* Emulation of BSD signals
*
* Copyright (c) 2003 - 2008 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include "qemu.h"
#include "target_signal.h"
//#define DEBUG_SIGNAL
void signal_init(void)
{
}
void process_pending_signals(CPUState *cpu_env)
{
}

View File

@@ -1,9 +0,0 @@
struct target_pt_regs {
abi_ulong psr;
abi_ulong pc;
abi_ulong npc;
abi_ulong y;
abi_ulong u_regs[16];
};
#define UNAME_MACHINE "sun4"

View File

@@ -1,27 +0,0 @@
#ifndef TARGET_SIGNAL_H
#define TARGET_SIGNAL_H
#include "cpu.h"
/* this struct defines a stack used during syscall handling */
typedef struct target_sigaltstack {
abi_ulong ss_sp;
abi_long ss_flags;
abi_ulong ss_size;
} target_stack_t;
#ifndef UREG_I6
#define UREG_I6 6
#endif
#ifndef UREG_FP
#define UREG_FP UREG_I6
#endif
static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
{
return state->regwptr[UREG_FP];
}
#endif /* TARGET_SIGNAL_H */

View File

@@ -1,10 +0,0 @@
struct target_pt_regs {
abi_ulong u_regs[16];
abi_ulong tstate;
abi_ulong pc;
abi_ulong npc;
abi_ulong y;
abi_ulong fprs;
};
#define UNAME_MACHINE "sun4u"

View File

@@ -1,27 +0,0 @@
#ifndef TARGET_SIGNAL_H
#define TARGET_SIGNAL_H
#include "cpu.h"
/* this struct defines a stack used during syscall handling */
typedef struct target_sigaltstack {
abi_ulong ss_sp;
abi_long ss_flags;
abi_ulong ss_size;
} target_stack_t;
#ifndef UREG_I6
#define UREG_I6 6
#endif
#ifndef UREG_FP
#define UREG_FP UREG_I6
#endif
static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
{
return state->regwptr[UREG_FP];
}
#endif /* TARGET_SIGNAL_H */

View File

@@ -1,191 +0,0 @@
#include <stdio.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "qemu.h"
int do_strace=0;
struct syscallname {
int nr;
const char *name;
const char *format;
void (*call)(const struct syscallname *,
abi_long, abi_long, abi_long,
abi_long, abi_long, abi_long);
void (*result)(const struct syscallname *, abi_long);
};
/*
* Utility functions
*/
static void
print_execve(const struct syscallname *name,
abi_long arg1, abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5, abi_long arg6)
{
abi_ulong arg_ptr_addr;
char *s;
if (!(s = lock_user_string(arg1)))
return;
gemu_log("%s(\"%s\",{", name->name, s);
unlock_user(s, arg1, 0);
for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) {
abi_ulong *arg_ptr, arg_addr, s_addr;
arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
if (!arg_ptr)
return;
arg_addr = tswapl(*arg_ptr);
unlock_user(arg_ptr, arg_ptr_addr, 0);
if (!arg_addr)
break;
if ((s = lock_user_string(arg_addr))) {
gemu_log("\"%s\",", s);
unlock_user(s, s_addr, 0);
}
}
gemu_log("NULL})");
}
/*
* Variants for the return value output function
*/
static void
print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
{
if( ret == -1 ) {
gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno));
} else {
gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
}
}
#if 0 /* currently unused */
static void
print_syscall_ret_raw(struct syscallname *name, abi_long ret)
{
gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
}
#endif
/*
* An array of all of the syscalls we know about
*/
static const struct syscallname freebsd_scnames[] = {
#include "freebsd/strace.list"
};
static const struct syscallname netbsd_scnames[] = {
#include "netbsd/strace.list"
};
static const struct syscallname openbsd_scnames[] = {
#include "openbsd/strace.list"
};
static void
print_syscall(int num, const struct syscallname *scnames, unsigned int nscnames,
abi_long arg1, abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5, abi_long arg6)
{
unsigned int i;
const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
TARGET_ABI_FMT_ld ")";
gemu_log("%d ", getpid() );
for (i = 0; i < nscnames; i++)
if (scnames[i].nr == num) {
if (scnames[i].call != NULL) {
scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5,
arg6);
} else {
/* XXX: this format system is broken because it uses
host types and host pointers for strings */
if (scnames[i].format != NULL)
format = scnames[i].format;
gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4,
arg5, arg6);
}
return;
}
gemu_log("Unknown syscall %d\n", num);
}
static void
print_syscall_ret(int num, abi_long ret, const struct syscallname *scnames,
unsigned int nscnames)
{
unsigned int i;
for (i = 0; i < nscnames; i++)
if (scnames[i].nr == num) {
if (scnames[i].result != NULL) {
scnames[i].result(&scnames[i], ret);
} else {
if( ret < 0 ) {
gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret,
strerror(-ret));
} else {
gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
}
}
break;
}
}
/*
* The public interface to this module.
*/
void
print_freebsd_syscall(int num,
abi_long arg1, abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5, abi_long arg6)
{
print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames),
arg1, arg2, arg3, arg4, arg5, arg6);
}
void
print_freebsd_syscall_ret(int num, abi_long ret)
{
print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames));
}
void
print_netbsd_syscall(int num,
abi_long arg1, abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5, abi_long arg6)
{
print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames),
arg1, arg2, arg3, arg4, arg5, arg6);
}
void
print_netbsd_syscall_ret(int num, abi_long ret)
{
print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames));
}
void
print_openbsd_syscall(int num,
abi_long arg1, abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5, abi_long arg6)
{
print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames),
arg1, arg2, arg3, arg4, arg5, arg6);
}
void
print_openbsd_syscall_ret(int num, abi_long ret)
{
print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
}

View File

@@ -1,272 +0,0 @@
/*
* BSD syscalls
*
* Copyright (c) 2003 - 2008 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <signal.h>
#include <utime.h>
#include "qemu.h"
#include "qemu-common.h"
//#define DEBUG
static abi_ulong target_brk;
static abi_ulong target_original_brk;
#define get_errno(x) (x)
#define target_to_host_bitmask(x, tbl) (x)
void target_set_brk(abi_ulong new_brk)
{
target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
}
/* 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 ret;
void *p;
#ifdef DEBUG
gemu_log("freebsd syscall %d\n", num);
#endif
if(do_strace)
print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
switch(num) {
case TARGET_FREEBSD_NR_exit:
#ifdef HAVE_GPROF
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
/* XXX: should free thread stack and CPU env */
_exit(arg1);
ret = 0; /* avoid warning */
break;
case TARGET_FREEBSD_NR_read:
if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
goto efault;
ret = get_errno(read(arg1, p, arg3));
unlock_user(p, arg2, ret);
break;
case TARGET_FREEBSD_NR_write:
if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
goto efault;
ret = get_errno(write(arg1, p, arg3));
unlock_user(p, arg2, 0);
break;
case TARGET_FREEBSD_NR_open:
if (!(p = lock_user_string(arg1)))
goto efault;
ret = get_errno(open(path(p),
target_to_host_bitmask(arg2, fcntl_flags_tbl),
arg3));
unlock_user(p, arg1, 0);
break;
case TARGET_FREEBSD_NR_mmap:
ret = get_errno(target_mmap(arg1, arg2, arg3,
target_to_host_bitmask(arg4, mmap_flags_tbl),
arg5,
arg6));
break;
case TARGET_FREEBSD_NR_mprotect:
ret = get_errno(target_mprotect(arg1, arg2, arg3));
break;
case TARGET_FREEBSD_NR_syscall:
case TARGET_FREEBSD_NR___syscall:
ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
break;
default:
ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
break;
}
fail:
#ifdef DEBUG
gemu_log(" = %ld\n", ret);
#endif
if (do_strace)
print_freebsd_syscall_ret(num, ret);
return ret;
efault:
ret = -TARGET_EFAULT;
goto fail;
}
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)
{
abi_long ret;
void *p;
#ifdef DEBUG
gemu_log("netbsd syscall %d\n", num);
#endif
if(do_strace)
print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
switch(num) {
case TARGET_NETBSD_NR_exit:
#ifdef HAVE_GPROF
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
/* XXX: should free thread stack and CPU env */
_exit(arg1);
ret = 0; /* avoid warning */
break;
case TARGET_NETBSD_NR_read:
if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
goto efault;
ret = get_errno(read(arg1, p, arg3));
unlock_user(p, arg2, ret);
break;
case TARGET_NETBSD_NR_write:
if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
goto efault;
ret = get_errno(write(arg1, p, arg3));
unlock_user(p, arg2, 0);
break;
case TARGET_NETBSD_NR_open:
if (!(p = lock_user_string(arg1)))
goto efault;
ret = get_errno(open(path(p),
target_to_host_bitmask(arg2, fcntl_flags_tbl),
arg3));
unlock_user(p, arg1, 0);
break;
case TARGET_NETBSD_NR_mmap:
ret = get_errno(target_mmap(arg1, arg2, arg3,
target_to_host_bitmask(arg4, mmap_flags_tbl),
arg5,
arg6));
break;
case TARGET_NETBSD_NR_mprotect:
ret = get_errno(target_mprotect(arg1, arg2, arg3));
break;
case TARGET_NETBSD_NR_syscall:
case TARGET_NETBSD_NR___syscall:
ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
break;
default:
ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
break;
}
fail:
#ifdef DEBUG
gemu_log(" = %ld\n", ret);
#endif
if (do_strace)
print_netbsd_syscall_ret(num, ret);
return ret;
efault:
ret = -TARGET_EFAULT;
goto fail;
}
abi_long do_openbsd_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 ret;
void *p;
#ifdef DEBUG
gemu_log("openbsd syscall %d\n", num);
#endif
if(do_strace)
print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
switch(num) {
case TARGET_OPENBSD_NR_exit:
#ifdef HAVE_GPROF
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
/* XXX: should free thread stack and CPU env */
_exit(arg1);
ret = 0; /* avoid warning */
break;
case TARGET_OPENBSD_NR_read:
if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
goto efault;
ret = get_errno(read(arg1, p, arg3));
unlock_user(p, arg2, ret);
break;
case TARGET_OPENBSD_NR_write:
if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
goto efault;
ret = get_errno(write(arg1, p, arg3));
unlock_user(p, arg2, 0);
break;
case TARGET_OPENBSD_NR_open:
if (!(p = lock_user_string(arg1)))
goto efault;
ret = get_errno(open(path(p),
target_to_host_bitmask(arg2, fcntl_flags_tbl),
arg3));
unlock_user(p, arg1, 0);
break;
case TARGET_OPENBSD_NR_mmap:
ret = get_errno(target_mmap(arg1, arg2, arg3,
target_to_host_bitmask(arg4, mmap_flags_tbl),
arg5,
arg6));
break;
case TARGET_OPENBSD_NR_mprotect:
ret = get_errno(target_mprotect(arg1, arg2, arg3));
break;
case TARGET_OPENBSD_NR_syscall:
case TARGET_OPENBSD_NR___syscall:
ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
break;
default:
ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
break;
}
fail:
#ifdef DEBUG
gemu_log(" = %ld\n", ret);
#endif
if (do_strace)
print_openbsd_syscall_ret(num, ret);
return ret;
efault:
ret = -TARGET_EFAULT;
goto fail;
}
void syscall_init(void)
{
}

View File

@@ -1,108 +0,0 @@
/* $OpenBSD: signal.h,v 1.19 2006/01/08 14:20:16 millert Exp $ */
/* $NetBSD: signal.h,v 1.21 1996/02/09 18:25:32 christos Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)signal.h 8.2 (Berkeley) 1/21/94
*/
#define TARGET_NSIG 32 /* counting 0; could be 33 (mask is 1-32) */
#define TARGET_SIGHUP 1 /* hangup */
#define TARGET_SIGINT 2 /* interrupt */
#define TARGET_SIGQUIT 3 /* quit */
#define TARGET_SIGILL 4 /* illegal instruction (not reset when caught) */
#define TARGET_SIGTRAP 5 /* trace trap (not reset when caught) */
#define TARGET_SIGABRT 6 /* abort() */
#define TARGET_SIGIOT SIGABRT /* compatibility */
#define TARGET_SIGEMT 7 /* EMT instruction */
#define TARGET_SIGFPE 8 /* floating point exception */
#define TARGET_SIGKILL 9 /* kill (cannot be caught or ignored) */
#define TARGET_SIGBUS 10 /* bus error */
#define TARGET_SIGSEGV 11 /* segmentation violation */
#define TARGET_SIGSYS 12 /* bad argument to system call */
#define TARGET_SIGPIPE 13 /* write on a pipe with no one to read it */
#define TARGET_SIGALRM 14 /* alarm clock */
#define TARGET_SIGTERM 15 /* software termination signal from kill */
#define TARGET_SIGURG 16 /* urgent condition on IO channel */
#define TARGET_SIGSTOP 17 /* sendable stop signal not from tty */
#define TARGET_SIGTSTP 18 /* stop signal from tty */
#define TARGET_SIGCONT 19 /* continue a stopped process */
#define TARGET_SIGCHLD 20 /* to parent on child stop or exit */
#define TARGET_SIGTTIN 21 /* to readers pgrp upon background tty read */
#define TARGET_SIGTTOU 22 /* like TTIN for output if (tp->t_local&LTOSTOP) */
#define TARGET_SIGIO 23 /* input/output possible signal */
#define TARGET_SIGXCPU 24 /* exceeded CPU time limit */
#define TARGET_SIGXFSZ 25 /* exceeded file size limit */
#define TARGET_SIGVTALRM 26 /* virtual time alarm */
#define TARGET_SIGPROF 27 /* profiling time alarm */
#define TARGET_SIGWINCH 28 /* window size changes */
#define TARGET_SIGINFO 29 /* information request */
#define TARGET_SIGUSR1 30 /* user defined signal 1 */
#define TARGET_SIGUSR2 31 /* user defined signal 2 */
/*
* Language spec says we must list exactly one parameter, even though we
* actually supply three. Ugh!
*/
#define TARGET_SIG_DFL (void (*)(int))0
#define TARGET_SIG_IGN (void (*)(int))1
#define TARGET_SIG_ERR (void (*)(int))-1
#define TARGET_SA_ONSTACK 0x0001 /* take signal on signal stack */
#define TARGET_SA_RESTART 0x0002 /* restart system on signal return */
#define TARGET_SA_RESETHAND 0x0004 /* reset to SIG_DFL when taking signal */
#define TARGET_SA_NODEFER 0x0010 /* don't mask the signal we're delivering */
#define TARGET_SA_NOCLDWAIT 0x0020 /* don't create zombies (assign to pid 1) */
#define TARGET_SA_USERTRAMP 0x0100 /* do not bounce off kernel's sigtramp */
#define TARGET_SA_NOCLDSTOP 0x0008 /* do not generate SIGCHLD on child stop */
#define TARGET_SA_SIGINFO 0x0040 /* generate siginfo_t */
/*
* Flags for sigprocmask:
*/
#define TARGET_SIG_BLOCK 1 /* block specified signal set */
#define TARGET_SIG_UNBLOCK 2 /* unblock specified signal set */
#define TARGET_SIG_SETMASK 3 /* set specified signal set */
#define TARGET_BADSIG SIG_ERR
#define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */
#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */
#include "errno_defs.h"
#include "freebsd/syscall_nr.h"
#include "netbsd/syscall_nr.h"
#include "openbsd/syscall_nr.h"

View File

@@ -1,65 +0,0 @@
/* User memory access */
#include <stdio.h>
#include <string.h>
#include "qemu.h"
/* copy_from_user() and copy_to_user() are usually used to copy data
* buffers between the target and host. These internally perform
* locking/unlocking of the memory.
*/
abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
{
abi_long ret = 0;
void *ghptr;
if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) {
memcpy(hptr, ghptr, len);
unlock_user(ghptr, gaddr, 0);
} else
ret = -TARGET_EFAULT;
return ret;
}
abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
{
abi_long ret = 0;
void *ghptr;
if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) {
memcpy(ghptr, hptr, len);
unlock_user(ghptr, gaddr, len);
} else
ret = -TARGET_EFAULT;
return ret;
}
/* Return the length of a string in target memory or -TARGET_EFAULT if
access error */
abi_long target_strlen(abi_ulong guest_addr1)
{
uint8_t *ptr;
abi_ulong guest_addr;
int max_len, len;
guest_addr = guest_addr1;
for(;;) {
max_len = TARGET_PAGE_SIZE - (guest_addr & ~TARGET_PAGE_MASK);
ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1);
if (!ptr)
return -TARGET_EFAULT;
len = qemu_strnlen((char *)ptr, max_len);
unlock_user(ptr, guest_addr, 0);
guest_addr += len;
/* we don't allow wrapping or integer overflow */
if (guest_addr == 0 ||
(guest_addr - guest_addr1) > 0x7fffffff)
return -TARGET_EFAULT;
if (len != max_len)
break;
}
return guest_addr - guest_addr1;
}

View File

@@ -1,98 +0,0 @@
#define __USER_CS (0x33)
#define __USER_DS (0x2B)
struct target_pt_regs {
abi_ulong r15;
abi_ulong r14;
abi_ulong r13;
abi_ulong r12;
abi_ulong rbp;
abi_ulong rbx;
/* arguments: non interrupts/non tracing syscalls only save upto here*/
abi_ulong r11;
abi_ulong r10;
abi_ulong r9;
abi_ulong r8;
abi_ulong rax;
abi_ulong rcx;
abi_ulong rdx;
abi_ulong rsi;
abi_ulong rdi;
abi_ulong orig_rax;
/* end of arguments */
/* cpu exception frame or undefined */
abi_ulong rip;
abi_ulong cs;
abi_ulong eflags;
abi_ulong rsp;
abi_ulong ss;
/* top of stack page */
};
/* Maximum number of LDT entries supported. */
#define TARGET_LDT_ENTRIES 8192
/* The size of each LDT entry. */
#define TARGET_LDT_ENTRY_SIZE 8
#define TARGET_GDT_ENTRIES 16
#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
#define TARGET_GDT_ENTRY_TLS_MIN 12
#define TARGET_GDT_ENTRY_TLS_MAX 14
#if 0 // Redefine this
struct target_modify_ldt_ldt_s {
unsigned int entry_number;
abi_ulong base_addr;
unsigned int limit;
unsigned int seg_32bit:1;
unsigned int contents:2;
unsigned int read_exec_only:1;
unsigned int limit_in_pages:1;
unsigned int seg_not_present:1;
unsigned int useable:1;
unsigned int lm:1;
};
#else
struct target_modify_ldt_ldt_s {
unsigned int entry_number;
abi_ulong base_addr;
unsigned int limit;
unsigned int flags;
};
#endif
struct target_ipc64_perm
{
int key;
uint32_t uid;
uint32_t gid;
uint32_t cuid;
uint32_t cgid;
unsigned short mode;
unsigned short __pad1;
unsigned short seq;
unsigned short __pad2;
abi_ulong __unused1;
abi_ulong __unused2;
};
struct target_msqid64_ds {
struct target_ipc64_perm msg_perm;
unsigned int msg_stime; /* last msgsnd time */
unsigned int msg_rtime; /* last msgrcv time */
unsigned int msg_ctime; /* last change time */
abi_ulong msg_cbytes; /* current number of bytes on queue */
abi_ulong msg_qnum; /* number of messages in queue */
abi_ulong msg_qbytes; /* max number of bytes on queue */
unsigned int msg_lspid; /* pid of last msgsnd */
unsigned int msg_lrpid; /* last receive pid */
abi_ulong __unused4;
abi_ulong __unused5;
};
#define UNAME_MACHINE "x86_64"
#define TARGET_ARCH_SET_GS 0x1001
#define TARGET_ARCH_SET_FS 0x1002
#define TARGET_ARCH_GET_FS 0x1003
#define TARGET_ARCH_GET_GS 0x1004

View File

@@ -1,19 +0,0 @@
#ifndef TARGET_SIGNAL_H
#define TARGET_SIGNAL_H
#include "cpu.h"
/* this struct defines a stack used during syscall handling */
typedef struct target_sigaltstack {
abi_ulong ss_sp;
abi_long ss_flags;
abi_ulong ss_size;
} target_stack_t;
static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
{
return state->regs[R_ESP];
}
#endif /* TARGET_SIGNAL_H */

29
bswap.h
View File

@@ -5,12 +5,6 @@
#include <inttypes.h>
#ifdef HAVE_MACHINE_BSWAP_H
#include <sys/endian.h>
#include <sys/types.h>
#include <machine/bswap.h>
#else
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#else
@@ -54,18 +48,16 @@ static inline uint16_t bswap16(uint16_t x)
return bswap_16(x);
}
static inline uint32_t bswap32(uint32_t x)
static inline uint32_t bswap32(uint32_t x)
{
return bswap_32(x);
}
static inline uint64_t bswap64(uint64_t x)
static inline uint64_t bswap64(uint64_t x)
{
return bswap_64(x);
}
#endif /* ! HAVE_MACHINE_BSWAP_H */
static inline void bswap16s(uint16_t *s)
{
*s = bswap16(*s);
@@ -134,13 +126,12 @@ CPU_CONVERT(le, 64, uint64_t)
/* unaligned versions (optimized for frequent unaligned accesses)*/
#if defined(__i386__) || defined(_ARCH_PPC)
#if defined(__i386__) || defined(__powerpc__)
#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v)
#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
#define le16_to_cpupu(p) le16_to_cpup(p)
#define le32_to_cpupu(p) le32_to_cpup(p)
#define be32_to_cpupu(p) be32_to_cpup(p)
#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
@@ -151,7 +142,7 @@ static inline void cpu_to_le16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v & 0xff;
p1[0] = v;
p1[1] = v >> 8;
}
@@ -159,7 +150,7 @@ static inline void cpu_to_le32wu(uint32_t *p, uint32_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v & 0xff;
p1[0] = v;
p1[1] = v >> 8;
p1[2] = v >> 16;
p1[3] = v >> 24;
@@ -177,18 +168,12 @@ static inline uint32_t le32_to_cpupu(const uint32_t *p)
return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
}
static inline uint32_t be32_to_cpupu(const uint32_t *p)
{
const uint8_t *p1 = (const uint8_t *)p;
return p1[3] | (p1[2] << 8) | (p1[1] << 16) | (p1[0] << 24);
}
static inline void cpu_to_be16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v >> 8;
p1[1] = v & 0xff;
p1[1] = v;
}
static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
@@ -198,7 +183,7 @@ static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
p1[0] = v >> 24;
p1[1] = v >> 16;
p1[2] = v >> 8;
p1[3] = v & 0xff;
p1[3] = v;
}
#endif

206
bt-host.c
View File

@@ -1,206 +0,0 @@
/*
* Wrap a host Bluetooth HCI socket in a struct HCIInfo.
*
* Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu-common.h"
#include "qemu-char.h"
#include "sysemu.h"
#include "net.h"
#include "bt-host.h"
#ifndef _WIN32
# include <errno.h>
# include <sys/ioctl.h>
# include <sys/uio.h>
# ifdef CONFIG_BLUEZ
# include <bluetooth/bluetooth.h>
# include <bluetooth/hci.h>
# include <bluetooth/hci_lib.h>
# else
# include "hw/bt.h"
# define HCI_MAX_FRAME_SIZE 1028
# endif
struct bt_host_hci_s {
struct HCIInfo hci;
int fd;
uint8_t hdr[HCI_MAX_FRAME_SIZE];
int len;
};
static void bt_host_send(struct HCIInfo *hci,
int type, const uint8_t *data, int len)
{
struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci;
uint8_t pkt = type;
struct iovec iv[2];
int ret;
iv[0].iov_base = (void *)&pkt;
iv[0].iov_len = 1;
iv[1].iov_base = (void *) data;
iv[1].iov_len = len;
while ((ret = writev(s->fd, iv, 2)) < 0)
if (errno != EAGAIN && errno != EINTR) {
fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
errno);
return;
}
}
static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len)
{
bt_host_send(hci, HCI_COMMAND_PKT, data, len);
}
static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len)
{
bt_host_send(hci, HCI_ACLDATA_PKT, data, len);
}
static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len)
{
bt_host_send(hci, HCI_SCODATA_PKT, data, len);
}
static int bt_host_read_poll(void *opaque)
{
struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque;
return !!s->hci.evt_recv;
}
static void bt_host_read(void *opaque)
{
struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque;
uint8_t *pkt;
int pktlen;
/* Seems that we can't read only the header first and then the amount
* of data indicated in the header because Linux will discard everything
* that's not been read in one go. */
s->len = read(s->fd, s->hdr, sizeof(s->hdr));
if (s->len < 0) {
fprintf(stderr, "qemu: error %i reading HCI frame\n", errno);
return;
}
pkt = s->hdr;
while (s->len --)
switch (*pkt ++) {
case HCI_EVENT_PKT:
if (s->len < 2)
goto bad_pkt;
pktlen = MIN(pkt[1] + 2, s->len);
s->hci.evt_recv(s->hci.opaque, pkt, pktlen);
s->len -= pktlen;
pkt += pktlen;
/* TODO: if this is an Inquiry Result event, it's also
* interpreted by Linux kernel before we received it, possibly
* we should clean the kernel Inquiry cache through
* ioctl(s->fd, HCI_INQUIRY, ...). */
break;
case HCI_ACLDATA_PKT:
if (s->len < 4)
goto bad_pkt;
pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
s->hci.acl_recv(s->hci.opaque, pkt, pktlen);
s->len -= pktlen;
pkt += pktlen;
break;
case HCI_SCODATA_PKT:
if (s->len < 3)
goto bad_pkt;
pktlen = MIN(pkt[2] + 3, s->len);
s->len -= pktlen;
pkt += pktlen;
default:
bad_pkt:
fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
}
}
static int bt_host_bdaddr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
{
return -ENOTSUP;
}
struct HCIInfo *bt_host_hci(const char *id)
{
struct bt_host_hci_s *s;
int fd = -1;
# ifdef CONFIG_BLUEZ
int dev_id = hci_devid(id);
struct hci_filter flt;
if (dev_id < 0) {
fprintf(stderr, "qemu: `%s' not available\n", id);
return 0;
}
fd = hci_open_dev(dev_id);
/* XXX: can we ensure nobody else has the device opened? */
# endif
if (fd < 0) {
fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
id, strerror(errno), errno);
return NULL;
}
# ifdef CONFIG_BLUEZ
hci_filter_clear(&flt);
hci_filter_all_ptypes(&flt);
hci_filter_all_events(&flt);
if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
fprintf(stderr, "qemu: Can't set HCI filter on socket (%i)\n", errno);
return 0;
}
# endif
s = qemu_mallocz(sizeof(struct bt_host_hci_s));
s->fd = fd;
s->hci.cmd_send = bt_host_cmd;
s->hci.sco_send = bt_host_sco;
s->hci.acl_send = bt_host_acl;
s->hci.bdaddr_set = bt_host_bdaddr_set;
qemu_set_fd_handler2(s->fd, bt_host_read_poll, bt_host_read, NULL, s);
return &s->hci;
}
#else
struct HCIInfo *bt_host_hci(const char *id)
{
fprintf(stderr, "qemu: bluetooth passthrough not supported (yet)\n");
return 0;
}
#endif

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