Compare commits
1 Commits
v0.10.2
...
release_0_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f1a4fd795 |
42
.cvsignore
Normal file
42
.cvsignore
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
arm-user
|
||||||
|
arm-softmmu
|
||||||
|
armeb-user
|
||||||
|
config-host.*
|
||||||
|
dyngen
|
||||||
|
i386
|
||||||
|
i386-softmmu
|
||||||
|
i386-user
|
||||||
|
ppc-softmmu
|
||||||
|
ppc64-softmmu
|
||||||
|
ppc-user
|
||||||
|
qemu-doc.html
|
||||||
|
qemu-tech.html
|
||||||
|
qemu-doc.info
|
||||||
|
qemu-tech.info
|
||||||
|
qemu.1
|
||||||
|
qemu.pod
|
||||||
|
qemu-img.1
|
||||||
|
qemu-img.pod
|
||||||
|
sparc-user
|
||||||
|
qemu-img
|
||||||
|
sparc-softmmu
|
||||||
|
x86_64-softmmu
|
||||||
|
sparc64-user
|
||||||
|
sparc64-softmmu
|
||||||
|
mips-softmmu
|
||||||
|
mipsel-softmmu
|
||||||
|
mips-user
|
||||||
|
mipsel-user
|
||||||
|
.gdbinit
|
||||||
|
sh4-user
|
||||||
|
sh4-softmmu
|
||||||
|
*.aux
|
||||||
|
*.cp
|
||||||
|
*.dvi
|
||||||
|
*.fn
|
||||||
|
*.ky
|
||||||
|
*.log
|
||||||
|
*.pg
|
||||||
|
*.toc
|
||||||
|
*.tp
|
||||||
|
*.vr
|
||||||
38
.gitignore
vendored
38
.gitignore
vendored
@@ -1,38 +0,0 @@
|
|||||||
config-host.*
|
|
||||||
i386
|
|
||||||
*-softmmu
|
|
||||||
*-darwin-user
|
|
||||||
*-linux-user
|
|
||||||
*-bsd-user
|
|
||||||
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
|
|
||||||
.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-*
|
|
||||||
18
COPYING
18
COPYING
@@ -1,8 +1,8 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
675 Mass Ave, Cambridge, MA 02139, USA
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
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
|
General Public License applies to most of the Free Software
|
||||||
Foundation's software and to any other program whose authors commit to
|
Foundation's software and to any other program whose authors commit to
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
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.
|
your programs, too.
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
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.
|
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.>
|
<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
|
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
|
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
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
You should have received a copy of the GNU General Public License
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
along with this program; if not, write to the Free Software
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
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
|
If the program is interactive, make it output a short notice like this
|
||||||
when it starts in an interactive mode:
|
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'.
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
under certain conditions; type `show c' for details.
|
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
|
This General Public License does not permit incorporating your program into
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
consider it more useful to permit linking proprietary applications with the
|
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.
|
Public License instead of this License.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Version 2.1, February 1999
|
Version 2.1, February 1999
|
||||||
|
|
||||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
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
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
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
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
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.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
|||||||
118
Changelog
118
Changelog
@@ -1,117 +1,3 @@
|
|||||||
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: allow masking of notifications on empty queue (Alex Williamson)
|
|
||||||
- e1000: fix rx descriptor low threshold logic (Alex Willaimson)
|
|
||||||
- x86 tcg: add NULL checks to lsl instruction (Jan Kiszka)
|
|
||||||
- kvm vga: fix screen corruption with -std-vga and Windows (Avi Kivity)
|
|
||||||
- kvm vga: fix screen corruption with Ubuntu installations (Glauber Costa)
|
|
||||||
- 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:
|
version 0.8.2:
|
||||||
|
|
||||||
- ACPI support
|
- ACPI support
|
||||||
@@ -119,7 +5,7 @@ version 0.8.2:
|
|||||||
- switch to OpenBios for SPARC targets (Blue Swirl)
|
- switch to OpenBios for SPARC targets (Blue Swirl)
|
||||||
- VNC server fixes
|
- VNC server fixes
|
||||||
- MIPS FPU support (Marius Groeger)
|
- MIPS FPU support (Marius Groeger)
|
||||||
- Solaris/SPARC host support (Juergen Keil)
|
- Solaris/SPARC host support (Ben Taylor)
|
||||||
- PPC breakpoints and single stepping (Jason Wessel)
|
- PPC breakpoints and single stepping (Jason Wessel)
|
||||||
- USB updates (Paul Brook)
|
- USB updates (Paul Brook)
|
||||||
- UDP/TCP/telnet character devices (Jason Wessel)
|
- UDP/TCP/telnet character devices (Jason Wessel)
|
||||||
@@ -138,7 +24,7 @@ version 0.8.1:
|
|||||||
- PC speaker support (Joachim Henke)
|
- PC speaker support (Joachim Henke)
|
||||||
- IDE LBA48 support (Jens Axboe)
|
- IDE LBA48 support (Jens Axboe)
|
||||||
- SSE3 support
|
- SSE3 support
|
||||||
- Solaris port (Juergen Keil)
|
- Solaris port (Ben Taylor)
|
||||||
- Preliminary SH4 target (Samuel Tardieu)
|
- Preliminary SH4 target (Samuel Tardieu)
|
||||||
- VNC server (Anthony Liguori)
|
- VNC server (Anthony Liguori)
|
||||||
- slirp fixes (Ed Swierk et al.)
|
- slirp fixes (Ed Swierk et al.)
|
||||||
|
|||||||
20
LICENSE
20
LICENSE
@@ -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
|
2) The Linux user mode QEMU emulator is released under the GNU General
|
||||||
GNU General Public License. Hence each source file contains its own
|
Public License.
|
||||||
licensing information.
|
|
||||||
|
|
||||||
In particular, the QEMU virtual CPU core library (libqemu.a) is
|
3) QEMU is a trademark of Fabrice Bellard.
|
||||||
released under the GNU Lesser General Public License. Many hardware
|
|
||||||
device emulation sources are released under the BSD license.
|
|
||||||
|
|
||||||
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.
|
||||||
82
MAINTAINERS
82
MAINTAINERS
@@ -1,82 +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 ?
|
|
||||||
|
|
||||||
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
|
|
||||||
Alpha
|
|
||||||
|
|
||||||
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 ?
|
|
||||||
278
Makefile
278
Makefile
@@ -1,199 +1,47 @@
|
|||||||
# Makefile for QEMU.
|
# Makefile for QEMU.
|
||||||
|
|
||||||
include config-host.mak
|
include config-host.mak
|
||||||
include $(SRC_PATH)/rules.mak
|
|
||||||
|
|
||||||
.PHONY: all clean cscope distclean dvi html info install install-doc \
|
.PHONY: all clean distclean dvi info install install-doc tar tarbin \
|
||||||
recurse-all speed tar tarbin test
|
speed test test2 html dvi info
|
||||||
|
|
||||||
VPATH=$(SRC_PATH):$(SRC_PATH)/hw
|
CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I.
|
||||||
|
ifdef CONFIG_DARWIN
|
||||||
|
CFLAGS+= -mdynamic-no-pic
|
||||||
CFLAGS += $(OS_CFLAGS) $(ARCH_CFLAGS)
|
endif
|
||||||
LDFLAGS += $(OS_LDFLAGS) $(ARCH_LDFLAGS)
|
ifeq ($(ARCH),sparc)
|
||||||
|
CFLAGS+=-mcpu=ultrasparc
|
||||||
CPPFLAGS += -I. -I$(SRC_PATH) -MMD -MP -MT $@
|
endif
|
||||||
CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
LDFLAGS=-g
|
||||||
LIBS=
|
LIBS=
|
||||||
|
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||||
|
TOOLS=qemu-img$(EXESUF)
|
||||||
ifdef CONFIG_STATIC
|
ifdef CONFIG_STATIC
|
||||||
LDFLAGS+=-static
|
LDFLAGS+=-static
|
||||||
endif
|
endif
|
||||||
ifdef BUILD_DOCS
|
ifdef BUILD_DOCS
|
||||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8
|
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
|
||||||
else
|
else
|
||||||
DOCS=
|
DOCS=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LIBS+=$(AIOLIBS)
|
|
||||||
|
|
||||||
ifdef CONFIG_SOLARIS
|
|
||||||
LIBS+=-lsocket -lnsl -lresolv
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifdef CONFIG_WIN32
|
|
||||||
LIBS+=-lwinmm -lws2_32 -liphlpapi
|
|
||||||
endif
|
|
||||||
|
|
||||||
all: $(TOOLS) $(DOCS) recurse-all
|
all: $(TOOLS) $(DOCS) recurse-all
|
||||||
|
|
||||||
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
|
subdir-%: dyngen$(EXESUF)
|
||||||
|
$(MAKE) -C $(subst subdir-,,$@) all
|
||||||
|
|
||||||
subdir-%:
|
recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
|
||||||
$(call quiet-command,$(MAKE) -C $* V="$(V)" TARGET_DIR="$*/" all,)
|
|
||||||
|
|
||||||
$(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.a
|
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 block-vvfat.c
|
||||||
$(filter %-user,$(SUBDIR_RULES)): libqemu_user.a
|
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
|
||||||
|
|
||||||
recurse-all: $(SUBDIR_RULES)
|
dyngen$(EXESUF): dyngen.c
|
||||||
|
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
|
||||||
#######################################################################
|
|
||||||
# BLOCK_OBJS is code used by both qemu system emulation and qemu-img
|
|
||||||
|
|
||||||
BLOCK_OBJS=cutils.o qemu-malloc.o
|
|
||||||
BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
|
|
||||||
BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
|
|
||||||
BLOCK_OBJS+=block-qcow2.o block-parallels.o block-nbd.o
|
|
||||||
BLOCK_OBJS+=nbd.o block.o aio.o
|
|
||||||
|
|
||||||
ifdef CONFIG_WIN32
|
|
||||||
BLOCK_OBJS += block-raw-win32.o
|
|
||||||
else
|
|
||||||
ifdef CONFIG_AIO
|
|
||||||
BLOCK_OBJS += posix-aio-compat.o
|
|
||||||
endif
|
|
||||||
BLOCK_OBJS += block-raw-posix.o
|
|
||||||
endif
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
OBJS=$(BLOCK_OBJS)
|
|
||||||
OBJS+=readline.o console.o
|
|
||||||
|
|
||||||
OBJS+=irq.o
|
|
||||||
OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
|
|
||||||
OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o
|
|
||||||
OBJS+=tmp105.o lm832x.o
|
|
||||||
OBJS+=scsi-disk.o cdrom.o
|
|
||||||
OBJS+=scsi-generic.o
|
|
||||||
OBJS+=usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
|
|
||||||
OBJS+=usb-serial.o usb-net.o
|
|
||||||
OBJS+=sd.o ssi-sd.o
|
|
||||||
OBJS+=bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
|
|
||||||
OBJS+=buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
|
|
||||||
OBJS+=qemu-char.o aio.o net-checksum.o savevm.o cache-utils.o
|
|
||||||
|
|
||||||
ifdef CONFIG_BRLAPI
|
|
||||||
OBJS+= baum.o
|
|
||||||
LIBS+=-lbrlapi
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifdef CONFIG_WIN32
|
|
||||||
OBJS+=tap-win32.o
|
|
||||||
else
|
|
||||||
OBJS+=migration-exec.o
|
|
||||||
endif
|
|
||||||
|
|
||||||
AUDIO_OBJS = audio.o noaudio.o wavaudio.o mixeng.o
|
|
||||||
ifdef CONFIG_SDL
|
|
||||||
AUDIO_OBJS += sdlaudio.o
|
|
||||||
endif
|
|
||||||
ifdef CONFIG_OSS
|
|
||||||
AUDIO_OBJS += ossaudio.o
|
|
||||||
endif
|
|
||||||
ifdef CONFIG_COREAUDIO
|
|
||||||
AUDIO_OBJS += coreaudio.o
|
|
||||||
AUDIO_PT = yes
|
|
||||||
endif
|
|
||||||
ifdef CONFIG_ALSA
|
|
||||||
AUDIO_OBJS += alsaaudio.o
|
|
||||||
endif
|
|
||||||
ifdef CONFIG_DSOUND
|
|
||||||
AUDIO_OBJS += dsoundaudio.o
|
|
||||||
endif
|
|
||||||
ifdef CONFIG_FMOD
|
|
||||||
AUDIO_OBJS += fmodaudio.o
|
|
||||||
audio/audio.o audio/fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS)
|
|
||||||
endif
|
|
||||||
ifdef CONFIG_ESD
|
|
||||||
AUDIO_PT = yes
|
|
||||||
AUDIO_PT_INT = yes
|
|
||||||
AUDIO_OBJS += esdaudio.o
|
|
||||||
endif
|
|
||||||
ifdef CONFIG_PA
|
|
||||||
AUDIO_PT = yes
|
|
||||||
AUDIO_PT_INT = yes
|
|
||||||
AUDIO_OBJS += paaudio.o
|
|
||||||
endif
|
|
||||||
ifdef AUDIO_PT
|
|
||||||
LDFLAGS += -pthread
|
|
||||||
endif
|
|
||||||
ifdef AUDIO_PT_INT
|
|
||||||
AUDIO_OBJS += audio_pt_int.o
|
|
||||||
endif
|
|
||||||
AUDIO_OBJS+= wavcapture.o
|
|
||||||
OBJS+=$(addprefix audio/, $(AUDIO_OBJS))
|
|
||||||
|
|
||||||
ifdef CONFIG_SDL
|
|
||||||
OBJS+=sdl.o x_keymap.o
|
|
||||||
endif
|
|
||||||
ifdef CONFIG_CURSES
|
|
||||||
OBJS+=curses.o
|
|
||||||
endif
|
|
||||||
OBJS+=vnc.o d3des.o
|
|
||||||
|
|
||||||
ifdef CONFIG_COCOA
|
|
||||||
OBJS+=cocoa.o
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifdef CONFIG_SLIRP
|
|
||||||
CPPFLAGS+=-I$(SRC_PATH)/slirp
|
|
||||||
SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
|
|
||||||
slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \
|
|
||||||
tcp_subr.o tcp_timer.o udp.o bootp.o debug.o tftp.o
|
|
||||||
OBJS+=$(addprefix slirp/, $(SLIRP_OBJS))
|
|
||||||
endif
|
|
||||||
|
|
||||||
LIBS+=$(VDE_LIBS)
|
|
||||||
|
|
||||||
cocoa.o: cocoa.m
|
|
||||||
|
|
||||||
sdl.o: sdl.c keymaps.c sdl_keysym.h
|
|
||||||
|
|
||||||
sdl.o audio/sdlaudio.o: CFLAGS += $(SDL_CFLAGS)
|
|
||||||
|
|
||||||
vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h
|
|
||||||
|
|
||||||
vnc.o: CFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
|
|
||||||
|
|
||||||
curses.o: curses.c keymaps.c curses_keys.h
|
|
||||||
|
|
||||||
bt-host.o: CFLAGS += $(CONFIG_BLUEZ_CFLAGS)
|
|
||||||
|
|
||||||
libqemu_common.a: $(OBJS)
|
|
||||||
|
|
||||||
#######################################################################
|
|
||||||
# USER_OBJS is code used by qemu userspace emulation
|
|
||||||
USER_OBJS=cutils.o cache-utils.o
|
|
||||||
|
|
||||||
libqemu_user.a: $(USER_OBJS)
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
qemu-img$(EXESUF): qemu-img.o qemu-tool.o osdep.o $(BLOCK_OBJS)
|
|
||||||
|
|
||||||
qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o osdep.o $(BLOCK_OBJS)
|
|
||||||
|
|
||||||
qemu-img$(EXESUF) qemu-nbd$(EXESUF): LIBS += -lz
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
# avoid old build problems by removing potentially incorrect old files
|
# 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 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 *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~
|
||||||
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d
|
|
||||||
$(MAKE) -C tests clean
|
$(MAKE) -C tests clean
|
||||||
for d in $(TARGET_DIRS); do \
|
for d in $(TARGET_DIRS); do \
|
||||||
$(MAKE) -C $$d $@ || exit 1 ; \
|
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||||
@@ -210,39 +58,25 @@ 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 \
|
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
|
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
|
|
||||||
else
|
|
||||||
BLOBS=
|
|
||||||
endif
|
|
||||||
|
|
||||||
install-doc: $(DOCS)
|
install-doc: $(DOCS)
|
||||||
mkdir -p "$(DESTDIR)$(docdir)"
|
mkdir -p "$(DESTDIR)$(docdir)"
|
||||||
$(INSTALL) -m 644 qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
|
$(INSTALL) -m 644 qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
|
||||||
ifndef CONFIG_WIN32
|
ifndef CONFIG_WIN32
|
||||||
mkdir -p "$(DESTDIR)$(mandir)/man1"
|
mkdir -p "$(DESTDIR)$(mandir)/man1"
|
||||||
$(INSTALL) -m 644 qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
|
$(INSTALL) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
|
||||||
mkdir -p "$(DESTDIR)$(mandir)/man8"
|
|
||||||
$(INSTALL) -m 644 qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
install: all $(if $(BUILD_DOCS),install-doc)
|
install: all $(if $(BUILD_DOCS),install-doc)
|
||||||
mkdir -p "$(DESTDIR)$(bindir)"
|
mkdir -p "$(DESTDIR)$(bindir)"
|
||||||
ifneq ($(TOOLS),)
|
|
||||||
$(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
|
$(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
|
||||||
endif
|
|
||||||
ifneq ($(BLOBS),)
|
|
||||||
mkdir -p "$(DESTDIR)$(datadir)"
|
mkdir -p "$(DESTDIR)$(datadir)"
|
||||||
set -e; for x in $(BLOBS); do \
|
for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
|
||||||
|
video.x openbios-sparc32 linux_boot.bin; do \
|
||||||
$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
|
$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
|
||||||
done
|
done
|
||||||
endif
|
|
||||||
ifndef CONFIG_WIN32
|
ifndef CONFIG_WIN32
|
||||||
mkdir -p "$(DESTDIR)$(datadir)/keymaps"
|
mkdir -p "$(DESTDIR)$(datadir)/keymaps"
|
||||||
set -e; for x in $(KEYMAPS); do \
|
for x in $(KEYMAPS); do \
|
||||||
$(INSTALL) -m 644 $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
|
$(INSTALL) -m 644 $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
|
||||||
done
|
done
|
||||||
endif
|
endif
|
||||||
@@ -251,7 +85,7 @@ endif
|
|||||||
done
|
done
|
||||||
|
|
||||||
# various test targets
|
# various test targets
|
||||||
test speed: all
|
test speed test2: all
|
||||||
$(MAKE) -C tests $@
|
$(MAKE) -C tests $@
|
||||||
|
|
||||||
TAGS:
|
TAGS:
|
||||||
@@ -259,7 +93,7 @@ TAGS:
|
|||||||
|
|
||||||
cscope:
|
cscope:
|
||||||
rm -f ./cscope.*
|
rm -f ./cscope.*
|
||||||
find . -name "*.[ch]" -print | sed 's,^\./,,' > ./cscope.files
|
find . -name "*.[ch]" -print > ./cscope.files
|
||||||
cscope -b
|
cscope -b
|
||||||
|
|
||||||
# documentation
|
# documentation
|
||||||
@@ -280,82 +114,50 @@ qemu-img.1: qemu-img.texi
|
|||||||
$(SRC_PATH)/texi2pod.pl $< qemu-img.pod
|
$(SRC_PATH)/texi2pod.pl $< qemu-img.pod
|
||||||
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
|
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
|
||||||
|
|
||||||
qemu-nbd.8: qemu-nbd.texi
|
|
||||||
$(SRC_PATH)/texi2pod.pl $< qemu-nbd.pod
|
|
||||||
pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@
|
|
||||||
|
|
||||||
info: qemu-doc.info qemu-tech.info
|
info: qemu-doc.info qemu-tech.info
|
||||||
|
|
||||||
dvi: qemu-doc.dvi qemu-tech.dvi
|
dvi: qemu-doc.dvi qemu-tech.dvi
|
||||||
|
|
||||||
html: qemu-doc.html qemu-tech.html
|
html: qemu-doc.html qemu-tech.html
|
||||||
|
|
||||||
qemu-doc.dvi qemu-doc.html qemu-doc.info: qemu-img.texi qemu-nbd.texi
|
FILE=qemu-$(shell cat VERSION)
|
||||||
|
|
||||||
VERSION ?= $(shell cat VERSION)
|
|
||||||
FILE = qemu-$(VERSION)
|
|
||||||
|
|
||||||
# tar release (use 'make -k tar' on a checkouted tree)
|
# tar release (use 'make -k tar' on a checkouted tree)
|
||||||
tar:
|
tar:
|
||||||
rm -rf /tmp/$(FILE)
|
rm -rf /tmp/$(FILE)
|
||||||
cp -r . /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)
|
rm -rf /tmp/$(FILE)
|
||||||
|
|
||||||
# generate a binary distribution
|
# generate a binary distribution
|
||||||
tarbin:
|
tarbin:
|
||||||
cd / && tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \
|
( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
|
||||||
$(bindir)/qemu \
|
$(bindir)/qemu \
|
||||||
|
$(bindir)/qemu-system-ppc \
|
||||||
|
$(bindir)/qemu-system-sparc \
|
||||||
$(bindir)/qemu-system-x86_64 \
|
$(bindir)/qemu-system-x86_64 \
|
||||||
$(bindir)/qemu-system-arm \
|
|
||||||
$(bindir)/qemu-system-cris \
|
|
||||||
$(bindir)/qemu-system-m68k \
|
|
||||||
$(bindir)/qemu-system-mips \
|
$(bindir)/qemu-system-mips \
|
||||||
$(bindir)/qemu-system-mipsel \
|
$(bindir)/qemu-system-mipsel \
|
||||||
$(bindir)/qemu-system-mips64 \
|
$(bindir)/qemu-system-arm \
|
||||||
$(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-i386 \
|
$(bindir)/qemu-i386 \
|
||||||
$(bindir)/qemu-x86_64 \
|
|
||||||
$(bindir)/qemu-alpha \
|
|
||||||
$(bindir)/qemu-arm \
|
$(bindir)/qemu-arm \
|
||||||
$(bindir)/qemu-armeb \
|
$(bindir)/qemu-armeb \
|
||||||
$(bindir)/qemu-cris \
|
$(bindir)/qemu-sparc \
|
||||||
$(bindir)/qemu-m68k \
|
$(bindir)/qemu-ppc \
|
||||||
$(bindir)/qemu-mips \
|
$(bindir)/qemu-mips \
|
||||||
$(bindir)/qemu-mipsel \
|
$(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-img \
|
||||||
$(bindir)/qemu-nbd \
|
|
||||||
$(datadir)/bios.bin \
|
$(datadir)/bios.bin \
|
||||||
$(datadir)/vgabios.bin \
|
$(datadir)/vgabios.bin \
|
||||||
$(datadir)/vgabios-cirrus.bin \
|
$(datadir)/vgabios-cirrus.bin \
|
||||||
$(datadir)/ppc_rom.bin \
|
$(datadir)/ppc_rom.bin \
|
||||||
$(datadir)/video.x \
|
$(datadir)/video.x \
|
||||||
$(datadir)/openbios-sparc32 \
|
$(datadir)/openbios-sparc32 \
|
||||||
$(datadir)/openbios-sparc64 \
|
$(datadir)/linux_boot.bin \
|
||||||
$(datadir)/openbios-ppc \
|
|
||||||
$(datadir)/pxe-ne2k_pci.bin \
|
|
||||||
$(datadir)/pxe-rtl8139.bin \
|
|
||||||
$(datadir)/pxe-pcnet.bin \
|
|
||||||
$(datadir)/pxe-e1000.bin \
|
|
||||||
$(docdir)/qemu-doc.html \
|
$(docdir)/qemu-doc.html \
|
||||||
$(docdir)/qemu-tech.html \
|
$(docdir)/qemu-tech.html \
|
||||||
$(mandir)/man1/qemu.1 \
|
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
|
||||||
$(mandir)/man1/qemu-img.1 \
|
|
||||||
$(mandir)/man8/qemu-nbd.8
|
|
||||||
|
|
||||||
# Include automatically generated dependency files
|
ifneq ($(wildcard .depend),)
|
||||||
-include $(wildcard *.d audio/*.d slirp/*.d)
|
include .depend
|
||||||
|
endif
|
||||||
|
|||||||
888
Makefile.target
888
Makefile.target
File diff suppressed because it is too large
Load Diff
16
README.distrib
Normal file
16
README.distrib
Normal 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
|
||||||
28
TODO
28
TODO
@@ -1,19 +1,30 @@
|
|||||||
General:
|
short term:
|
||||||
-------
|
----------
|
||||||
- cycle counter for all archs
|
- cycle counter for all archs
|
||||||
- cpu_interrupt() win32/SMP fix
|
- cpu_interrupt() win32/SMP fix
|
||||||
|
- support variable tsc freq
|
||||||
|
- USB host async
|
||||||
|
- IDE async
|
||||||
|
- debug option in 'configure' script + disable -fomit-frame-pointer
|
||||||
|
- Precise VGA timings for old games/demos (malc patch)
|
||||||
- merge PIC spurious interrupt patch
|
- merge PIC spurious interrupt patch
|
||||||
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
|
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
|
||||||
- config file (at least for windows/Mac OS X)
|
- config file (at least for windows/Mac OS X)
|
||||||
- update doc: PCI infos.
|
- update doc: PCI infos.
|
||||||
- basic VGA optimizations
|
- basic VGA optimizations
|
||||||
- better code fetch
|
- better code fetch (different exception handling + CS.limit support)
|
||||||
- do not resize vga if invalid size.
|
- do not resize vga if invalid size.
|
||||||
|
- avoid looping if only exceptions
|
||||||
- TLB code protection support for PPC
|
- TLB code protection support for PPC
|
||||||
|
- see openMosix Doc
|
||||||
- disable SMC handling for ARM/SPARC/PPC (not finished)
|
- disable SMC handling for ARM/SPARC/PPC (not finished)
|
||||||
- see undefined flags for BTx insn
|
- see undefined flags for BTx insn
|
||||||
|
- user/kernel PUSHL/POPL in helper.c
|
||||||
- keyboard output buffer filling timing emulation
|
- keyboard output buffer filling timing emulation
|
||||||
|
- return UD exception if LOCK prefix incorrectly used
|
||||||
|
- test ldt limit < 7 ?
|
||||||
- tests for each target CPU
|
- tests for each target CPU
|
||||||
|
- fix CCOP optimisation
|
||||||
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
||||||
state, find a solution for tb_flush()).
|
state, find a solution for tb_flush()).
|
||||||
|
|
||||||
@@ -24,14 +35,21 @@ ppc specific:
|
|||||||
|
|
||||||
linux-user specific:
|
linux-user specific:
|
||||||
-------------------
|
-------------------
|
||||||
- remove threading support as it cannot work at this point
|
- add IPC syscalls
|
||||||
- improve IPC syscalls
|
- handle rare page fault cases (in particular if page fault in helpers or
|
||||||
|
in syscall emulation code).
|
||||||
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
|
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
|
||||||
issues, fix 16 bit uid issues)
|
issues, fix 16 bit uid issues)
|
||||||
|
- use page_unprotect_range in every suitable syscall to handle all
|
||||||
|
cases of self modifying code.
|
||||||
|
- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
|
||||||
- use kernel traps for unaligned accesses on ARM ?
|
- use kernel traps for unaligned accesses on ARM ?
|
||||||
|
|
||||||
|
|
||||||
lower priority:
|
lower priority:
|
||||||
--------------
|
--------------
|
||||||
- int15 ah=86: use better timing
|
- 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)
|
||||||
- use -msoft-float on ARM
|
- use -msoft-float on ARM
|
||||||
|
|||||||
105
a.out.h
105
a.out.h
@@ -25,9 +25,9 @@ extern "C" {
|
|||||||
struct external_filehdr {
|
struct external_filehdr {
|
||||||
short f_magic; /* magic number */
|
short f_magic; /* magic number */
|
||||||
short f_nscns; /* number of sections */
|
short f_nscns; /* number of sections */
|
||||||
host_ulong f_timdat; /* time & date stamp */
|
unsigned long f_timdat; /* time & date stamp */
|
||||||
host_ulong f_symptr; /* file pointer to symtab */
|
unsigned long f_symptr; /* file pointer to symtab */
|
||||||
host_ulong f_nsyms; /* number of symtab entries */
|
unsigned long f_nsyms; /* number of symtab entries */
|
||||||
short f_opthdr; /* sizeof(optional hdr) */
|
short f_opthdr; /* sizeof(optional hdr) */
|
||||||
short f_flags; /* flags */
|
short f_flags; /* flags */
|
||||||
};
|
};
|
||||||
@@ -72,12 +72,12 @@ typedef struct
|
|||||||
{
|
{
|
||||||
unsigned short magic; /* type of file */
|
unsigned short magic; /* type of file */
|
||||||
unsigned short vstamp; /* version stamp */
|
unsigned short vstamp; /* version stamp */
|
||||||
host_ulong tsize; /* text size in bytes, padded to FW bdry*/
|
unsigned long tsize; /* text size in bytes, padded to FW bdry*/
|
||||||
host_ulong dsize; /* initialized data " " */
|
unsigned long dsize; /* initialized data " " */
|
||||||
host_ulong bsize; /* uninitialized data " " */
|
unsigned long bsize; /* uninitialized data " " */
|
||||||
host_ulong entry; /* entry pt. */
|
unsigned long entry; /* entry pt. */
|
||||||
host_ulong text_start; /* base of text used for this file */
|
unsigned long text_start; /* base of text used for this file */
|
||||||
host_ulong data_start; /* base of data used for this file=
|
unsigned long data_start; /* base of data used for this file=
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
AOUTHDR;
|
AOUTHDR;
|
||||||
@@ -103,16 +103,16 @@ AOUTHDR;
|
|||||||
|
|
||||||
struct external_scnhdr {
|
struct external_scnhdr {
|
||||||
char s_name[8]; /* section name */
|
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 */
|
of last addr in scn */
|
||||||
host_ulong s_vaddr; /* virtual address */
|
unsigned long s_vaddr; /* virtual address */
|
||||||
host_ulong s_size; /* section size */
|
unsigned long s_size; /* section size */
|
||||||
host_ulong s_scnptr; /* file ptr to raw data for section */
|
unsigned long s_scnptr; /* file ptr to raw data for section */
|
||||||
host_ulong s_relptr; /* file ptr to relocation */
|
unsigned long s_relptr; /* file ptr to relocation */
|
||||||
host_ulong s_lnnoptr; /* file ptr to line numbers */
|
unsigned long s_lnnoptr; /* file ptr to line numbers */
|
||||||
unsigned short s_nreloc; /* number of relocation entries */
|
unsigned short s_nreloc; /* number of relocation entries */
|
||||||
unsigned short s_nlnno; /* number of line number 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
|
#define SCNHDR struct external_scnhdr
|
||||||
@@ -136,8 +136,8 @@ struct external_scnhdr {
|
|||||||
*/
|
*/
|
||||||
struct external_lineno {
|
struct external_lineno {
|
||||||
union {
|
union {
|
||||||
host_ulong l_symndx; /* function name symbol index, iff l_lnno 0 */
|
unsigned long l_symndx; /* function name symbol index, iff l_lnno 0 */
|
||||||
host_ulong l_paddr; /* (physical) address of line number */
|
unsigned long l_paddr; /* (physical) address of line number */
|
||||||
} l_addr;
|
} l_addr;
|
||||||
unsigned short l_lnno; /* line number */
|
unsigned short l_lnno; /* line number */
|
||||||
};
|
};
|
||||||
@@ -156,11 +156,11 @@ struct __attribute__((packed)) external_syment
|
|||||||
union {
|
union {
|
||||||
char e_name[E_SYMNMLEN];
|
char e_name[E_SYMNMLEN];
|
||||||
struct {
|
struct {
|
||||||
host_ulong e_zeroes;
|
unsigned long e_zeroes;
|
||||||
host_ulong e_offset;
|
unsigned long e_offset;
|
||||||
} e;
|
} e;
|
||||||
} e;
|
} e;
|
||||||
host_ulong e_value;
|
unsigned long e_value;
|
||||||
unsigned short e_scnum;
|
unsigned short e_scnum;
|
||||||
unsigned short e_type;
|
unsigned short e_type;
|
||||||
char e_sclass[1];
|
char e_sclass[1];
|
||||||
@@ -174,18 +174,18 @@ struct __attribute__((packed)) external_syment
|
|||||||
|
|
||||||
union external_auxent {
|
union external_auxent {
|
||||||
struct {
|
struct {
|
||||||
host_ulong x_tagndx; /* str, un, or enum tag indx */
|
unsigned long x_tagndx; /* str, un, or enum tag indx */
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
unsigned short x_lnno; /* declaration line number */
|
unsigned short x_lnno; /* declaration line number */
|
||||||
unsigned short x_size; /* str/union/array size */
|
unsigned short x_size; /* str/union/array size */
|
||||||
} x_lnsz;
|
} x_lnsz;
|
||||||
host_ulong x_fsize; /* size of function */
|
unsigned long x_fsize; /* size of function */
|
||||||
} x_misc;
|
} x_misc;
|
||||||
union {
|
union {
|
||||||
struct { /* if ISFCN, tag, or .bb */
|
struct { /* if ISFCN, tag, or .bb */
|
||||||
host_ulong x_lnnoptr;/* ptr to fcn line # */
|
unsigned long x_lnnoptr;/* ptr to fcn line # */
|
||||||
host_ulong x_endndx; /* entry ndx past block end */
|
unsigned long x_endndx; /* entry ndx past block end */
|
||||||
} x_fcn;
|
} x_fcn;
|
||||||
struct { /* if ISARY, up to 4 dimen. */
|
struct { /* if ISARY, up to 4 dimen. */
|
||||||
char x_dimen[E_DIMNUM][2];
|
char x_dimen[E_DIMNUM][2];
|
||||||
@@ -197,22 +197,22 @@ union external_auxent {
|
|||||||
union {
|
union {
|
||||||
char x_fname[E_FILNMLEN];
|
char x_fname[E_FILNMLEN];
|
||||||
struct {
|
struct {
|
||||||
host_ulong x_zeroes;
|
unsigned long x_zeroes;
|
||||||
host_ulong x_offset;
|
unsigned long x_offset;
|
||||||
} x_n;
|
} x_n;
|
||||||
} x_file;
|
} x_file;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
host_ulong x_scnlen; /* section length */
|
unsigned long x_scnlen; /* section length */
|
||||||
unsigned short x_nreloc; /* # relocation entries */
|
unsigned short x_nreloc; /* # relocation entries */
|
||||||
unsigned short x_nlinno; /* # line numbers */
|
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 */
|
unsigned short x_associated;/* COMDAT associated section index */
|
||||||
char x_comdat[1]; /* COMDAT selection number */
|
char x_comdat[1]; /* COMDAT selection number */
|
||||||
} x_scn;
|
} x_scn;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
host_ulong x_tvfill; /* tv fill value */
|
unsigned long x_tvfill; /* tv fill value */
|
||||||
unsigned short x_tvlen; /* length of .tv */
|
unsigned short x_tvlen; /* length of .tv */
|
||||||
char x_tvran[2][2]; /* tv range */
|
char x_tvran[2][2]; /* tv range */
|
||||||
} x_tv; /* info about .tv section (in auxent of symbol .tv)) */
|
} 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_oemid; /* OEM identifier (for e_oeminfo), 0x0 */
|
||||||
unsigned short e_oeminfo; /* OEM information; e_oemid specific, 0x0 */
|
unsigned short e_oeminfo; /* OEM information; e_oemid specific, 0x0 */
|
||||||
char e_res2[10][2]; /* Reserved words, all 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 */
|
char dos_message[16][4]; /* other stuff, always follow DOS header */
|
||||||
unsigned int nt_signature; /* required NT signature, 0x4550 */
|
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_magic; /* magic number */
|
||||||
unsigned short f_nscns; /* number of sections */
|
unsigned short f_nscns; /* number of sections */
|
||||||
host_ulong f_timdat; /* time & date stamp */
|
unsigned long f_timdat; /* time & date stamp */
|
||||||
host_ulong f_symptr; /* file pointer to symtab */
|
unsigned long f_symptr; /* file pointer to symtab */
|
||||||
host_ulong f_nsyms; /* number of symtab entries */
|
unsigned long f_nsyms; /* number of symtab entries */
|
||||||
unsigned short f_opthdr; /* sizeof(optional hdr) */
|
unsigned short f_opthdr; /* sizeof(optional hdr) */
|
||||||
unsigned short f_flags; /* flags */
|
unsigned short f_flags; /* flags */
|
||||||
};
|
};
|
||||||
@@ -370,17 +370,17 @@ typedef struct
|
|||||||
{
|
{
|
||||||
unsigned short magic; /* type of file */
|
unsigned short magic; /* type of file */
|
||||||
unsigned short vstamp; /* version stamp */
|
unsigned short vstamp; /* version stamp */
|
||||||
host_ulong tsize; /* text size in bytes, padded to FW bdry*/
|
unsigned long tsize; /* text size in bytes, padded to FW bdry*/
|
||||||
host_ulong dsize; /* initialized data " " */
|
unsigned long dsize; /* initialized data " " */
|
||||||
host_ulong bsize; /* uninitialized data " " */
|
unsigned long bsize; /* uninitialized data " " */
|
||||||
host_ulong entry; /* entry pt. */
|
unsigned long entry; /* entry pt. */
|
||||||
host_ulong text_start; /* base of text used for this file */
|
unsigned long text_start; /* base of text used for this file */
|
||||||
host_ulong data_start; /* base of all data used for this file */
|
unsigned long data_start; /* base of all data used for this file */
|
||||||
|
|
||||||
/* NT extra fields; see internal.h for descriptions */
|
/* NT extra fields; see internal.h for descriptions */
|
||||||
host_ulong ImageBase;
|
unsigned long ImageBase;
|
||||||
host_ulong SectionAlignment;
|
unsigned long SectionAlignment;
|
||||||
host_ulong FileAlignment;
|
unsigned long FileAlignment;
|
||||||
unsigned short MajorOperatingSystemVersion;
|
unsigned short MajorOperatingSystemVersion;
|
||||||
unsigned short MinorOperatingSystemVersion;
|
unsigned short MinorOperatingSystemVersion;
|
||||||
unsigned short MajorImageVersion;
|
unsigned short MajorImageVersion;
|
||||||
@@ -388,17 +388,17 @@ typedef struct
|
|||||||
unsigned short MajorSubsystemVersion;
|
unsigned short MajorSubsystemVersion;
|
||||||
unsigned short MinorSubsystemVersion;
|
unsigned short MinorSubsystemVersion;
|
||||||
char Reserved1[4];
|
char Reserved1[4];
|
||||||
host_ulong SizeOfImage;
|
unsigned long SizeOfImage;
|
||||||
host_ulong SizeOfHeaders;
|
unsigned long SizeOfHeaders;
|
||||||
host_ulong CheckSum;
|
unsigned long CheckSum;
|
||||||
unsigned short Subsystem;
|
unsigned short Subsystem;
|
||||||
unsigned short DllCharacteristics;
|
unsigned short DllCharacteristics;
|
||||||
host_ulong SizeOfStackReserve;
|
unsigned long SizeOfStackReserve;
|
||||||
host_ulong SizeOfStackCommit;
|
unsigned long SizeOfStackCommit;
|
||||||
host_ulong SizeOfHeapReserve;
|
unsigned long SizeOfHeapReserve;
|
||||||
host_ulong SizeOfHeapCommit;
|
unsigned long SizeOfHeapCommit;
|
||||||
host_ulong LoaderFlags;
|
unsigned long LoaderFlags;
|
||||||
host_ulong NumberOfRvaAndSizes;
|
unsigned long NumberOfRvaAndSizes;
|
||||||
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
|
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
|
||||||
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
|
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
|
||||||
|
|
||||||
@@ -428,3 +428,4 @@ typedef struct
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _A_OUT_H_ */
|
#endif /* _A_OUT_H_ */
|
||||||
|
|
||||||
|
|||||||
5
aes.c
5
aes.c
@@ -27,13 +27,10 @@
|
|||||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "aes.h"
|
#include "aes.h"
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
typedef uint32_t u32;
|
typedef uint32_t u32;
|
||||||
|
|||||||
193
aio.c
193
aio.c
@@ -1,193 +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)
|
|
||||||
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;
|
|
||||||
|
|
||||||
LIST_FOREACH(node, &aio_handlers, node) {
|
|
||||||
ret |= node->io_flush(node->opaque);
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_aio_wait();
|
|
||||||
} while (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);
|
|
||||||
}
|
|
||||||
@@ -17,8 +17,8 @@ the GNU General Public License for more details.
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this file; see the file COPYING. If not, write to the Free
|
along with this file; see the file COPYING. If not, write to the Free
|
||||||
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
|
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
02110-1301, USA. */
|
02111-1307, USA. */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "dis-asm.h"
|
#include "dis-asm.h"
|
||||||
|
|||||||
470
arm-semi.c
470
arm-semi.c
@@ -1,470 +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, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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
26
arm.ld
@@ -53,43 +53,17 @@ SECTIONS
|
|||||||
.fini : { *(.fini) } =0x47ff041f
|
.fini : { *(.fini) } =0x47ff041f
|
||||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||||
.rodata1 : { *(.rodata1) }
|
.rodata1 : { *(.rodata1) }
|
||||||
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
|
|
||||||
__exidx_start = .;
|
|
||||||
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
|
|
||||||
__exidx_end = .;
|
|
||||||
.reginfo : { *(.reginfo) }
|
.reginfo : { *(.reginfo) }
|
||||||
/* Adjust the address for the data segment. We want to adjust up to
|
/* Adjust the address for the data segment. We want to adjust up to
|
||||||
the same address within the page on the next page up. */
|
the same address within the page on the next page up. */
|
||||||
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
||||||
.data :
|
.data :
|
||||||
{
|
{
|
||||||
*(.gen_code)
|
|
||||||
*(.data)
|
*(.data)
|
||||||
*(.gnu.linkonce.d*)
|
*(.gnu.linkonce.d*)
|
||||||
CONSTRUCTORS
|
CONSTRUCTORS
|
||||||
}
|
}
|
||||||
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
|
||||||
.data1 : { *(.data1) }
|
.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 :
|
||||||
{
|
{
|
||||||
*(.ctors)
|
*(.ctors)
|
||||||
|
|||||||
@@ -22,8 +22,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "audio.h"
|
|
||||||
|
|
||||||
#define AUDIO_CAP "alsa"
|
#define AUDIO_CAP "alsa"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
@@ -51,24 +50,44 @@ static struct {
|
|||||||
unsigned int period_size_out;
|
unsigned int period_size_out;
|
||||||
unsigned int threshold;
|
unsigned int threshold;
|
||||||
|
|
||||||
int buffer_size_in_overridden;
|
int buffer_size_in_overriden;
|
||||||
int period_size_in_overridden;
|
int period_size_in_overriden;
|
||||||
|
|
||||||
int buffer_size_out_overridden;
|
int buffer_size_out_overriden;
|
||||||
int period_size_out_overridden;
|
int period_size_out_overriden;
|
||||||
int verbose;
|
int verbose;
|
||||||
} conf = {
|
} conf = {
|
||||||
.buffer_size_out = 1024,
|
#ifdef HIGH_LATENCY
|
||||||
|
.size_in_usec_in = 1,
|
||||||
|
.size_in_usec_out = 1,
|
||||||
|
#endif
|
||||||
.pcm_name_out = "default",
|
.pcm_name_out = "default",
|
||||||
.pcm_name_in = "default",
|
.pcm_name_in = "default",
|
||||||
|
#ifdef HIGH_LATENCY
|
||||||
|
.buffer_size_in = 400000,
|
||||||
|
.period_size_in = 400000 / 4,
|
||||||
|
.buffer_size_out = 400000,
|
||||||
|
.period_size_out = 400000 / 4,
|
||||||
|
#else
|
||||||
|
#define DEFAULT_BUFFER_SIZE 1024
|
||||||
|
#define DEFAULT_PERIOD_SIZE 256
|
||||||
|
.buffer_size_in = DEFAULT_BUFFER_SIZE * 4,
|
||||||
|
.period_size_in = DEFAULT_PERIOD_SIZE * 4,
|
||||||
|
.buffer_size_out = DEFAULT_BUFFER_SIZE,
|
||||||
|
.period_size_out = DEFAULT_PERIOD_SIZE,
|
||||||
|
.buffer_size_in_overriden = 0,
|
||||||
|
.buffer_size_out_overriden = 0,
|
||||||
|
.period_size_in_overriden = 0,
|
||||||
|
.period_size_out_overriden = 0,
|
||||||
|
#endif
|
||||||
|
.threshold = 0,
|
||||||
|
.verbose = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
struct alsa_params_req {
|
struct alsa_params_req {
|
||||||
int freq;
|
int freq;
|
||||||
snd_pcm_format_t fmt;
|
audfmt_e fmt;
|
||||||
int nchannels;
|
int nchannels;
|
||||||
int size_in_usec;
|
|
||||||
int override_mask;
|
|
||||||
unsigned int buffer_size;
|
unsigned int buffer_size;
|
||||||
unsigned int period_size;
|
unsigned int period_size;
|
||||||
};
|
};
|
||||||
@@ -76,7 +95,6 @@ struct alsa_params_req {
|
|||||||
struct alsa_params_obt {
|
struct alsa_params_obt {
|
||||||
int freq;
|
int freq;
|
||||||
audfmt_e fmt;
|
audfmt_e fmt;
|
||||||
int endianness;
|
|
||||||
int nchannels;
|
int nchannels;
|
||||||
snd_pcm_uframes_t samples;
|
snd_pcm_uframes_t samples;
|
||||||
};
|
};
|
||||||
@@ -124,7 +142,7 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len)
|
|||||||
return audio_pcm_sw_write (sw, buf, len);
|
return audio_pcm_sw_write (sw, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
|
static int aud_to_alsafmt (audfmt_e fmt)
|
||||||
{
|
{
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case AUD_FMT_S8:
|
case AUD_FMT_S8:
|
||||||
@@ -139,12 +157,6 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
|
|||||||
case AUD_FMT_U16:
|
case AUD_FMT_U16:
|
||||||
return SND_PCM_FORMAT_U16_LE;
|
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:
|
default:
|
||||||
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
@@ -154,8 +166,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
|
static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
|
||||||
int *endianness)
|
|
||||||
{
|
{
|
||||||
switch (alsafmt) {
|
switch (alsafmt) {
|
||||||
case SND_PCM_FORMAT_S8:
|
case SND_PCM_FORMAT_S8:
|
||||||
@@ -188,26 +199,6 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
|
|||||||
*fmt = AUD_FMT_U16;
|
*fmt = AUD_FMT_U16;
|
||||||
break;
|
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:
|
default:
|
||||||
dolog ("Unrecognized audio format %d\n", alsafmt);
|
dolog ("Unrecognized audio format %d\n", alsafmt);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -216,6 +207,7 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined DEBUG_MISMATCHES || defined DEBUG
|
||||||
static void alsa_dump_info (struct alsa_params_req *req,
|
static void alsa_dump_info (struct alsa_params_req *req,
|
||||||
struct alsa_params_obt *obt)
|
struct alsa_params_obt *obt)
|
||||||
{
|
{
|
||||||
@@ -229,6 +221,7 @@ static void alsa_dump_info (struct alsa_params_req *req,
|
|||||||
req->buffer_size, req->period_size);
|
req->buffer_size, req->period_size);
|
||||||
dolog ("obtained: samples %ld\n", obt->samples);
|
dolog ("obtained: samples %ld\n", obt->samples);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
|
static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
|
||||||
{
|
{
|
||||||
@@ -265,17 +258,16 @@ static int alsa_open (int in, struct alsa_params_req *req,
|
|||||||
{
|
{
|
||||||
snd_pcm_t *handle;
|
snd_pcm_t *handle;
|
||||||
snd_pcm_hw_params_t *hw_params;
|
snd_pcm_hw_params_t *hw_params;
|
||||||
int err;
|
int err, freq, nchannels;
|
||||||
int size_in_usec;
|
|
||||||
unsigned int freq, nchannels;
|
|
||||||
const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
|
const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
|
||||||
|
unsigned int period_size, buffer_size;
|
||||||
snd_pcm_uframes_t obt_buffer_size;
|
snd_pcm_uframes_t obt_buffer_size;
|
||||||
const char *typ = in ? "ADC" : "DAC";
|
const char *typ = in ? "ADC" : "DAC";
|
||||||
snd_pcm_format_t obtfmt;
|
|
||||||
|
|
||||||
freq = req->freq;
|
freq = req->freq;
|
||||||
|
period_size = req->period_size;
|
||||||
|
buffer_size = req->buffer_size;
|
||||||
nchannels = req->nchannels;
|
nchannels = req->nchannels;
|
||||||
size_in_usec = req->size_in_usec;
|
|
||||||
|
|
||||||
snd_pcm_hw_params_alloca (&hw_params);
|
snd_pcm_hw_params_alloca (&hw_params);
|
||||||
|
|
||||||
@@ -307,8 +299,9 @@ static int alsa_open (int in, struct alsa_params_req *req,
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
|
err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
|
||||||
if (err < 0 && conf.verbose) {
|
if (err < 0) {
|
||||||
alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
|
alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
|
err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
|
||||||
@@ -335,79 +328,130 @@ static int alsa_open (int in, struct alsa_params_req *req,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req->buffer_size) {
|
if (!((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out))) {
|
||||||
unsigned long obt;
|
if (!buffer_size) {
|
||||||
|
buffer_size = DEFAULT_BUFFER_SIZE;
|
||||||
|
period_size= DEFAULT_PERIOD_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (size_in_usec) {
|
if (buffer_size) {
|
||||||
int dir = 0;
|
if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) {
|
||||||
unsigned int btime = req->buffer_size;
|
if (period_size) {
|
||||||
|
err = snd_pcm_hw_params_set_period_time_near (
|
||||||
|
handle,
|
||||||
|
hw_params,
|
||||||
|
&period_size,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if (err < 0) {
|
||||||
|
alsa_logerr2 (err, typ,
|
||||||
|
"Failed to set period time %d\n",
|
||||||
|
req->period_size);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_buffer_time_near (
|
err = snd_pcm_hw_params_set_buffer_time_near (
|
||||||
handle,
|
handle,
|
||||||
hw_params,
|
hw_params,
|
||||||
&btime,
|
&buffer_size,
|
||||||
&dir
|
0
|
||||||
);
|
);
|
||||||
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) {
|
if (err < 0) {
|
||||||
alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
|
alsa_logerr2 (err, typ,
|
||||||
size_in_usec ? "time" : "size", req->period_size);
|
"Failed to set buffer time %d\n",
|
||||||
|
req->buffer_size);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int dir;
|
||||||
|
snd_pcm_uframes_t minval;
|
||||||
|
|
||||||
if ((req->override_mask & 1) && (obt - req->period_size))
|
if (period_size) {
|
||||||
dolog ("Requested period %s %u was rejected, using %lu\n",
|
minval = period_size;
|
||||||
size_in_usec ? "time" : "size", req->period_size, obt);
|
dir = 0;
|
||||||
|
|
||||||
|
err = snd_pcm_hw_params_get_period_size_min (
|
||||||
|
hw_params,
|
||||||
|
&minval,
|
||||||
|
&dir
|
||||||
|
);
|
||||||
|
if (err < 0) {
|
||||||
|
alsa_logerr (
|
||||||
|
err,
|
||||||
|
"Could not get minmal period size for %s\n",
|
||||||
|
typ
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (period_size < minval) {
|
||||||
|
if ((in && conf.period_size_in_overriden)
|
||||||
|
|| (!in && conf.period_size_out_overriden)) {
|
||||||
|
dolog ("%s period size(%d) is less "
|
||||||
|
"than minmal period size(%ld)\n",
|
||||||
|
typ,
|
||||||
|
period_size,
|
||||||
|
minval);
|
||||||
|
}
|
||||||
|
period_size = minval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = snd_pcm_hw_params_set_period_size (
|
||||||
|
handle,
|
||||||
|
hw_params,
|
||||||
|
period_size,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if (err < 0) {
|
||||||
|
alsa_logerr2 (err, typ, "Failed to set period size %d\n",
|
||||||
|
req->period_size);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
minval = buffer_size;
|
||||||
|
err = snd_pcm_hw_params_get_buffer_size_min (
|
||||||
|
hw_params,
|
||||||
|
&minval
|
||||||
|
);
|
||||||
|
if (err < 0) {
|
||||||
|
alsa_logerr (err, "Could not get minmal buffer size for %s\n",
|
||||||
|
typ);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (buffer_size < minval) {
|
||||||
|
if ((in && conf.buffer_size_in_overriden)
|
||||||
|
|| (!in && conf.buffer_size_out_overriden)) {
|
||||||
|
dolog (
|
||||||
|
"%s buffer size(%d) is less "
|
||||||
|
"than minimal buffer size(%ld)\n",
|
||||||
|
typ,
|
||||||
|
buffer_size,
|
||||||
|
minval
|
||||||
|
);
|
||||||
|
}
|
||||||
|
buffer_size = minval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = snd_pcm_hw_params_set_buffer_size (
|
||||||
|
handle,
|
||||||
|
hw_params,
|
||||||
|
buffer_size
|
||||||
|
);
|
||||||
|
if (err < 0) {
|
||||||
|
alsa_logerr2 (err, typ, "Failed to set buffer size %d\n",
|
||||||
|
req->buffer_size);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dolog ("warning: Buffer size is not set\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_hw_params (handle, hw_params);
|
err = snd_pcm_hw_params (handle, hw_params);
|
||||||
@@ -422,17 +466,6 @@ static int alsa_open (int in, struct alsa_params_req *req,
|
|||||||
goto err;
|
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);
|
err = snd_pcm_prepare (handle);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
|
alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
|
||||||
@@ -443,41 +476,28 @@ static int alsa_open (int in, struct alsa_params_req *req,
|
|||||||
snd_pcm_uframes_t threshold;
|
snd_pcm_uframes_t threshold;
|
||||||
int bytes_per_sec;
|
int bytes_per_sec;
|
||||||
|
|
||||||
bytes_per_sec = freq << (nchannels == 2);
|
bytes_per_sec = freq
|
||||||
|
<< (nchannels == 2)
|
||||||
switch (obt->fmt) {
|
<< (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16);
|
||||||
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;
|
threshold = (conf.threshold * bytes_per_sec) / 1000;
|
||||||
alsa_set_threshold (handle, threshold);
|
alsa_set_threshold (handle, threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obt->fmt = req->fmt;
|
||||||
obt->nchannels = nchannels;
|
obt->nchannels = nchannels;
|
||||||
obt->freq = freq;
|
obt->freq = freq;
|
||||||
obt->samples = obt_buffer_size;
|
obt->samples = obt_buffer_size;
|
||||||
|
|
||||||
*handlep = handle;
|
*handlep = handle;
|
||||||
|
|
||||||
if (conf.verbose &&
|
#if defined DEBUG_MISMATCHES || defined DEBUG
|
||||||
(obt->fmt != req->fmt ||
|
if (obt->fmt != req->fmt ||
|
||||||
obt->nchannels != req->nchannels ||
|
obt->nchannels != req->nchannels ||
|
||||||
obt->freq != req->freq)) {
|
obt->freq != req->freq) {
|
||||||
dolog ("Audio paramters for %s\n", typ);
|
dolog ("Audio paramters mismatch for %s\n", typ);
|
||||||
alsa_dump_info (req, obt);
|
alsa_dump_info (req, obt);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
alsa_dump_info (req, obt);
|
alsa_dump_info (req, obt);
|
||||||
@@ -527,7 +547,7 @@ static int alsa_run_out (HWVoiceOut *hw)
|
|||||||
int rpos, live, decr;
|
int rpos, live, decr;
|
||||||
int samples;
|
int samples;
|
||||||
uint8_t *dst;
|
uint8_t *dst;
|
||||||
struct st_sample *src;
|
st_sample_t *src;
|
||||||
snd_pcm_sframes_t avail;
|
snd_pcm_sframes_t avail;
|
||||||
|
|
||||||
live = audio_pcm_hw_get_live_out (hw);
|
live = audio_pcm_hw_get_live_out (hw);
|
||||||
@@ -612,31 +632,37 @@ static void alsa_fini_out (HWVoiceOut *hw)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
|
static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||||
{
|
{
|
||||||
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
|
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
|
||||||
struct alsa_params_req req;
|
struct alsa_params_req req;
|
||||||
struct alsa_params_obt obt;
|
struct alsa_params_obt obt;
|
||||||
|
audfmt_e effective_fmt;
|
||||||
|
int endianness;
|
||||||
|
int err;
|
||||||
snd_pcm_t *handle;
|
snd_pcm_t *handle;
|
||||||
struct audsettings obt_as;
|
audsettings_t obt_as;
|
||||||
|
|
||||||
req.fmt = aud_to_alsafmt (as->fmt);
|
req.fmt = aud_to_alsafmt (as->fmt);
|
||||||
req.freq = as->freq;
|
req.freq = as->freq;
|
||||||
req.nchannels = as->nchannels;
|
req.nchannels = as->nchannels;
|
||||||
req.period_size = conf.period_size_out;
|
req.period_size = conf.period_size_out;
|
||||||
req.buffer_size = conf.buffer_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
|
|
||||||
| (!!conf.buffer_size_out_overridden << 1);
|
|
||||||
|
|
||||||
if (alsa_open (0, &req, &obt, &handle)) {
|
if (alsa_open (0, &req, &obt, &handle)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
|
||||||
|
if (err) {
|
||||||
|
alsa_anal_close (&handle);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
obt_as.freq = obt.freq;
|
obt_as.freq = obt.freq;
|
||||||
obt_as.nchannels = obt.nchannels;
|
obt_as.nchannels = obt.nchannels;
|
||||||
obt_as.fmt = obt.fmt;
|
obt_as.fmt = effective_fmt;
|
||||||
obt_as.endianness = obt.endianness;
|
obt_as.endianness = endianness;
|
||||||
|
|
||||||
audio_pcm_init_info (&hw->info, &obt_as);
|
audio_pcm_init_info (&hw->info, &obt_as);
|
||||||
hw->samples = obt.samples;
|
hw->samples = obt.samples;
|
||||||
@@ -692,31 +718,37 @@ static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
|
static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
|
||||||
{
|
{
|
||||||
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
|
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
|
||||||
struct alsa_params_req req;
|
struct alsa_params_req req;
|
||||||
struct alsa_params_obt obt;
|
struct alsa_params_obt obt;
|
||||||
|
int endianness;
|
||||||
|
int err;
|
||||||
|
audfmt_e effective_fmt;
|
||||||
snd_pcm_t *handle;
|
snd_pcm_t *handle;
|
||||||
struct audsettings obt_as;
|
audsettings_t obt_as;
|
||||||
|
|
||||||
req.fmt = aud_to_alsafmt (as->fmt);
|
req.fmt = aud_to_alsafmt (as->fmt);
|
||||||
req.freq = as->freq;
|
req.freq = as->freq;
|
||||||
req.nchannels = as->nchannels;
|
req.nchannels = as->nchannels;
|
||||||
req.period_size = conf.period_size_in;
|
req.period_size = conf.period_size_in;
|
||||||
req.buffer_size = conf.buffer_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
|
|
||||||
| (!!conf.buffer_size_in_overridden << 1);
|
|
||||||
|
|
||||||
if (alsa_open (1, &req, &obt, &handle)) {
|
if (alsa_open (1, &req, &obt, &handle)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
|
||||||
|
if (err) {
|
||||||
|
alsa_anal_close (&handle);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
obt_as.freq = obt.freq;
|
obt_as.freq = obt.freq;
|
||||||
obt_as.nchannels = obt.nchannels;
|
obt_as.nchannels = obt.nchannels;
|
||||||
obt_as.fmt = obt.fmt;
|
obt_as.fmt = effective_fmt;
|
||||||
obt_as.endianness = obt.endianness;
|
obt_as.endianness = endianness;
|
||||||
|
|
||||||
audio_pcm_init_info (&hw->info, &obt_as);
|
audio_pcm_init_info (&hw->info, &obt_as);
|
||||||
hw->samples = obt.samples;
|
hw->samples = obt.samples;
|
||||||
@@ -792,7 +824,7 @@ static int alsa_run_in (HWVoiceIn *hw)
|
|||||||
|
|
||||||
for (i = 0; i < 2; ++i) {
|
for (i = 0; i < 2; ++i) {
|
||||||
void *src;
|
void *src;
|
||||||
struct st_sample *dst;
|
st_sample_t *dst;
|
||||||
snd_pcm_sframes_t nread;
|
snd_pcm_sframes_t nread;
|
||||||
snd_pcm_uframes_t len;
|
snd_pcm_uframes_t len;
|
||||||
|
|
||||||
@@ -887,20 +919,16 @@ static struct audio_option alsa_options[] = {
|
|||||||
{"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,
|
{"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/buffer size in microseconds (otherwise in frames)", NULL, 0},
|
||||||
{"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
|
{"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
|
||||||
"DAC period size (0 to go with system default)",
|
"DAC period size", &conf.period_size_out_overriden, 0},
|
||||||
&conf.period_size_out_overridden, 0},
|
|
||||||
{"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
|
{"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
|
||||||
"DAC buffer size (0 to go with system default)",
|
"DAC buffer size", &conf.buffer_size_out_overriden, 0},
|
||||||
&conf.buffer_size_out_overridden, 0},
|
|
||||||
|
|
||||||
{"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,
|
{"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/buffer size in microseconds (otherwise in frames)", NULL, 0},
|
||||||
{"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
|
{"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
|
||||||
"ADC period size (0 to go with system default)",
|
"ADC period size", &conf.period_size_in_overriden, 0},
|
||||||
&conf.period_size_in_overridden, 0},
|
|
||||||
{"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
|
{"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
|
||||||
"ADC buffer size (0 to go with system default)",
|
"ADC buffer size", &conf.buffer_size_in_overriden, 0},
|
||||||
&conf.buffer_size_in_overridden, 0},
|
|
||||||
|
|
||||||
{"THRESHOLD", AUD_OPT_INT, &conf.threshold,
|
{"THRESHOLD", AUD_OPT_INT, &conf.threshold,
|
||||||
"(undocumented)", NULL, 0},
|
"(undocumented)", NULL, 0},
|
||||||
|
|||||||
260
audio/audio.c
260
audio/audio.c
@@ -21,11 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "hw/hw.h"
|
#include "vl.h"
|
||||||
#include "audio.h"
|
|
||||||
#include "console.h"
|
|
||||||
#include "qemu-timer.h"
|
|
||||||
#include "sysemu.h"
|
|
||||||
|
|
||||||
#define AUDIO_CAP "audio"
|
#define AUDIO_CAP "audio"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
@@ -38,7 +34,24 @@
|
|||||||
#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
|
#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
|
||||||
|
|
||||||
static struct audio_driver *drvtab[] = {
|
static struct audio_driver *drvtab[] = {
|
||||||
AUDIO_DRIVERS
|
#ifdef CONFIG_OSS
|
||||||
|
&oss_audio_driver,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_ALSA
|
||||||
|
&alsa_audio_driver,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_COREAUDIO
|
||||||
|
&coreaudio_audio_driver,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_DSOUND
|
||||||
|
&dsound_audio_driver,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_FMOD
|
||||||
|
&fmod_audio_driver,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_SDL
|
||||||
|
&sdl_audio_driver,
|
||||||
|
#endif
|
||||||
&no_audio_driver,
|
&no_audio_driver,
|
||||||
&wav_audio_driver
|
&wav_audio_driver
|
||||||
};
|
};
|
||||||
@@ -47,14 +60,14 @@ struct fixed_settings {
|
|||||||
int enabled;
|
int enabled;
|
||||||
int nb_voices;
|
int nb_voices;
|
||||||
int greedy;
|
int greedy;
|
||||||
struct audsettings settings;
|
audsettings_t settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
struct fixed_settings fixed_out;
|
struct fixed_settings fixed_out;
|
||||||
struct fixed_settings fixed_in;
|
struct fixed_settings fixed_in;
|
||||||
union {
|
union {
|
||||||
int hertz;
|
int hz;
|
||||||
int64_t ticks;
|
int64_t ticks;
|
||||||
} period;
|
} period;
|
||||||
int plive;
|
int plive;
|
||||||
@@ -67,8 +80,7 @@ static struct {
|
|||||||
{
|
{
|
||||||
44100, /* freq */
|
44100, /* freq */
|
||||||
2, /* nchannels */
|
2, /* nchannels */
|
||||||
AUD_FMT_S16, /* fmt */
|
AUD_FMT_S16 /* fmt */
|
||||||
AUDIO_HOST_ENDIANNESS
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -79,26 +91,25 @@ static struct {
|
|||||||
{
|
{
|
||||||
44100, /* freq */
|
44100, /* freq */
|
||||||
2, /* nchannels */
|
2, /* nchannels */
|
||||||
AUD_FMT_S16, /* fmt */
|
AUD_FMT_S16 /* fmt */
|
||||||
AUDIO_HOST_ENDIANNESS
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{ 250 }, /* period */
|
{ 0 }, /* period */
|
||||||
0, /* plive */
|
0, /* plive */
|
||||||
0 /* log_to_monitor */
|
0 /* log_to_monitor */
|
||||||
};
|
};
|
||||||
|
|
||||||
static AudioState glob_audio_state;
|
static AudioState glob_audio_state;
|
||||||
|
|
||||||
struct mixeng_volume nominal_volume = {
|
volume_t nominal_volume = {
|
||||||
0,
|
0,
|
||||||
#ifdef FLOAT_MIXENG
|
#ifdef FLOAT_MIXENG
|
||||||
1.0,
|
1.0,
|
||||||
1.0
|
1.0
|
||||||
#else
|
#else
|
||||||
1ULL << 32,
|
UINT_MAX,
|
||||||
1ULL << 32
|
UINT_MAX
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -155,25 +166,6 @@ int audio_bug (const char *funcname, int cond)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline int audio_bits_to_index (int bits)
|
|
||||||
{
|
|
||||||
switch (bits) {
|
|
||||||
case 8:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 16:
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case 32:
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
default:
|
|
||||||
audio_bug ("bits_to_index", 1);
|
|
||||||
AUD_log (NULL, "invalid bits %d\n", bits);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *audio_calloc (const char *funcname, int nmemb, size_t size)
|
void *audio_calloc (const char *funcname, int nmemb, size_t size)
|
||||||
{
|
{
|
||||||
int cond;
|
int cond;
|
||||||
@@ -197,8 +189,8 @@ void *audio_calloc (const char *funcname, int nmemb, size_t size)
|
|||||||
static char *audio_alloc_prefix (const char *s)
|
static char *audio_alloc_prefix (const char *s)
|
||||||
{
|
{
|
||||||
const char qemu_prefix[] = "QEMU_";
|
const char qemu_prefix[] = "QEMU_";
|
||||||
size_t len, i;
|
size_t len;
|
||||||
char *r, *u;
|
char *r;
|
||||||
|
|
||||||
if (!s) {
|
if (!s) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -207,19 +199,21 @@ static char *audio_alloc_prefix (const char *s)
|
|||||||
len = strlen (s);
|
len = strlen (s);
|
||||||
r = qemu_malloc (len + sizeof (qemu_prefix));
|
r = qemu_malloc (len + sizeof (qemu_prefix));
|
||||||
|
|
||||||
u = r + sizeof (qemu_prefix) - 1;
|
if (r) {
|
||||||
|
size_t i;
|
||||||
|
char *u = r + sizeof (qemu_prefix) - 1;
|
||||||
|
|
||||||
pstrcpy (r, len + sizeof (qemu_prefix), qemu_prefix);
|
strcpy (r, qemu_prefix);
|
||||||
pstrcat (r, len + sizeof (qemu_prefix), s);
|
strcat (r, s);
|
||||||
|
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
u[i] = qemu_toupper(u[i]);
|
u[i] = toupper (u[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *audio_audfmt_to_string (audfmt_e fmt)
|
const char *audio_audfmt_to_string (audfmt_e fmt)
|
||||||
{
|
{
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case AUD_FMT_U8:
|
case AUD_FMT_U8:
|
||||||
@@ -233,20 +227,13 @@ static const char *audio_audfmt_to_string (audfmt_e fmt)
|
|||||||
|
|
||||||
case AUD_FMT_S16:
|
case AUD_FMT_S16:
|
||||||
return "S16";
|
return "S16";
|
||||||
|
|
||||||
case AUD_FMT_U32:
|
|
||||||
return "U32";
|
|
||||||
|
|
||||||
case AUD_FMT_S32:
|
|
||||||
return "S32";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dolog ("Bogus audfmt %d returning S16\n", fmt);
|
dolog ("Bogus audfmt %d returning S16\n", fmt);
|
||||||
return "S16";
|
return "S16";
|
||||||
}
|
}
|
||||||
|
|
||||||
static audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval,
|
audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp)
|
||||||
int *defaultp)
|
|
||||||
{
|
{
|
||||||
if (!strcasecmp (s, "u8")) {
|
if (!strcasecmp (s, "u8")) {
|
||||||
*defaultp = 0;
|
*defaultp = 0;
|
||||||
@@ -256,10 +243,6 @@ static audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval,
|
|||||||
*defaultp = 0;
|
*defaultp = 0;
|
||||||
return AUD_FMT_U16;
|
return AUD_FMT_U16;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp (s, "u32")) {
|
|
||||||
*defaultp = 0;
|
|
||||||
return AUD_FMT_U32;
|
|
||||||
}
|
|
||||||
else if (!strcasecmp (s, "s8")) {
|
else if (!strcasecmp (s, "s8")) {
|
||||||
*defaultp = 0;
|
*defaultp = 0;
|
||||||
return AUD_FMT_S8;
|
return AUD_FMT_S8;
|
||||||
@@ -268,10 +251,6 @@ static audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval,
|
|||||||
*defaultp = 0;
|
*defaultp = 0;
|
||||||
return AUD_FMT_S16;
|
return AUD_FMT_S16;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp (s, "s32")) {
|
|
||||||
*defaultp = 0;
|
|
||||||
return AUD_FMT_S32;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
dolog ("Bogus audio format `%s' using %s\n",
|
dolog ("Bogus audio format `%s' using %s\n",
|
||||||
s, audio_audfmt_to_string (defval));
|
s, audio_audfmt_to_string (defval));
|
||||||
@@ -372,7 +351,7 @@ static void audio_print_options (const char *prefix,
|
|||||||
const char *state = "default";
|
const char *state = "default";
|
||||||
printf (" %s_%s: ", uprefix, opt->name);
|
printf (" %s_%s: ", uprefix, opt->name);
|
||||||
|
|
||||||
if (opt->overriddenp && *opt->overriddenp) {
|
if (opt->overridenp && *opt->overridenp) {
|
||||||
state = "current";
|
state = "current";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +374,7 @@ static void audio_print_options (const char *prefix,
|
|||||||
{
|
{
|
||||||
audfmt_e *fmtp = opt->valp;
|
audfmt_e *fmtp = opt->valp;
|
||||||
printf (
|
printf (
|
||||||
"format, %s = %s, (one of: U8 S8 U16 S16 U32 S32)\n",
|
"format, %s = %s, (one of: U8 S8 U16 S16)\n",
|
||||||
state,
|
state,
|
||||||
audio_audfmt_to_string (*fmtp)
|
audio_audfmt_to_string (*fmtp)
|
||||||
);
|
);
|
||||||
@@ -428,7 +407,7 @@ static void audio_process_options (const char *prefix,
|
|||||||
{
|
{
|
||||||
char *optname;
|
char *optname;
|
||||||
const char qemu_prefix[] = "QEMU_";
|
const char qemu_prefix[] = "QEMU_";
|
||||||
size_t preflen, optlen;
|
size_t preflen;
|
||||||
|
|
||||||
if (audio_bug (AUDIO_FUNC, !prefix)) {
|
if (audio_bug (AUDIO_FUNC, !prefix)) {
|
||||||
dolog ("prefix = NULL\n");
|
dolog ("prefix = NULL\n");
|
||||||
@@ -456,17 +435,21 @@ static void audio_process_options (const char *prefix,
|
|||||||
/* len of opt->name + len of prefix + size of qemu_prefix
|
/* len of opt->name + len of prefix + size of qemu_prefix
|
||||||
* (includes trailing zero) + zero + underscore (on behalf of
|
* (includes trailing zero) + zero + underscore (on behalf of
|
||||||
* sizeof) */
|
* sizeof) */
|
||||||
optlen = len + preflen + sizeof (qemu_prefix) + 1;
|
optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1);
|
||||||
optname = qemu_malloc (optlen);
|
if (!optname) {
|
||||||
|
dolog ("Could not allocate memory for option name `%s'\n",
|
||||||
|
opt->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
pstrcpy (optname, optlen, qemu_prefix);
|
strcpy (optname, qemu_prefix);
|
||||||
|
|
||||||
/* copy while upper-casing, including trailing zero */
|
/* copy while upper-casing, including trailing zero */
|
||||||
for (i = 0; i <= preflen; ++i) {
|
for (i = 0; i <= preflen; ++i) {
|
||||||
optname[i + sizeof (qemu_prefix) - 1] = qemu_toupper(prefix[i]);
|
optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]);
|
||||||
}
|
}
|
||||||
pstrcat (optname, optlen, "_");
|
strcat (optname, "_");
|
||||||
pstrcat (optname, optlen, opt->name);
|
strcat (optname, opt->name);
|
||||||
|
|
||||||
def = 1;
|
def = 1;
|
||||||
switch (opt->tag) {
|
switch (opt->tag) {
|
||||||
@@ -498,15 +481,15 @@ static void audio_process_options (const char *prefix,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opt->overriddenp) {
|
if (!opt->overridenp) {
|
||||||
opt->overriddenp = &opt->overridden;
|
opt->overridenp = &opt->overriden;
|
||||||
}
|
}
|
||||||
*opt->overriddenp = !def;
|
*opt->overridenp = !def;
|
||||||
qemu_free (optname);
|
qemu_free (optname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void audio_print_settings (struct audsettings *as)
|
static void audio_print_settings (audsettings_t *as)
|
||||||
{
|
{
|
||||||
dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels);
|
dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels);
|
||||||
|
|
||||||
@@ -523,12 +506,6 @@ static void audio_print_settings (struct audsettings *as)
|
|||||||
case AUD_FMT_U16:
|
case AUD_FMT_U16:
|
||||||
AUD_log (NULL, "U16");
|
AUD_log (NULL, "U16");
|
||||||
break;
|
break;
|
||||||
case AUD_FMT_S32:
|
|
||||||
AUD_log (NULL, "S32");
|
|
||||||
break;
|
|
||||||
case AUD_FMT_U32:
|
|
||||||
AUD_log (NULL, "U32");
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
AUD_log (NULL, "invalid(%d)", as->fmt);
|
AUD_log (NULL, "invalid(%d)", as->fmt);
|
||||||
break;
|
break;
|
||||||
@@ -549,7 +526,7 @@ static void audio_print_settings (struct audsettings *as)
|
|||||||
AUD_log (NULL, "\n");
|
AUD_log (NULL, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int audio_validate_settings (struct audsettings *as)
|
static int audio_validate_settings (audsettings_t *as)
|
||||||
{
|
{
|
||||||
int invalid;
|
int invalid;
|
||||||
|
|
||||||
@@ -561,8 +538,6 @@ static int audio_validate_settings (struct audsettings *as)
|
|||||||
case AUD_FMT_U8:
|
case AUD_FMT_U8:
|
||||||
case AUD_FMT_S16:
|
case AUD_FMT_S16:
|
||||||
case AUD_FMT_U16:
|
case AUD_FMT_U16:
|
||||||
case AUD_FMT_S32:
|
|
||||||
case AUD_FMT_U32:
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
invalid = 1;
|
invalid = 1;
|
||||||
@@ -573,7 +548,7 @@ static int audio_validate_settings (struct audsettings *as)
|
|||||||
return invalid ? -1 : 0;
|
return invalid ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *as)
|
static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
|
||||||
{
|
{
|
||||||
int bits = 8, sign = 0;
|
int bits = 8, sign = 0;
|
||||||
|
|
||||||
@@ -588,12 +563,6 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a
|
|||||||
case AUD_FMT_U16:
|
case AUD_FMT_U16:
|
||||||
bits = 16;
|
bits = 16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUD_FMT_S32:
|
|
||||||
sign = 1;
|
|
||||||
case AUD_FMT_U32:
|
|
||||||
bits = 32;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return info->freq == as->freq
|
return info->freq == as->freq
|
||||||
&& info->nchannels == as->nchannels
|
&& info->nchannels == as->nchannels
|
||||||
@@ -602,9 +571,9 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a
|
|||||||
&& info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
|
&& info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
|
||||||
{
|
{
|
||||||
int bits = 8, sign = 0, shift = 0;
|
int bits = 8, sign = 0;
|
||||||
|
|
||||||
switch (as->fmt) {
|
switch (as->fmt) {
|
||||||
case AUD_FMT_S8:
|
case AUD_FMT_S8:
|
||||||
@@ -616,14 +585,6 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
|||||||
sign = 1;
|
sign = 1;
|
||||||
case AUD_FMT_U16:
|
case AUD_FMT_U16:
|
||||||
bits = 16;
|
bits = 16;
|
||||||
shift = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AUD_FMT_S32:
|
|
||||||
sign = 1;
|
|
||||||
case AUD_FMT_U32:
|
|
||||||
bits = 32;
|
|
||||||
shift = 2;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,7 +592,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
|||||||
info->bits = bits;
|
info->bits = bits;
|
||||||
info->sign = sign;
|
info->sign = sign;
|
||||||
info->nchannels = as->nchannels;
|
info->nchannels = as->nchannels;
|
||||||
info->shift = (as->nchannels == 2) + shift;
|
info->shift = (as->nchannels == 2) + (bits == 16);
|
||||||
info->align = (1 << info->shift) - 1;
|
info->align = (1 << info->shift) - 1;
|
||||||
info->bytes_per_second = info->freq << info->shift;
|
info->bytes_per_second = info->freq << info->shift;
|
||||||
info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
|
info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
|
||||||
@@ -644,16 +605,13 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (info->sign) {
|
if (info->sign) {
|
||||||
memset (buf, 0x00, len << info->shift);
|
memset (buf, len << info->shift, 0x00);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (info->bits == 8) {
|
||||||
|
memset (buf, len << info->shift, 0x80);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switch (info->bits) {
|
|
||||||
case 8:
|
|
||||||
memset (buf, 0x80, len << info->shift);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 16:
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
uint16_t *p = buf;
|
uint16_t *p = buf;
|
||||||
int shift = info->nchannels - 1;
|
int shift = info->nchannels - 1;
|
||||||
@@ -667,38 +625,14 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
|||||||
p[i] = s;
|
p[i] = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case 32:
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
uint32_t *p = buf;
|
|
||||||
int shift = info->nchannels - 1;
|
|
||||||
int32_t s = INT32_MAX;
|
|
||||||
|
|
||||||
if (info->swap_endianness) {
|
|
||||||
s = bswap32 (s);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < len << shift; i++) {
|
|
||||||
p[i] = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
AUD_log (NULL, "audio_pcm_info_clear_buf: invalid bits %d\n",
|
|
||||||
info->bits);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Capture
|
* Capture
|
||||||
*/
|
*/
|
||||||
static void noop_conv (struct st_sample *dst, const void *src,
|
static void noop_conv (st_sample_t *dst, const void *src,
|
||||||
int samples, struct mixeng_volume *vol)
|
int samples, volume_t *vol)
|
||||||
{
|
{
|
||||||
(void) src;
|
(void) src;
|
||||||
(void) dst;
|
(void) dst;
|
||||||
@@ -708,7 +642,7 @@ static void noop_conv (struct st_sample *dst, const void *src,
|
|||||||
|
|
||||||
static CaptureVoiceOut *audio_pcm_capture_find_specific (
|
static CaptureVoiceOut *audio_pcm_capture_find_specific (
|
||||||
AudioState *s,
|
AudioState *s,
|
||||||
struct audsettings *as
|
audsettings_t *as
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
CaptureVoiceOut *cap;
|
CaptureVoiceOut *cap;
|
||||||
@@ -884,7 +818,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
|
|||||||
{
|
{
|
||||||
HWVoiceIn *hw = sw->hw;
|
HWVoiceIn *hw = sw->hw;
|
||||||
int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
|
int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
|
||||||
struct st_sample *src, *dst = sw->buf;
|
st_sample_t *src, *dst = sw->buf;
|
||||||
|
|
||||||
rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
|
rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
|
||||||
|
|
||||||
@@ -1127,7 +1061,6 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
|
|||||||
|
|
||||||
hw = sw->hw;
|
hw = sw->hw;
|
||||||
if (sw->active != on) {
|
if (sw->active != on) {
|
||||||
AudioState *s = &glob_audio_state;
|
|
||||||
SWVoiceOut *temp_sw;
|
SWVoiceOut *temp_sw;
|
||||||
SWVoiceCap *sc;
|
SWVoiceCap *sc;
|
||||||
|
|
||||||
@@ -1135,11 +1068,9 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
|
|||||||
hw->pending_disable = 0;
|
hw->pending_disable = 0;
|
||||||
if (!hw->enabled) {
|
if (!hw->enabled) {
|
||||||
hw->enabled = 1;
|
hw->enabled = 1;
|
||||||
if (s->vm_running) {
|
|
||||||
hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
|
hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
if (hw->enabled) {
|
if (hw->enabled) {
|
||||||
int nb_active = 0;
|
int nb_active = 0;
|
||||||
@@ -1173,16 +1104,13 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
|
|||||||
|
|
||||||
hw = sw->hw;
|
hw = sw->hw;
|
||||||
if (sw->active != on) {
|
if (sw->active != on) {
|
||||||
AudioState *s = &glob_audio_state;
|
|
||||||
SWVoiceIn *temp_sw;
|
SWVoiceIn *temp_sw;
|
||||||
|
|
||||||
if (on) {
|
if (on) {
|
||||||
if (!hw->enabled) {
|
if (!hw->enabled) {
|
||||||
hw->enabled = 1;
|
hw->enabled = 1;
|
||||||
if (s->vm_running) {
|
|
||||||
hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
|
hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
sw->total_hw_samples_acquired = hw->total_samples_captured;
|
sw->total_hw_samples_acquired = hw->total_samples_captured;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1441,7 +1369,7 @@ static void audio_run_capture (AudioState *s)
|
|||||||
while (live) {
|
while (live) {
|
||||||
int left = hw->samples - rpos;
|
int left = hw->samples - rpos;
|
||||||
int to_capture = audio_MIN (live, left);
|
int to_capture = audio_MIN (live, left);
|
||||||
struct st_sample *src;
|
st_sample_t *src;
|
||||||
struct capture_callback *cb;
|
struct capture_callback *cb;
|
||||||
|
|
||||||
src = hw->mix_buf + rpos;
|
src = hw->mix_buf + rpos;
|
||||||
@@ -1519,14 +1447,14 @@ static struct audio_option audio_options[] = {
|
|||||||
"Number of voices for ADC", NULL, 0},
|
"Number of voices for ADC", NULL, 0},
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
{"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hertz,
|
{"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hz,
|
||||||
"Timer period in HZ (0 - use lowest possible)", NULL, 0},
|
"Timer period in HZ (0 - use lowest possible)", NULL, 0},
|
||||||
|
|
||||||
{"PLIVE", AUD_OPT_BOOL, &conf.plive,
|
{"PLIVE", AUD_OPT_BOOL, &conf.plive,
|
||||||
"(undocumented)", NULL, 0},
|
"(undocumented)", NULL, 0},
|
||||||
|
|
||||||
{"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor,
|
{"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor,
|
||||||
"print logging messages to monitor instead of stderr", NULL, 0},
|
"print logging messages to montior instead of stderr", NULL, 0},
|
||||||
|
|
||||||
{NULL, 0, NULL, NULL, NULL, 0}
|
{NULL, 0, NULL, NULL, NULL, 0}
|
||||||
};
|
};
|
||||||
@@ -1555,7 +1483,7 @@ void AUD_help (void)
|
|||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
audio_process_options ("AUDIO", audio_options);
|
audio_process_options ("AUDIO", audio_options);
|
||||||
for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
|
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
|
||||||
struct audio_driver *d = drvtab[i];
|
struct audio_driver *d = drvtab[i];
|
||||||
if (d->options) {
|
if (d->options) {
|
||||||
audio_process_options (d->name, d->options);
|
audio_process_options (d->name, d->options);
|
||||||
@@ -1568,7 +1496,7 @@ void AUD_help (void)
|
|||||||
|
|
||||||
printf ("Available drivers:\n");
|
printf ("Available drivers:\n");
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
|
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
|
||||||
struct audio_driver *d = drvtab[i];
|
struct audio_driver *d = drvtab[i];
|
||||||
|
|
||||||
printf ("Name: %s\n", d->name);
|
printf ("Name: %s\n", d->name);
|
||||||
@@ -1621,15 +1549,13 @@ static int audio_driver_init (AudioState *s, struct audio_driver *drv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void audio_vm_change_state_handler (void *opaque, int running,
|
static void audio_vm_change_state_handler (void *opaque, int running)
|
||||||
int reason)
|
|
||||||
{
|
{
|
||||||
AudioState *s = opaque;
|
AudioState *s = opaque;
|
||||||
HWVoiceOut *hwo = NULL;
|
HWVoiceOut *hwo = NULL;
|
||||||
HWVoiceIn *hwi = NULL;
|
HWVoiceIn *hwi = NULL;
|
||||||
int op = running ? VOICE_ENABLE : VOICE_DISABLE;
|
int op = running ? VOICE_ENABLE : VOICE_DISABLE;
|
||||||
|
|
||||||
s->vm_running = running;
|
|
||||||
while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
|
while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
|
||||||
hwo->pcm_ops->ctl_out (hwo, op);
|
hwo->pcm_ops->ctl_out (hwo, op);
|
||||||
}
|
}
|
||||||
@@ -1747,7 +1673,7 @@ AudioState *AUD_init (void)
|
|||||||
if (drvname) {
|
if (drvname) {
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
|
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
|
||||||
if (!strcmp (drvname, drvtab[i]->name)) {
|
if (!strcmp (drvname, drvtab[i]->name)) {
|
||||||
done = !audio_driver_init (s, drvtab[i]);
|
done = !audio_driver_init (s, drvtab[i]);
|
||||||
found = 1;
|
found = 1;
|
||||||
@@ -1762,7 +1688,7 @@ AudioState *AUD_init (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
for (i = 0; !done && i < ARRAY_SIZE (drvtab); i++) {
|
for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
|
||||||
if (drvtab[i]->can_be_default) {
|
if (drvtab[i]->can_be_default) {
|
||||||
done = !audio_driver_init (s, drvtab[i]);
|
done = !audio_driver_init (s, drvtab[i]);
|
||||||
}
|
}
|
||||||
@@ -1782,16 +1708,16 @@ AudioState *AUD_init (void)
|
|||||||
if (done) {
|
if (done) {
|
||||||
VMChangeStateEntry *e;
|
VMChangeStateEntry *e;
|
||||||
|
|
||||||
if (conf.period.hertz <= 0) {
|
if (conf.period.hz <= 0) {
|
||||||
if (conf.period.hertz < 0) {
|
if (conf.period.hz < 0) {
|
||||||
dolog ("warning: Timer period is negative - %d "
|
dolog ("warning: Timer period is negative - %d "
|
||||||
"treating as zero\n",
|
"treating as zero\n",
|
||||||
conf.period.hertz);
|
conf.period.hz);
|
||||||
}
|
}
|
||||||
conf.period.ticks = 1;
|
conf.period.ticks = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
conf.period.ticks = ticks_per_sec / conf.period.hertz;
|
conf.period.ticks = ticks_per_sec / conf.period.hz;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
|
e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
|
||||||
@@ -1813,7 +1739,7 @@ AudioState *AUD_init (void)
|
|||||||
|
|
||||||
CaptureVoiceOut *AUD_add_capture (
|
CaptureVoiceOut *AUD_add_capture (
|
||||||
AudioState *s,
|
AudioState *s,
|
||||||
struct audsettings *as,
|
audsettings_t *as,
|
||||||
struct audio_capture_ops *ops,
|
struct audio_capture_ops *ops,
|
||||||
void *cb_opaque
|
void *cb_opaque
|
||||||
)
|
)
|
||||||
@@ -1864,7 +1790,7 @@ CaptureVoiceOut *AUD_add_capture (
|
|||||||
/* XXX find a more elegant way */
|
/* XXX find a more elegant way */
|
||||||
hw->samples = 4096 * 4;
|
hw->samples = 4096 * 4;
|
||||||
hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
|
hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
|
||||||
sizeof (struct st_sample));
|
sizeof (st_sample_t));
|
||||||
if (!hw->mix_buf) {
|
if (!hw->mix_buf) {
|
||||||
dolog ("Could not allocate capture mix buffer (%d samples)\n",
|
dolog ("Could not allocate capture mix buffer (%d samples)\n",
|
||||||
hw->samples);
|
hw->samples);
|
||||||
@@ -1885,7 +1811,7 @@ CaptureVoiceOut *AUD_add_capture (
|
|||||||
[hw->info.nchannels == 2]
|
[hw->info.nchannels == 2]
|
||||||
[hw->info.sign]
|
[hw->info.sign]
|
||||||
[hw->info.swap_endianness]
|
[hw->info.swap_endianness]
|
||||||
[audio_bits_to_index (hw->info.bits)];
|
[hw->info.bits == 16];
|
||||||
|
|
||||||
LIST_INSERT_HEAD (&s->cap_head, cap, entries);
|
LIST_INSERT_HEAD (&s->cap_head, cap, entries);
|
||||||
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
||||||
@@ -1943,21 +1869,3 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
|
|
||||||
{
|
|
||||||
if (sw) {
|
|
||||||
sw->vol.mute = mute;
|
|
||||||
sw->vol.l = nominal_volume.l * lvol / 255;
|
|
||||||
sw->vol.r = nominal_volume.r * rvol / 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
|
|
||||||
{
|
|
||||||
if (sw) {
|
|
||||||
sw->vol.mute = mute;
|
|
||||||
sw->vol.l = nominal_volume.l * lvol / 255;
|
|
||||||
sw->vol.r = nominal_volume.r * rvol / 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
#ifndef QEMU_AUDIO_H
|
#ifndef QEMU_AUDIO_H
|
||||||
#define QEMU_AUDIO_H
|
#define QEMU_AUDIO_H
|
||||||
|
|
||||||
#include "config-host.h"
|
#include "config.h"
|
||||||
#include "sys-queue.h"
|
#include "sys-queue.h"
|
||||||
|
|
||||||
typedef void (*audio_callback_fn_t) (void *opaque, int avail);
|
typedef void (*audio_callback_fn_t) (void *opaque, int avail);
|
||||||
@@ -33,9 +33,7 @@ typedef enum {
|
|||||||
AUD_FMT_U8,
|
AUD_FMT_U8,
|
||||||
AUD_FMT_S8,
|
AUD_FMT_S8,
|
||||||
AUD_FMT_U16,
|
AUD_FMT_U16,
|
||||||
AUD_FMT_S16,
|
AUD_FMT_S16
|
||||||
AUD_FMT_U32,
|
|
||||||
AUD_FMT_S32
|
|
||||||
} audfmt_e;
|
} audfmt_e;
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
@@ -44,12 +42,12 @@ typedef enum {
|
|||||||
#define AUDIO_HOST_ENDIANNESS 0
|
#define AUDIO_HOST_ENDIANNESS 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct audsettings {
|
typedef struct {
|
||||||
int freq;
|
int freq;
|
||||||
int nchannels;
|
int nchannels;
|
||||||
audfmt_e fmt;
|
audfmt_e fmt;
|
||||||
int endianness;
|
int endianness;
|
||||||
};
|
} audsettings_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AUD_CNOTIFY_ENABLE,
|
AUD_CNOTIFY_ENABLE,
|
||||||
@@ -73,6 +71,7 @@ typedef struct CaptureState {
|
|||||||
LIST_ENTRY (CaptureState) entries;
|
LIST_ENTRY (CaptureState) entries;
|
||||||
} CaptureState;
|
} CaptureState;
|
||||||
|
|
||||||
|
typedef struct AudioState AudioState;
|
||||||
typedef struct SWVoiceOut SWVoiceOut;
|
typedef struct SWVoiceOut SWVoiceOut;
|
||||||
typedef struct CaptureVoiceOut CaptureVoiceOut;
|
typedef struct CaptureVoiceOut CaptureVoiceOut;
|
||||||
typedef struct SWVoiceIn SWVoiceIn;
|
typedef struct SWVoiceIn SWVoiceIn;
|
||||||
@@ -100,7 +99,7 @@ void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
|
|||||||
void AUD_remove_card (QEMUSoundCard *card);
|
void AUD_remove_card (QEMUSoundCard *card);
|
||||||
CaptureVoiceOut *AUD_add_capture (
|
CaptureVoiceOut *AUD_add_capture (
|
||||||
AudioState *s,
|
AudioState *s,
|
||||||
struct audsettings *as,
|
audsettings_t *as,
|
||||||
struct audio_capture_ops *ops,
|
struct audio_capture_ops *ops,
|
||||||
void *opaque
|
void *opaque
|
||||||
);
|
);
|
||||||
@@ -112,7 +111,7 @@ SWVoiceOut *AUD_open_out (
|
|||||||
const char *name,
|
const char *name,
|
||||||
void *callback_opaque,
|
void *callback_opaque,
|
||||||
audio_callback_fn_t callback_fn,
|
audio_callback_fn_t callback_fn,
|
||||||
struct audsettings *settings
|
audsettings_t *settings
|
||||||
);
|
);
|
||||||
|
|
||||||
void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
|
void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
|
||||||
@@ -124,16 +123,13 @@ int AUD_is_active_out (SWVoiceOut *sw);
|
|||||||
void AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
|
void AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
|
||||||
uint64_t AUD_get_elapsed_usec_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 (
|
SWVoiceIn *AUD_open_in (
|
||||||
QEMUSoundCard *card,
|
QEMUSoundCard *card,
|
||||||
SWVoiceIn *sw,
|
SWVoiceIn *sw,
|
||||||
const char *name,
|
const char *name,
|
||||||
void *callback_opaque,
|
void *callback_opaque,
|
||||||
audio_callback_fn_t callback_fn,
|
audio_callback_fn_t callback_fn,
|
||||||
struct audsettings *settings
|
audsettings_t *settings
|
||||||
);
|
);
|
||||||
|
|
||||||
void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
|
void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
|
||||||
@@ -170,7 +166,4 @@ uint32_t lsbindex (uint32_t u);
|
|||||||
#define audio_MAX(a, b) ((a)<(b)?(b):(a))
|
#define audio_MAX(a, b) ((a)<(b)?(b):(a))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int wav_start_capture (CaptureState *s, const char *path, int freq,
|
|
||||||
int bits, int nchannels);
|
|
||||||
|
|
||||||
#endif /* audio.h */
|
#endif /* audio.h */
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ struct audio_option {
|
|||||||
audio_option_tag_e tag;
|
audio_option_tag_e tag;
|
||||||
void *valp;
|
void *valp;
|
||||||
const char *descr;
|
const char *descr;
|
||||||
int *overriddenp;
|
int *overridenp;
|
||||||
int overridden;
|
int overriden;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct audio_callback {
|
struct audio_callback {
|
||||||
@@ -76,7 +76,7 @@ typedef struct HWVoiceOut {
|
|||||||
int rpos;
|
int rpos;
|
||||||
uint64_t ts_helper;
|
uint64_t ts_helper;
|
||||||
|
|
||||||
struct st_sample *mix_buf;
|
st_sample_t *mix_buf;
|
||||||
|
|
||||||
int samples;
|
int samples;
|
||||||
LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
|
LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
|
||||||
@@ -95,7 +95,7 @@ typedef struct HWVoiceIn {
|
|||||||
int total_samples_captured;
|
int total_samples_captured;
|
||||||
uint64_t ts_helper;
|
uint64_t ts_helper;
|
||||||
|
|
||||||
struct st_sample *conv_buf;
|
st_sample_t *conv_buf;
|
||||||
|
|
||||||
int samples;
|
int samples;
|
||||||
LIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
|
LIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
|
||||||
@@ -107,14 +107,14 @@ struct SWVoiceOut {
|
|||||||
struct audio_pcm_info info;
|
struct audio_pcm_info info;
|
||||||
t_sample *conv;
|
t_sample *conv;
|
||||||
int64_t ratio;
|
int64_t ratio;
|
||||||
struct st_sample *buf;
|
st_sample_t *buf;
|
||||||
void *rate;
|
void *rate;
|
||||||
int total_hw_samples_mixed;
|
int total_hw_samples_mixed;
|
||||||
int active;
|
int active;
|
||||||
int empty;
|
int empty;
|
||||||
HWVoiceOut *hw;
|
HWVoiceOut *hw;
|
||||||
char *name;
|
char *name;
|
||||||
struct mixeng_volume vol;
|
volume_t vol;
|
||||||
struct audio_callback callback;
|
struct audio_callback callback;
|
||||||
LIST_ENTRY (SWVoiceOut) entries;
|
LIST_ENTRY (SWVoiceOut) entries;
|
||||||
};
|
};
|
||||||
@@ -125,11 +125,11 @@ struct SWVoiceIn {
|
|||||||
int64_t ratio;
|
int64_t ratio;
|
||||||
void *rate;
|
void *rate;
|
||||||
int total_hw_samples_acquired;
|
int total_hw_samples_acquired;
|
||||||
struct st_sample *buf;
|
st_sample_t *buf;
|
||||||
f_sample *clip;
|
f_sample *clip;
|
||||||
HWVoiceIn *hw;
|
HWVoiceIn *hw;
|
||||||
char *name;
|
char *name;
|
||||||
struct mixeng_volume vol;
|
volume_t vol;
|
||||||
struct audio_callback callback;
|
struct audio_callback callback;
|
||||||
LIST_ENTRY (SWVoiceIn) entries;
|
LIST_ENTRY (SWVoiceIn) entries;
|
||||||
};
|
};
|
||||||
@@ -149,13 +149,13 @@ struct audio_driver {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct audio_pcm_ops {
|
struct audio_pcm_ops {
|
||||||
int (*init_out)(HWVoiceOut *hw, struct audsettings *as);
|
int (*init_out)(HWVoiceOut *hw, audsettings_t *as);
|
||||||
void (*fini_out)(HWVoiceOut *hw);
|
void (*fini_out)(HWVoiceOut *hw);
|
||||||
int (*run_out) (HWVoiceOut *hw);
|
int (*run_out) (HWVoiceOut *hw);
|
||||||
int (*write) (SWVoiceOut *sw, void *buf, int size);
|
int (*write) (SWVoiceOut *sw, void *buf, int size);
|
||||||
int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
|
int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
|
||||||
|
|
||||||
int (*init_in) (HWVoiceIn *hw, struct audsettings *as);
|
int (*init_in) (HWVoiceIn *hw, audsettings_t *as);
|
||||||
void (*fini_in) (HWVoiceIn *hw);
|
void (*fini_in) (HWVoiceIn *hw);
|
||||||
int (*run_in) (HWVoiceIn *hw);
|
int (*run_in) (HWVoiceIn *hw);
|
||||||
int (*read) (SWVoiceIn *sw, void *buf, int size);
|
int (*read) (SWVoiceIn *sw, void *buf, int size);
|
||||||
@@ -192,7 +192,6 @@ struct AudioState {
|
|||||||
LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
|
LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
|
||||||
int nb_hw_voices_out;
|
int nb_hw_voices_out;
|
||||||
int nb_hw_voices_in;
|
int nb_hw_voices_in;
|
||||||
int vm_running;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct audio_driver no_audio_driver;
|
extern struct audio_driver no_audio_driver;
|
||||||
@@ -203,11 +202,9 @@ extern struct audio_driver fmod_audio_driver;
|
|||||||
extern struct audio_driver alsa_audio_driver;
|
extern struct audio_driver alsa_audio_driver;
|
||||||
extern struct audio_driver coreaudio_audio_driver;
|
extern struct audio_driver coreaudio_audio_driver;
|
||||||
extern struct audio_driver dsound_audio_driver;
|
extern struct audio_driver dsound_audio_driver;
|
||||||
extern struct audio_driver esd_audio_driver;
|
extern volume_t nominal_volume;
|
||||||
extern struct audio_driver pa_audio_driver;
|
|
||||||
extern struct mixeng_volume nominal_volume;
|
|
||||||
|
|
||||||
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
|
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as);
|
||||||
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
|
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_sw_write (SWVoiceOut *sw, void *buf, int len);
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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 */
|
|
||||||
@@ -82,7 +82,7 @@ static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
|
|||||||
|
|
||||||
static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
|
static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
|
||||||
{
|
{
|
||||||
HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (struct st_sample));
|
HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t));
|
||||||
if (!HWBUF) {
|
if (!HWBUF) {
|
||||||
dolog ("Could not allocate " NAME " buffer (%d samples)\n",
|
dolog ("Could not allocate " NAME " buffer (%d samples)\n",
|
||||||
hw->samples);
|
hw->samples);
|
||||||
@@ -116,7 +116,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
|
|||||||
samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
|
samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample));
|
sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t));
|
||||||
if (!sw->buf) {
|
if (!sw->buf) {
|
||||||
dolog ("Could not allocate buffer for `%s' (%d samples)\n",
|
dolog ("Could not allocate buffer for `%s' (%d samples)\n",
|
||||||
SW_NAME (sw), samples);
|
SW_NAME (sw), samples);
|
||||||
@@ -140,7 +140,7 @@ static int glue (audio_pcm_sw_init_, TYPE) (
|
|||||||
SW *sw,
|
SW *sw,
|
||||||
HW *hw,
|
HW *hw,
|
||||||
const char *name,
|
const char *name,
|
||||||
struct audsettings *as
|
audsettings_t *as
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@@ -164,7 +164,7 @@ static int glue (audio_pcm_sw_init_, TYPE) (
|
|||||||
[sw->info.nchannels == 2]
|
[sw->info.nchannels == 2]
|
||||||
[sw->info.sign]
|
[sw->info.sign]
|
||||||
[sw->info.swap_endianness]
|
[sw->info.swap_endianness]
|
||||||
[audio_bits_to_index (sw->info.bits)];
|
[sw->info.bits == 16];
|
||||||
|
|
||||||
sw->name = qemu_strdup (name);
|
sw->name = qemu_strdup (name);
|
||||||
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
|
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
|
||||||
@@ -229,7 +229,7 @@ static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (AudioState *s, HW *hw)
|
|||||||
static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
|
static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
|
||||||
AudioState *s,
|
AudioState *s,
|
||||||
HW *hw,
|
HW *hw,
|
||||||
struct audsettings *as
|
audsettings_t *as
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
|
while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
|
||||||
@@ -240,8 +240,7 @@ static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s,
|
static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
|
||||||
struct audsettings *as)
|
|
||||||
{
|
{
|
||||||
HW *hw;
|
HW *hw;
|
||||||
struct audio_driver *drv = s->drv;
|
struct audio_driver *drv = s->drv;
|
||||||
@@ -289,7 +288,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s,
|
|||||||
[hw->info.nchannels == 2]
|
[hw->info.nchannels == 2]
|
||||||
[hw->info.sign]
|
[hw->info.sign]
|
||||||
[hw->info.swap_endianness]
|
[hw->info.swap_endianness]
|
||||||
[audio_bits_to_index (hw->info.bits)];
|
[hw->info.bits == 16];
|
||||||
|
|
||||||
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
|
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
|
||||||
goto err1;
|
goto err1;
|
||||||
@@ -309,8 +308,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s,
|
static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as)
|
||||||
struct audsettings *as)
|
|
||||||
{
|
{
|
||||||
HW *hw;
|
HW *hw;
|
||||||
|
|
||||||
@@ -337,12 +335,12 @@ static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s,
|
|||||||
static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
||||||
AudioState *s,
|
AudioState *s,
|
||||||
const char *sw_name,
|
const char *sw_name,
|
||||||
struct audsettings *as
|
audsettings_t *as
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
SW *sw;
|
SW *sw;
|
||||||
HW *hw;
|
HW *hw;
|
||||||
struct audsettings hw_as;
|
audsettings_t hw_as;
|
||||||
|
|
||||||
if (glue (conf.fixed_, TYPE).enabled) {
|
if (glue (conf.fixed_, TYPE).enabled) {
|
||||||
hw_as = glue (conf.fixed_, TYPE).settings;
|
hw_as = glue (conf.fixed_, TYPE).settings;
|
||||||
@@ -407,7 +405,7 @@ SW *glue (AUD_open_, TYPE) (
|
|||||||
const char *name,
|
const char *name,
|
||||||
void *callback_opaque ,
|
void *callback_opaque ,
|
||||||
audio_callback_fn_t callback_fn,
|
audio_callback_fn_t callback_fn,
|
||||||
struct audsettings *as
|
audsettings_t *as
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
AudioState *s;
|
AudioState *s;
|
||||||
|
|||||||
@@ -26,8 +26,7 @@
|
|||||||
#include <string.h> /* strerror */
|
#include <string.h> /* strerror */
|
||||||
#include <pthread.h> /* pthread_X */
|
#include <pthread.h> /* pthread_X */
|
||||||
|
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "audio.h"
|
|
||||||
|
|
||||||
#define AUDIO_CAP "coreaudio"
|
#define AUDIO_CAP "coreaudio"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
@@ -233,7 +232,7 @@ static OSStatus audioDeviceIOProc(
|
|||||||
HWVoiceOut *hw = hwptr;
|
HWVoiceOut *hw = hwptr;
|
||||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
|
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
|
||||||
int rpos, live;
|
int rpos, live;
|
||||||
struct st_sample *src;
|
st_sample_t *src;
|
||||||
#ifndef FLOAT_MIXENG
|
#ifndef FLOAT_MIXENG
|
||||||
#ifdef RECIPROCAL
|
#ifdef RECIPROCAL
|
||||||
const float scale = 1.f / UINT_MAX;
|
const float scale = 1.f / UINT_MAX;
|
||||||
@@ -289,12 +288,13 @@ static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
|
|||||||
return audio_pcm_sw_write (sw, buf, len);
|
return audio_pcm_sw_write (sw, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
|
static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||||
{
|
{
|
||||||
OSStatus status;
|
OSStatus status;
|
||||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||||
UInt32 propertySize;
|
UInt32 propertySize;
|
||||||
int err;
|
int err;
|
||||||
|
int bits = 8;
|
||||||
const char *typ = "playback";
|
const char *typ = "playback";
|
||||||
AudioValueRange frameRange;
|
AudioValueRange frameRange;
|
||||||
|
|
||||||
@@ -305,6 +305,10 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
|
||||||
|
bits = 16;
|
||||||
|
}
|
||||||
|
|
||||||
audio_pcm_init_info (&hw->info, as);
|
audio_pcm_init_info (&hw->info, as);
|
||||||
|
|
||||||
/* open default output device */
|
/* open default output device */
|
||||||
|
|||||||
@@ -23,20 +23,16 @@
|
|||||||
*/
|
*/
|
||||||
#ifdef DSBTYPE_IN
|
#ifdef DSBTYPE_IN
|
||||||
#define NAME "capture buffer"
|
#define NAME "capture buffer"
|
||||||
#define NAME2 "DirectSoundCapture"
|
|
||||||
#define TYPE in
|
#define TYPE in
|
||||||
#define IFACE IDirectSoundCaptureBuffer
|
#define IFACE IDirectSoundCaptureBuffer
|
||||||
#define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
|
#define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
|
||||||
#define FIELD dsound_capture_buffer
|
#define FIELD dsound_capture_buffer
|
||||||
#define FIELD2 dsound_capture
|
|
||||||
#else
|
#else
|
||||||
#define NAME "playback buffer"
|
#define NAME "playback buffer"
|
||||||
#define NAME2 "DirectSound"
|
|
||||||
#define TYPE out
|
#define TYPE out
|
||||||
#define IFACE IDirectSoundBuffer
|
#define IFACE IDirectSoundBuffer
|
||||||
#define BUFPTR LPDIRECTSOUNDBUFFER
|
#define BUFPTR LPDIRECTSOUNDBUFFER
|
||||||
#define FIELD dsound_buffer
|
#define FIELD dsound_buffer
|
||||||
#define FIELD2 dsound
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int glue (dsound_unlock_, TYPE) (
|
static int glue (dsound_unlock_, TYPE) (
|
||||||
@@ -174,16 +170,16 @@ static void dsound_fini_out (HWVoiceOut *hw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DSBTYPE_IN
|
#ifdef DSBTYPE_IN
|
||||||
static int dsound_init_in (HWVoiceIn *hw, struct audsettings *as)
|
static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as)
|
||||||
#else
|
#else
|
||||||
static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
|
static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
dsound *s = &glob_dsound;
|
dsound *s = &glob_dsound;
|
||||||
WAVEFORMATEX wfx;
|
WAVEFORMATEX wfx;
|
||||||
struct audsettings obt_as;
|
audsettings_t obt_as;
|
||||||
#ifdef DSBTYPE_IN
|
#ifdef DSBTYPE_IN
|
||||||
const char *typ = "ADC";
|
const char *typ = "ADC";
|
||||||
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
||||||
@@ -196,11 +192,6 @@ static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
|
|||||||
DSBCAPS bc;
|
DSBCAPS bc;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!s->FIELD2) {
|
|
||||||
dolog ("Attempt to initialize voice without " NAME2 " object\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = waveformat_from_audio_settings (&wfx, as);
|
err = waveformat_from_audio_settings (&wfx, as);
|
||||||
if (err) {
|
if (err) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -285,9 +276,7 @@ static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#undef NAME
|
#undef NAME
|
||||||
#undef NAME2
|
|
||||||
#undef TYPE
|
#undef TYPE
|
||||||
#undef IFACE
|
#undef IFACE
|
||||||
#undef BUFPTR
|
#undef BUFPTR
|
||||||
#undef FIELD
|
#undef FIELD
|
||||||
#undef FIELD2
|
|
||||||
|
|||||||
@@ -26,15 +26,12 @@
|
|||||||
* SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
|
* SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "audio.h"
|
|
||||||
|
|
||||||
#define AUDIO_CAP "dsound"
|
#define AUDIO_CAP "dsound"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <mmsystem.h>
|
|
||||||
#include <objbase.h>
|
#include <objbase.h>
|
||||||
#include <dsound.h>
|
#include <dsound.h>
|
||||||
|
|
||||||
@@ -47,7 +44,7 @@ static struct {
|
|||||||
int set_primary;
|
int set_primary;
|
||||||
int bufsize_in;
|
int bufsize_in;
|
||||||
int bufsize_out;
|
int bufsize_out;
|
||||||
struct audsettings settings;
|
audsettings_t settings;
|
||||||
int latency_millis;
|
int latency_millis;
|
||||||
} conf = {
|
} conf = {
|
||||||
1,
|
1,
|
||||||
@@ -68,7 +65,7 @@ typedef struct {
|
|||||||
LPDIRECTSOUND dsound;
|
LPDIRECTSOUND dsound;
|
||||||
LPDIRECTSOUNDCAPTURE dsound_capture;
|
LPDIRECTSOUNDCAPTURE dsound_capture;
|
||||||
LPDIRECTSOUNDBUFFER dsound_primary_buffer;
|
LPDIRECTSOUNDBUFFER dsound_primary_buffer;
|
||||||
struct audsettings settings;
|
audsettings_t settings;
|
||||||
} dsound;
|
} dsound;
|
||||||
|
|
||||||
static dsound glob_dsound;
|
static dsound glob_dsound;
|
||||||
@@ -307,8 +304,7 @@ static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
|
static int waveformat_from_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as)
|
||||||
struct audsettings *as)
|
|
||||||
{
|
{
|
||||||
memset (wfx, 0, sizeof (*wfx));
|
memset (wfx, 0, sizeof (*wfx));
|
||||||
|
|
||||||
@@ -321,22 +317,23 @@ static int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
|
|||||||
|
|
||||||
switch (as->fmt) {
|
switch (as->fmt) {
|
||||||
case AUD_FMT_S8:
|
case AUD_FMT_S8:
|
||||||
|
wfx->wBitsPerSample = 8;
|
||||||
|
break;
|
||||||
|
|
||||||
case AUD_FMT_U8:
|
case AUD_FMT_U8:
|
||||||
wfx->wBitsPerSample = 8;
|
wfx->wBitsPerSample = 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUD_FMT_S16:
|
case AUD_FMT_S16:
|
||||||
case AUD_FMT_U16:
|
|
||||||
wfx->wBitsPerSample = 16;
|
wfx->wBitsPerSample = 16;
|
||||||
wfx->nAvgBytesPerSec <<= 1;
|
wfx->nAvgBytesPerSec <<= 1;
|
||||||
wfx->nBlockAlign <<= 1;
|
wfx->nBlockAlign <<= 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUD_FMT_S32:
|
case AUD_FMT_U16:
|
||||||
case AUD_FMT_U32:
|
wfx->wBitsPerSample = 16;
|
||||||
wfx->wBitsPerSample = 32;
|
wfx->nAvgBytesPerSec <<= 1;
|
||||||
wfx->nAvgBytesPerSec <<= 2;
|
wfx->nBlockAlign <<= 1;
|
||||||
wfx->nBlockAlign <<= 2;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -347,8 +344,7 @@ static int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
|
static int waveformat_to_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as)
|
||||||
struct audsettings *as)
|
|
||||||
{
|
{
|
||||||
if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
|
if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
|
||||||
dolog ("Invalid wave format, tag is not PCM, but %d\n",
|
dolog ("Invalid wave format, tag is not PCM, but %d\n",
|
||||||
@@ -388,13 +384,8 @@ static int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
|
|||||||
as->fmt = AUD_FMT_S16;
|
as->fmt = AUD_FMT_S16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 32:
|
|
||||||
as->fmt = AUD_FMT_S32;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dolog ("Invalid wave format, bits per sample is not "
|
dolog ("Invalid wave format, bits per sample is not 8 or 16, but %d\n",
|
||||||
"8, 16 or 32, but %d\n",
|
|
||||||
wfx->wBitsPerSample);
|
wfx->wBitsPerSample);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -450,8 +441,8 @@ static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
|
|||||||
int src_len1 = dst_len;
|
int src_len1 = dst_len;
|
||||||
int src_len2 = 0;
|
int src_len2 = 0;
|
||||||
int pos = hw->rpos + dst_len;
|
int pos = hw->rpos + dst_len;
|
||||||
struct st_sample *src1 = hw->mix_buf + hw->rpos;
|
st_sample_t *src1 = hw->mix_buf + hw->rpos;
|
||||||
struct st_sample *src2 = NULL;
|
st_sample_t *src2 = NULL;
|
||||||
|
|
||||||
if (pos > hw->samples) {
|
if (pos > hw->samples) {
|
||||||
src_len1 = hw->samples - hw->rpos;
|
src_len1 = hw->samples - hw->rpos;
|
||||||
|
|||||||
596
audio/esdaudio.c
596
audio/esdaudio.c
@@ -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)
|
|
||||||
};
|
|
||||||
@@ -23,8 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <fmod.h>
|
#include <fmod.h>
|
||||||
#include <fmod_errors.h>
|
#include <fmod_errors.h>
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "audio.h"
|
|
||||||
|
|
||||||
#define AUDIO_CAP "fmod"
|
#define AUDIO_CAP "fmod"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
@@ -142,8 +141,8 @@ static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
|
|||||||
int src_len1 = dst_len;
|
int src_len1 = dst_len;
|
||||||
int src_len2 = 0;
|
int src_len2 = 0;
|
||||||
int pos = hw->rpos + dst_len;
|
int pos = hw->rpos + dst_len;
|
||||||
struct st_sample *src1 = hw->mix_buf + hw->rpos;
|
st_sample_t *src1 = hw->mix_buf + hw->rpos;
|
||||||
struct st_sample *src2 = NULL;
|
st_sample_t *src2 = NULL;
|
||||||
|
|
||||||
if (pos > hw->samples) {
|
if (pos > hw->samples) {
|
||||||
src_len1 = hw->samples - hw->rpos;
|
src_len1 = hw->samples - hw->rpos;
|
||||||
@@ -355,11 +354,11 @@ static void fmod_fini_out (HWVoiceOut *hw)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
|
static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||||
{
|
{
|
||||||
int bits16, mode, channel;
|
int bits16, mode, channel;
|
||||||
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
|
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
|
||||||
struct audsettings obt_as = *as;
|
audsettings_t obt_as = *as;
|
||||||
|
|
||||||
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
|
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
|
||||||
fmd->fmod_sample = FSOUND_Sample_Alloc (
|
fmd->fmod_sample = FSOUND_Sample_Alloc (
|
||||||
@@ -417,11 +416,11 @@ static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
|
static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as)
|
||||||
{
|
{
|
||||||
int bits16, mode;
|
int bits16, mode;
|
||||||
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
|
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
|
||||||
struct audsettings obt_as = *as;
|
audsettings_t obt_as = *as;
|
||||||
|
|
||||||
if (conf.broken_adc) {
|
if (conf.broken_adc) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -564,7 +563,7 @@ static void *fmod_audio_init (void)
|
|||||||
|
|
||||||
if (drv) {
|
if (drv) {
|
||||||
int found = 0;
|
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)) {
|
if (!strcmp (drv, drvtab[i].name)) {
|
||||||
output_type = drvtab[i].type;
|
output_type = drvtab[i].type;
|
||||||
found = 1;
|
found = 1;
|
||||||
@@ -574,7 +573,7 @@ static void *fmod_audio_init (void)
|
|||||||
if (!found) {
|
if (!found) {
|
||||||
dolog ("Unknown FMOD driver `%s'\n", drv);
|
dolog ("Unknown FMOD driver `%s'\n", drv);
|
||||||
dolog ("Valid drivers:\n");
|
dolog ("Valid drivers:\n");
|
||||||
for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
|
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
|
||||||
dolog (" %s\n", drvtab[i].name);
|
dolog (" %s\n", drvtab[i].name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
106
audio/mixeng.c
106
audio/mixeng.c
@@ -22,12 +22,13 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "audio.h"
|
|
||||||
|
|
||||||
#define AUDIO_CAP "mixeng"
|
#define AUDIO_CAP "mixeng"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
|
|
||||||
|
#define NOVOL
|
||||||
|
|
||||||
/* 8 bit */
|
/* 8 bit */
|
||||||
#define ENDIAN_CONVERSION natural
|
#define ENDIAN_CONVERSION natural
|
||||||
#define ENDIAN_CONVERT(v) (v)
|
#define ENDIAN_CONVERT(v) (v)
|
||||||
@@ -81,7 +82,6 @@
|
|||||||
#undef IN_T
|
#undef IN_T
|
||||||
#undef SHIFT
|
#undef SHIFT
|
||||||
|
|
||||||
/* Unsigned 16 bit */
|
|
||||||
#define IN_T uint16_t
|
#define IN_T uint16_t
|
||||||
#define IN_MIN 0
|
#define IN_MIN 0
|
||||||
#define IN_MAX USHRT_MAX
|
#define IN_MAX USHRT_MAX
|
||||||
@@ -101,72 +101,26 @@
|
|||||||
#undef IN_T
|
#undef IN_T
|
||||||
#undef SHIFT
|
#undef SHIFT
|
||||||
|
|
||||||
/* Signed 32 bit */
|
t_sample *mixeng_conv[2][2][2][2] = {
|
||||||
#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] = {
|
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
conv_natural_uint8_t_to_mono,
|
conv_natural_uint8_t_to_mono,
|
||||||
conv_natural_uint16_t_to_mono,
|
conv_natural_uint16_t_to_mono
|
||||||
conv_natural_uint32_t_to_mono
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
conv_natural_uint8_t_to_mono,
|
conv_natural_uint8_t_to_mono,
|
||||||
conv_swap_uint16_t_to_mono,
|
conv_swap_uint16_t_to_mono
|
||||||
conv_swap_uint32_t_to_mono,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
conv_natural_int8_t_to_mono,
|
conv_natural_int8_t_to_mono,
|
||||||
conv_natural_int16_t_to_mono,
|
conv_natural_int16_t_to_mono
|
||||||
conv_natural_int32_t_to_mono
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
conv_natural_int8_t_to_mono,
|
conv_natural_int8_t_to_mono,
|
||||||
conv_swap_int16_t_to_mono,
|
conv_swap_int16_t_to_mono
|
||||||
conv_swap_int32_t_to_mono
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -174,54 +128,46 @@ t_sample *mixeng_conv[2][2][2][3] = {
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
conv_natural_uint8_t_to_stereo,
|
conv_natural_uint8_t_to_stereo,
|
||||||
conv_natural_uint16_t_to_stereo,
|
conv_natural_uint16_t_to_stereo
|
||||||
conv_natural_uint32_t_to_stereo
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
conv_natural_uint8_t_to_stereo,
|
conv_natural_uint8_t_to_stereo,
|
||||||
conv_swap_uint16_t_to_stereo,
|
conv_swap_uint16_t_to_stereo
|
||||||
conv_swap_uint32_t_to_stereo
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
conv_natural_int8_t_to_stereo,
|
conv_natural_int8_t_to_stereo,
|
||||||
conv_natural_int16_t_to_stereo,
|
conv_natural_int16_t_to_stereo
|
||||||
conv_natural_int32_t_to_stereo
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
conv_natural_int8_t_to_stereo,
|
conv_natural_int8_t_to_stereo,
|
||||||
conv_swap_int16_t_to_stereo,
|
conv_swap_int16_t_to_stereo
|
||||||
conv_swap_int32_t_to_stereo,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
f_sample *mixeng_clip[2][2][2][3] = {
|
f_sample *mixeng_clip[2][2][2][2] = {
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
clip_natural_uint8_t_from_mono,
|
clip_natural_uint8_t_from_mono,
|
||||||
clip_natural_uint16_t_from_mono,
|
clip_natural_uint16_t_from_mono
|
||||||
clip_natural_uint32_t_from_mono
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
clip_natural_uint8_t_from_mono,
|
clip_natural_uint8_t_from_mono,
|
||||||
clip_swap_uint16_t_from_mono,
|
clip_swap_uint16_t_from_mono
|
||||||
clip_swap_uint32_t_from_mono
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
clip_natural_int8_t_from_mono,
|
clip_natural_int8_t_from_mono,
|
||||||
clip_natural_int16_t_from_mono,
|
clip_natural_int16_t_from_mono
|
||||||
clip_natural_int32_t_from_mono
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
clip_natural_int8_t_from_mono,
|
clip_natural_int8_t_from_mono,
|
||||||
clip_swap_int16_t_from_mono,
|
clip_swap_int16_t_from_mono
|
||||||
clip_swap_int32_t_from_mono
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -229,25 +175,21 @@ f_sample *mixeng_clip[2][2][2][3] = {
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
clip_natural_uint8_t_from_stereo,
|
clip_natural_uint8_t_from_stereo,
|
||||||
clip_natural_uint16_t_from_stereo,
|
clip_natural_uint16_t_from_stereo
|
||||||
clip_natural_uint32_t_from_stereo
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
clip_natural_uint8_t_from_stereo,
|
clip_natural_uint8_t_from_stereo,
|
||||||
clip_swap_uint16_t_from_stereo,
|
clip_swap_uint16_t_from_stereo
|
||||||
clip_swap_uint32_t_from_stereo
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
clip_natural_int8_t_from_stereo,
|
clip_natural_int8_t_from_stereo,
|
||||||
clip_natural_int16_t_from_stereo,
|
clip_natural_int16_t_from_stereo
|
||||||
clip_natural_int32_t_from_stereo
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
clip_natural_int8_t_from_stereo,
|
clip_natural_int8_t_from_stereo,
|
||||||
clip_swap_int16_t_from_stereo,
|
clip_swap_int16_t_from_stereo
|
||||||
clip_swap_int32_t_from_stereo
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,7 +232,7 @@ struct rate {
|
|||||||
uint64_t opos;
|
uint64_t opos;
|
||||||
uint64_t opos_inc;
|
uint64_t opos_inc;
|
||||||
uint32_t ipos; /* position in the input stream (integer) */
|
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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -329,7 +271,7 @@ void st_rate_stop (void *opaque)
|
|||||||
qemu_free (opaque);
|
qemu_free (opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mixeng_clear (struct st_sample *buf, int len)
|
void mixeng_clear (st_sample_t *buf, int len)
|
||||||
{
|
{
|
||||||
memset (buf, 0, len * sizeof (struct st_sample));
|
memset (buf, 0, len * sizeof (st_sample_t));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,27 +25,27 @@
|
|||||||
#define QEMU_MIXENG_H
|
#define QEMU_MIXENG_H
|
||||||
|
|
||||||
#ifdef FLOAT_MIXENG
|
#ifdef FLOAT_MIXENG
|
||||||
typedef float mixeng_real;
|
typedef float real_t;
|
||||||
struct mixeng_volume { int mute; mixeng_real r; mixeng_real l; };
|
typedef struct { int mute; real_t r; real_t l; } volume_t;
|
||||||
struct mixeng_sample { mixeng_real l; mixeng_real r; };
|
typedef struct { real_t l; real_t r; } st_sample_t;
|
||||||
#else
|
#else
|
||||||
struct mixeng_volume { int mute; int64_t r; int64_t l; };
|
typedef struct { int mute; int64_t r; int64_t l; } volume_t;
|
||||||
struct st_sample { int64_t l; int64_t r; };
|
typedef struct { int64_t l; int64_t r; } st_sample_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef void (t_sample) (struct st_sample *dst, const void *src,
|
typedef void (t_sample) (st_sample_t *dst, const void *src,
|
||||||
int samples, struct mixeng_volume *vol);
|
int samples, volume_t *vol);
|
||||||
typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
|
typedef void (f_sample) (void *dst, const st_sample_t *src, int samples);
|
||||||
|
|
||||||
extern t_sample *mixeng_conv[2][2][2][3];
|
extern t_sample *mixeng_conv[2][2][2][2];
|
||||||
extern f_sample *mixeng_clip[2][2][2][3];
|
extern f_sample *mixeng_clip[2][2][2][2];
|
||||||
|
|
||||||
void *st_rate_start (int inrate, int outrate);
|
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);
|
int *isamp, int *osamp);
|
||||||
void st_rate_flow_mix (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
void st_rate_flow_mix (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
|
||||||
int *isamp, int *osamp);
|
int *isamp, int *osamp);
|
||||||
void st_rate_stop (void *opaque);
|
void st_rate_stop (void *opaque);
|
||||||
void mixeng_clear (struct st_sample *buf, int len);
|
void mixeng_clear (st_sample_t *buf, int len);
|
||||||
|
|
||||||
#endif /* mixeng.h */
|
#endif /* mixeng.h */
|
||||||
|
|||||||
@@ -31,39 +31,39 @@
|
|||||||
#define HALF (IN_MAX >> 1)
|
#define HALF (IN_MAX >> 1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_MIXEMU
|
#ifdef NOVOL
|
||||||
|
#define VOL(a, b) a
|
||||||
|
#else
|
||||||
#ifdef FLOAT_MIXENG
|
#ifdef FLOAT_MIXENG
|
||||||
#define VOL(a, b) ((a) * (b))
|
#define VOL(a, b) ((a) * (b))
|
||||||
#else
|
#else
|
||||||
#define VOL(a, b) ((a) * (b)) >> 32
|
#define VOL(a, b) ((a) * (b)) >> 32
|
||||||
#endif
|
#endif
|
||||||
#else
|
|
||||||
#define VOL(a, b) a
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
|
#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
|
||||||
|
|
||||||
#ifdef FLOAT_MIXENG
|
#ifdef FLOAT_MIXENG
|
||||||
static mixeng_real inline glue (conv_, ET) (IN_T v)
|
static real_t inline glue (conv_, ET) (IN_T v)
|
||||||
{
|
{
|
||||||
IN_T nv = ENDIAN_CONVERT (v);
|
IN_T nv = ENDIAN_CONVERT (v);
|
||||||
|
|
||||||
#ifdef RECIPROCAL
|
#ifdef RECIPROCAL
|
||||||
#ifdef SIGNED
|
#ifdef SIGNED
|
||||||
return nv * (1.f / (mixeng_real) (IN_MAX - IN_MIN));
|
return nv * (1.f / (real_t) (IN_MAX - IN_MIN));
|
||||||
#else
|
#else
|
||||||
return (nv - HALF) * (1.f / (mixeng_real) IN_MAX);
|
return (nv - HALF) * (1.f / (real_t) IN_MAX);
|
||||||
#endif
|
#endif
|
||||||
#else /* !RECIPROCAL */
|
#else /* !RECIPROCAL */
|
||||||
#ifdef SIGNED
|
#ifdef SIGNED
|
||||||
return nv / (mixeng_real) (IN_MAX - IN_MIN);
|
return nv / (real_t) (IN_MAX - IN_MIN);
|
||||||
#else
|
#else
|
||||||
return (nv - HALF) / (mixeng_real) IN_MAX;
|
return (nv - HALF) / (real_t) IN_MAX;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static IN_T inline glue (clip_, ET) (mixeng_real v)
|
static IN_T inline glue (clip_, ET) (real_t v)
|
||||||
{
|
{
|
||||||
if (v >= 0.5) {
|
if (v >= 0.5) {
|
||||||
return IN_MAX;
|
return IN_MAX;
|
||||||
@@ -109,11 +109,11 @@ static inline IN_T glue (clip_, ET) (int64_t v)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void glue (glue (conv_, ET), _to_stereo)
|
static void glue (glue (conv_, ET), _to_stereo)
|
||||||
(struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
|
(st_sample_t *dst, const void *src, int samples, volume_t *vol)
|
||||||
{
|
{
|
||||||
struct st_sample *out = dst;
|
st_sample_t *out = dst;
|
||||||
IN_T *in = (IN_T *) src;
|
IN_T *in = (IN_T *) src;
|
||||||
#ifdef CONFIG_MIXEMU
|
#ifndef NOVOL
|
||||||
if (vol->mute) {
|
if (vol->mute) {
|
||||||
mixeng_clear (dst, samples);
|
mixeng_clear (dst, samples);
|
||||||
return;
|
return;
|
||||||
@@ -129,11 +129,11 @@ static void glue (glue (conv_, ET), _to_stereo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void glue (glue (conv_, ET), _to_mono)
|
static void glue (glue (conv_, ET), _to_mono)
|
||||||
(struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
|
(st_sample_t *dst, const void *src, int samples, volume_t *vol)
|
||||||
{
|
{
|
||||||
struct st_sample *out = dst;
|
st_sample_t *out = dst;
|
||||||
IN_T *in = (IN_T *) src;
|
IN_T *in = (IN_T *) src;
|
||||||
#ifdef CONFIG_MIXEMU
|
#ifndef NOVOL
|
||||||
if (vol->mute) {
|
if (vol->mute) {
|
||||||
mixeng_clear (dst, samples);
|
mixeng_clear (dst, samples);
|
||||||
return;
|
return;
|
||||||
@@ -150,9 +150,9 @@ static void glue (glue (conv_, ET), _to_mono)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void glue (glue (clip_, ET), _from_stereo)
|
static void glue (glue (clip_, ET), _from_stereo)
|
||||||
(void *dst, const struct st_sample *src, int samples)
|
(void *dst, const st_sample_t *src, int samples)
|
||||||
{
|
{
|
||||||
const struct st_sample *in = src;
|
const st_sample_t *in = src;
|
||||||
IN_T *out = (IN_T *) dst;
|
IN_T *out = (IN_T *) dst;
|
||||||
while (samples--) {
|
while (samples--) {
|
||||||
*out++ = glue (clip_, ET) (in->l);
|
*out++ = glue (clip_, ET) (in->l);
|
||||||
@@ -162,9 +162,9 @@ static void glue (glue (clip_, ET), _from_stereo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void glue (glue (clip_, ET), _from_mono)
|
static void glue (glue (clip_, ET), _from_mono)
|
||||||
(void *dst, const struct st_sample *src, int samples)
|
(void *dst, const st_sample_t *src, int samples)
|
||||||
{
|
{
|
||||||
const struct st_sample *in = src;
|
const st_sample_t *in = src;
|
||||||
IN_T *out = (IN_T *) dst;
|
IN_T *out = (IN_T *) dst;
|
||||||
while (samples--) {
|
while (samples--) {
|
||||||
*out++ = glue (clip_, ET) (in->l + in->r);
|
*out++ = glue (clip_, ET) (in->l + in->r);
|
||||||
|
|||||||
@@ -21,9 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "audio.h"
|
|
||||||
#include "qemu-timer.h"
|
|
||||||
|
|
||||||
#define AUDIO_CAP "noaudio"
|
#define AUDIO_CAP "noaudio"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
@@ -68,7 +66,7 @@ static int no_write (SWVoiceOut *sw, void *buf, int len)
|
|||||||
return audio_pcm_sw_write (sw, buf, len);
|
return audio_pcm_sw_write (sw, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int no_init_out (HWVoiceOut *hw, struct audsettings *as)
|
static int no_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||||
{
|
{
|
||||||
audio_pcm_init_info (&hw->info, as);
|
audio_pcm_init_info (&hw->info, as);
|
||||||
hw->samples = 1024;
|
hw->samples = 1024;
|
||||||
@@ -87,7 +85,7 @@ static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int no_init_in (HWVoiceIn *hw, struct audsettings *as)
|
static int no_init_in (HWVoiceIn *hw, audsettings_t *as)
|
||||||
{
|
{
|
||||||
audio_pcm_init_info (&hw->info, as);
|
audio_pcm_init_info (&hw->info, as);
|
||||||
hw->samples = 1024;
|
hw->samples = 1024;
|
||||||
|
|||||||
@@ -21,17 +21,11 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#ifdef __OpenBSD__
|
|
||||||
#include <soundcard.h>
|
|
||||||
#else
|
|
||||||
#include <sys/soundcard.h>
|
#include <sys/soundcard.h>
|
||||||
#endif
|
#include "vl.h"
|
||||||
#include "qemu-common.h"
|
|
||||||
#include "audio.h"
|
|
||||||
|
|
||||||
#define AUDIO_CAP "oss"
|
#define AUDIO_CAP "oss"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
@@ -237,7 +231,7 @@ static int oss_open (int in, struct oss_params *req,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
|
if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
|
||||||
oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
|
oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@@ -254,12 +248,6 @@ static int oss_open (int in, struct oss_params *req,
|
|||||||
goto err;
|
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);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
obt->fmt = fmt;
|
obt->fmt = fmt;
|
||||||
obt->nchannels = nchannels;
|
obt->nchannels = nchannels;
|
||||||
obt->freq = freq;
|
obt->freq = freq;
|
||||||
@@ -294,7 +282,7 @@ static int oss_run_out (HWVoiceOut *hw)
|
|||||||
int err, rpos, live, decr;
|
int err, rpos, live, decr;
|
||||||
int samples;
|
int samples;
|
||||||
uint8_t *dst;
|
uint8_t *dst;
|
||||||
struct st_sample *src;
|
st_sample_t *src;
|
||||||
struct audio_buf_info abinfo;
|
struct audio_buf_info abinfo;
|
||||||
struct count_info cntinfo;
|
struct count_info cntinfo;
|
||||||
int bufsize;
|
int bufsize;
|
||||||
@@ -434,7 +422,7 @@ static void oss_fini_out (HWVoiceOut *hw)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
|
static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||||
{
|
{
|
||||||
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
|
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
|
||||||
struct oss_params req, obt;
|
struct oss_params req, obt;
|
||||||
@@ -442,7 +430,7 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
|
|||||||
int err;
|
int err;
|
||||||
int fd;
|
int fd;
|
||||||
audfmt_e effective_fmt;
|
audfmt_e effective_fmt;
|
||||||
struct audsettings obt_as;
|
audsettings_t obt_as;
|
||||||
|
|
||||||
oss->fd = -1;
|
oss->fd = -1;
|
||||||
|
|
||||||
@@ -576,7 +564,7 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
|
static int oss_init_in (HWVoiceIn *hw, audsettings_t *as)
|
||||||
{
|
{
|
||||||
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
|
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
|
||||||
struct oss_params req, obt;
|
struct oss_params req, obt;
|
||||||
@@ -584,7 +572,7 @@ static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
|
|||||||
int err;
|
int err;
|
||||||
int fd;
|
int fd;
|
||||||
audfmt_e effective_fmt;
|
audfmt_e effective_fmt;
|
||||||
struct audsettings obt_as;
|
audsettings_t obt_as;
|
||||||
|
|
||||||
oss->fd = -1;
|
oss->fd = -1;
|
||||||
|
|
||||||
|
|||||||
515
audio/paaudio.c
515
audio/paaudio.c
@@ -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:
|
|
||||||
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:
|
|
||||||
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)
|
|
||||||
};
|
|
||||||
@@ -27,15 +27,15 @@
|
|||||||
* Processed signed long samples from ibuf to obuf.
|
* Processed signed long samples from ibuf to obuf.
|
||||||
* Return number of samples processed.
|
* Return number of samples processed.
|
||||||
*/
|
*/
|
||||||
void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
|
||||||
int *isamp, int *osamp)
|
int *isamp, int *osamp)
|
||||||
{
|
{
|
||||||
struct rate *rate = opaque;
|
struct rate *rate = opaque;
|
||||||
struct st_sample *istart, *iend;
|
st_sample_t *istart, *iend;
|
||||||
struct st_sample *ostart, *oend;
|
st_sample_t *ostart, *oend;
|
||||||
struct st_sample ilast, icur, out;
|
st_sample_t ilast, icur, out;
|
||||||
#ifdef FLOAT_MIXENG
|
#ifdef FLOAT_MIXENG
|
||||||
mixeng_real t;
|
real_t t;
|
||||||
#else
|
#else
|
||||||
int64_t t;
|
int64_t t;
|
||||||
#endif
|
#endif
|
||||||
@@ -84,7 +84,7 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
|||||||
#ifdef RECIPROCAL
|
#ifdef RECIPROCAL
|
||||||
t = (rate->opos & UINT_MAX) * (1.f / UINT_MAX);
|
t = (rate->opos & UINT_MAX) * (1.f / UINT_MAX);
|
||||||
#else
|
#else
|
||||||
t = (rate->opos & UINT_MAX) / (mixeng_real) UINT_MAX;
|
t = (rate->opos & UINT_MAX) / (real_t) UINT_MAX;
|
||||||
#endif
|
#endif
|
||||||
out.l = (ilast.l * (1.0 - t)) + icur.l * t;
|
out.l = (ilast.l * (1.0 - t)) + icur.l * t;
|
||||||
out.r = (ilast.r * (1.0 - t)) + icur.r * t;
|
out.r = (ilast.r * (1.0 - t)) + icur.r * t;
|
||||||
|
|||||||
@@ -23,17 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <SDL_thread.h>
|
#include <SDL_thread.h>
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "audio.h"
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#ifdef __sun__
|
|
||||||
#define _POSIX_PTHREAD_SEMANTICS 1
|
|
||||||
#elif defined(__OpenBSD__) || defined(__FreeBSD__)
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
#include <signal.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define AUDIO_CAP "sdl"
|
#define AUDIO_CAP "sdl"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
@@ -51,7 +41,7 @@ static struct {
|
|||||||
1024
|
1024
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct SDLAudioState {
|
struct SDLAudioState {
|
||||||
int exit;
|
int exit;
|
||||||
SDL_mutex *mutex;
|
SDL_mutex *mutex;
|
||||||
SDL_sem *sem;
|
SDL_sem *sem;
|
||||||
@@ -187,22 +177,11 @@ static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
|
|||||||
static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
|
static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
|
||||||
{
|
{
|
||||||
int status;
|
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);
|
status = SDL_OpenAudio (req, obt);
|
||||||
if (status) {
|
if (status) {
|
||||||
sdl_logerr ("SDL_OpenAudio failed\n");
|
sdl_logerr ("SDL_OpenAudio failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
pthread_sigmask (SIG_SETMASK, &old, 0);
|
|
||||||
#endif
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +236,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
|||||||
decr = to_mix;
|
decr = to_mix;
|
||||||
while (to_mix) {
|
while (to_mix) {
|
||||||
int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
|
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); */
|
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
|
||||||
hw->clip (buf, src, chunk);
|
hw->clip (buf, src, chunk);
|
||||||
@@ -323,7 +302,7 @@ static void sdl_fini_out (HWVoiceOut *hw)
|
|||||||
sdl_close (&glob_sdl);
|
sdl_close (&glob_sdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
|
static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||||
{
|
{
|
||||||
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
|
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
|
||||||
SDLAudioState *s = &glob_sdl;
|
SDLAudioState *s = &glob_sdl;
|
||||||
@@ -332,7 +311,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
|
|||||||
int endianess;
|
int endianess;
|
||||||
int err;
|
int err;
|
||||||
audfmt_e effective_fmt;
|
audfmt_e effective_fmt;
|
||||||
struct audsettings obt_as;
|
audsettings_t obt_as;
|
||||||
|
|
||||||
shift <<= as->nchannels == 2;
|
shift <<= as->nchannels == 2;
|
||||||
|
|
||||||
|
|||||||
241
audio/sys-queue.h
Normal file
241
audio/sys-queue.h
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1991, 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.
|
||||||
|
*
|
||||||
|
* @(#)queue.h 8.3 (Berkeley) 12/13/93
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_QUEUE_H
|
||||||
|
#define _SYS_QUEUE_H 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file defines three types of data structures: lists, tail queues,
|
||||||
|
* and circular queues.
|
||||||
|
*
|
||||||
|
* A list is headed by a single forward pointer (or an array of forward
|
||||||
|
* pointers for a hash table header). The elements are doubly linked
|
||||||
|
* so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list after
|
||||||
|
* an existing element or at the head of the list. A list may only be
|
||||||
|
* traversed in the forward direction.
|
||||||
|
*
|
||||||
|
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||||
|
* list and the other to the tail of the list. The elements are doubly
|
||||||
|
* linked so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list after
|
||||||
|
* an existing element, at the head of the list, or at the end of the
|
||||||
|
* list. A tail queue may only be traversed in the forward direction.
|
||||||
|
*
|
||||||
|
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||||
|
* list and the other to the tail of the list. The elements are doubly
|
||||||
|
* linked so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list before or after
|
||||||
|
* an existing element, at the head of the list, or at the end of the list.
|
||||||
|
* A circle queue may be traversed in either direction, but has a more
|
||||||
|
* complex end of list detection.
|
||||||
|
*
|
||||||
|
* For details on the use of these macros, see the queue(3) manual page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List definitions.
|
||||||
|
*/
|
||||||
|
#define LIST_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *lh_first; /* first element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIST_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *le_next; /* next element */ \
|
||||||
|
struct type **le_prev; /* address of previous next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List functions.
|
||||||
|
*/
|
||||||
|
#define LIST_INIT(head) { \
|
||||||
|
(head)->lh_first = NULL; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIST_INSERT_AFTER(listelm, elm, field) { \
|
||||||
|
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||||
|
(listelm)->field.le_next->field.le_prev = \
|
||||||
|
&(elm)->field.le_next; \
|
||||||
|
(listelm)->field.le_next = (elm); \
|
||||||
|
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIST_INSERT_HEAD(head, elm, field) { \
|
||||||
|
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||||
|
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||||
|
(head)->lh_first = (elm); \
|
||||||
|
(elm)->field.le_prev = &(head)->lh_first; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIST_REMOVE(elm, field) { \
|
||||||
|
if ((elm)->field.le_next != NULL) \
|
||||||
|
(elm)->field.le_next->field.le_prev = \
|
||||||
|
(elm)->field.le_prev; \
|
||||||
|
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tail queue definitions.
|
||||||
|
*/
|
||||||
|
#define TAILQ_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *tqh_first; /* first element */ \
|
||||||
|
struct type **tqh_last; /* addr of last next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TAILQ_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *tqe_next; /* next element */ \
|
||||||
|
struct type **tqe_prev; /* address of previous next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tail queue functions.
|
||||||
|
*/
|
||||||
|
#define TAILQ_INIT(head) { \
|
||||||
|
(head)->tqh_first = NULL; \
|
||||||
|
(head)->tqh_last = &(head)->tqh_first; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_HEAD(head, elm, field) { \
|
||||||
|
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||||
|
(elm)->field.tqe_next->field.tqe_prev = \
|
||||||
|
&(elm)->field.tqe_next; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
(head)->tqh_first = (elm); \
|
||||||
|
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_TAIL(head, elm, field) { \
|
||||||
|
(elm)->field.tqe_next = NULL; \
|
||||||
|
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||||
|
*(head)->tqh_last = (elm); \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) { \
|
||||||
|
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||||
|
(elm)->field.tqe_next->field.tqe_prev = \
|
||||||
|
&(elm)->field.tqe_next; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
(listelm)->field.tqe_next = (elm); \
|
||||||
|
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TAILQ_REMOVE(head, elm, field) { \
|
||||||
|
if (((elm)->field.tqe_next) != NULL) \
|
||||||
|
(elm)->field.tqe_next->field.tqe_prev = \
|
||||||
|
(elm)->field.tqe_prev; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||||
|
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Circular queue definitions.
|
||||||
|
*/
|
||||||
|
#define CIRCLEQ_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *cqh_first; /* first element */ \
|
||||||
|
struct type *cqh_last; /* last element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CIRCLEQ_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *cqe_next; /* next element */ \
|
||||||
|
struct type *cqe_prev; /* previous element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Circular queue functions.
|
||||||
|
*/
|
||||||
|
#define CIRCLEQ_INIT(head) { \
|
||||||
|
(head)->cqh_first = (void *)(head); \
|
||||||
|
(head)->cqh_last = (void *)(head); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) { \
|
||||||
|
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||||
|
(elm)->field.cqe_prev = (listelm); \
|
||||||
|
if ((listelm)->field.cqe_next == (void *)(head)) \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
else \
|
||||||
|
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||||
|
(listelm)->field.cqe_next = (elm); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) { \
|
||||||
|
(elm)->field.cqe_next = (listelm); \
|
||||||
|
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||||
|
if ((listelm)->field.cqe_prev == (void *)(head)) \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
else \
|
||||||
|
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||||
|
(listelm)->field.cqe_prev = (elm); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_HEAD(head, elm, field) { \
|
||||||
|
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||||
|
(elm)->field.cqe_prev = (void *)(head); \
|
||||||
|
if ((head)->cqh_last == (void *)(head)) \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
else \
|
||||||
|
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_TAIL(head, elm, field) { \
|
||||||
|
(elm)->field.cqe_next = (void *)(head); \
|
||||||
|
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||||
|
if ((head)->cqh_first == (void *)(head)) \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
else \
|
||||||
|
(head)->cqh_last->field.cqe_next = (elm); \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CIRCLEQ_REMOVE(head, elm, field) { \
|
||||||
|
if ((elm)->field.cqe_next == (void *)(head)) \
|
||||||
|
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||||
|
else \
|
||||||
|
(elm)->field.cqe_next->field.cqe_prev = \
|
||||||
|
(elm)->field.cqe_prev; \
|
||||||
|
if ((elm)->field.cqe_prev == (void *)(head)) \
|
||||||
|
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||||
|
else \
|
||||||
|
(elm)->field.cqe_prev->field.cqe_next = \
|
||||||
|
(elm)->field.cqe_next; \
|
||||||
|
}
|
||||||
|
#endif /* sys/queue.h */
|
||||||
@@ -21,9 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "hw/hw.h"
|
#include "vl.h"
|
||||||
#include "qemu-timer.h"
|
|
||||||
#include "audio.h"
|
|
||||||
|
|
||||||
#define AUDIO_CAP "wav"
|
#define AUDIO_CAP "wav"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
@@ -37,14 +35,13 @@ typedef struct WAVVoiceOut {
|
|||||||
} WAVVoiceOut;
|
} WAVVoiceOut;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
struct audsettings settings;
|
audsettings_t settings;
|
||||||
const char *wav_path;
|
const char *wav_path;
|
||||||
} conf = {
|
} conf = {
|
||||||
{
|
{
|
||||||
44100,
|
44100,
|
||||||
2,
|
2,
|
||||||
AUD_FMT_S16,
|
AUD_FMT_S16
|
||||||
0
|
|
||||||
},
|
},
|
||||||
"qemu.wav"
|
"qemu.wav"
|
||||||
};
|
};
|
||||||
@@ -54,7 +51,7 @@ static int wav_run_out (HWVoiceOut *hw)
|
|||||||
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
|
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
|
||||||
int rpos, live, decr, samples;
|
int rpos, live, decr, samples;
|
||||||
uint8_t *dst;
|
uint8_t *dst;
|
||||||
struct st_sample *src;
|
st_sample_t *src;
|
||||||
int64_t now = qemu_get_clock (vm_clock);
|
int64_t now = qemu_get_clock (vm_clock);
|
||||||
int64_t ticks = now - wav->old_ticks;
|
int64_t ticks = now - wav->old_ticks;
|
||||||
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
|
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
|
||||||
@@ -109,7 +106,7 @@ 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_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||||
{
|
{
|
||||||
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
|
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
|
||||||
int bits16 = 0, stereo = 0;
|
int bits16 = 0, stereo = 0;
|
||||||
@@ -119,7 +116,7 @@ static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
|
|||||||
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
|
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
|
||||||
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
|
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
struct audsettings wav_as = conf.settings;
|
audsettings_t wav_as = conf.settings;
|
||||||
|
|
||||||
(void) as;
|
(void) as;
|
||||||
|
|
||||||
@@ -134,11 +131,6 @@ static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
|
|||||||
case AUD_FMT_U16:
|
case AUD_FMT_U16:
|
||||||
bits16 = 1;
|
bits16 = 1;
|
||||||
break;
|
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;
|
hdr[34] = bits16 ? 0x10 : 0x08;
|
||||||
@@ -159,7 +151,7 @@ static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
|
|||||||
le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
|
le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
|
||||||
le_store (hdr + 32, 1 << (bits16 + stereo), 2);
|
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) {
|
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));
|
conf.wav_path, strerror (errno));
|
||||||
@@ -193,7 +185,7 @@ static void wav_fini_out (HWVoiceOut *hw)
|
|||||||
qemu_fseek (wav->f, 32, SEEK_CUR);
|
qemu_fseek (wav->f, 32, SEEK_CUR);
|
||||||
qemu_put_buffer (wav->f, dlen, 4);
|
qemu_put_buffer (wav->f, dlen, 4);
|
||||||
|
|
||||||
qemu_fclose (wav->f);
|
fclose (wav->f);
|
||||||
wav->f = NULL;
|
wav->f = NULL;
|
||||||
|
|
||||||
qemu_free (wav->pcm_buf);
|
qemu_free (wav->pcm_buf);
|
||||||
@@ -218,7 +210,7 @@ static void wav_audio_fini (void *opaque)
|
|||||||
ldebug ("wav_fini");
|
ldebug ("wav_fini");
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct audio_option wav_options[] = {
|
struct audio_option wav_options[] = {
|
||||||
{"FREQUENCY", AUD_OPT_INT, &conf.settings.freq,
|
{"FREQUENCY", AUD_OPT_INT, &conf.settings.freq,
|
||||||
"Frequency", NULL, 0},
|
"Frequency", NULL, 0},
|
||||||
|
|
||||||
@@ -233,7 +225,7 @@ static struct audio_option wav_options[] = {
|
|||||||
{NULL, 0, NULL, NULL, NULL, 0}
|
{NULL, 0, NULL, NULL, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct audio_pcm_ops wav_pcm_ops = {
|
struct audio_pcm_ops wav_pcm_ops = {
|
||||||
wav_init_out,
|
wav_init_out,
|
||||||
wav_fini_out,
|
wav_fini_out,
|
||||||
wav_run_out,
|
wav_run_out,
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#include "hw/hw.h"
|
#include "vl.h"
|
||||||
#include "console.h"
|
|
||||||
#include "audio.h"
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QEMUFile *f;
|
QEMUFile *f;
|
||||||
@@ -36,7 +34,10 @@ static void wav_destroy (void *opaque)
|
|||||||
uint32_t datalen = wav->bytes;
|
uint32_t datalen = wav->bytes;
|
||||||
uint32_t rifflen = datalen + 36;
|
uint32_t rifflen = datalen + 36;
|
||||||
|
|
||||||
if (wav->f) {
|
if (!wav->f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
le_store (rlen, rifflen, 4);
|
le_store (rlen, rifflen, 4);
|
||||||
le_store (dlen, datalen, 4);
|
le_store (dlen, datalen, 4);
|
||||||
|
|
||||||
@@ -45,11 +46,11 @@ static void wav_destroy (void *opaque)
|
|||||||
|
|
||||||
qemu_fseek (wav->f, 32, SEEK_CUR);
|
qemu_fseek (wav->f, 32, SEEK_CUR);
|
||||||
qemu_put_buffer (wav->f, dlen, 4);
|
qemu_put_buffer (wav->f, dlen, 4);
|
||||||
qemu_fclose (wav->f);
|
fclose (wav->f);
|
||||||
}
|
if (wav->path) {
|
||||||
|
|
||||||
qemu_free (wav->path);
|
qemu_free (wav->path);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void wav_capture (void *opaque, void *buf, int size)
|
static void wav_capture (void *opaque, void *buf, int size)
|
||||||
{
|
{
|
||||||
@@ -91,7 +92,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
|
|||||||
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
|
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
|
||||||
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
|
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
struct audsettings as;
|
audsettings_t as;
|
||||||
struct audio_capture_ops ops;
|
struct audio_capture_ops ops;
|
||||||
int stereo, bits16, shift;
|
int stereo, bits16, shift;
|
||||||
CaptureVoiceOut *cap;
|
CaptureVoiceOut *cap;
|
||||||
@@ -120,6 +121,11 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
|
|||||||
ops.destroy = wav_destroy;
|
ops.destroy = wav_destroy;
|
||||||
|
|
||||||
wav = qemu_mallocz (sizeof (*wav));
|
wav = qemu_mallocz (sizeof (*wav));
|
||||||
|
if (!wav) {
|
||||||
|
term_printf ("Could not allocate memory for wav capture (%zu bytes)",
|
||||||
|
sizeof (*wav));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
shift = bits16 + stereo;
|
shift = bits16 + stereo;
|
||||||
hdr[34] = bits16 ? 0x10 : 0x08;
|
hdr[34] = bits16 ? 0x10 : 0x08;
|
||||||
@@ -129,7 +135,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
|
|||||||
le_store (hdr + 28, freq << shift, 4);
|
le_store (hdr + 28, freq << shift, 4);
|
||||||
le_store (hdr + 32, 1 << shift, 2);
|
le_store (hdr + 32, 1 << shift, 2);
|
||||||
|
|
||||||
wav->f = qemu_fopen (path, "wb");
|
wav->f = fopen (path, "wb");
|
||||||
if (!wav->f) {
|
if (!wav->f) {
|
||||||
term_printf ("Failed to open wave file `%s'\nReason: %s\n",
|
term_printf ("Failed to open wave file `%s'\nReason: %s\n",
|
||||||
path, strerror (errno));
|
path, strerror (errno));
|
||||||
@@ -147,8 +153,6 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
|
|||||||
cap = AUD_add_capture (NULL, &as, &ops, wav);
|
cap = AUD_add_capture (NULL, &as, &ops, wav);
|
||||||
if (!cap) {
|
if (!cap) {
|
||||||
term_printf ("Failed to add audio capture\n");
|
term_printf ("Failed to add audio capture\n");
|
||||||
qemu_free (wav->path);
|
|
||||||
qemu_fclose (wav->f);
|
|
||||||
qemu_free (wav);
|
qemu_free (wav);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
27
balloon.h
27
balloon.h
@@ -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
|
|
||||||
@@ -22,14 +22,13 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
|
|
||||||
/**************************************************************/
|
/**************************************************************/
|
||||||
|
|
||||||
#define HEADER_MAGIC "Bochs Virtual HD Image"
|
#define HEADER_MAGIC "Bochs Virtual HD Image"
|
||||||
#define HEADER_VERSION 0x00020000
|
#define HEADER_VERSION 0x00010000
|
||||||
#define HEADER_V1 0x00010000
|
|
||||||
#define HEADER_SIZE 512
|
#define HEADER_SIZE 512
|
||||||
|
|
||||||
#define REDOLOG_TYPE "Redolog"
|
#define REDOLOG_TYPE "Redolog"
|
||||||
@@ -37,26 +36,6 @@
|
|||||||
|
|
||||||
// not allocated: 0xffffffff
|
// not allocated: 0xffffffff
|
||||||
|
|
||||||
// always little-endian
|
|
||||||
struct bochs_header_v1 {
|
|
||||||
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
|
|
||||||
uint64_t disk; // disk size
|
|
||||||
char padding[HEADER_SIZE - 64 - 8 - 20];
|
|
||||||
} redolog;
|
|
||||||
char padding[HEADER_SIZE - 64 - 8];
|
|
||||||
} extra;
|
|
||||||
};
|
|
||||||
|
|
||||||
// always little-endian
|
// always little-endian
|
||||||
struct bochs_header {
|
struct bochs_header {
|
||||||
char magic[32]; // "Bochs Virtual HD Image"
|
char magic[32]; // "Bochs Virtual HD Image"
|
||||||
@@ -70,9 +49,8 @@ struct bochs_header {
|
|||||||
uint32_t catalog; // num of entries
|
uint32_t catalog; // num of entries
|
||||||
uint32_t bitmap; // bitmap size
|
uint32_t bitmap; // bitmap size
|
||||||
uint32_t extent; // extent size
|
uint32_t extent; // extent size
|
||||||
uint32_t reserved; // for ???
|
|
||||||
uint64_t disk; // disk size
|
uint64_t disk; // disk size
|
||||||
char padding[HEADER_SIZE - 64 - 8 - 24];
|
char padding[HEADER_SIZE - 64 - 8 - 20];
|
||||||
} redolog;
|
} redolog;
|
||||||
char padding[HEADER_SIZE - 64 - 8];
|
char padding[HEADER_SIZE - 64 - 8];
|
||||||
} extra;
|
} extra;
|
||||||
@@ -101,23 +79,21 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
|
|||||||
if (!strcmp(bochs->magic, HEADER_MAGIC) &&
|
if (!strcmp(bochs->magic, HEADER_MAGIC) &&
|
||||||
!strcmp(bochs->type, REDOLOG_TYPE) &&
|
!strcmp(bochs->type, REDOLOG_TYPE) &&
|
||||||
!strcmp(bochs->subtype, GROWING_TYPE) &&
|
!strcmp(bochs->subtype, GROWING_TYPE) &&
|
||||||
((le32_to_cpu(bochs->version) == HEADER_VERSION) ||
|
(le32_to_cpu(bochs->version) == HEADER_VERSION))
|
||||||
(le32_to_cpu(bochs->version) == HEADER_V1)))
|
|
||||||
return 100;
|
return 100;
|
||||||
|
|
||||||
return 0;
|
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;
|
BDRVBochsState *s = bs->opaque;
|
||||||
int fd, i;
|
int fd, i;
|
||||||
struct bochs_header bochs;
|
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) {
|
if (fd < 0) {
|
||||||
fd = open(filename, O_RDONLY | O_BINARY);
|
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -133,22 +109,18 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
if (strcmp(bochs.magic, HEADER_MAGIC) ||
|
if (strcmp(bochs.magic, HEADER_MAGIC) ||
|
||||||
strcmp(bochs.type, REDOLOG_TYPE) ||
|
strcmp(bochs.type, REDOLOG_TYPE) ||
|
||||||
strcmp(bochs.subtype, GROWING_TYPE) ||
|
strcmp(bochs.subtype, GROWING_TYPE) ||
|
||||||
((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
|
(le32_to_cpu(bochs.version) != HEADER_VERSION)) {
|
||||||
(le32_to_cpu(bochs.version) != HEADER_V1))) {
|
|
||||||
goto fail;
|
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);
|
lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
|
||||||
|
|
||||||
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
|
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
|
||||||
s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
|
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) !=
|
if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
|
||||||
s->catalog_size * 4)
|
s->catalog_size * 4)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
@@ -50,14 +50,14 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
|
|||||||
return 0;
|
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;
|
BDRVCloopState *s = bs->opaque;
|
||||||
uint32_t offsets_size,max_compressed_block_size=1,i;
|
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)
|
if (s->fd < 0)
|
||||||
return -errno;
|
return -1;
|
||||||
bs->read_only = 1;
|
bs->read_only = 1;
|
||||||
|
|
||||||
/* read header */
|
/* read header */
|
||||||
@@ -75,7 +75,8 @@ cloop_close:
|
|||||||
|
|
||||||
/* read offsets */
|
/* read offsets */
|
||||||
offsets_size=s->n_blocks*sizeof(uint64_t);
|
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)
|
if(read(s->fd,s->offsets,offsets_size)<offsets_size)
|
||||||
goto cloop_close;
|
goto cloop_close;
|
||||||
for(i=0;i<s->n_blocks;i++) {
|
for(i=0;i<s->n_blocks;i++) {
|
||||||
@@ -88,8 +89,10 @@ cloop_close:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* initialize zlib engine */
|
/* initialize zlib engine */
|
||||||
s->compressed_block = qemu_malloc(max_compressed_block_size+1);
|
if(!(s->compressed_block = malloc(max_compressed_block_size+1)))
|
||||||
s->uncompressed_block = qemu_malloc(s->block_size);
|
goto cloop_close;
|
||||||
|
if(!(s->uncompressed_block = malloc(s->block_size)))
|
||||||
|
goto cloop_close;
|
||||||
if(inflateInit(&s->zstream) != Z_OK)
|
if(inflateInit(&s->zstream) != Z_OK)
|
||||||
goto cloop_close;
|
goto cloop_close;
|
||||||
s->current_block=s->n_blocks;
|
s->current_block=s->n_blocks;
|
||||||
@@ -162,3 +165,5 @@ BlockDriver bdrv_cloop = {
|
|||||||
NULL,
|
NULL,
|
||||||
cloop_close,
|
cloop_close,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
40
block-cow.c
40
block-cow.c
@@ -22,7 +22,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
|||||||
return 0;
|
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;
|
BDRVCowState *s = bs->opaque;
|
||||||
int fd;
|
int fd;
|
||||||
@@ -93,6 +93,22 @@ static int cow_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
|
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
|
||||||
cow_header.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 */
|
/* mmap the bitmap */
|
||||||
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
|
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
|
||||||
s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
|
s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
|
||||||
@@ -162,16 +178,9 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
ret = read(s->fd, buf, n * 512);
|
ret = read(s->fd, buf, n * 512);
|
||||||
if (ret != n * 512)
|
if (ret != n * 512)
|
||||||
return -1;
|
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 {
|
} else {
|
||||||
memset(buf, 0, n * 512);
|
memset(buf, 0, n * 512);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
nb_sectors -= n;
|
nb_sectors -= n;
|
||||||
sector_num += n;
|
sector_num += n;
|
||||||
buf += n * 512;
|
buf += n * 512;
|
||||||
@@ -211,7 +220,7 @@ static int cow_create(const char *filename, int64_t image_sectors,
|
|||||||
if (flags)
|
if (flags)
|
||||||
return -ENOTSUP;
|
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);
|
0644);
|
||||||
if (cow_fd < 0)
|
if (cow_fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -219,23 +228,18 @@ static int cow_create(const char *filename, int64_t image_sectors,
|
|||||||
cow_header.magic = cpu_to_be32(COW_MAGIC);
|
cow_header.magic = cpu_to_be32(COW_MAGIC);
|
||||||
cow_header.version = cpu_to_be32(COW_VERSION);
|
cow_header.version = cpu_to_be32(COW_VERSION);
|
||||||
if (image_filename) {
|
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);
|
fd = open(image_filename, O_RDONLY | O_BINARY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
close(cow_fd);
|
close(cow_fd);
|
||||||
goto mtime_fail;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fstat(fd, &st) != 0) {
|
if (fstat(fd, &st) != 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
goto mtime_fail;
|
return -1;
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
cow_header.mtime = cpu_to_be32(st.st_mtime);
|
cow_header.mtime = cpu_to_be32(st.st_mtime);
|
||||||
mtime_fail:
|
realpath(image_filename, cow_header.backing_file);
|
||||||
pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
|
|
||||||
image_filename);
|
|
||||||
}
|
}
|
||||||
cow_header.sectorsize = cpu_to_be32(512);
|
cow_header.sectorsize = cpu_to_be32(512);
|
||||||
cow_header.size = cpu_to_be64(image_sectors * 512);
|
cow_header.size = cpu_to_be64(image_sectors * 512);
|
||||||
|
|||||||
27
block-dmg.c
27
block-dmg.c
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
#include "bswap.h"
|
#include "bswap.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
@@ -73,16 +73,16 @@ static off_t read_uint32(int fd)
|
|||||||
return be32_to_cpu(buffer);
|
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;
|
BDRVDMGState *s = bs->opaque;
|
||||||
off_t info_begin,info_end,last_in_offset,last_out_offset;
|
off_t info_begin,info_end,last_in_offset,last_out_offset;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
|
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)
|
if (s->fd < 0)
|
||||||
return -errno;
|
return -1;
|
||||||
bs->read_only = 1;
|
bs->read_only = 1;
|
||||||
s->n_chunks = 0;
|
s->n_chunks = 0;
|
||||||
s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
|
s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
|
||||||
@@ -93,7 +93,7 @@ dmg_close:
|
|||||||
close(s->fd);
|
close(s->fd);
|
||||||
/* open raw instead */
|
/* open raw instead */
|
||||||
bs->drv=&bdrv_raw;
|
bs->drv=&bdrv_raw;
|
||||||
return bs->drv->bdrv_open(bs, filename, flags);
|
return bs->drv->bdrv_open(bs,filename);
|
||||||
}
|
}
|
||||||
info_begin=read_off(s->fd);
|
info_begin=read_off(s->fd);
|
||||||
if(info_begin==0)
|
if(info_begin==0)
|
||||||
@@ -125,11 +125,11 @@ dmg_close:
|
|||||||
goto dmg_close;
|
goto dmg_close;
|
||||||
chunk_count = (count-204)/40;
|
chunk_count = (count-204)/40;
|
||||||
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
|
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
|
||||||
s->types = qemu_realloc(s->types, new_size/2);
|
s->types = realloc(s->types, new_size/2);
|
||||||
s->offsets = qemu_realloc(s->offsets, new_size);
|
s->offsets = realloc(s->offsets, new_size);
|
||||||
s->lengths = qemu_realloc(s->lengths, new_size);
|
s->lengths = realloc(s->lengths, new_size);
|
||||||
s->sectors = qemu_realloc(s->sectors, new_size);
|
s->sectors = realloc(s->sectors, new_size);
|
||||||
s->sectorcounts = qemu_realloc(s->sectorcounts, new_size);
|
s->sectorcounts = realloc(s->sectorcounts, new_size);
|
||||||
|
|
||||||
for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
|
for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
|
||||||
s->types[i] = read_uint32(s->fd);
|
s->types[i] = read_uint32(s->fd);
|
||||||
@@ -159,8 +159,10 @@ dmg_close:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* initialize zlib engine */
|
/* initialize zlib engine */
|
||||||
s->compressed_chunk = qemu_malloc(max_compressed_size+1);
|
if(!(s->compressed_chunk = malloc(max_compressed_size+1)))
|
||||||
s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk);
|
goto dmg_close;
|
||||||
|
if(!(s->uncompressed_chunk = malloc(512*max_sectors_per_chunk)))
|
||||||
|
goto dmg_close;
|
||||||
if(inflateInit(&s->zstream) != Z_OK)
|
if(inflateInit(&s->zstream) != Z_OK)
|
||||||
goto dmg_close;
|
goto dmg_close;
|
||||||
|
|
||||||
@@ -292,3 +294,4 @@ BlockDriver bdrv_dmg = {
|
|||||||
NULL,
|
NULL,
|
||||||
dmg_close,
|
dmg_close,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
189
block-nbd.c
189
block-nbd.c
@@ -1,189 +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 <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;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockDriver bdrv_nbd = {
|
|
||||||
"nbd",
|
|
||||||
sizeof(BDRVNBDState),
|
|
||||||
NULL, /* no probe for protocols */
|
|
||||||
nbd_open,
|
|
||||||
nbd_read,
|
|
||||||
nbd_write,
|
|
||||||
nbd_close,
|
|
||||||
.bdrv_getlength = nbd_getlength,
|
|
||||||
.protocol_name = "nbd",
|
|
||||||
};
|
|
||||||
@@ -1,174 +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"
|
|
||||||
|
|
||||||
/**************************************************************/
|
|
||||||
|
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockDriver bdrv_parallels = {
|
|
||||||
"parallels",
|
|
||||||
sizeof(BDRVParallelsState),
|
|
||||||
parallels_probe,
|
|
||||||
parallels_open,
|
|
||||||
parallels_read,
|
|
||||||
NULL,
|
|
||||||
parallels_close,
|
|
||||||
};
|
|
||||||
372
block-qcow.c
372
block-qcow.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Block driver for the QCOW format
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include "aes.h"
|
#include "aes.h"
|
||||||
@@ -53,7 +53,7 @@ typedef struct QCowHeader {
|
|||||||
#define L2_CACHE_SIZE 16
|
#define L2_CACHE_SIZE 16
|
||||||
|
|
||||||
typedef struct BDRVQcowState {
|
typedef struct BDRVQcowState {
|
||||||
BlockDriverState *hd;
|
int fd;
|
||||||
int cluster_bits;
|
int cluster_bits;
|
||||||
int cluster_size;
|
int cluster_size;
|
||||||
int cluster_sectors;
|
int cluster_sectors;
|
||||||
@@ -89,16 +89,20 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
|||||||
return 0;
|
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;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int len, i, shift, ret;
|
int fd, len, i, shift;
|
||||||
QCowHeader header;
|
QCowHeader header;
|
||||||
|
|
||||||
ret = bdrv_file_open(&s->hd, filename, flags);
|
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
|
||||||
if (ret < 0)
|
if (fd < 0) {
|
||||||
return ret;
|
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||||
if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
s->fd = fd;
|
||||||
|
if (read(fd, &header, sizeof(header)) != sizeof(header))
|
||||||
goto fail;
|
goto fail;
|
||||||
be32_to_cpus(&header.magic);
|
be32_to_cpus(&header.magic);
|
||||||
be32_to_cpus(&header.version);
|
be32_to_cpus(&header.version);
|
||||||
@@ -134,7 +138,8 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
|
s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
|
||||||
if (!s->l1_table)
|
if (!s->l1_table)
|
||||||
goto fail;
|
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))
|
s->l1_size * sizeof(uint64_t))
|
||||||
goto fail;
|
goto fail;
|
||||||
for(i = 0;i < s->l1_size; i++) {
|
for(i = 0;i < s->l1_size; i++) {
|
||||||
@@ -157,7 +162,8 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
len = header.backing_file_size;
|
len = header.backing_file_size;
|
||||||
if (len > 1023)
|
if (len > 1023)
|
||||||
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;
|
goto fail;
|
||||||
bs->backing_file[len] = '\0';
|
bs->backing_file[len] = '\0';
|
||||||
}
|
}
|
||||||
@@ -168,7 +174,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
qemu_free(s->l2_cache);
|
qemu_free(s->l2_cache);
|
||||||
qemu_free(s->cluster_cache);
|
qemu_free(s->cluster_cache);
|
||||||
qemu_free(s->cluster_data);
|
qemu_free(s->cluster_data);
|
||||||
bdrv_delete(s->hd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,14 +276,14 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
|||||||
if (!allocate)
|
if (!allocate)
|
||||||
return 0;
|
return 0;
|
||||||
/* allocate a new l2 entry */
|
/* allocate a new l2 entry */
|
||||||
l2_offset = bdrv_getlength(s->hd);
|
l2_offset = lseek(s->fd, 0, SEEK_END);
|
||||||
/* round to cluster size */
|
/* round to cluster size */
|
||||||
l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
|
l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
|
||||||
/* update the L1 entry */
|
/* update the L1 entry */
|
||||||
s->l1_table[l1_index] = l2_offset;
|
s->l1_table[l1_index] = l2_offset;
|
||||||
tmp = cpu_to_be64(l2_offset);
|
tmp = cpu_to_be64(l2_offset);
|
||||||
if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
|
lseek(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET);
|
||||||
&tmp, sizeof(tmp)) != sizeof(tmp))
|
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||||
return 0;
|
return 0;
|
||||||
new_l2_table = 1;
|
new_l2_table = 1;
|
||||||
}
|
}
|
||||||
@@ -303,13 +309,14 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
l2_table = s->l2_cache + (min_index << s->l2_bits);
|
l2_table = s->l2_cache + (min_index << s->l2_bits);
|
||||||
|
lseek(s->fd, l2_offset, SEEK_SET);
|
||||||
if (new_l2_table) {
|
if (new_l2_table) {
|
||||||
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
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))
|
s->l2_size * sizeof(uint64_t))
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} 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))
|
s->l2_size * sizeof(uint64_t))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -330,40 +337,41 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
|||||||
overwritten */
|
overwritten */
|
||||||
if (decompress_cluster(s, cluster_offset) < 0)
|
if (decompress_cluster(s, cluster_offset) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
cluster_offset = bdrv_getlength(s->hd);
|
cluster_offset = lseek(s->fd, 0, SEEK_END);
|
||||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||||
~(s->cluster_size - 1);
|
~(s->cluster_size - 1);
|
||||||
/* write the cluster content */
|
/* 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)
|
s->cluster_size)
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
cluster_offset = bdrv_getlength(s->hd);
|
cluster_offset = lseek(s->fd, 0, SEEK_END);
|
||||||
if (allocate == 1) {
|
if (allocate == 1) {
|
||||||
/* round to cluster size */
|
/* round to cluster size */
|
||||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||||
~(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
|
/* if encrypted, we must initialize the cluster
|
||||||
content which won't be written */
|
content which won't be written */
|
||||||
if (s->crypt_method &&
|
if (s->crypt_method &&
|
||||||
(n_end - n_start) < s->cluster_sectors) {
|
(n_end - n_start) < s->cluster_sectors) {
|
||||||
uint64_t start_sect;
|
uint64_t start_sect;
|
||||||
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
|
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++) {
|
for(i = 0; i < s->cluster_sectors; i++) {
|
||||||
if (i < n_start || i >= n_end) {
|
if (i < n_start || i >= n_end) {
|
||||||
encrypt_sectors(s, start_sect + i,
|
encrypt_sectors(s, start_sect + i,
|
||||||
s->cluster_data,
|
s->cluster_data,
|
||||||
s->cluster_data + 512, 1, 1,
|
s->cluster_data + 512, 1, 1,
|
||||||
&s->aes_encrypt_key);
|
&s->aes_encrypt_key);
|
||||||
if (bdrv_pwrite(s->hd, cluster_offset + i * 512,
|
lseek(s->fd, cluster_offset + i * 512, SEEK_SET);
|
||||||
s->cluster_data, 512) != 512)
|
if (write(s->fd, s->cluster_data, 512) != 512)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (allocate == 2) {
|
} else {
|
||||||
cluster_offset |= QCOW_OFLAG_COMPRESSED |
|
cluster_offset |= QCOW_OFLAG_COMPRESSED |
|
||||||
(uint64_t)compressed_size << (63 - s->cluster_bits);
|
(uint64_t)compressed_size << (63 - s->cluster_bits);
|
||||||
}
|
}
|
||||||
@@ -371,8 +379,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
|||||||
/* update L2 table */
|
/* update L2 table */
|
||||||
tmp = cpu_to_be64(cluster_offset);
|
tmp = cpu_to_be64(cluster_offset);
|
||||||
l2_table[l2_index] = tmp;
|
l2_table[l2_index] = tmp;
|
||||||
if (bdrv_pwrite(s->hd,
|
lseek(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET);
|
||||||
l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
|
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return cluster_offset;
|
return cluster_offset;
|
||||||
@@ -430,7 +438,8 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
|
|||||||
if (s->cluster_cache_offset != coffset) {
|
if (s->cluster_cache_offset != coffset) {
|
||||||
csize = cluster_offset >> (63 - s->cluster_bits);
|
csize = cluster_offset >> (63 - s->cluster_bits);
|
||||||
csize &= (s->cluster_size - 1);
|
csize &= (s->cluster_size - 1);
|
||||||
ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize);
|
lseek(s->fd, coffset, SEEK_SET);
|
||||||
|
ret = read(s->fd, s->cluster_data, csize);
|
||||||
if (ret != csize)
|
if (ret != csize)
|
||||||
return -1;
|
return -1;
|
||||||
if (decompress_buffer(s->cluster_cache, s->cluster_size,
|
if (decompress_buffer(s->cluster_cache, s->cluster_size,
|
||||||
@@ -442,8 +451,6 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
|
|||||||
return 0;
|
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)
|
uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
@@ -458,20 +465,14 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
if (n > nb_sectors)
|
if (n > nb_sectors)
|
||||||
n = nb_sectors;
|
n = nb_sectors;
|
||||||
if (!cluster_offset) {
|
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) {
|
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
||||||
if (decompress_cluster(s, cluster_offset) < 0)
|
if (decompress_cluster(s, cluster_offset) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
|
memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
|
||||||
} else {
|
} else {
|
||||||
ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
|
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
|
||||||
|
ret = read(s->fd, buf, n * 512);
|
||||||
if (ret != n * 512)
|
if (ret != n * 512)
|
||||||
return -1;
|
return -1;
|
||||||
if (s->crypt_method) {
|
if (s->crypt_method) {
|
||||||
@@ -485,7 +486,6 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
|
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
|
||||||
const uint8_t *buf, int nb_sectors)
|
const uint8_t *buf, int nb_sectors)
|
||||||
@@ -504,13 +504,13 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num,
|
|||||||
index_in_cluster + n);
|
index_in_cluster + n);
|
||||||
if (!cluster_offset)
|
if (!cluster_offset)
|
||||||
return -1;
|
return -1;
|
||||||
|
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
|
||||||
if (s->crypt_method) {
|
if (s->crypt_method) {
|
||||||
encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
|
encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
|
||||||
&s->aes_encrypt_key);
|
&s->aes_encrypt_key);
|
||||||
ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
|
ret = write(s->fd, s->cluster_data, n * 512);
|
||||||
s->cluster_data, n * 512);
|
|
||||||
} else {
|
} else {
|
||||||
ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
|
ret = write(s->fd, buf, n * 512);
|
||||||
}
|
}
|
||||||
if (ret != n * 512)
|
if (ret != n * 512)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -522,209 +522,6 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct QCowAIOCB {
|
|
||||||
BlockDriverAIOCB common;
|
|
||||||
int64_t sector_num;
|
|
||||||
uint8_t *buf;
|
|
||||||
int nb_sectors;
|
|
||||||
int n;
|
|
||||||
uint64_t cluster_offset;
|
|
||||||
uint8_t *cluster_data;
|
|
||||||
BlockDriverAIOCB *hd_aiocb;
|
|
||||||
} QCowAIOCB;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
fail:
|
|
||||||
acb->common.cb(acb->common.opaque, ret);
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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 */
|
|
||||||
acb->common.cb(acb->common.opaque, 0);
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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_aiocb = bdrv_aio_read(bs->backing_hd,
|
|
||||||
acb->sector_num, acb->buf, acb->n, qcow_aio_read_cb, acb);
|
|
||||||
if (acb->hd_aiocb == NULL)
|
|
||||||
goto fail;
|
|
||||||
} else {
|
|
||||||
/* Note: in this case, no need to wait */
|
|
||||||
memset(acb->buf, 0, 512 * acb->n);
|
|
||||||
goto redo;
|
|
||||||
}
|
|
||||||
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
|
||||||
/* add AIO support for compressed blocks ? */
|
|
||||||
if (decompress_cluster(s, acb->cluster_offset) < 0)
|
|
||||||
goto fail;
|
|
||||||
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 fail;
|
|
||||||
}
|
|
||||||
acb->hd_aiocb = bdrv_aio_read(s->hd,
|
|
||||||
(acb->cluster_offset >> 9) + index_in_cluster,
|
|
||||||
acb->buf, acb->n, qcow_aio_read_cb, acb);
|
|
||||||
if (acb->hd_aiocb == NULL)
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs,
|
|
||||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
|
||||||
{
|
|
||||||
QCowAIOCB *acb;
|
|
||||||
|
|
||||||
acb = qemu_aio_get(bs, cb, opaque);
|
|
||||||
if (!acb)
|
|
||||||
return NULL;
|
|
||||||
acb->hd_aiocb = NULL;
|
|
||||||
acb->sector_num = sector_num;
|
|
||||||
acb->buf = buf;
|
|
||||||
acb->nb_sectors = nb_sectors;
|
|
||||||
acb->n = 0;
|
|
||||||
acb->cluster_offset = 0;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
fail:
|
|
||||||
acb->common.cb(acb->common.opaque, ret);
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
acb->nb_sectors -= acb->n;
|
|
||||||
acb->sector_num += acb->n;
|
|
||||||
acb->buf += acb->n * 512;
|
|
||||||
|
|
||||||
if (acb->nb_sectors == 0) {
|
|
||||||
/* request completed */
|
|
||||||
acb->common.cb(acb->common.opaque, 0);
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 fail;
|
|
||||||
}
|
|
||||||
if (s->crypt_method) {
|
|
||||||
if (!acb->cluster_data) {
|
|
||||||
acb->cluster_data = qemu_mallocz(s->cluster_size);
|
|
||||||
if (!acb->cluster_data) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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_aiocb = bdrv_aio_write(s->hd,
|
|
||||||
(cluster_offset >> 9) + index_in_cluster,
|
|
||||||
src_buf, acb->n,
|
|
||||||
qcow_aio_write_cb, acb);
|
|
||||||
if (acb->hd_aiocb == NULL)
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs,
|
|
||||||
int64_t sector_num, const uint8_t *buf, int nb_sectors,
|
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
|
||||||
{
|
|
||||||
BDRVQcowState *s = bs->opaque;
|
|
||||||
QCowAIOCB *acb;
|
|
||||||
|
|
||||||
s->cluster_cache_offset = -1; /* disable compressed cache */
|
|
||||||
|
|
||||||
acb = qemu_aio_get(bs, cb, opaque);
|
|
||||||
if (!acb)
|
|
||||||
return NULL;
|
|
||||||
acb->hd_aiocb = NULL;
|
|
||||||
acb->sector_num = sector_num;
|
|
||||||
acb->buf = (uint8_t *)buf;
|
|
||||||
acb->nb_sectors = nb_sectors;
|
|
||||||
acb->n = 0;
|
|
||||||
|
|
||||||
qcow_aio_write_cb(acb, 0);
|
|
||||||
return &acb->common;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
|
|
||||||
{
|
|
||||||
QCowAIOCB *acb = (QCowAIOCB *)blockacb;
|
|
||||||
if (acb->hd_aiocb)
|
|
||||||
bdrv_aio_cancel(acb->hd_aiocb);
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qcow_close(BlockDriverState *bs)
|
static void qcow_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
@@ -732,7 +529,7 @@ static void qcow_close(BlockDriverState *bs)
|
|||||||
qemu_free(s->l2_cache);
|
qemu_free(s->l2_cache);
|
||||||
qemu_free(s->cluster_cache);
|
qemu_free(s->cluster_cache);
|
||||||
qemu_free(s->cluster_data);
|
qemu_free(s->cluster_data);
|
||||||
bdrv_delete(s->hd);
|
close(s->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcow_create(const char *filename, int64_t total_size,
|
static int qcow_create(const char *filename, int64_t total_size,
|
||||||
@@ -740,9 +537,12 @@ static int qcow_create(const char *filename, int64_t total_size,
|
|||||||
{
|
{
|
||||||
int fd, header_size, backing_filename_len, l1_size, i, shift;
|
int fd, header_size, backing_filename_len, l1_size, i, shift;
|
||||||
QCowHeader header;
|
QCowHeader header;
|
||||||
|
char backing_filename[1024];
|
||||||
uint64_t tmp;
|
uint64_t tmp;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
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)
|
if (fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
memset(&header, 0, sizeof(header));
|
memset(&header, 0, sizeof(header));
|
||||||
@@ -753,14 +553,27 @@ static int qcow_create(const char *filename, int64_t total_size,
|
|||||||
backing_filename_len = 0;
|
backing_filename_len = 0;
|
||||||
if (backing_file) {
|
if (backing_file) {
|
||||||
if (strcmp(backing_file, "fat:")) {
|
if (strcmp(backing_file, "fat:")) {
|
||||||
|
const char *p;
|
||||||
|
/* XXX: this is a hack: we do not attempt to check for URL
|
||||||
|
like syntax */
|
||||||
|
p = strchr(backing_file, ':');
|
||||||
|
if (p && (p - backing_file) >= 2) {
|
||||||
|
/* URL like but exclude "c:" like filenames */
|
||||||
|
pstrcpy(backing_filename, sizeof(backing_filename),
|
||||||
|
backing_file);
|
||||||
|
} else {
|
||||||
|
realpath(backing_file, backing_filename);
|
||||||
|
if (stat(backing_filename, &st) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
header.backing_file_offset = cpu_to_be64(header_size);
|
header.backing_file_offset = cpu_to_be64(header_size);
|
||||||
backing_filename_len = strlen(backing_file);
|
backing_filename_len = strlen(backing_filename);
|
||||||
header.backing_file_size = cpu_to_be32(backing_filename_len);
|
header.backing_file_size = cpu_to_be32(backing_filename_len);
|
||||||
header_size += backing_filename_len;
|
header_size += backing_filename_len;
|
||||||
} else {
|
} else
|
||||||
/* special backing file for vvfat */
|
|
||||||
backing_file = NULL;
|
backing_file = NULL;
|
||||||
}
|
header.mtime = cpu_to_be32(st.st_mtime);
|
||||||
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
|
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
|
||||||
unmodifyed sectors */
|
unmodifyed sectors */
|
||||||
header.l2_bits = 12; /* 32 KB L2 tables */
|
header.l2_bits = 12; /* 32 KB L2 tables */
|
||||||
@@ -773,7 +586,7 @@ static int qcow_create(const char *filename, int64_t total_size,
|
|||||||
l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift;
|
l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift;
|
||||||
|
|
||||||
header.l1_table_offset = cpu_to_be64(header_size);
|
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);
|
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
|
||||||
} else {
|
} else {
|
||||||
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
|
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
|
||||||
@@ -782,7 +595,7 @@ static int qcow_create(const char *filename, int64_t total_size,
|
|||||||
/* write all the data */
|
/* write all the data */
|
||||||
write(fd, &header, sizeof(header));
|
write(fd, &header, sizeof(header));
|
||||||
if (backing_file) {
|
if (backing_file) {
|
||||||
write(fd, backing_file, backing_filename_len);
|
write(fd, backing_filename, backing_filename_len);
|
||||||
}
|
}
|
||||||
lseek(fd, header_size, SEEK_SET);
|
lseek(fd, header_size, SEEK_SET);
|
||||||
tmp = 0;
|
tmp = 0;
|
||||||
@@ -793,18 +606,16 @@ static int qcow_create(const char *filename, int64_t total_size,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcow_make_empty(BlockDriverState *bs)
|
int qcow_make_empty(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint32_t l1_length = s->l1_size * sizeof(uint64_t);
|
uint32_t l1_length = s->l1_size * sizeof(uint64_t);
|
||||||
int ret;
|
|
||||||
|
|
||||||
memset(s->l1_table, 0, l1_length);
|
memset(s->l1_table, 0, l1_length);
|
||||||
if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
|
lseek(s->fd, s->l1_table_offset, SEEK_SET);
|
||||||
|
if (write(s->fd, s->l1_table, l1_length) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
|
ftruncate(s->fd, 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, 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_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
|
||||||
@@ -813,10 +624,18 @@ static int qcow_make_empty(BlockDriverState *bs)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int qcow_get_cluster_size(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
if (bs->drv != &bdrv_qcow)
|
||||||
|
return -1;
|
||||||
|
return s->cluster_size;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: put compressed sectors first, then all the cluster aligned
|
/* XXX: put compressed sectors first, then all the cluster aligned
|
||||||
tables to avoid losing bytes in alignment */
|
tables to avoid losing bytes in alignment */
|
||||||
static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
|
||||||
const uint8_t *buf, int nb_sectors)
|
const uint8_t *buf)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
z_stream strm;
|
z_stream strm;
|
||||||
@@ -824,8 +643,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
|||||||
uint8_t *out_buf;
|
uint8_t *out_buf;
|
||||||
uint64_t cluster_offset;
|
uint64_t cluster_offset;
|
||||||
|
|
||||||
if (nb_sectors != s->cluster_sectors)
|
if (bs->drv != &bdrv_qcow)
|
||||||
return -EINVAL;
|
return -1;
|
||||||
|
|
||||||
out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
|
out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
|
||||||
if (!out_buf)
|
if (!out_buf)
|
||||||
@@ -863,7 +682,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
|||||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
|
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
|
||||||
out_len, 0, 0);
|
out_len, 0, 0);
|
||||||
cluster_offset &= s->cluster_offset_mask;
|
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);
|
qemu_free(out_buf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -876,14 +696,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
|||||||
static void qcow_flush(BlockDriverState *bs)
|
static void qcow_flush(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
bdrv_flush(s->hd);
|
fsync(s->fd);
|
||||||
}
|
|
||||||
|
|
||||||
static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
|
||||||
{
|
|
||||||
BDRVQcowState *s = bs->opaque;
|
|
||||||
bdi->cluster_size = s->cluster_size;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockDriver bdrv_qcow = {
|
BlockDriver bdrv_qcow = {
|
||||||
@@ -891,19 +704,14 @@ BlockDriver bdrv_qcow = {
|
|||||||
sizeof(BDRVQcowState),
|
sizeof(BDRVQcowState),
|
||||||
qcow_probe,
|
qcow_probe,
|
||||||
qcow_open,
|
qcow_open,
|
||||||
NULL,
|
qcow_read,
|
||||||
NULL,
|
qcow_write,
|
||||||
qcow_close,
|
qcow_close,
|
||||||
qcow_create,
|
qcow_create,
|
||||||
qcow_flush,
|
qcow_flush,
|
||||||
qcow_is_allocated,
|
qcow_is_allocated,
|
||||||
qcow_set_key,
|
qcow_set_key,
|
||||||
qcow_make_empty,
|
qcow_make_empty
|
||||||
|
|
||||||
.bdrv_aio_read = qcow_aio_read,
|
|
||||||
.bdrv_aio_write = qcow_aio_write,
|
|
||||||
.bdrv_aio_cancel = qcow_aio_cancel,
|
|
||||||
.aiocb_size = sizeof(QCowAIOCB),
|
|
||||||
.bdrv_write_compressed = qcow_write_compressed,
|
|
||||||
.bdrv_get_info = qcow_get_info,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2657
block-qcow2.c
2657
block-qcow2.c
File diff suppressed because it is too large
Load Diff
1197
block-raw-posix.c
1197
block-raw-posix.c
File diff suppressed because it is too large
Load Diff
@@ -1,522 +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 <assert.h>
|
|
||||||
#include <winioctl.h>
|
|
||||||
|
|
||||||
//#define WIN32_AIO
|
|
||||||
|
|
||||||
#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;
|
|
||||||
|
|
||||||
typedef struct RawAIOCB {
|
|
||||||
BlockDriverAIOCB common;
|
|
||||||
HANDLE hEvent;
|
|
||||||
OVERLAPPED ov;
|
|
||||||
int count;
|
|
||||||
} RawAIOCB;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
#ifdef WIN32_AIO
|
|
||||||
overlapped = FILE_FLAG_OVERLAPPED;
|
|
||||||
#else
|
|
||||||
overlapped = FILE_ATTRIBUTE_NORMAL;
|
|
||||||
#endif
|
|
||||||
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_pread(BlockDriverState *bs, int64_t offset,
|
|
||||||
uint8_t *buf, int count)
|
|
||||||
{
|
|
||||||
BDRVRawState *s = bs->opaque;
|
|
||||||
OVERLAPPED ov;
|
|
||||||
DWORD ret_count;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
memset(&ov, 0, sizeof(ov));
|
|
||||||
ov.Offset = offset;
|
|
||||||
ov.OffsetHigh = offset >> 32;
|
|
||||||
ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
|
|
||||||
if (!ret) {
|
|
||||||
#ifdef WIN32_AIO
|
|
||||||
ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
|
|
||||||
if (!ret)
|
|
||||||
return -EIO;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
return ret_count;
|
|
||||||
}
|
|
||||||
return ret_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int raw_pwrite(BlockDriverState *bs, int64_t offset,
|
|
||||||
const uint8_t *buf, int count)
|
|
||||||
{
|
|
||||||
BDRVRawState *s = bs->opaque;
|
|
||||||
OVERLAPPED ov;
|
|
||||||
DWORD ret_count;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
memset(&ov, 0, sizeof(ov));
|
|
||||||
ov.Offset = offset;
|
|
||||||
ov.OffsetHigh = offset >> 32;
|
|
||||||
ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
|
|
||||||
if (!ret) {
|
|
||||||
#ifdef WIN32_AIO
|
|
||||||
ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
|
|
||||||
if (!ret)
|
|
||||||
return -EIO;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
return ret_count;
|
|
||||||
}
|
|
||||||
return ret_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN32_AIO
|
|
||||||
static void raw_aio_cb(void *opaque)
|
|
||||||
{
|
|
||||||
RawAIOCB *acb = opaque;
|
|
||||||
BlockDriverState *bs = acb->common.bs;
|
|
||||||
BDRVRawState *s = bs->opaque;
|
|
||||||
DWORD ret_count;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
|
|
||||||
if (!ret || ret_count != acb->count) {
|
|
||||||
acb->common.cb(acb->common.opaque, -EIO);
|
|
||||||
} else {
|
|
||||||
acb->common.cb(acb->common.opaque, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
|
|
||||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
|
||||||
{
|
|
||||||
RawAIOCB *acb;
|
|
||||||
int64_t offset;
|
|
||||||
|
|
||||||
acb = qemu_aio_get(bs, cb, opaque);
|
|
||||||
if (acb->hEvent) {
|
|
||||||
acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
if (!acb->hEvent) {
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memset(&acb->ov, 0, sizeof(acb->ov));
|
|
||||||
offset = sector_num * 512;
|
|
||||||
acb->ov.Offset = offset;
|
|
||||||
acb->ov.OffsetHigh = offset >> 32;
|
|
||||||
acb->ov.hEvent = acb->hEvent;
|
|
||||||
acb->count = nb_sectors * 512;
|
|
||||||
qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
|
|
||||||
return acb;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
|
|
||||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
|
||||||
{
|
|
||||||
BDRVRawState *s = bs->opaque;
|
|
||||||
RawAIOCB *acb;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
|
|
||||||
if (!acb)
|
|
||||||
return NULL;
|
|
||||||
ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
|
|
||||||
if (!ret) {
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
return (BlockDriverAIOCB *)acb;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
|
|
||||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
|
||||||
{
|
|
||||||
BDRVRawState *s = bs->opaque;
|
|
||||||
RawAIOCB *acb;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
|
|
||||||
if (!acb)
|
|
||||||
return NULL;
|
|
||||||
ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
|
|
||||||
if (!ret) {
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
return (BlockDriverAIOCB *)acb;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
|
|
||||||
{
|
|
||||||
RawAIOCB *acb = (RawAIOCB *)blockacb;
|
|
||||||
BlockDriverState *bs = acb->common.bs;
|
|
||||||
BDRVRawState *s = bs->opaque;
|
|
||||||
|
|
||||||
qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
|
|
||||||
/* XXX: if more than one async I/O it is not correct */
|
|
||||||
CancelIo(s->hfile);
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
}
|
|
||||||
#endif /* #if WIN32_AIO */
|
|
||||||
|
|
||||||
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;
|
|
||||||
DWORD 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, &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, int64_t total_size,
|
|
||||||
const char *backing_file, int flags)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (flags || backing_file)
|
|
||||||
return -ENOTSUP;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockDriver bdrv_raw = {
|
|
||||||
"raw",
|
|
||||||
sizeof(BDRVRawState),
|
|
||||||
NULL, /* no probe for protocols */
|
|
||||||
raw_open,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
raw_close,
|
|
||||||
raw_create,
|
|
||||||
raw_flush,
|
|
||||||
|
|
||||||
#ifdef WIN32_AIO
|
|
||||||
.bdrv_aio_read = raw_aio_read,
|
|
||||||
.bdrv_aio_write = raw_aio_write,
|
|
||||||
.bdrv_aio_cancel = raw_aio_cancel,
|
|
||||||
.aiocb_size = sizeof(RawAIOCB);
|
|
||||||
#endif
|
|
||||||
.bdrv_pread = raw_pread,
|
|
||||||
.bdrv_pwrite = raw_pwrite,
|
|
||||||
.bdrv_truncate = raw_truncate,
|
|
||||||
.bdrv_getlength = raw_getlength,
|
|
||||||
};
|
|
||||||
|
|
||||||
/***********************************************/
|
|
||||||
/* 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_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;
|
|
||||||
|
|
||||||
#ifdef WIN32_AIO
|
|
||||||
overlapped = FILE_FLAG_OVERLAPPED;
|
|
||||||
#else
|
|
||||||
overlapped = FILE_ATTRIBUTE_NORMAL;
|
|
||||||
#endif
|
|
||||||
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
|
|
||||||
|
|
||||||
BlockDriver bdrv_host_device = {
|
|
||||||
"host_device",
|
|
||||||
sizeof(BDRVRawState),
|
|
||||||
NULL, /* no probe for protocols */
|
|
||||||
hdev_open,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
raw_close,
|
|
||||||
NULL,
|
|
||||||
raw_flush,
|
|
||||||
|
|
||||||
#ifdef WIN32_AIO
|
|
||||||
.bdrv_aio_read = raw_aio_read,
|
|
||||||
.bdrv_aio_write = raw_aio_write,
|
|
||||||
.bdrv_aio_cancel = raw_aio_cancel,
|
|
||||||
.aiocb_size = sizeof(RawAIOCB);
|
|
||||||
#endif
|
|
||||||
.bdrv_pread = raw_pread,
|
|
||||||
.bdrv_pwrite = raw_pwrite,
|
|
||||||
.bdrv_getlength = raw_getlength,
|
|
||||||
};
|
|
||||||
507
block-vmdk.c
507
block-vmdk.c
@@ -22,8 +22,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#include "vl.h"
|
||||||
#include "qemu-common.h"
|
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
|
|
||||||
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
|
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
|
||||||
@@ -60,7 +59,7 @@ typedef struct {
|
|||||||
#define L2_CACHE_SIZE 16
|
#define L2_CACHE_SIZE 16
|
||||||
|
|
||||||
typedef struct BDRVVmdkState {
|
typedef struct BDRVVmdkState {
|
||||||
BlockDriverState *hd;
|
int fd;
|
||||||
int64_t l1_table_offset;
|
int64_t l1_table_offset;
|
||||||
int64_t l1_backup_table_offset;
|
int64_t l1_backup_table_offset;
|
||||||
uint32_t *l1_table;
|
uint32_t *l1_table;
|
||||||
@@ -74,26 +73,8 @@ typedef struct BDRVVmdkState {
|
|||||||
uint32_t l2_cache_counts[L2_CACHE_SIZE];
|
uint32_t l2_cache_counts[L2_CACHE_SIZE];
|
||||||
|
|
||||||
unsigned int cluster_sectors;
|
unsigned int cluster_sectors;
|
||||||
uint32_t parent_cid;
|
|
||||||
int is_parent;
|
|
||||||
} BDRVVmdkState;
|
} 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)
|
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
{
|
{
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
@@ -108,283 +89,27 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_CID 1
|
static int vmdk_open(BlockDriverState *bs, const char *filename)
|
||||||
|
|
||||||
#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)) != 0) {
|
|
||||||
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")) != 0) {
|
|
||||||
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 = s->hd->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")) != 0) {
|
|
||||||
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")) != 0) {
|
|
||||||
char *end_name;
|
|
||||||
struct stat file_buf;
|
|
||||||
|
|
||||||
p_name += sizeof("parentFileNameHint") + 1;
|
|
||||||
if ((end_name = strchr(p_name,'\"')) == 0)
|
|
||||||
return -1;
|
|
||||||
if ((end_name - p_name) > sizeof (s->hd->backing_file) - 1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
pstrcpy(s->hd->backing_file, end_name - p_name + 1, p_name);
|
|
||||||
if (stat(s->hd->backing_file, &file_buf) != 0) {
|
|
||||||
path_combine(parent_img_name, sizeof(parent_img_name),
|
|
||||||
filename, s->hd->backing_file);
|
|
||||||
} else {
|
|
||||||
pstrcpy(parent_img_name, sizeof(parent_img_name),
|
|
||||||
s->hd->backing_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
s->hd->backing_hd = bdrv_new("");
|
|
||||||
if (!s->hd->backing_hd) {
|
|
||||||
failure:
|
|
||||||
bdrv_close(s->hd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
parent_open = 1;
|
|
||||||
if (bdrv_open(s->hd->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;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
int fd, i;
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
int l1_size, i, ret;
|
int l1_size;
|
||||||
|
|
||||||
if (parent_open)
|
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
|
||||||
// Parent must be opened as RO.
|
if (fd < 0) {
|
||||||
flags = BDRV_O_RDONLY;
|
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||||
|
if (fd < 0)
|
||||||
ret = bdrv_file_open(&s->hd, filename, flags);
|
return -1;
|
||||||
if (ret < 0)
|
bs->read_only = 1;
|
||||||
return ret;
|
}
|
||||||
if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic))
|
if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
magic = be32_to_cpu(magic);
|
magic = be32_to_cpu(magic);
|
||||||
if (magic == VMDK3_MAGIC) {
|
if (magic == VMDK3_MAGIC) {
|
||||||
VMDK3Header header;
|
VMDK3Header header;
|
||||||
|
if (read(fd, &header, sizeof(header)) !=
|
||||||
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
|
sizeof(header))
|
||||||
goto fail;
|
goto fail;
|
||||||
s->cluster_sectors = le32_to_cpu(header.granularity);
|
s->cluster_sectors = le32_to_cpu(header.granularity);
|
||||||
s->l2_size = 1 << 9;
|
s->l2_size = 1 << 9;
|
||||||
@@ -396,7 +121,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
} else if (magic == VMDK4_MAGIC) {
|
} else if (magic == VMDK4_MAGIC) {
|
||||||
VMDK4Header header;
|
VMDK4Header header;
|
||||||
|
|
||||||
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
|
if (read(fd, &header, sizeof(header)) != sizeof(header))
|
||||||
goto fail;
|
goto fail;
|
||||||
bs->total_sectors = le64_to_cpu(header.capacity);
|
bs->total_sectors = le64_to_cpu(header.capacity);
|
||||||
s->cluster_sectors = le64_to_cpu(header.granularity);
|
s->cluster_sectors = le64_to_cpu(header.granularity);
|
||||||
@@ -408,25 +133,17 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
/ s->l1_entry_sectors;
|
/ s->l1_entry_sectors;
|
||||||
s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
|
s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
|
||||||
s->l1_backup_table_offset = le64_to_cpu(header.gd_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 {
|
} else {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read the L1 table */
|
/* read the L1 table */
|
||||||
l1_size = s->l1_size * sizeof(uint32_t);
|
l1_size = s->l1_size * sizeof(uint32_t);
|
||||||
s->l1_table = qemu_malloc(l1_size);
|
s->l1_table = qemu_malloc(l1_size);
|
||||||
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != 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;
|
goto fail;
|
||||||
for(i = 0; i < s->l1_size; i++) {
|
for(i = 0; i < s->l1_size; i++) {
|
||||||
le32_to_cpus(&s->l1_table[i]);
|
le32_to_cpus(&s->l1_table[i]);
|
||||||
@@ -434,7 +151,11 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
|
|
||||||
if (s->l1_backup_table_offset) {
|
if (s->l1_backup_table_offset) {
|
||||||
s->l1_backup_table = qemu_malloc(l1_size);
|
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)
|
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;
|
goto fail;
|
||||||
for(i = 0; i < s->l1_size; i++) {
|
for(i = 0; i < s->l1_size; i++) {
|
||||||
le32_to_cpus(&s->l1_backup_table[i]);
|
le32_to_cpus(&s->l1_backup_table[i]);
|
||||||
@@ -442,80 +163,27 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
|
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;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
qemu_free(s->l1_backup_table);
|
qemu_free(s->l1_backup_table);
|
||||||
qemu_free(s->l1_table);
|
qemu_free(s->l1_table);
|
||||||
qemu_free(s->l2_cache);
|
qemu_free(s->l2_cache);
|
||||||
bdrv_delete(s->hd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
|
static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||||
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 (s->hd->backing_hd) {
|
|
||||||
BDRVVmdkState *ps = s->hd->backing_hd->opaque;
|
|
||||||
|
|
||||||
if (!vmdk_is_cid_valid(bs))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
parent_cluster_offset = get_cluster_offset(s->hd->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)
|
uint64_t offset, int allocate)
|
||||||
{
|
{
|
||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
unsigned int l1_index, l2_offset, l2_index;
|
unsigned int l1_index, l2_offset, l2_index;
|
||||||
int min_index, i, j;
|
int min_index, i, j;
|
||||||
uint32_t min_count, *l2_table, tmp = 0;
|
uint32_t min_count, *l2_table, tmp;
|
||||||
uint64_t cluster_offset;
|
uint64_t cluster_offset;
|
||||||
|
|
||||||
if (m_data)
|
|
||||||
m_data->valid = 0;
|
|
||||||
|
|
||||||
l1_index = (offset >> 9) / s->l1_entry_sectors;
|
l1_index = (offset >> 9) / s->l1_entry_sectors;
|
||||||
if (l1_index >= s->l1_size)
|
if (l1_index >= s->l1_size)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -544,45 +212,33 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
l2_table = s->l2_cache + (min_index * s->l2_size);
|
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)) !=
|
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))
|
s->l2_size * sizeof(uint32_t))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
s->l2_cache_offsets[min_index] = l2_offset;
|
s->l2_cache_offsets[min_index] = l2_offset;
|
||||||
s->l2_cache_counts[min_index] = 1;
|
s->l2_cache_counts[min_index] = 1;
|
||||||
found:
|
found:
|
||||||
l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
|
l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
|
||||||
cluster_offset = le32_to_cpu(l2_table[l2_index]);
|
cluster_offset = le32_to_cpu(l2_table[l2_index]);
|
||||||
|
|
||||||
if (!cluster_offset) {
|
if (!cluster_offset) {
|
||||||
if (!allocate)
|
if (!allocate)
|
||||||
return 0;
|
return 0;
|
||||||
// Avoid the L2 tables update for the images that have snapshots.
|
cluster_offset = lseek(s->fd, 0, SEEK_END);
|
||||||
if (!s->is_parent) {
|
ftruncate(s->fd, cluster_offset + (s->cluster_sectors << 9));
|
||||||
cluster_offset = bdrv_getlength(s->hd);
|
|
||||||
bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
|
|
||||||
|
|
||||||
cluster_offset >>= 9;
|
cluster_offset >>= 9;
|
||||||
|
/* update L2 table */
|
||||||
tmp = cpu_to_le32(cluster_offset);
|
tmp = cpu_to_le32(cluster_offset);
|
||||||
l2_table[l2_index] = tmp;
|
l2_table[l2_index] = tmp;
|
||||||
// Save the active image state
|
lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
|
||||||
activeBDRV.cluster_offset = cluster_offset;
|
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||||
activeBDRV.hd = bs;
|
return 0;
|
||||||
}
|
/* update backup L2 table */
|
||||||
/* First of all we write grain itself, to avoid race condition
|
if (s->l1_backup_table_offset != 0) {
|
||||||
* that may to corrupt the image.
|
l2_offset = s->l1_backup_table[l1_index];
|
||||||
* This problem may occur because of insufficient space on host disk
|
lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
|
||||||
* or inappropriate VM shutdown.
|
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||||
*/
|
|
||||||
if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1)
|
|
||||||
return 0;
|
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;
|
cluster_offset <<= 9;
|
||||||
@@ -596,7 +252,7 @@ static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
|||||||
int index_in_cluster, n;
|
int index_in_cluster, n;
|
||||||
uint64_t cluster_offset;
|
uint64_t cluster_offset;
|
||||||
|
|
||||||
cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
|
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
|
||||||
index_in_cluster = sector_num % s->cluster_sectors;
|
index_in_cluster = sector_num % s->cluster_sectors;
|
||||||
n = s->cluster_sectors - index_in_cluster;
|
n = s->cluster_sectors - index_in_cluster;
|
||||||
if (n > nb_sectors)
|
if (n > nb_sectors)
|
||||||
@@ -609,28 +265,21 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
uint8_t *buf, int nb_sectors)
|
uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
int index_in_cluster, n, ret;
|
int ret, index_in_cluster, n;
|
||||||
uint64_t cluster_offset;
|
uint64_t cluster_offset;
|
||||||
|
|
||||||
while (nb_sectors > 0) {
|
while (nb_sectors > 0) {
|
||||||
cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
|
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
|
||||||
index_in_cluster = sector_num % s->cluster_sectors;
|
index_in_cluster = sector_num % s->cluster_sectors;
|
||||||
n = s->cluster_sectors - index_in_cluster;
|
n = s->cluster_sectors - index_in_cluster;
|
||||||
if (n > nb_sectors)
|
if (n > nb_sectors)
|
||||||
n = nb_sectors;
|
n = nb_sectors;
|
||||||
if (!cluster_offset) {
|
if (!cluster_offset) {
|
||||||
// try to read from parent image, if exist
|
|
||||||
if (s->hd->backing_hd) {
|
|
||||||
if (!vmdk_is_cid_valid(bs))
|
|
||||||
return -1;
|
|
||||||
ret = bdrv_read(s->hd->backing_hd, sector_num, buf, n);
|
|
||||||
if (ret < 0)
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
memset(buf, 0, 512 * n);
|
memset(buf, 0, 512 * n);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != 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;
|
return -1;
|
||||||
}
|
}
|
||||||
nb_sectors -= n;
|
nb_sectors -= n;
|
||||||
@@ -644,44 +293,24 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
|||||||
const uint8_t *buf, int nb_sectors)
|
const uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
VmdkMetaData m_data;
|
int ret, index_in_cluster, n;
|
||||||
int index_in_cluster, n;
|
|
||||||
uint64_t cluster_offset;
|
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) {
|
while (nb_sectors > 0) {
|
||||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||||
n = s->cluster_sectors - index_in_cluster;
|
n = s->cluster_sectors - index_in_cluster;
|
||||||
if (n > nb_sectors)
|
if (n > nb_sectors)
|
||||||
n = nb_sectors;
|
n = nb_sectors;
|
||||||
cluster_offset = get_cluster_offset(bs, &m_data, sector_num << 9, 1);
|
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1);
|
||||||
if (!cluster_offset)
|
if (!cluster_offset)
|
||||||
return -1;
|
return -1;
|
||||||
|
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
|
||||||
if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
|
ret = write(s->fd, buf, n * 512);
|
||||||
|
if (ret != n * 512)
|
||||||
return -1;
|
return -1;
|
||||||
if (m_data.valid) {
|
|
||||||
/* update L2 tables */
|
|
||||||
if (vmdk_L2update(bs, &m_data) == -1)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
nb_sectors -= n;
|
nb_sectors -= n;
|
||||||
sector_num += n;
|
sector_num += n;
|
||||||
buf += n * 512;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -692,7 +321,7 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
|||||||
int fd, i;
|
int fd, i;
|
||||||
VMDK4Header header;
|
VMDK4Header header;
|
||||||
uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
|
uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
|
||||||
static const char desc_template[] =
|
char *desc_template =
|
||||||
"# Disk DescriptorFile\n"
|
"# Disk DescriptorFile\n"
|
||||||
"version=1\n"
|
"version=1\n"
|
||||||
"CID=%x\n"
|
"CID=%x\n"
|
||||||
@@ -700,13 +329,13 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
|||||||
"createType=\"monolithicSparse\"\n"
|
"createType=\"monolithicSparse\"\n"
|
||||||
"\n"
|
"\n"
|
||||||
"# Extent description\n"
|
"# Extent description\n"
|
||||||
"RW %" PRId64 " SPARSE \"%s\"\n"
|
"RW %lu SPARSE \"%s\"\n"
|
||||||
"\n"
|
"\n"
|
||||||
"# The Disk Data Base \n"
|
"# The Disk Data Base \n"
|
||||||
"#DDB\n"
|
"#DDB\n"
|
||||||
"\n"
|
"\n"
|
||||||
"ddb.virtualHWVersion = \"%d\"\n"
|
"ddb.virtualHWVersion = \"3\"\n"
|
||||||
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
|
"ddb.geometry.cylinders = \"%lu\"\n"
|
||||||
"ddb.geometry.heads = \"16\"\n"
|
"ddb.geometry.heads = \"16\"\n"
|
||||||
"ddb.geometry.sectors = \"63\"\n"
|
"ddb.geometry.sectors = \"63\"\n"
|
||||||
"ddb.adapterType = \"ide\"\n";
|
"ddb.adapterType = \"ide\"\n";
|
||||||
@@ -714,9 +343,6 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
|||||||
const char *real_filename, *temp_str;
|
const char *real_filename, *temp_str;
|
||||||
|
|
||||||
/* XXX: add support for backing file */
|
/* 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,
|
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||||
0644);
|
0644);
|
||||||
@@ -781,10 +407,8 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
|||||||
real_filename = temp_str + 1;
|
real_filename = temp_str + 1;
|
||||||
if ((temp_str = strrchr(real_filename, ':')) != NULL)
|
if ((temp_str = strrchr(real_filename, ':')) != NULL)
|
||||||
real_filename = temp_str + 1;
|
real_filename = temp_str + 1;
|
||||||
snprintf(desc, sizeof(desc), desc_template, (unsigned int)time(NULL),
|
sprintf(desc, desc_template, time(NULL), (unsigned long)total_size,
|
||||||
total_size, real_filename,
|
real_filename, total_size / (63 * 16));
|
||||||
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
|
|
||||||
total_size / (int64_t)(63 * 16));
|
|
||||||
|
|
||||||
/* write the descriptor */
|
/* write the descriptor */
|
||||||
lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
|
lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
|
||||||
@@ -797,18 +421,15 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
|||||||
static void vmdk_close(BlockDriverState *bs)
|
static void vmdk_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
|
||||||
qemu_free(s->l1_table);
|
qemu_free(s->l1_table);
|
||||||
qemu_free(s->l2_cache);
|
qemu_free(s->l2_cache);
|
||||||
// try to close parent image, if exist
|
close(s->fd);
|
||||||
vmdk_parent_close(s->hd);
|
|
||||||
bdrv_delete(s->hd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vmdk_flush(BlockDriverState *bs)
|
static void vmdk_flush(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
bdrv_flush(s->hd);
|
fsync(s->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockDriver bdrv_vmdk = {
|
BlockDriver bdrv_vmdk = {
|
||||||
|
|||||||
515
block-vpc.c
515
block-vpc.c
@@ -2,7 +2,6 @@
|
|||||||
* Block driver for Conectix/Microsoft Virtual PC images
|
* Block driver for Conectix/Microsoft Virtual PC images
|
||||||
*
|
*
|
||||||
* Copyright (c) 2005 Alex Beregszaszi
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
|
|
||||||
/**************************************************************/
|
/**************************************************************/
|
||||||
@@ -31,96 +30,46 @@
|
|||||||
|
|
||||||
//#define CACHE
|
//#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
|
// always big-endian
|
||||||
struct vhd_footer {
|
struct vpc_subheader {
|
||||||
char creator[8]; // "conectix"
|
char magic[8]; // "conectix" / "cxsparse"
|
||||||
uint32_t features;
|
union {
|
||||||
uint32_t version;
|
struct {
|
||||||
|
uint32_t unk1[2];
|
||||||
// Offset of next header structure, 0xFFFFFFFF if none
|
uint32_t unk2; // always zero?
|
||||||
uint64_t data_offset;
|
uint32_t subheader_offset;
|
||||||
|
uint32_t unk3; // some size?
|
||||||
// Seconds since Jan 1, 2000 0:00:00 (UTC)
|
char creator[4]; // "vpc "
|
||||||
uint32_t timestamp;
|
|
||||||
|
|
||||||
char creator_app[4]; // "vpc "
|
|
||||||
uint16_t major;
|
uint16_t major;
|
||||||
uint16_t minor;
|
uint16_t minor;
|
||||||
char creator_os[4]; // "Wi2k"
|
char guest[4]; // "Wi2k"
|
||||||
|
uint32_t unk4[7];
|
||||||
uint64_t orig_size;
|
uint8_t vnet_id[16]; // virtual network id, purpose unknown
|
||||||
uint64_t size;
|
// next 16 longs are used, but dunno the purpose
|
||||||
|
// next 6 longs unknown, following 7 long maybe a serial
|
||||||
uint16_t cyls;
|
char padding[HEADER_SIZE - 84];
|
||||||
uint8_t heads;
|
} main;
|
||||||
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 {
|
struct {
|
||||||
uint32_t platform;
|
uint32_t unk1[2]; // all bits set
|
||||||
uint32_t data_space;
|
uint32_t unk2; // always zero?
|
||||||
uint32_t data_length;
|
uint32_t pagetable_offset;
|
||||||
uint32_t reserved;
|
uint32_t unk3;
|
||||||
uint64_t data_offset;
|
uint32_t pagetable_entries; // 32bit/entry
|
||||||
} parent_locator[8];
|
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 {
|
typedef struct BDRVVPCState {
|
||||||
BlockDriverState *hd;
|
int fd;
|
||||||
|
|
||||||
uint8_t footer_buf[HEADER_SIZE];
|
int pagetable_entries;
|
||||||
uint64_t free_data_block_offset;
|
|
||||||
int max_table_entries;
|
|
||||||
uint32_t *pagetable;
|
uint32_t *pagetable;
|
||||||
uint64_t bat_offset;
|
|
||||||
uint64_t last_bitmap_offset;
|
|
||||||
|
|
||||||
uint32_t block_size;
|
|
||||||
uint32_t bitmap_size;
|
|
||||||
|
|
||||||
|
uint32_t pageentry_size;
|
||||||
#ifdef CACHE
|
#ifdef CACHE
|
||||||
uint8_t *pageentry_u8;
|
uint8_t *pageentry_u8;
|
||||||
uint32_t *pageentry_u32;
|
uint32_t *pageentry_u32;
|
||||||
@@ -130,96 +79,63 @@ typedef struct BDRVVPCState {
|
|||||||
#endif
|
#endif
|
||||||
} BDRVVPCState;
|
} 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)
|
static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
{
|
{
|
||||||
if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
|
if (buf_size >= 8 && !strncmp(buf, "conectix", 8))
|
||||||
return 100;
|
return 100;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
|
static int vpc_open(BlockDriverState *bs, const char *filename)
|
||||||
{
|
{
|
||||||
BDRVVPCState *s = bs->opaque;
|
BDRVVPCState *s = bs->opaque;
|
||||||
int ret, i;
|
int fd, i;
|
||||||
struct vhd_footer* footer;
|
struct vpc_subheader header;
|
||||||
struct vhd_dyndisk_header* dyndisk_header;
|
|
||||||
uint8_t buf[HEADER_SIZE];
|
|
||||||
uint32_t checksum;
|
|
||||||
|
|
||||||
ret = bdrv_file_open(&s->hd, filename, flags);
|
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
|
||||||
if (ret < 0)
|
if (fd < 0) {
|
||||||
return ret;
|
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (bdrv_pread(s->hd, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
|
bs->read_only = 1; // no write support yet
|
||||||
|
|
||||||
|
s->fd = fd;
|
||||||
|
|
||||||
|
if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
footer = (struct vhd_footer*) s->footer_buf;
|
if (strncmp(header.magic, "conectix", 8))
|
||||||
if (strncmp(footer->creator, "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;
|
goto fail;
|
||||||
|
|
||||||
checksum = be32_to_cpu(footer->checksum);
|
if (strncmp(header.magic, "cxsparse", 8))
|
||||||
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;
|
goto fail;
|
||||||
|
|
||||||
dyndisk_header = (struct vhd_dyndisk_header*) buf;
|
bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) *
|
||||||
|
be32_to_cpu(header.type.sparse.pageentry_size)) / 512;
|
||||||
|
|
||||||
if (strncmp(dyndisk_header->magic, "cxsparse", 8))
|
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;
|
goto fail;
|
||||||
|
if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
|
||||||
|
s->pagetable_entries * 4)
|
||||||
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;
|
goto fail;
|
||||||
|
for (i = 0; i < s->pagetable_entries; i++)
|
||||||
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]);
|
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;
|
|
||||||
|
|
||||||
|
s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size);
|
||||||
#ifdef CACHE
|
#ifdef CACHE
|
||||||
s->pageentry_u8 = qemu_malloc(512);
|
s->pageentry_u8 = qemu_malloc(512);
|
||||||
|
if (!s->pageentry_u8)
|
||||||
|
goto fail;
|
||||||
s->pageentry_u32 = s->pageentry_u8;
|
s->pageentry_u32 = s->pageentry_u8;
|
||||||
s->pageentry_u16 = s->pageentry_u8;
|
s->pageentry_u16 = s->pageentry_u8;
|
||||||
s->last_pagetable = -1;
|
s->last_pagetable = -1;
|
||||||
@@ -227,46 +143,25 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
bdrv_delete(s->hd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||||
* 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;
|
BDRVVPCState *s = bs->opaque;
|
||||||
uint64_t offset = sector_num * 512;
|
uint64_t offset = sector_num * 512;
|
||||||
uint64_t bitmap_offset, block_offset;
|
uint64_t bitmap_offset, block_offset;
|
||||||
uint32_t pagetable_index, pageentry_index;
|
uint32_t pagetable_index, pageentry_index;
|
||||||
|
|
||||||
pagetable_index = offset / s->block_size;
|
pagetable_index = offset / s->pageentry_size;
|
||||||
pageentry_index = (offset % s->block_size) / 512;
|
pageentry_index = (offset % s->pageentry_size) / 512;
|
||||||
|
|
||||||
if (pagetable_index >= s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
|
if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
|
||||||
return -1; // not allocated
|
return -1; // not allocated
|
||||||
|
|
||||||
bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index];
|
bitmap_offset = 512 * s->pagetable[pagetable_index];
|
||||||
block_offset = bitmap_offset + s->bitmap_size + (512 * pageentry_index);
|
block_offset = bitmap_offset + 512 + (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",
|
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
|
||||||
// sector_num, pagetable_index, pageentry_index,
|
// sector_num, pagetable_index, pageentry_index,
|
||||||
@@ -299,97 +194,26 @@ static inline int64_t get_sector_offset(BlockDriverState *bs,
|
|||||||
return -1; // not allocated
|
return -1; // not allocated
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
lseek(s->fd, block_offset, SEEK_SET);
|
||||||
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;
|
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,
|
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
uint8_t *buf, int nb_sectors)
|
uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
BDRVVPCState *s = bs->opaque;
|
BDRVVPCState *s = bs->opaque;
|
||||||
int ret;
|
int ret;
|
||||||
int64_t offset;
|
|
||||||
|
|
||||||
while (nb_sectors > 0) {
|
while (nb_sectors > 0) {
|
||||||
offset = get_sector_offset(bs, sector_num, 0);
|
if (!seek_to_sector(bs, sector_num))
|
||||||
|
{
|
||||||
if (offset == -1) {
|
ret = read(s->fd, buf, 512);
|
||||||
|
if (ret != 512)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
memset(buf, 0, 512);
|
memset(buf, 0, 512);
|
||||||
} else {
|
|
||||||
ret = bdrv_pread(s->hd, offset, buf, 512);
|
|
||||||
if (ret != 512)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
nb_sectors--;
|
nb_sectors--;
|
||||||
sector_num++;
|
sector_num++;
|
||||||
buf += 512;
|
buf += 512;
|
||||||
@@ -397,180 +221,6 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
return 0;
|
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.
|
|
||||||
*/
|
|
||||||
static void 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)
|
|
||||||
total_sectors = 65535 * 16 * 255;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vpc_create(const char *filename, int64_t total_sectors,
|
|
||||||
const char *backing_file, int flags)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (backing_file != NULL)
|
|
||||||
return -ENOTSUP;
|
|
||||||
|
|
||||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
|
|
||||||
if (fd < 0)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
// Calculate matching total_size and geometry
|
|
||||||
calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl);
|
|
||||||
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)
|
static void vpc_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVVPCState *s = bs->opaque;
|
BDRVVPCState *s = bs->opaque;
|
||||||
@@ -578,7 +228,7 @@ static void vpc_close(BlockDriverState *bs)
|
|||||||
#ifdef CACHE
|
#ifdef CACHE
|
||||||
qemu_free(s->pageentry_u8);
|
qemu_free(s->pageentry_u8);
|
||||||
#endif
|
#endif
|
||||||
bdrv_delete(s->hd);
|
close(s->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockDriver bdrv_vpc = {
|
BlockDriver bdrv_vpc = {
|
||||||
@@ -587,7 +237,6 @@ BlockDriver bdrv_vpc = {
|
|||||||
vpc_probe,
|
vpc_probe,
|
||||||
vpc_open,
|
vpc_open,
|
||||||
vpc_read,
|
vpc_read,
|
||||||
vpc_write,
|
NULL,
|
||||||
vpc_close,
|
vpc_close,
|
||||||
vpc_create,
|
|
||||||
};
|
};
|
||||||
|
|||||||
234
block-vvfat.c
234
block-vvfat.c
@@ -25,7 +25,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "qemu-common.h"
|
#include "vl.h"
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
|
|
||||||
#ifndef S_IWGRP
|
#ifndef S_IWGRP
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
#define stderr STDERR
|
#define stderr STDERR
|
||||||
FILE* stderr = NULL;
|
FILE* stderr = NULL;
|
||||||
|
|
||||||
static void checkpoint(void);
|
static void checkpoint();
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
void nonono(const char* file, int line, const char* msg) {
|
void nonono(const char* file, int line, const char* msg) {
|
||||||
@@ -61,7 +61,7 @@ void nonono(const char* file, int line, const char* msg) {
|
|||||||
exit(-5);
|
exit(-5);
|
||||||
}
|
}
|
||||||
#undef assert
|
#undef assert
|
||||||
#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
|
#define assert(a) if (!(a)) nonono(__FILE__, __LINE__, #a)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -93,6 +93,7 @@ static inline void array_free(array_t* array)
|
|||||||
|
|
||||||
/* does not automatically grow */
|
/* does not automatically grow */
|
||||||
static inline void* array_get(array_t* array,unsigned int index) {
|
static inline void* array_get(array_t* array,unsigned int index) {
|
||||||
|
assert(index >= 0);
|
||||||
assert(index < array->next);
|
assert(index < array->next);
|
||||||
return array->pointer + index * array->item_size;
|
return array->pointer + index * array->item_size;
|
||||||
}
|
}
|
||||||
@@ -101,7 +102,7 @@ static inline int array_ensure_allocated(array_t* array, int index)
|
|||||||
{
|
{
|
||||||
if((index + 1) * array->item_size > array->size) {
|
if((index + 1) * array->item_size > array->size) {
|
||||||
int new_size = (index + 32) * array->item_size;
|
int new_size = (index + 32) * array->item_size;
|
||||||
array->pointer = qemu_realloc(array->pointer, new_size);
|
array->pointer = realloc(array->pointer, new_size);
|
||||||
if (!array->pointer)
|
if (!array->pointer)
|
||||||
return -1;
|
return -1;
|
||||||
array->size = new_size;
|
array->size = new_size;
|
||||||
@@ -127,7 +128,7 @@ static inline void* array_get_next(array_t* array) {
|
|||||||
static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
|
static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
|
||||||
if((array->next+count)*array->item_size>array->size) {
|
if((array->next+count)*array->item_size>array->size) {
|
||||||
int increment=count*array->item_size;
|
int increment=count*array->item_size;
|
||||||
array->pointer=qemu_realloc(array->pointer,array->size+increment);
|
array->pointer=realloc(array->pointer,array->size+increment);
|
||||||
if(!array->pointer)
|
if(!array->pointer)
|
||||||
return 0;
|
return 0;
|
||||||
array->size+=increment;
|
array->size+=increment;
|
||||||
@@ -159,7 +160,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
|
|||||||
is=array->item_size;
|
is=array->item_size;
|
||||||
from=array->pointer+index_from*is;
|
from=array->pointer+index_from*is;
|
||||||
to=array->pointer+index_to*is;
|
to=array->pointer+index_to*is;
|
||||||
buf=qemu_malloc(is*count);
|
buf=malloc(is*count);
|
||||||
memcpy(buf,from,is*count);
|
memcpy(buf,from,is*count);
|
||||||
|
|
||||||
if(index_to<index_from)
|
if(index_to<index_from)
|
||||||
@@ -174,7 +175,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int array_remove_slice(array_t* array,int index, int count)
|
inline int array_remove_slice(array_t* array,int index, int count)
|
||||||
{
|
{
|
||||||
assert(index >=0);
|
assert(index >=0);
|
||||||
assert(count > 0);
|
assert(count > 0);
|
||||||
@@ -185,15 +186,16 @@ static inline int array_remove_slice(array_t* array,int index, int count)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int array_remove(array_t* array,int index)
|
int array_remove(array_t* array,int index)
|
||||||
{
|
{
|
||||||
return array_remove_slice(array, index, 1);
|
return array_remove_slice(array, index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return the index for a given member */
|
/* return the index for a given member */
|
||||||
static int array_index(array_t* array, void* pointer)
|
int array_index(array_t* array, void* pointer)
|
||||||
{
|
{
|
||||||
size_t offset = (char*)pointer - array->pointer;
|
size_t offset = (char*)pointer - array->pointer;
|
||||||
|
assert(offset >= 0);
|
||||||
assert((offset % array->item_size) == 0);
|
assert((offset % array->item_size) == 0);
|
||||||
assert(offset/array->item_size < array->next);
|
assert(offset/array->item_size < array->next);
|
||||||
return offset/array->item_size;
|
return offset/array->item_size;
|
||||||
@@ -240,25 +242,21 @@ typedef struct bootsector_t {
|
|||||||
uint8_t magic[2];
|
uint8_t magic[2];
|
||||||
} __attribute__((packed)) bootsector_t;
|
} __attribute__((packed)) bootsector_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t head;
|
|
||||||
uint8_t sector;
|
|
||||||
uint8_t cylinder;
|
|
||||||
} mbr_chs_t;
|
|
||||||
|
|
||||||
typedef struct partition_t {
|
typedef struct partition_t {
|
||||||
uint8_t attributes; /* 0x80 = bootable */
|
uint8_t attributes; /* 0x80 = bootable */
|
||||||
mbr_chs_t start_CHS;
|
uint8_t start_head;
|
||||||
uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
|
uint8_t start_sector;
|
||||||
mbr_chs_t end_CHS;
|
uint8_t start_cylinder;
|
||||||
|
uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
|
||||||
|
uint8_t end_head;
|
||||||
|
uint8_t end_sector;
|
||||||
|
uint8_t end_cylinder;
|
||||||
uint32_t start_sector_long;
|
uint32_t start_sector_long;
|
||||||
uint32_t length_sector_long;
|
uint32_t end_sector_long;
|
||||||
} __attribute__((packed)) partition_t;
|
} __attribute__((packed)) partition_t;
|
||||||
|
|
||||||
typedef struct mbr_t {
|
typedef struct mbr_t {
|
||||||
uint8_t ignored[0x1b8];
|
uint8_t ignored[0x1be];
|
||||||
uint32_t nt_id;
|
|
||||||
uint8_t ignored2[2];
|
|
||||||
partition_t partition[4];
|
partition_t partition[4];
|
||||||
uint8_t magic[2];
|
uint8_t magic[2];
|
||||||
} __attribute__((packed)) mbr_t;
|
} __attribute__((packed)) mbr_t;
|
||||||
@@ -352,26 +350,11 @@ typedef struct BDRVVVFATState {
|
|||||||
int downcase_short_names;
|
int downcase_short_names;
|
||||||
} BDRVVVFATState;
|
} BDRVVVFATState;
|
||||||
|
|
||||||
/* take the sector position spos and convert it to Cylinder/Head/Sector position
|
|
||||||
* if the position is outside the specified geometry, fill maximum value for CHS
|
static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
* and return 1 to signal overflow.
|
{
|
||||||
*/
|
if (strstart(filename, "fat:", NULL))
|
||||||
static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
|
return 100;
|
||||||
int head,sector;
|
|
||||||
sector = spos % (bs->secs); spos/= bs->secs;
|
|
||||||
head = spos % (bs->heads); spos/= bs->heads;
|
|
||||||
if(spos >= bs->cyls){
|
|
||||||
/* Overflow,
|
|
||||||
it happens if 32bit sector positions are used, while CHS is only 24bit.
|
|
||||||
Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
|
|
||||||
chs->head = 0xFF;
|
|
||||||
chs->sector = 0xFF;
|
|
||||||
chs->cylinder = 0xFF;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
chs->head = (uint8_t)head;
|
|
||||||
chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
|
|
||||||
chs->cylinder = (uint8_t)spos;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,29 +363,20 @@ static void init_mbr(BDRVVVFATState* s)
|
|||||||
/* TODO: if the files mbr.img and bootsect.img exist, use them */
|
/* TODO: if the files mbr.img and bootsect.img exist, use them */
|
||||||
mbr_t* real_mbr=(mbr_t*)s->first_sectors;
|
mbr_t* real_mbr=(mbr_t*)s->first_sectors;
|
||||||
partition_t* partition=&(real_mbr->partition[0]);
|
partition_t* partition=&(real_mbr->partition[0]);
|
||||||
int lba;
|
|
||||||
|
|
||||||
memset(s->first_sectors,0,512);
|
memset(s->first_sectors,0,512);
|
||||||
|
|
||||||
/* Win NT Disk Signature */
|
|
||||||
real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
|
|
||||||
|
|
||||||
partition->attributes=0x80; /* bootable */
|
partition->attributes=0x80; /* bootable */
|
||||||
|
partition->start_head=1;
|
||||||
/* LBA is used when partition is outside the CHS geometry */
|
partition->start_sector=1;
|
||||||
lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
|
partition->start_cylinder=0;
|
||||||
lba|= sector2CHS(s->bs, &partition->end_CHS, s->sector_count);
|
|
||||||
|
|
||||||
/*LBA partitions are identified only by start/length_sector_long not by CHS*/
|
|
||||||
partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
|
|
||||||
partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
|
|
||||||
|
|
||||||
/* FAT12/FAT16/FAT32 */
|
/* FAT12/FAT16/FAT32 */
|
||||||
/* DOS uses different types when partition is LBA,
|
partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
|
||||||
probably to prevent older versions from using CHS on them */
|
partition->end_head=s->bs->heads-1;
|
||||||
partition->fs_type= s->fat_type==12 ? 0x1:
|
partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
|
||||||
s->fat_type==16 ? (lba?0xe:0x06):
|
partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
|
||||||
/*fat_tyoe==32*/ (lba?0xc:0x0b);
|
partition->start_sector_long=cpu_to_le32(s->bs->secs);
|
||||||
|
partition->end_sector_long=cpu_to_le32(s->sector_count);
|
||||||
|
|
||||||
real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
|
real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
|
||||||
}
|
}
|
||||||
@@ -410,19 +384,17 @@ static void init_mbr(BDRVVVFATState* s)
|
|||||||
/* direntry functions */
|
/* direntry functions */
|
||||||
|
|
||||||
/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
|
/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
|
||||||
static inline int short2long_name(char* dest,const char* src)
|
static inline int short2long_name(unsigned char* dest,const char* src)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int len;
|
|
||||||
for(i=0;i<129 && src[i];i++) {
|
for(i=0;i<129 && src[i];i++) {
|
||||||
dest[2*i]=src[i];
|
dest[2*i]=src[i];
|
||||||
dest[2*i+1]=0;
|
dest[2*i+1]=0;
|
||||||
}
|
}
|
||||||
len=2*i;
|
|
||||||
dest[2*i]=dest[2*i+1]=0;
|
dest[2*i]=dest[2*i+1]=0;
|
||||||
for(i=2*i+2;(i%26);i++)
|
for(i=2*i+2;(i%26);i++)
|
||||||
dest[i]=0xff;
|
dest[i]=0xff;
|
||||||
return len;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
|
static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
|
||||||
@@ -439,7 +411,7 @@ static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* fil
|
|||||||
entry->begin=0;
|
entry->begin=0;
|
||||||
entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
|
entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
|
||||||
}
|
}
|
||||||
for(i=0;i<26*number_of_entries;i++) {
|
for(i=0;i<length;i++) {
|
||||||
int offset=(i%26);
|
int offset=(i%26);
|
||||||
if(offset<10) offset=1+offset;
|
if(offset<10) offset=1+offset;
|
||||||
else if(offset<22) offset=14+offset-10;
|
else if(offset<22) offset=14+offset-10;
|
||||||
@@ -452,7 +424,8 @@ static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* fil
|
|||||||
|
|
||||||
static char is_free(const direntry_t* direntry)
|
static char is_free(const direntry_t* direntry)
|
||||||
{
|
{
|
||||||
return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
|
/* return direntry->name[0]==0 ; */
|
||||||
|
return direntry->attributes == 0 || direntry->name[0]==0xe5;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char is_volume_label(const direntry_t* direntry)
|
static char is_volume_label(const direntry_t* direntry)
|
||||||
@@ -564,7 +537,7 @@ static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
|
|||||||
uint16_t* entry=array_get(&(s->fat),cluster);
|
uint16_t* entry=array_get(&(s->fat),cluster);
|
||||||
return le16_to_cpu(*entry);
|
return le16_to_cpu(*entry);
|
||||||
} else {
|
} else {
|
||||||
const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
|
const uint8_t* x=s->fat.pointer+cluster*3/2;
|
||||||
return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
|
return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -625,7 +598,7 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
|
|||||||
|
|
||||||
entry=array_get_next(&(s->directory));
|
entry=array_get_next(&(s->directory));
|
||||||
memset(entry->name,0x20,11);
|
memset(entry->name,0x20,11);
|
||||||
memcpy(entry->name, filename, i);
|
strncpy(entry->name,filename,i);
|
||||||
|
|
||||||
if(j > 0)
|
if(j > 0)
|
||||||
for (i = 0; i < 3 && filename[j+1+i]; i++)
|
for (i = 0; i < 3 && filename[j+1+i]; i++)
|
||||||
@@ -725,7 +698,8 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
|
|||||||
if(first_cluster == 0 && (is_dotdot || is_dot))
|
if(first_cluster == 0 && (is_dotdot || is_dot))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
buffer=(char*)qemu_malloc(length);
|
buffer=(char*)malloc(length);
|
||||||
|
assert(buffer);
|
||||||
snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
|
snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
|
||||||
|
|
||||||
if(stat(buffer,&st)<0) {
|
if(stat(buffer,&st)<0) {
|
||||||
@@ -846,7 +820,8 @@ static int init_directories(BDRVVVFATState* s,
|
|||||||
memset(&(s->first_sectors[0]),0,0x40*0x200);
|
memset(&(s->first_sectors[0]),0,0x40*0x200);
|
||||||
|
|
||||||
s->cluster_size=s->sectors_per_cluster*0x200;
|
s->cluster_size=s->sectors_per_cluster*0x200;
|
||||||
s->cluster_buffer=qemu_malloc(s->cluster_size);
|
s->cluster_buffer=malloc(s->cluster_size);
|
||||||
|
assert(s->cluster_buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The formula: sc = spf+1+spf*spc*(512*8/fat_type),
|
* The formula: sc = spf+1+spf*spc*(512*8/fat_type),
|
||||||
@@ -865,7 +840,7 @@ static int init_directories(BDRVVVFATState* s,
|
|||||||
{
|
{
|
||||||
direntry_t* entry=array_get_next(&(s->directory));
|
direntry_t* entry=array_get_next(&(s->directory));
|
||||||
entry->attributes=0x28; /* archive | volume label */
|
entry->attributes=0x28; /* archive | volume label */
|
||||||
snprintf((char*)entry->name,11,"QEMU VVFAT");
|
snprintf(entry->name,11,"QEMU VVFAT");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now build FAT, and write back information into directory */
|
/* Now build FAT, and write back information into directory */
|
||||||
@@ -888,6 +863,7 @@ static int init_directories(BDRVVVFATState* s,
|
|||||||
s->path = mapping->path;
|
s->path = mapping->path;
|
||||||
|
|
||||||
for (i = 0, cluster = 0; i < s->mapping.next; i++) {
|
for (i = 0, cluster = 0; i < s->mapping.next; i++) {
|
||||||
|
int j;
|
||||||
/* MS-DOS expects the FAT to be 0 for the root directory
|
/* MS-DOS expects the FAT to be 0 for the root directory
|
||||||
* (except for the media byte). */
|
* (except for the media byte). */
|
||||||
/* LATER TODO: still true for FAT32? */
|
/* LATER TODO: still true for FAT32? */
|
||||||
@@ -920,24 +896,19 @@ static int init_directories(BDRVVVFATState* s,
|
|||||||
|
|
||||||
assert(mapping->begin < mapping->end);
|
assert(mapping->begin < mapping->end);
|
||||||
|
|
||||||
|
/* fix fat for entry */
|
||||||
|
if (fix_fat) {
|
||||||
|
for(j = mapping->begin; j < mapping->end - 1; j++)
|
||||||
|
fat_set(s, j, j+1);
|
||||||
|
fat_set(s, mapping->end - 1, s->max_fat_value);
|
||||||
|
}
|
||||||
|
|
||||||
/* next free cluster */
|
/* next free cluster */
|
||||||
cluster = mapping->end;
|
cluster = mapping->end;
|
||||||
|
|
||||||
if(cluster > s->cluster_count) {
|
if(cluster > s->cluster_count) {
|
||||||
fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
|
fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
|
||||||
s->fat_type,
|
return -1;
|
||||||
s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
|
|
||||||
: "2.88 MB"
|
|
||||||
: "504MB");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fix fat for entry */
|
|
||||||
if (fix_fat) {
|
|
||||||
int j;
|
|
||||||
for(j = mapping->begin; j < mapping->end - 1; j++)
|
|
||||||
fat_set(s, j, j+1);
|
|
||||||
fat_set(s, mapping->end - 1, s->max_fat_value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -983,22 +954,18 @@ static int init_directories(BDRVVVFATState* s,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
static BDRVVVFATState *vvv = NULL;
|
static BDRVVVFATState *vvv = NULL;
|
||||||
#endif
|
|
||||||
|
|
||||||
static int enable_write_target(BDRVVVFATState *s);
|
static int enable_write_target(BDRVVVFATState *s);
|
||||||
static int is_consistent(BDRVVVFATState *s);
|
static int is_consistent(BDRVVVFATState *s);
|
||||||
|
|
||||||
static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
|
static int vvfat_open(BlockDriverState *bs, const char* dirname)
|
||||||
{
|
{
|
||||||
BDRVVVFATState *s = bs->opaque;
|
BDRVVVFATState *s = bs->opaque;
|
||||||
int floppy = 0;
|
int floppy = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
vvv = s;
|
vvv = s;
|
||||||
#endif
|
|
||||||
|
|
||||||
DLOG(if (stderr == NULL) {
|
DLOG(if (stderr == NULL) {
|
||||||
stderr = fopen("vvfat.log", "a");
|
stderr = fopen("vvfat.log", "a");
|
||||||
@@ -1009,9 +976,10 @@ DLOG(if (stderr == NULL) {
|
|||||||
|
|
||||||
s->fat_type=16;
|
s->fat_type=16;
|
||||||
/* LATER TODO: if FAT32, adjust */
|
/* LATER TODO: if FAT32, adjust */
|
||||||
|
s->sector_count=0xec04f;
|
||||||
s->sectors_per_cluster=0x10;
|
s->sectors_per_cluster=0x10;
|
||||||
/* 504MB disk*/
|
/* LATER TODO: this could be wrong for FAT32 */
|
||||||
bs->cyls=1024; bs->heads=16; bs->secs=63;
|
bs->cyls=1023; bs->heads=15; bs->secs=63;
|
||||||
|
|
||||||
s->current_cluster=0xffffffff;
|
s->current_cluster=0xffffffff;
|
||||||
|
|
||||||
@@ -1026,6 +994,12 @@ DLOG(if (stderr == NULL) {
|
|||||||
if (!strstart(dirname, "fat:", NULL))
|
if (!strstart(dirname, "fat:", NULL))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (strstr(dirname, ":rw:")) {
|
||||||
|
if (enable_write_target(s))
|
||||||
|
return -1;
|
||||||
|
bs->read_only = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (strstr(dirname, ":floppy:")) {
|
if (strstr(dirname, ":floppy:")) {
|
||||||
floppy = 1;
|
floppy = 1;
|
||||||
s->fat_type = 12;
|
s->fat_type = 12;
|
||||||
@@ -1034,8 +1008,6 @@ DLOG(if (stderr == NULL) {
|
|||||||
bs->cyls = 80; bs->heads = 2; bs->secs = 36;
|
bs->cyls = 80; bs->heads = 2; bs->secs = 36;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->sector_count=bs->cyls*bs->heads*bs->secs;
|
|
||||||
|
|
||||||
if (strstr(dirname, ":32:")) {
|
if (strstr(dirname, ":32:")) {
|
||||||
fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
|
fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
|
||||||
s->fat_type = 32;
|
s->fat_type = 32;
|
||||||
@@ -1046,27 +1018,20 @@ DLOG(if (stderr == NULL) {
|
|||||||
s->sector_count=2880;
|
s->sector_count=2880;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strstr(dirname, ":rw:")) {
|
|
||||||
if (enable_write_target(s))
|
|
||||||
return -1;
|
|
||||||
bs->read_only = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = strrchr(dirname, ':') - dirname;
|
i = strrchr(dirname, ':') - dirname;
|
||||||
assert(i >= 3);
|
assert(i >= 3);
|
||||||
if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
|
if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
|
||||||
/* workaround for DOS drive names */
|
/* workaround for DOS drive names */
|
||||||
dirname += i-1;
|
dirname += i-1;
|
||||||
else
|
else
|
||||||
dirname += i+1;
|
dirname += i+1;
|
||||||
|
|
||||||
bs->total_sectors=bs->cyls*bs->heads*bs->secs;
|
bs->total_sectors=bs->cyls*bs->heads*bs->secs;
|
||||||
|
if (s->sector_count > bs->total_sectors)
|
||||||
|
s->sector_count = bs->total_sectors;
|
||||||
if(init_directories(s, dirname))
|
if(init_directories(s, dirname))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
|
|
||||||
|
|
||||||
if(s->first_sectors_number==0x40)
|
if(s->first_sectors_number==0x40)
|
||||||
init_mbr(s);
|
init_mbr(s);
|
||||||
|
|
||||||
@@ -1075,6 +1040,7 @@ DLOG(if (stderr == NULL) {
|
|||||||
bs->heads = bs->cyls = bs->secs = 0;
|
bs->heads = bs->cyls = bs->secs = 0;
|
||||||
|
|
||||||
// assert(is_consistent(s));
|
// assert(is_consistent(s));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1188,7 +1154,7 @@ static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
|
|||||||
s->current_mapping = mapping;
|
s->current_mapping = mapping;
|
||||||
read_cluster_directory:
|
read_cluster_directory:
|
||||||
offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
|
offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
|
||||||
s->cluster = (unsigned char*)s->directory.pointer+offset
|
s->cluster = s->directory.pointer+offset
|
||||||
+ 0x20*s->current_mapping->info.dir.first_dir_index;
|
+ 0x20*s->current_mapping->info.dir.first_dir_index;
|
||||||
assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
|
assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
|
||||||
assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
|
assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
|
||||||
@@ -1247,7 +1213,7 @@ static void print_direntry(const direntry_t* direntry)
|
|||||||
unsigned char* c=(unsigned char*)direntry;
|
unsigned char* c=(unsigned char*)direntry;
|
||||||
int i;
|
int i;
|
||||||
for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
|
for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
|
||||||
#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
|
#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '<27>'; j++;}
|
||||||
ADD_CHAR(c[i]);
|
ADD_CHAR(c[i]);
|
||||||
for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
|
for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
|
||||||
ADD_CHAR(c[i]);
|
ADD_CHAR(c[i]);
|
||||||
@@ -1410,12 +1376,7 @@ static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/*
|
unsigned char name[1024];
|
||||||
* Since the sequence number is at most 0x3f, and the filename
|
|
||||||
* length is at most 13 times the sequence number, the maximal
|
|
||||||
* filename length is 0x3f * 13 bytes.
|
|
||||||
*/
|
|
||||||
unsigned char name[0x3f * 13 + 1];
|
|
||||||
int checksum, len;
|
int checksum, len;
|
||||||
int sequence_number;
|
int sequence_number;
|
||||||
} long_file_name;
|
} long_file_name;
|
||||||
@@ -1440,7 +1401,6 @@ static int parse_long_name(long_file_name* lfn,
|
|||||||
lfn->sequence_number = pointer[0] & 0x3f;
|
lfn->sequence_number = pointer[0] & 0x3f;
|
||||||
lfn->checksum = pointer[13];
|
lfn->checksum = pointer[13];
|
||||||
lfn->name[0] = 0;
|
lfn->name[0] = 0;
|
||||||
lfn->name[lfn->sequence_number * 13] = 0;
|
|
||||||
} else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
|
} else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
|
||||||
return -1;
|
return -1;
|
||||||
else if (pointer[13] != lfn->checksum)
|
else if (pointer[13] != lfn->checksum)
|
||||||
@@ -1464,7 +1424,7 @@ static int parse_long_name(long_file_name* lfn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pointer[0] & 0x40)
|
if (pointer[0] & 0x40)
|
||||||
lfn->len = offset + strlen((char*)lfn->name + offset);
|
lfn->len = offset + strlen(lfn->name + offset);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1483,7 +1443,7 @@ static int parse_short_name(BDRVVVFATState* s,
|
|||||||
if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
|
if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
|
||||||
return -1;
|
return -1;
|
||||||
else if (s->downcase_short_names)
|
else if (s->downcase_short_names)
|
||||||
lfn->name[i] = qemu_tolower(direntry->name[i]);
|
lfn->name[i] = tolower(direntry->name[i]);
|
||||||
else
|
else
|
||||||
lfn->name[i] = direntry->name[i];
|
lfn->name[i] = direntry->name[i];
|
||||||
}
|
}
|
||||||
@@ -1496,14 +1456,14 @@ static int parse_short_name(BDRVVVFATState* s,
|
|||||||
if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
|
if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
|
||||||
return -2;
|
return -2;
|
||||||
else if (s->downcase_short_names)
|
else if (s->downcase_short_names)
|
||||||
lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
|
lfn->name[i + j] = tolower(direntry->extension[j]);
|
||||||
else
|
else
|
||||||
lfn->name[i + j] = direntry->extension[j];
|
lfn->name[i + j] = direntry->extension[j];
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
lfn->name[i + j + 1] = '\0';
|
lfn->name[i + j + 1] = '\0';
|
||||||
|
|
||||||
lfn->len = strlen((char*)lfn->name);
|
lfn->len = strlen(lfn->name);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1726,7 +1686,7 @@ static int check_directory_consistency(BDRVVVFATState *s,
|
|||||||
int cluster_num, const char* path)
|
int cluster_num, const char* path)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned char* cluster = qemu_malloc(s->cluster_size);
|
unsigned char* cluster = malloc(s->cluster_size);
|
||||||
direntry_t* direntries = (direntry_t*)cluster;
|
direntry_t* direntries = (direntry_t*)cluster;
|
||||||
mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
|
mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
|
||||||
|
|
||||||
@@ -1735,7 +1695,7 @@ static int check_directory_consistency(BDRVVVFATState *s,
|
|||||||
char path2[PATH_MAX];
|
char path2[PATH_MAX];
|
||||||
|
|
||||||
assert(path_len < PATH_MAX); /* len was tested before! */
|
assert(path_len < PATH_MAX); /* len was tested before! */
|
||||||
pstrcpy(path2, sizeof(path2), path);
|
strcpy(path2, path);
|
||||||
path2[path_len] = '/';
|
path2[path_len] = '/';
|
||||||
path2[path_len + 1] = '\0';
|
path2[path_len + 1] = '\0';
|
||||||
|
|
||||||
@@ -1799,8 +1759,8 @@ DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i)
|
|||||||
fprintf(stderr, "Error in short name (%d)\n", subret);
|
fprintf(stderr, "Error in short name (%d)\n", subret);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (subret > 0 || !strcmp((char*)lfn.name, ".")
|
if (subret > 0 || !strcmp(lfn.name, ".")
|
||||||
|| !strcmp((char*)lfn.name, ".."))
|
|| !strcmp(lfn.name, ".."))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
lfn.checksum = 0x100; /* cannot use long name twice */
|
lfn.checksum = 0x100; /* cannot use long name twice */
|
||||||
@@ -1809,8 +1769,7 @@ DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i)
|
|||||||
fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
|
fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
|
strcpy(path2 + path_len + 1, lfn.name);
|
||||||
(char*)lfn.name);
|
|
||||||
|
|
||||||
if (is_directory(direntries + i)) {
|
if (is_directory(direntries + i)) {
|
||||||
if (begin_of_direntry(direntries + i) == 0) {
|
if (begin_of_direntry(direntries + i) == 0) {
|
||||||
@@ -1867,7 +1826,7 @@ DLOG(checkpoint());
|
|||||||
*/
|
*/
|
||||||
if (s->fat2 == NULL) {
|
if (s->fat2 == NULL) {
|
||||||
int size = 0x200 * s->sectors_per_fat;
|
int size = 0x200 * s->sectors_per_fat;
|
||||||
s->fat2 = qemu_malloc(size);
|
s->fat2 = malloc(size);
|
||||||
memcpy(s->fat2, s->fat.pointer, size);
|
memcpy(s->fat2, s->fat.pointer, size);
|
||||||
}
|
}
|
||||||
check = vvfat_read(s->bs,
|
check = vvfat_read(s->bs,
|
||||||
@@ -2209,7 +2168,7 @@ static int commit_one_file(BDRVVVFATState* s,
|
|||||||
uint32_t first_cluster = c;
|
uint32_t first_cluster = c;
|
||||||
mapping_t* mapping = find_mapping_for_cluster(s, c);
|
mapping_t* mapping = find_mapping_for_cluster(s, c);
|
||||||
uint32_t size = filesize_of_direntry(direntry);
|
uint32_t size = filesize_of_direntry(direntry);
|
||||||
char* cluster = qemu_malloc(s->cluster_size);
|
char* cluster = malloc(s->cluster_size);
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
int fd = 0;
|
int fd = 0;
|
||||||
|
|
||||||
@@ -2219,7 +2178,7 @@ static int commit_one_file(BDRVVVFATState* s,
|
|||||||
for (i = s->cluster_size; i < offset; i += s->cluster_size)
|
for (i = s->cluster_size; i < offset; i += s->cluster_size)
|
||||||
c = modified_fat_get(s, c);
|
c = modified_fat_get(s, c);
|
||||||
|
|
||||||
fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
|
fd = open(mapping->path, O_RDWR | O_CREAT, 0666);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
|
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
|
||||||
strerror(errno), errno);
|
strerror(errno), errno);
|
||||||
@@ -2239,9 +2198,10 @@ static int commit_one_file(BDRVVVFATState* s,
|
|||||||
|
|
||||||
assert((size - offset == 0 && fat_eof(s, c)) ||
|
assert((size - offset == 0 && fat_eof(s, c)) ||
|
||||||
(size > offset && c >=2 && !fat_eof(s, c)));
|
(size > offset && c >=2 && !fat_eof(s, c)));
|
||||||
|
assert(size >= 0);
|
||||||
|
|
||||||
ret = vvfat_read(s->bs, cluster2sector(s, c),
|
ret = vvfat_read(s->bs, cluster2sector(s, c),
|
||||||
(uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
|
cluster, (rest_size + 0x1ff) / 0x200);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -2371,13 +2331,12 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
|
|||||||
mapping_t* m = find_mapping_for_cluster(s,
|
mapping_t* m = find_mapping_for_cluster(s,
|
||||||
begin_of_direntry(d));
|
begin_of_direntry(d));
|
||||||
int l = strlen(m->path);
|
int l = strlen(m->path);
|
||||||
char* new_path = qemu_malloc(l + diff + 1);
|
char* new_path = malloc(l + diff + 1);
|
||||||
|
|
||||||
assert(!strncmp(m->path, mapping->path, l2));
|
assert(!strncmp(m->path, mapping->path, l2));
|
||||||
|
|
||||||
pstrcpy(new_path, l + diff + 1, mapping->path);
|
strcpy(new_path, mapping->path);
|
||||||
pstrcpy(new_path + l1, l + diff + 1 - l1,
|
strcpy(new_path + l1, m->path + l2);
|
||||||
m->path + l2);
|
|
||||||
|
|
||||||
schedule_rename(s, m->begin, new_path);
|
schedule_rename(s, m->begin, new_path);
|
||||||
}
|
}
|
||||||
@@ -2772,8 +2731,9 @@ static int enable_write_target(BDRVVVFATState *s)
|
|||||||
|
|
||||||
array_init(&(s->commits), sizeof(commit_t));
|
array_init(&(s->commits), sizeof(commit_t));
|
||||||
|
|
||||||
s->qcow_filename = qemu_malloc(1024);
|
s->qcow_filename = malloc(1024);
|
||||||
get_tmp_filename(s->qcow_filename, 1024);
|
strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
|
||||||
|
get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
|
||||||
if (bdrv_create(&bdrv_qcow,
|
if (bdrv_create(&bdrv_qcow,
|
||||||
s->qcow_filename, s->sector_count, "fat:", 0) < 0)
|
s->qcow_filename, s->sector_count, "fat:", 0) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -2807,19 +2767,18 @@ static void vvfat_close(BlockDriverState *bs)
|
|||||||
BlockDriver bdrv_vvfat = {
|
BlockDriver bdrv_vvfat = {
|
||||||
"vvfat",
|
"vvfat",
|
||||||
sizeof(BDRVVVFATState),
|
sizeof(BDRVVVFATState),
|
||||||
NULL, /* no probe for protocols */
|
vvfat_probe,
|
||||||
vvfat_open,
|
vvfat_open,
|
||||||
vvfat_read,
|
vvfat_read,
|
||||||
vvfat_write,
|
vvfat_write,
|
||||||
vvfat_close,
|
vvfat_close,
|
||||||
NULL, /* ??? Not sure if we can do any meaningful flushing. */
|
NULL, /* ??? Not sure if we can do any meaningful flushing. */
|
||||||
NULL,
|
NULL,
|
||||||
vvfat_is_allocated,
|
vvfat_is_allocated
|
||||||
.protocol_name = "fat",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static void checkpoint(void) {
|
static void checkpoint() {
|
||||||
assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
|
assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
|
||||||
check1(vvv);
|
check1(vvv);
|
||||||
check2(vvv);
|
check2(vvv);
|
||||||
@@ -2846,3 +2805,4 @@ static void checkpoint(void) {
|
|||||||
print_direntry(NULL);
|
print_direntry(NULL);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
177
block.h
177
block.h
@@ -1,177 +0,0 @@
|
|||||||
#ifndef BLOCK_H
|
|
||||||
#define BLOCK_H
|
|
||||||
|
|
||||||
#include "qemu-aio.h"
|
|
||||||
#include "qemu-common.h"
|
|
||||||
|
|
||||||
/* block.c */
|
|
||||||
typedef struct BlockDriver BlockDriver;
|
|
||||||
|
|
||||||
extern BlockDriver bdrv_raw;
|
|
||||||
extern BlockDriver bdrv_host_device;
|
|
||||||
extern BlockDriver bdrv_cow;
|
|
||||||
extern BlockDriver bdrv_qcow;
|
|
||||||
extern BlockDriver bdrv_vmdk;
|
|
||||||
extern BlockDriver bdrv_cloop;
|
|
||||||
extern BlockDriver bdrv_dmg;
|
|
||||||
extern BlockDriver bdrv_bochs;
|
|
||||||
extern BlockDriver bdrv_vpc;
|
|
||||||
extern BlockDriver bdrv_vvfat;
|
|
||||||
extern BlockDriver bdrv_qcow2;
|
|
||||||
extern BlockDriver bdrv_parallels;
|
|
||||||
extern BlockDriver bdrv_nbd;
|
|
||||||
|
|
||||||
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_DEF 0x0080 /* use default caching */
|
|
||||||
|
|
||||||
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_CACHE_DEF)
|
|
||||||
|
|
||||||
void bdrv_info(void);
|
|
||||||
void bdrv_info_stats(void);
|
|
||||||
|
|
||||||
void bdrv_init(void);
|
|
||||||
BlockDriver *bdrv_find_format(const char *format_name);
|
|
||||||
int bdrv_create(BlockDriver *drv,
|
|
||||||
const char *filename, int64_t size_in_sectors,
|
|
||||||
const char *backing_file, 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_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);
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
|
|
||||||
uint8_t *buf, int nb_sectors,
|
|
||||||
BlockDriverCompletionFunc *cb, void *opaque);
|
|
||||||
BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
|
|
||||||
const uint8_t *buf, int nb_sectors,
|
|
||||||
BlockDriverCompletionFunc *cb, void *opaque);
|
|
||||||
void bdrv_aio_cancel(BlockDriverAIOCB *acb);
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
void 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);
|
|
||||||
int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);
|
|
||||||
|
|
||||||
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_put_buffer(BlockDriverState *bs, const uint8_t *buf,
|
|
||||||
int64_t pos, int size);
|
|
||||||
|
|
||||||
int bdrv_get_buffer(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
90
block_int.h
90
block_int.h
@@ -24,17 +24,11 @@
|
|||||||
#ifndef BLOCK_INT_H
|
#ifndef BLOCK_INT_H
|
||||||
#define BLOCK_INT_H
|
#define BLOCK_INT_H
|
||||||
|
|
||||||
#include "block.h"
|
|
||||||
|
|
||||||
#define BLOCK_FLAG_ENCRYPT 1
|
|
||||||
#define BLOCK_FLAG_COMPRESS 2
|
|
||||||
#define BLOCK_FLAG_COMPAT6 4
|
|
||||||
|
|
||||||
struct BlockDriver {
|
struct BlockDriver {
|
||||||
const char *format_name;
|
const char *format_name;
|
||||||
int instance_size;
|
int instance_size;
|
||||||
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
|
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
|
||||||
int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
|
int (*bdrv_open)(BlockDriverState *bs, const char *filename);
|
||||||
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
|
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
|
||||||
uint8_t *buf, int nb_sectors);
|
uint8_t *buf, int nb_sectors);
|
||||||
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
|
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
|
||||||
@@ -47,88 +41,32 @@ struct BlockDriver {
|
|||||||
int nb_sectors, int *pnum);
|
int nb_sectors, int *pnum);
|
||||||
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
|
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
|
||||||
int (*bdrv_make_empty)(BlockDriverState *bs);
|
int (*bdrv_make_empty)(BlockDriverState *bs);
|
||||||
/* aio */
|
|
||||||
BlockDriverAIOCB *(*bdrv_aio_read)(BlockDriverState *bs,
|
|
||||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
|
||||||
BlockDriverCompletionFunc *cb, void *opaque);
|
|
||||||
BlockDriverAIOCB *(*bdrv_aio_write)(BlockDriverState *bs,
|
|
||||||
int64_t sector_num, const uint8_t *buf, int nb_sectors,
|
|
||||||
BlockDriverCompletionFunc *cb, void *opaque);
|
|
||||||
void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
|
|
||||||
int aiocb_size;
|
|
||||||
|
|
||||||
const char *protocol_name;
|
|
||||||
int (*bdrv_pread)(BlockDriverState *bs, int64_t offset,
|
|
||||||
uint8_t *buf, int count);
|
|
||||||
int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset,
|
|
||||||
const uint8_t *buf, int count);
|
|
||||||
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_put_buffer)(BlockDriverState *bs, const uint8_t *buf,
|
|
||||||
int64_t pos, int size);
|
|
||||||
int (*bdrv_get_buffer)(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 *free_aiocb;
|
|
||||||
struct BlockDriver *next;
|
struct BlockDriver *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BlockDriverState {
|
struct BlockDriverState {
|
||||||
int64_t total_sectors; /* if we are reading a disk image, give its
|
int64_t total_sectors;
|
||||||
size in sectors */
|
|
||||||
int read_only; /* if true, the media is read only */
|
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 removable; /* if true, the media can be removed */
|
||||||
int locked; /* if true, the media cannot temporarily be ejected */
|
int locked; /* if true, the media cannot temporarily be ejected */
|
||||||
int encrypted; /* if true, the media is encrypted */
|
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 */
|
/* event callback when inserting/removing */
|
||||||
void (*change_cb)(void *opaque);
|
void (*change_cb)(void *opaque);
|
||||||
void *change_opaque;
|
void *change_opaque;
|
||||||
|
|
||||||
BlockDriver *drv; /* NULL means no media */
|
BlockDriver *drv;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
|
|
||||||
|
int boot_sector_enabled;
|
||||||
|
uint8_t boot_sector_data[512];
|
||||||
|
|
||||||
char filename[1024];
|
char filename[1024];
|
||||||
char backing_file[1024]; /* if non zero, the image is a diff of
|
char backing_file[1024]; /* if non zero, the image is a diff of
|
||||||
this file image */
|
this file image */
|
||||||
int is_temporary;
|
int is_temporary;
|
||||||
int media_changed;
|
|
||||||
|
|
||||||
BlockDriverState *backing_hd;
|
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;
|
|
||||||
|
|
||||||
/* NOTE: the following infos are only hints for real hardware
|
/* NOTE: the following infos are only hints for real hardware
|
||||||
drivers. They are not used by the block driver */
|
drivers. They are not used by the block driver */
|
||||||
@@ -136,22 +74,8 @@ struct BlockDriverState {
|
|||||||
int type;
|
int type;
|
||||||
char device_name[32];
|
char device_name[32];
|
||||||
BlockDriverState *next;
|
BlockDriverState *next;
|
||||||
void *private;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BlockDriverAIOCB {
|
|
||||||
BlockDriverState *bs;
|
|
||||||
BlockDriverCompletionFunc *cb;
|
|
||||||
void *opaque;
|
|
||||||
BlockDriverAIOCB *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void get_tmp_filename(char *filename, int size);
|
void get_tmp_filename(char *filename, int size);
|
||||||
|
|
||||||
void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
|
|
||||||
void *opaque);
|
|
||||||
void qemu_aio_release(void *p);
|
|
||||||
|
|
||||||
extern BlockDriverState *bdrv_first;
|
|
||||||
|
|
||||||
#endif /* BLOCK_INT_H */
|
#endif /* BLOCK_INT_H */
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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 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[NGROUPS];
|
|
||||||
|
|
||||||
ngroup = getgroups(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] = 0;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
1523
bsd-user/elfload.c
1523
bsd-user/elfload.c
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
|
||||||
@@ -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 },
|
|
||||||
@@ -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
|
|
||||||
584
bsd-user/main.c
584
bsd-user/main.c
@@ -1,584 +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, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <machine/trap.h>
|
|
||||||
|
|
||||||
#include "qemu.h"
|
|
||||||
#include "qemu-common.h"
|
|
||||||
/* For tb_lock */
|
|
||||||
#include "exec-all.h"
|
|
||||||
|
|
||||||
#define DEBUG_LOGFILE "/tmp/qemu.log"
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
#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"
|
|
||||||
"-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 = ®s1;
|
|
||||||
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, "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_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_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;
|
|
||||||
}
|
|
||||||
562
bsd-user/mmap.c
562
bsd-user/mmap.c
@@ -1,562 +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, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
#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);
|
|
||||||
}
|
|
||||||
@@ -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 },
|
|
||||||
@@ -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
|
|
||||||
@@ -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 },
|
|
||||||
@@ -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) */
|
|
||||||
163
bsd-user/path.c
163
bsd-user/path.c
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
387
bsd-user/qemu.h
387
bsd-user/qemu.h
@@ -1,387 +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);
|
|
||||||
#if defined(USE_NPTL)
|
|
||||||
void mmap_fork_start(void);
|
|
||||||
void mmap_fork_end(int child);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
@@ -1,40 +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, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
#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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
@@ -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 */
|
|
||||||
@@ -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"
|
|
||||||
@@ -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 */
|
|
||||||
@@ -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));
|
|
||||||
}
|
|
||||||
@@ -1,274 +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, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
#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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -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<OSTOP) */
|
|
||||||
#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"
|
|
||||||
@@ -1,76 +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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX: use host strnlen if available ? */
|
|
||||||
static int qemu_strnlen(const char *s, int max_len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for(i = 0; i < max_len; i++) {
|
|
||||||
if (s[i] == '\0')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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(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;
|
|
||||||
}
|
|
||||||
17
bswap.h
17
bswap.h
@@ -5,12 +5,6 @@
|
|||||||
|
|
||||||
#include <inttypes.h>
|
#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
|
#ifdef HAVE_BYTESWAP_H
|
||||||
#include <byteswap.h>
|
#include <byteswap.h>
|
||||||
#else
|
#else
|
||||||
@@ -64,8 +58,6 @@ static inline uint64_t bswap64(uint64_t x)
|
|||||||
return bswap_64(x);
|
return bswap_64(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* ! HAVE_MACHINE_BSWAP_H */
|
|
||||||
|
|
||||||
static inline void bswap16s(uint16_t *s)
|
static inline void bswap16s(uint16_t *s)
|
||||||
{
|
{
|
||||||
*s = bswap16(*s);
|
*s = bswap16(*s);
|
||||||
@@ -134,13 +126,12 @@ CPU_CONVERT(le, 64, uint64_t)
|
|||||||
|
|
||||||
/* unaligned versions (optimized for frequent unaligned accesses)*/
|
/* 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_le16wu(p, v) cpu_to_le16w(p, v)
|
||||||
#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
|
#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
|
||||||
#define le16_to_cpupu(p) le16_to_cpup(p)
|
#define le16_to_cpupu(p) le16_to_cpup(p)
|
||||||
#define le32_to_cpupu(p) le32_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_be16wu(p, v) cpu_to_be16w(p, v)
|
||||||
#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
|
#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
|
||||||
@@ -177,12 +168,6 @@ static inline uint32_t le32_to_cpupu(const uint32_t *p)
|
|||||||
return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
|
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)
|
static inline void cpu_to_be16wu(uint16_t *p, uint16_t v)
|
||||||
{
|
{
|
||||||
uint8_t *p1 = (uint8_t *)p;
|
uint8_t *p1 = (uint8_t *)p;
|
||||||
|
|||||||
206
bt-host.c
206
bt-host.c
@@ -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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "qemu-common.h"
|
|
||||||
#include "qemu-char.h"
|
|
||||||
#include "sysemu.h"
|
|
||||||
#include "net.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 = &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 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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, 0, 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
|
|
||||||
169
bt-vhci.c
169
bt-vhci.c
@@ -1,169 +0,0 @@
|
|||||||
/*
|
|
||||||
* Support for host VHCIs inside qemu scatternets.
|
|
||||||
*
|
|
||||||
* 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "qemu-common.h"
|
|
||||||
#include "qemu-char.h"
|
|
||||||
#include "sysemu.h"
|
|
||||||
#include "net.h"
|
|
||||||
#include "hw/bt.h"
|
|
||||||
|
|
||||||
#define VHCI_DEV "/dev/vhci"
|
|
||||||
#define VHCI_UDEV "/dev/hci_vhci"
|
|
||||||
|
|
||||||
struct bt_vhci_s {
|
|
||||||
int fd;
|
|
||||||
struct HCIInfo *info;
|
|
||||||
|
|
||||||
uint8_t hdr[4096];
|
|
||||||
int len;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void vhci_read(void *opaque)
|
|
||||||
{
|
|
||||||
struct bt_vhci_s *s = (struct bt_vhci_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 the PDU\n", errno);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt = s->hdr;
|
|
||||||
while (s->len --)
|
|
||||||
switch (*pkt ++) {
|
|
||||||
case HCI_COMMAND_PKT:
|
|
||||||
if (s->len < 3)
|
|
||||||
goto bad_pkt;
|
|
||||||
|
|
||||||
pktlen = MIN(pkt[2] + 3, s->len);
|
|
||||||
s->info->cmd_send(s->info, pkt, pktlen);
|
|
||||||
s->len -= pktlen;
|
|
||||||
pkt += pktlen;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HCI_ACLDATA_PKT:
|
|
||||||
if (s->len < 4)
|
|
||||||
goto bad_pkt;
|
|
||||||
|
|
||||||
pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
|
|
||||||
s->info->acl_send(s->info, 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->info->sco_send(s->info, pkt, pktlen);
|
|
||||||
s->len -= pktlen;
|
|
||||||
pkt += pktlen;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
bad_pkt:
|
|
||||||
fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vhci_host_send(void *opaque,
|
|
||||||
int type, const uint8_t *data, int len)
|
|
||||||
{
|
|
||||||
struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
|
|
||||||
#if 0
|
|
||||||
uint8_t pkt = type;
|
|
||||||
struct iovec iv[2];
|
|
||||||
|
|
||||||
iv[0].iov_base = &pkt;
|
|
||||||
iv[0].iov_len = 1;
|
|
||||||
iv[1].iov_base = (void *) data;
|
|
||||||
iv[1].iov_len = len;
|
|
||||||
|
|
||||||
while (writev(s->fd, iv, 2) < 0)
|
|
||||||
if (errno != EAGAIN && errno != EINTR) {
|
|
||||||
fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
|
|
||||||
errno);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* Apparently VHCI wants us to write everything in one chunk :-( */
|
|
||||||
static uint8_t buf[4096];
|
|
||||||
|
|
||||||
buf[0] = type;
|
|
||||||
memcpy(buf + 1, data, len);
|
|
||||||
|
|
||||||
while (write(s->fd, buf, len + 1) < 0)
|
|
||||||
if (errno != EAGAIN && errno != EINTR) {
|
|
||||||
fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
|
|
||||||
errno);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vhci_out_hci_packet_event(void *opaque,
|
|
||||||
const uint8_t *data, int len)
|
|
||||||
{
|
|
||||||
vhci_host_send(opaque, HCI_EVENT_PKT, data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vhci_out_hci_packet_acl(void *opaque,
|
|
||||||
const uint8_t *data, int len)
|
|
||||||
{
|
|
||||||
vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bt_vhci_init(struct HCIInfo *info)
|
|
||||||
{
|
|
||||||
struct bt_vhci_s *s;
|
|
||||||
int err[2];
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
fd = open(VHCI_DEV, O_RDWR);
|
|
||||||
err[0] = errno;
|
|
||||||
if (fd < 0) {
|
|
||||||
fd = open(VHCI_UDEV, O_RDWR);
|
|
||||||
err[1] = errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fd < 0) {
|
|
||||||
fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
|
|
||||||
VHCI_DEV, strerror(err[0]), err[0]);
|
|
||||||
fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
|
|
||||||
VHCI_UDEV, strerror(err[1]), err[1]);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(struct bt_vhci_s));
|
|
||||||
s->fd = fd;
|
|
||||||
s->info = info ?: qemu_next_hci();
|
|
||||||
s->info->opaque = s;
|
|
||||||
s->info->evt_recv = vhci_out_hci_packet_event;
|
|
||||||
s->info->acl_recv = vhci_out_hci_packet_acl;
|
|
||||||
|
|
||||||
qemu_set_fd_handler(s->fd, vhci_read, 0, s);
|
|
||||||
}
|
|
||||||
247
buffered_file.c
247
buffered_file.c
@@ -1,247 +0,0 @@
|
|||||||
/*
|
|
||||||
* QEMU buffered QEMUFile
|
|
||||||
*
|
|
||||||
* 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 "hw/hw.h"
|
|
||||||
#include "qemu-timer.h"
|
|
||||||
#include "sysemu.h"
|
|
||||||
#include "qemu-char.h"
|
|
||||||
#include "buffered_file.h"
|
|
||||||
|
|
||||||
//#define DEBUG_BUFFERED_FILE
|
|
||||||
|
|
||||||
typedef struct QEMUFileBuffered
|
|
||||||
{
|
|
||||||
BufferedPutFunc *put_buffer;
|
|
||||||
BufferedPutReadyFunc *put_ready;
|
|
||||||
BufferedWaitForUnfreezeFunc *wait_for_unfreeze;
|
|
||||||
BufferedCloseFunc *close;
|
|
||||||
void *opaque;
|
|
||||||
QEMUFile *file;
|
|
||||||
int has_error;
|
|
||||||
int freeze_output;
|
|
||||||
size_t bytes_xfer;
|
|
||||||
size_t xfer_limit;
|
|
||||||
uint8_t *buffer;
|
|
||||||
size_t buffer_size;
|
|
||||||
size_t buffer_capacity;
|
|
||||||
QEMUTimer *timer;
|
|
||||||
} QEMUFileBuffered;
|
|
||||||
|
|
||||||
#ifdef DEBUG_BUFFERED_FILE
|
|
||||||
#define dprintf(fmt, ...) \
|
|
||||||
do { printf("buffered-file: " fmt, ## __VA_ARGS__); } while (0)
|
|
||||||
#else
|
|
||||||
#define dprintf(fmt, ...) \
|
|
||||||
do { } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void buffered_append(QEMUFileBuffered *s,
|
|
||||||
const uint8_t *buf, size_t size)
|
|
||||||
{
|
|
||||||
if (size > (s->buffer_capacity - s->buffer_size)) {
|
|
||||||
void *tmp;
|
|
||||||
|
|
||||||
dprintf("increasing buffer capacity from %ld by %ld\n",
|
|
||||||
s->buffer_capacity, size + 1024);
|
|
||||||
|
|
||||||
s->buffer_capacity += size + 1024;
|
|
||||||
|
|
||||||
tmp = qemu_realloc(s->buffer, s->buffer_capacity);
|
|
||||||
if (tmp == NULL) {
|
|
||||||
fprintf(stderr, "qemu file buffer expansion failed\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
s->buffer = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(s->buffer + s->buffer_size, buf, size);
|
|
||||||
s->buffer_size += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void buffered_flush(QEMUFileBuffered *s)
|
|
||||||
{
|
|
||||||
size_t offset = 0;
|
|
||||||
|
|
||||||
if (s->has_error) {
|
|
||||||
dprintf("flush when error, bailing\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintf("flushing %ld byte(s) of data\n", s->buffer_size);
|
|
||||||
|
|
||||||
while (offset < s->buffer_size) {
|
|
||||||
ssize_t ret;
|
|
||||||
|
|
||||||
ret = s->put_buffer(s->opaque, s->buffer + offset,
|
|
||||||
s->buffer_size - offset);
|
|
||||||
if (ret == -EAGAIN) {
|
|
||||||
dprintf("backend not ready, freezing\n");
|
|
||||||
s->freeze_output = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret <= 0) {
|
|
||||||
dprintf("error flushing data, %ld\n", ret);
|
|
||||||
s->has_error = 1;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
dprintf("flushed %ld byte(s)\n", ret);
|
|
||||||
offset += ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintf("flushed %ld of %ld byte(s)\n", offset, s->buffer_size);
|
|
||||||
memmove(s->buffer, s->buffer + offset, s->buffer_size - offset);
|
|
||||||
s->buffer_size -= offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
|
|
||||||
{
|
|
||||||
QEMUFileBuffered *s = opaque;
|
|
||||||
int offset = 0;
|
|
||||||
ssize_t ret;
|
|
||||||
|
|
||||||
dprintf("putting %ld bytes at %Ld\n", size, pos);
|
|
||||||
|
|
||||||
if (s->has_error) {
|
|
||||||
dprintf("flush when error, bailing\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintf("unfreezing output\n");
|
|
||||||
s->freeze_output = 0;
|
|
||||||
|
|
||||||
buffered_flush(s);
|
|
||||||
|
|
||||||
while (!s->freeze_output && offset < size) {
|
|
||||||
if (s->bytes_xfer > s->xfer_limit) {
|
|
||||||
dprintf("transfer limit exceeded when putting\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = s->put_buffer(s->opaque, buf + offset, size - offset);
|
|
||||||
if (ret == -EAGAIN) {
|
|
||||||
dprintf("backend not ready, freezing\n");
|
|
||||||
s->freeze_output = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret <= 0) {
|
|
||||||
dprintf("error putting\n");
|
|
||||||
s->has_error = 1;
|
|
||||||
offset = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintf("put %ld byte(s)\n", ret);
|
|
||||||
offset += ret;
|
|
||||||
s->bytes_xfer += ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset >= 0) {
|
|
||||||
dprintf("buffering %ld bytes\n", size - offset);
|
|
||||||
buffered_append(s, buf + offset, size - offset);
|
|
||||||
offset = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int buffered_close(void *opaque)
|
|
||||||
{
|
|
||||||
QEMUFileBuffered *s = opaque;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
dprintf("closing\n");
|
|
||||||
|
|
||||||
while (!s->has_error && s->buffer_size) {
|
|
||||||
buffered_flush(s);
|
|
||||||
if (s->freeze_output)
|
|
||||||
s->wait_for_unfreeze(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = s->close(s->opaque);
|
|
||||||
|
|
||||||
qemu_del_timer(s->timer);
|
|
||||||
qemu_free_timer(s->timer);
|
|
||||||
qemu_free(s->buffer);
|
|
||||||
qemu_free(s);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int buffered_rate_limit(void *opaque)
|
|
||||||
{
|
|
||||||
QEMUFileBuffered *s = opaque;
|
|
||||||
|
|
||||||
if (s->has_error)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (s->freeze_output)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (s->bytes_xfer > s->xfer_limit)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void buffered_rate_tick(void *opaque)
|
|
||||||
{
|
|
||||||
QEMUFileBuffered *s = opaque;
|
|
||||||
|
|
||||||
if (s->has_error)
|
|
||||||
return;
|
|
||||||
|
|
||||||
qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100);
|
|
||||||
|
|
||||||
if (s->freeze_output)
|
|
||||||
return;
|
|
||||||
|
|
||||||
s->bytes_xfer = 0;
|
|
||||||
|
|
||||||
buffered_flush(s);
|
|
||||||
|
|
||||||
/* Add some checks around this */
|
|
||||||
s->put_ready(s->opaque);
|
|
||||||
}
|
|
||||||
|
|
||||||
QEMUFile *qemu_fopen_ops_buffered(void *opaque,
|
|
||||||
size_t bytes_per_sec,
|
|
||||||
BufferedPutFunc *put_buffer,
|
|
||||||
BufferedPutReadyFunc *put_ready,
|
|
||||||
BufferedWaitForUnfreezeFunc *wait_for_unfreeze,
|
|
||||||
BufferedCloseFunc *close)
|
|
||||||
{
|
|
||||||
QEMUFileBuffered *s;
|
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(*s));
|
|
||||||
|
|
||||||
s->opaque = opaque;
|
|
||||||
s->xfer_limit = bytes_per_sec / 10;
|
|
||||||
s->put_buffer = put_buffer;
|
|
||||||
s->put_ready = put_ready;
|
|
||||||
s->wait_for_unfreeze = wait_for_unfreeze;
|
|
||||||
s->close = close;
|
|
||||||
|
|
||||||
s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL,
|
|
||||||
buffered_close, buffered_rate_limit);
|
|
||||||
|
|
||||||
s->timer = qemu_new_timer(rt_clock, buffered_rate_tick, s);
|
|
||||||
|
|
||||||
qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100);
|
|
||||||
|
|
||||||
return s->file;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* QEMU buffered QEMUFile
|
|
||||||
*
|
|
||||||
* 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_BUFFERED_FILE_H
|
|
||||||
#define QEMU_BUFFERED_FILE_H
|
|
||||||
|
|
||||||
#include "hw/hw.h"
|
|
||||||
|
|
||||||
typedef ssize_t (BufferedPutFunc)(void *opaque, const void *data, size_t size);
|
|
||||||
typedef void (BufferedPutReadyFunc)(void *opaque);
|
|
||||||
typedef void (BufferedWaitForUnfreezeFunc)(void *opaque);
|
|
||||||
typedef int (BufferedCloseFunc)(void *opaque);
|
|
||||||
|
|
||||||
QEMUFile *qemu_fopen_ops_buffered(void *opaque, size_t xfer_limit,
|
|
||||||
BufferedPutFunc *put_buffer,
|
|
||||||
BufferedPutReadyFunc *put_ready,
|
|
||||||
BufferedWaitForUnfreezeFunc *wait_for_unfreeze,
|
|
||||||
BufferedCloseFunc *close);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
#include "cache-utils.h"
|
|
||||||
|
|
||||||
#if defined(_ARCH_PPC)
|
|
||||||
struct qemu_cache_conf qemu_cache_conf = {
|
|
||||||
.dcache_bsize = 16,
|
|
||||||
.icache_bsize = 16
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined _AIX
|
|
||||||
#include <sys/systemcfg.h>
|
|
||||||
|
|
||||||
static void ppc_init_cacheline_sizes(void)
|
|
||||||
{
|
|
||||||
qemu_cache_conf.icache_bsize = _system_configuration.icache_line;
|
|
||||||
qemu_cache_conf.dcache_bsize = _system_configuration.dcache_line;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined __linux__
|
|
||||||
|
|
||||||
#define QEMU_AT_NULL 0
|
|
||||||
#define QEMU_AT_DCACHEBSIZE 19
|
|
||||||
#define QEMU_AT_ICACHEBSIZE 20
|
|
||||||
|
|
||||||
static void ppc_init_cacheline_sizes(char **envp)
|
|
||||||
{
|
|
||||||
unsigned long *auxv;
|
|
||||||
|
|
||||||
while (*envp++);
|
|
||||||
|
|
||||||
for (auxv = (unsigned long *) envp; *auxv != QEMU_AT_NULL; auxv += 2) {
|
|
||||||
switch (*auxv) {
|
|
||||||
case QEMU_AT_DCACHEBSIZE: qemu_cache_conf.dcache_bsize = auxv[1]; break;
|
|
||||||
case QEMU_AT_ICACHEBSIZE: qemu_cache_conf.icache_bsize = auxv[1]; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined __APPLE__
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/sysctl.h>
|
|
||||||
|
|
||||||
static void ppc_init_cacheline_sizes(void)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
unsigned cacheline;
|
|
||||||
int name[2] = { CTL_HW, HW_CACHELINE };
|
|
||||||
|
|
||||||
len = sizeof(cacheline);
|
|
||||||
if (sysctl(name, 2, &cacheline, &len, NULL, 0)) {
|
|
||||||
perror("sysctl CTL_HW HW_CACHELINE failed");
|
|
||||||
} else {
|
|
||||||
qemu_cache_conf.dcache_bsize = cacheline;
|
|
||||||
qemu_cache_conf.icache_bsize = cacheline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
void qemu_cache_utils_init(char **envp)
|
|
||||||
{
|
|
||||||
ppc_init_cacheline_sizes(envp);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void qemu_cache_utils_init(char **envp)
|
|
||||||
{
|
|
||||||
(void) envp;
|
|
||||||
ppc_init_cacheline_sizes();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _ARCH_PPC */
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#ifndef QEMU_CACHE_UTILS_H
|
|
||||||
#define QEMU_CACHE_UTILS_H
|
|
||||||
|
|
||||||
#if defined(_ARCH_PPC)
|
|
||||||
struct qemu_cache_conf {
|
|
||||||
unsigned long dcache_bsize;
|
|
||||||
unsigned long icache_bsize;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct qemu_cache_conf qemu_cache_conf;
|
|
||||||
|
|
||||||
extern void qemu_cache_utils_init(char **envp);
|
|
||||||
|
|
||||||
/* mildly adjusted code from tcg-dyngen.c */
|
|
||||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
|
||||||
{
|
|
||||||
unsigned long p, start1, stop1;
|
|
||||||
unsigned long dsize = qemu_cache_conf.dcache_bsize;
|
|
||||||
unsigned long isize = qemu_cache_conf.icache_bsize;
|
|
||||||
|
|
||||||
start1 = start & ~(dsize - 1);
|
|
||||||
stop1 = (stop + dsize - 1) & ~(dsize - 1);
|
|
||||||
for (p = start1; p < stop1; p += dsize) {
|
|
||||||
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
|
|
||||||
}
|
|
||||||
asm volatile ("sync" : : : "memory");
|
|
||||||
|
|
||||||
start &= start & ~(isize - 1);
|
|
||||||
stop1 = (stop + isize - 1) & ~(isize - 1);
|
|
||||||
for (p = start1; p < stop1; p += isize) {
|
|
||||||
asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
|
|
||||||
}
|
|
||||||
asm volatile ("sync" : : : "memory");
|
|
||||||
asm volatile ("isync" : : : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* QEMU_CACHE_UTILS_H */
|
|
||||||
320
console.h
320
console.h
@@ -1,320 +0,0 @@
|
|||||||
#ifndef CONSOLE_H
|
|
||||||
#define CONSOLE_H
|
|
||||||
|
|
||||||
#include "qemu-char.h"
|
|
||||||
|
|
||||||
/* keyboard/mouse support */
|
|
||||||
|
|
||||||
#define MOUSE_EVENT_LBUTTON 0x01
|
|
||||||
#define MOUSE_EVENT_RBUTTON 0x02
|
|
||||||
#define MOUSE_EVENT_MBUTTON 0x04
|
|
||||||
|
|
||||||
/* in ms */
|
|
||||||
#define GUI_REFRESH_INTERVAL 30
|
|
||||||
|
|
||||||
typedef void QEMUPutKBDEvent(void *opaque, int keycode);
|
|
||||||
typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state);
|
|
||||||
|
|
||||||
typedef struct QEMUPutMouseEntry {
|
|
||||||
QEMUPutMouseEvent *qemu_put_mouse_event;
|
|
||||||
void *qemu_put_mouse_event_opaque;
|
|
||||||
int qemu_put_mouse_event_absolute;
|
|
||||||
char *qemu_put_mouse_event_name;
|
|
||||||
|
|
||||||
/* used internally by qemu for handling mice */
|
|
||||||
struct QEMUPutMouseEntry *next;
|
|
||||||
} QEMUPutMouseEntry;
|
|
||||||
|
|
||||||
void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
|
|
||||||
QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
|
|
||||||
void *opaque, int absolute,
|
|
||||||
const char *name);
|
|
||||||
void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry);
|
|
||||||
|
|
||||||
void kbd_put_keycode(int keycode);
|
|
||||||
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
|
|
||||||
int kbd_mouse_is_absolute(void);
|
|
||||||
|
|
||||||
struct mouse_transform_info_s {
|
|
||||||
/* Touchscreen resolution */
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
/* Calibration values as used/generated by tslib */
|
|
||||||
int a[7];
|
|
||||||
};
|
|
||||||
|
|
||||||
void do_info_mice(void);
|
|
||||||
void do_mouse_set(int index);
|
|
||||||
|
|
||||||
/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
|
|
||||||
constants) */
|
|
||||||
#define QEMU_KEY_ESC1(c) ((c) | 0xe100)
|
|
||||||
#define QEMU_KEY_BACKSPACE 0x007f
|
|
||||||
#define QEMU_KEY_UP QEMU_KEY_ESC1('A')
|
|
||||||
#define QEMU_KEY_DOWN QEMU_KEY_ESC1('B')
|
|
||||||
#define QEMU_KEY_RIGHT QEMU_KEY_ESC1('C')
|
|
||||||
#define QEMU_KEY_LEFT QEMU_KEY_ESC1('D')
|
|
||||||
#define QEMU_KEY_HOME QEMU_KEY_ESC1(1)
|
|
||||||
#define QEMU_KEY_END QEMU_KEY_ESC1(4)
|
|
||||||
#define QEMU_KEY_PAGEUP QEMU_KEY_ESC1(5)
|
|
||||||
#define QEMU_KEY_PAGEDOWN QEMU_KEY_ESC1(6)
|
|
||||||
#define QEMU_KEY_DELETE QEMU_KEY_ESC1(3)
|
|
||||||
|
|
||||||
#define QEMU_KEY_CTRL_UP 0xe400
|
|
||||||
#define QEMU_KEY_CTRL_DOWN 0xe401
|
|
||||||
#define QEMU_KEY_CTRL_LEFT 0xe402
|
|
||||||
#define QEMU_KEY_CTRL_RIGHT 0xe403
|
|
||||||
#define QEMU_KEY_CTRL_HOME 0xe404
|
|
||||||
#define QEMU_KEY_CTRL_END 0xe405
|
|
||||||
#define QEMU_KEY_CTRL_PAGEUP 0xe406
|
|
||||||
#define QEMU_KEY_CTRL_PAGEDOWN 0xe407
|
|
||||||
|
|
||||||
void kbd_put_keysym(int keysym);
|
|
||||||
|
|
||||||
/* consoles */
|
|
||||||
|
|
||||||
#define QEMU_BIG_ENDIAN_FLAG 0x01
|
|
||||||
#define QEMU_ALLOCATED_FLAG 0x02
|
|
||||||
|
|
||||||
struct PixelFormat {
|
|
||||||
uint8_t bits_per_pixel;
|
|
||||||
uint8_t bytes_per_pixel;
|
|
||||||
uint8_t depth; /* color depth in bits */
|
|
||||||
uint32_t rmask, gmask, bmask, amask;
|
|
||||||
uint8_t rshift, gshift, bshift, ashift;
|
|
||||||
uint8_t rmax, gmax, bmax, amax;
|
|
||||||
uint8_t rbits, gbits, bbits, abits;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DisplaySurface {
|
|
||||||
uint8_t flags;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
int linesize; /* bytes per line */
|
|
||||||
uint8_t *data;
|
|
||||||
|
|
||||||
struct PixelFormat pf;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DisplayChangeListener {
|
|
||||||
int idle;
|
|
||||||
uint64_t gui_timer_interval;
|
|
||||||
|
|
||||||
void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
|
|
||||||
void (*dpy_resize)(struct DisplayState *s);
|
|
||||||
void (*dpy_setdata)(struct DisplayState *s);
|
|
||||||
void (*dpy_refresh)(struct DisplayState *s);
|
|
||||||
void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y,
|
|
||||||
int dst_x, int dst_y, int w, int h);
|
|
||||||
void (*dpy_fill)(struct DisplayState *s, int x, int y,
|
|
||||||
int w, int h, uint32_t c);
|
|
||||||
void (*dpy_text_cursor)(struct DisplayState *s, int x, int y);
|
|
||||||
|
|
||||||
struct DisplayChangeListener *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DisplayState {
|
|
||||||
struct DisplaySurface *surface;
|
|
||||||
void *opaque;
|
|
||||||
struct QEMUTimer *gui_timer;
|
|
||||||
|
|
||||||
struct DisplayChangeListener* listeners;
|
|
||||||
|
|
||||||
void (*mouse_set)(int x, int y, int on);
|
|
||||||
void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y,
|
|
||||||
uint8_t *image, uint8_t *mask);
|
|
||||||
|
|
||||||
struct DisplayState *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
void register_displaystate(DisplayState *ds);
|
|
||||||
DisplayState *get_displaystate(void);
|
|
||||||
DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize);
|
|
||||||
DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,
|
|
||||||
int width, int height, int bpp, int linesize);
|
|
||||||
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
|
|
||||||
int linesize, uint8_t *data);
|
|
||||||
void qemu_free_displaysurface(DisplaySurface *surface);
|
|
||||||
PixelFormat qemu_different_endianness_pixelformat(int bpp);
|
|
||||||
PixelFormat qemu_default_pixelformat(int bpp);
|
|
||||||
|
|
||||||
static inline int is_buffer_shared(DisplaySurface *surface)
|
|
||||||
{
|
|
||||||
return (!(surface->flags & QEMU_ALLOCATED_FLAG));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl)
|
|
||||||
{
|
|
||||||
dcl->next = ds->listeners;
|
|
||||||
ds->listeners = dcl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
|
|
||||||
{
|
|
||||||
struct DisplayChangeListener *dcl = s->listeners;
|
|
||||||
while (dcl != NULL) {
|
|
||||||
dcl->dpy_update(s, x, y, w, h);
|
|
||||||
dcl = dcl->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dpy_resize(DisplayState *s)
|
|
||||||
{
|
|
||||||
struct DisplayChangeListener *dcl = s->listeners;
|
|
||||||
while (dcl != NULL) {
|
|
||||||
dcl->dpy_resize(s);
|
|
||||||
dcl = dcl->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dpy_setdata(DisplayState *s)
|
|
||||||
{
|
|
||||||
struct DisplayChangeListener *dcl = s->listeners;
|
|
||||||
while (dcl != NULL) {
|
|
||||||
if (dcl->dpy_setdata) dcl->dpy_setdata(s);
|
|
||||||
dcl = dcl->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dpy_refresh(DisplayState *s)
|
|
||||||
{
|
|
||||||
struct DisplayChangeListener *dcl = s->listeners;
|
|
||||||
while (dcl != NULL) {
|
|
||||||
if (dcl->dpy_refresh) dcl->dpy_refresh(s);
|
|
||||||
dcl = dcl->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dpy_copy(struct DisplayState *s, int src_x, int src_y,
|
|
||||||
int dst_x, int dst_y, int w, int h) {
|
|
||||||
struct DisplayChangeListener *dcl = s->listeners;
|
|
||||||
while (dcl != NULL) {
|
|
||||||
if (dcl->dpy_copy)
|
|
||||||
dcl->dpy_copy(s, src_x, src_y, dst_x, dst_y, w, h);
|
|
||||||
else /* TODO */
|
|
||||||
dcl->dpy_update(s, dst_x, dst_y, w, h);
|
|
||||||
dcl = dcl->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dpy_fill(struct DisplayState *s, int x, int y,
|
|
||||||
int w, int h, uint32_t c) {
|
|
||||||
struct DisplayChangeListener *dcl = s->listeners;
|
|
||||||
while (dcl != NULL) {
|
|
||||||
if (dcl->dpy_fill) dcl->dpy_fill(s, x, y, w, h, c);
|
|
||||||
dcl = dcl->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dpy_cursor(struct DisplayState *s, int x, int y) {
|
|
||||||
struct DisplayChangeListener *dcl = s->listeners;
|
|
||||||
while (dcl != NULL) {
|
|
||||||
if (dcl->dpy_text_cursor) dcl->dpy_text_cursor(s, x, y);
|
|
||||||
dcl = dcl->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ds_get_linesize(DisplayState *ds)
|
|
||||||
{
|
|
||||||
return ds->surface->linesize;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint8_t* ds_get_data(DisplayState *ds)
|
|
||||||
{
|
|
||||||
return ds->surface->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ds_get_width(DisplayState *ds)
|
|
||||||
{
|
|
||||||
return ds->surface->width;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ds_get_height(DisplayState *ds)
|
|
||||||
{
|
|
||||||
return ds->surface->height;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ds_get_bits_per_pixel(DisplayState *ds)
|
|
||||||
{
|
|
||||||
return ds->surface->pf.bits_per_pixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ds_get_bytes_per_pixel(DisplayState *ds)
|
|
||||||
{
|
|
||||||
return ds->surface->pf.bytes_per_pixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef unsigned long console_ch_t;
|
|
||||||
static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
|
|
||||||
{
|
|
||||||
cpu_to_le32wu((uint32_t *) dest, ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef void (*vga_hw_update_ptr)(void *);
|
|
||||||
typedef void (*vga_hw_invalidate_ptr)(void *);
|
|
||||||
typedef void (*vga_hw_screen_dump_ptr)(void *, const char *);
|
|
||||||
typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *);
|
|
||||||
|
|
||||||
DisplayState *graphic_console_init(vga_hw_update_ptr update,
|
|
||||||
vga_hw_invalidate_ptr invalidate,
|
|
||||||
vga_hw_screen_dump_ptr screen_dump,
|
|
||||||
vga_hw_text_update_ptr text_update,
|
|
||||||
void *opaque);
|
|
||||||
|
|
||||||
void vga_hw_update(void);
|
|
||||||
void vga_hw_invalidate(void);
|
|
||||||
void vga_hw_screen_dump(const char *filename);
|
|
||||||
void vga_hw_text_update(console_ch_t *chardata);
|
|
||||||
|
|
||||||
int is_graphic_console(void);
|
|
||||||
int is_fixedsize_console(void);
|
|
||||||
CharDriverState *text_console_init(const char *p);
|
|
||||||
void text_consoles_set_display(DisplayState *ds);
|
|
||||||
void console_select(unsigned int index);
|
|
||||||
void console_color_init(DisplayState *ds);
|
|
||||||
void qemu_console_resize(DisplayState *ds, int width, int height);
|
|
||||||
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
|
|
||||||
int dst_x, int dst_y, int w, int h);
|
|
||||||
|
|
||||||
/* sdl.c */
|
|
||||||
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
|
|
||||||
|
|
||||||
/* cocoa.m */
|
|
||||||
void cocoa_display_init(DisplayState *ds, int full_screen);
|
|
||||||
|
|
||||||
/* vnc.c */
|
|
||||||
void vnc_display_init(DisplayState *ds);
|
|
||||||
void vnc_display_close(DisplayState *ds);
|
|
||||||
int vnc_display_open(DisplayState *ds, const char *display);
|
|
||||||
int vnc_display_password(DisplayState *ds, const char *password);
|
|
||||||
void do_info_vnc(void);
|
|
||||||
|
|
||||||
/* curses.c */
|
|
||||||
void curses_display_init(DisplayState *ds, int full_screen);
|
|
||||||
|
|
||||||
/* FIXME: term_printf et al should probably go elsewhere so everything
|
|
||||||
does not need to include console.h */
|
|
||||||
/* monitor.c */
|
|
||||||
void monitor_init(CharDriverState *hd, int show_banner);
|
|
||||||
void term_puts(const char *str);
|
|
||||||
void term_vprintf(const char *fmt, va_list ap);
|
|
||||||
void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
|
|
||||||
void term_print_filename(const char *filename);
|
|
||||||
void term_flush(void);
|
|
||||||
void term_print_help(void);
|
|
||||||
void monitor_suspend(void);
|
|
||||||
void monitor_resume(void);
|
|
||||||
int monitor_read_bdrv_key(BlockDriverState *bs);
|
|
||||||
|
|
||||||
/* readline.c */
|
|
||||||
typedef void ReadLineFunc(void *opaque, const char *str);
|
|
||||||
|
|
||||||
extern int completion_index;
|
|
||||||
void add_completion(const char *str);
|
|
||||||
void readline_handle_byte(int ch);
|
|
||||||
void readline_find_completion(const char *cmdline);
|
|
||||||
const char *readline_get_history(unsigned int index);
|
|
||||||
void readline_start(const char *prompt, int is_password,
|
|
||||||
ReadLineFunc *readline_func, void *opaque);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
417
cpu-all.h
417
cpu-all.h
@@ -15,14 +15,12 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#ifndef CPU_ALL_H
|
#ifndef CPU_ALL_H
|
||||||
#define CPU_ALL_H
|
#define CPU_ALL_H
|
||||||
|
|
||||||
#include "qemu-common.h"
|
#if defined(__arm__) || defined(__sparc__)
|
||||||
|
|
||||||
#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__)
|
|
||||||
#define WORDS_ALIGNED
|
#define WORDS_ALIGNED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -40,7 +38,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "bswap.h"
|
#include "bswap.h"
|
||||||
#include "softfloat.h"
|
|
||||||
|
|
||||||
#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
|
#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
|
||||||
#define BSWAP_NEEDED
|
#define BSWAP_NEEDED
|
||||||
@@ -119,11 +116,6 @@ static inline void tswap64s(uint64_t *s)
|
|||||||
#define bswaptls(s) bswap64s(s)
|
#define bswaptls(s) bswap64s(s)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef union {
|
|
||||||
float32 f;
|
|
||||||
uint32_t l;
|
|
||||||
} CPU_FloatU;
|
|
||||||
|
|
||||||
/* NOTE: arm FPA is horrible as double 32 bit words are stored in big
|
/* NOTE: arm FPA is horrible as double 32 bit words are stored in big
|
||||||
endian ! */
|
endian ! */
|
||||||
typedef union {
|
typedef union {
|
||||||
@@ -143,36 +135,6 @@ typedef union {
|
|||||||
uint64_t ll;
|
uint64_t ll;
|
||||||
} CPU_DoubleU;
|
} CPU_DoubleU;
|
||||||
|
|
||||||
#ifdef TARGET_SPARC
|
|
||||||
typedef union {
|
|
||||||
float128 q;
|
|
||||||
#if defined(WORDS_BIGENDIAN) \
|
|
||||||
|| (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
|
|
||||||
struct {
|
|
||||||
uint32_t upmost;
|
|
||||||
uint32_t upper;
|
|
||||||
uint32_t lower;
|
|
||||||
uint32_t lowest;
|
|
||||||
} l;
|
|
||||||
struct {
|
|
||||||
uint64_t upper;
|
|
||||||
uint64_t lower;
|
|
||||||
} ll;
|
|
||||||
#else
|
|
||||||
struct {
|
|
||||||
uint32_t lowest;
|
|
||||||
uint32_t lower;
|
|
||||||
uint32_t upper;
|
|
||||||
uint32_t upmost;
|
|
||||||
} l;
|
|
||||||
struct {
|
|
||||||
uint64_t lower;
|
|
||||||
uint64_t upper;
|
|
||||||
} ll;
|
|
||||||
#endif
|
|
||||||
} CPU_QuadU;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* CPU memory access without any memory or io remapping */
|
/* CPU memory access without any memory or io remapping */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -208,12 +170,12 @@ typedef union {
|
|||||||
* user : user mode access using soft MMU
|
* user : user mode access using soft MMU
|
||||||
* kernel : kernel mode access using soft MMU
|
* kernel : kernel mode access using soft MMU
|
||||||
*/
|
*/
|
||||||
static inline int ldub_p(const void *ptr)
|
static inline int ldub_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(uint8_t *)ptr;
|
return *(uint8_t *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ldsb_p(const void *ptr)
|
static inline int ldsb_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(int8_t *)ptr;
|
return *(int8_t *)ptr;
|
||||||
}
|
}
|
||||||
@@ -229,45 +191,45 @@ static inline void stb_p(void *ptr, int v)
|
|||||||
#if defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
|
#if defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
|
||||||
|
|
||||||
/* conservative code for little endian unaligned accesses */
|
/* conservative code for little endian unaligned accesses */
|
||||||
static inline int lduw_le_p(const void *ptr)
|
static inline int lduw_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
#ifdef _ARCH_PPC
|
#ifdef __powerpc__
|
||||||
int val;
|
int val;
|
||||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||||
return val;
|
return val;
|
||||||
#else
|
#else
|
||||||
const uint8_t *p = ptr;
|
uint8_t *p = ptr;
|
||||||
return p[0] | (p[1] << 8);
|
return p[0] | (p[1] << 8);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ldsw_le_p(const void *ptr)
|
static inline int ldsw_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
#ifdef _ARCH_PPC
|
#ifdef __powerpc__
|
||||||
int val;
|
int val;
|
||||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||||
return (int16_t)val;
|
return (int16_t)val;
|
||||||
#else
|
#else
|
||||||
const uint8_t *p = ptr;
|
uint8_t *p = ptr;
|
||||||
return (int16_t)(p[0] | (p[1] << 8));
|
return (int16_t)(p[0] | (p[1] << 8));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ldl_le_p(const void *ptr)
|
static inline int ldl_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
#ifdef _ARCH_PPC
|
#ifdef __powerpc__
|
||||||
int val;
|
int val;
|
||||||
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||||
return val;
|
return val;
|
||||||
#else
|
#else
|
||||||
const uint8_t *p = ptr;
|
uint8_t *p = ptr;
|
||||||
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t ldq_le_p(const void *ptr)
|
static inline uint64_t ldq_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
const uint8_t *p = ptr;
|
uint8_t *p = ptr;
|
||||||
uint32_t v1, v2;
|
uint32_t v1, v2;
|
||||||
v1 = ldl_le_p(p);
|
v1 = ldl_le_p(p);
|
||||||
v2 = ldl_le_p(p + 4);
|
v2 = ldl_le_p(p + 4);
|
||||||
@@ -276,7 +238,7 @@ static inline uint64_t ldq_le_p(const void *ptr)
|
|||||||
|
|
||||||
static inline void stw_le_p(void *ptr, int v)
|
static inline void stw_le_p(void *ptr, int v)
|
||||||
{
|
{
|
||||||
#ifdef _ARCH_PPC
|
#ifdef __powerpc__
|
||||||
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
|
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
|
||||||
#else
|
#else
|
||||||
uint8_t *p = ptr;
|
uint8_t *p = ptr;
|
||||||
@@ -287,7 +249,7 @@ static inline void stw_le_p(void *ptr, int v)
|
|||||||
|
|
||||||
static inline void stl_le_p(void *ptr, int v)
|
static inline void stl_le_p(void *ptr, int v)
|
||||||
{
|
{
|
||||||
#ifdef _ARCH_PPC
|
#ifdef __powerpc__
|
||||||
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
|
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
|
||||||
#else
|
#else
|
||||||
uint8_t *p = ptr;
|
uint8_t *p = ptr;
|
||||||
@@ -307,7 +269,7 @@ static inline void stq_le_p(void *ptr, uint64_t v)
|
|||||||
|
|
||||||
/* float access */
|
/* float access */
|
||||||
|
|
||||||
static inline float32 ldfl_le_p(const void *ptr)
|
static inline float32 ldfl_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
float32 f;
|
float32 f;
|
||||||
@@ -327,7 +289,7 @@ static inline void stfl_le_p(void *ptr, float32 v)
|
|||||||
stl_le_p(ptr, u.i);
|
stl_le_p(ptr, u.i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline float64 ldfq_le_p(const void *ptr)
|
static inline float64 ldfq_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
CPU_DoubleU u;
|
CPU_DoubleU u;
|
||||||
u.l.lower = ldl_le_p(ptr);
|
u.l.lower = ldl_le_p(ptr);
|
||||||
@@ -345,22 +307,22 @@ static inline void stfq_le_p(void *ptr, float64 v)
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int lduw_le_p(const void *ptr)
|
static inline int lduw_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(uint16_t *)ptr;
|
return *(uint16_t *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ldsw_le_p(const void *ptr)
|
static inline int ldsw_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(int16_t *)ptr;
|
return *(int16_t *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ldl_le_p(const void *ptr)
|
static inline int ldl_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(uint32_t *)ptr;
|
return *(uint32_t *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t ldq_le_p(const void *ptr)
|
static inline uint64_t ldq_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(uint64_t *)ptr;
|
return *(uint64_t *)ptr;
|
||||||
}
|
}
|
||||||
@@ -382,12 +344,12 @@ static inline void stq_le_p(void *ptr, uint64_t v)
|
|||||||
|
|
||||||
/* float access */
|
/* float access */
|
||||||
|
|
||||||
static inline float32 ldfl_le_p(const void *ptr)
|
static inline float32 ldfl_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(float32 *)ptr;
|
return *(float32 *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline float64 ldfq_le_p(const void *ptr)
|
static inline float64 ldfq_le_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(float64 *)ptr;
|
return *(float64 *)ptr;
|
||||||
}
|
}
|
||||||
@@ -405,7 +367,7 @@ static inline void stfq_le_p(void *ptr, float64 v)
|
|||||||
|
|
||||||
#if !defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
|
#if !defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
|
||||||
|
|
||||||
static inline int lduw_be_p(const void *ptr)
|
static inline int lduw_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
int val;
|
int val;
|
||||||
@@ -415,12 +377,12 @@ static inline int lduw_be_p(const void *ptr)
|
|||||||
: "m" (*(uint16_t *)ptr));
|
: "m" (*(uint16_t *)ptr));
|
||||||
return val;
|
return val;
|
||||||
#else
|
#else
|
||||||
const uint8_t *b = ptr;
|
uint8_t *b = (uint8_t *) ptr;
|
||||||
return ((b[0] << 8) | b[1]);
|
return ((b[0] << 8) | b[1]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ldsw_be_p(const void *ptr)
|
static inline int ldsw_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
int val;
|
int val;
|
||||||
@@ -430,12 +392,12 @@ static inline int ldsw_be_p(const void *ptr)
|
|||||||
: "m" (*(uint16_t *)ptr));
|
: "m" (*(uint16_t *)ptr));
|
||||||
return (int16_t)val;
|
return (int16_t)val;
|
||||||
#else
|
#else
|
||||||
const uint8_t *b = ptr;
|
uint8_t *b = (uint8_t *) ptr;
|
||||||
return (int16_t)((b[0] << 8) | b[1]);
|
return (int16_t)((b[0] << 8) | b[1]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ldl_be_p(const void *ptr)
|
static inline int ldl_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
int val;
|
int val;
|
||||||
@@ -445,16 +407,16 @@ static inline int ldl_be_p(const void *ptr)
|
|||||||
: "m" (*(uint32_t *)ptr));
|
: "m" (*(uint32_t *)ptr));
|
||||||
return val;
|
return val;
|
||||||
#else
|
#else
|
||||||
const uint8_t *b = ptr;
|
uint8_t *b = (uint8_t *) ptr;
|
||||||
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
|
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t ldq_be_p(const void *ptr)
|
static inline uint64_t ldq_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
uint32_t a,b;
|
uint32_t a,b;
|
||||||
a = ldl_be_p(ptr);
|
a = ldl_be_p(ptr);
|
||||||
b = ldl_be_p((uint8_t *)ptr + 4);
|
b = ldl_be_p(ptr+4);
|
||||||
return (((uint64_t)a<<32)|b);
|
return (((uint64_t)a<<32)|b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,12 +453,12 @@ static inline void stl_be_p(void *ptr, int v)
|
|||||||
static inline void stq_be_p(void *ptr, uint64_t v)
|
static inline void stq_be_p(void *ptr, uint64_t v)
|
||||||
{
|
{
|
||||||
stl_be_p(ptr, v >> 32);
|
stl_be_p(ptr, v >> 32);
|
||||||
stl_be_p((uint8_t *)ptr + 4, v);
|
stl_be_p(ptr + 4, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* float access */
|
/* float access */
|
||||||
|
|
||||||
static inline float32 ldfl_be_p(const void *ptr)
|
static inline float32 ldfl_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
float32 f;
|
float32 f;
|
||||||
@@ -516,11 +478,11 @@ static inline void stfl_be_p(void *ptr, float32 v)
|
|||||||
stl_be_p(ptr, u.i);
|
stl_be_p(ptr, u.i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline float64 ldfq_be_p(const void *ptr)
|
static inline float64 ldfq_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
CPU_DoubleU u;
|
CPU_DoubleU u;
|
||||||
u.l.upper = ldl_be_p(ptr);
|
u.l.upper = ldl_be_p(ptr);
|
||||||
u.l.lower = ldl_be_p((uint8_t *)ptr + 4);
|
u.l.lower = ldl_be_p(ptr + 4);
|
||||||
return u.d;
|
return u.d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,27 +491,27 @@ static inline void stfq_be_p(void *ptr, float64 v)
|
|||||||
CPU_DoubleU u;
|
CPU_DoubleU u;
|
||||||
u.d = v;
|
u.d = v;
|
||||||
stl_be_p(ptr, u.l.upper);
|
stl_be_p(ptr, u.l.upper);
|
||||||
stl_be_p((uint8_t *)ptr + 4, u.l.lower);
|
stl_be_p(ptr + 4, u.l.lower);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int lduw_be_p(const void *ptr)
|
static inline int lduw_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(uint16_t *)ptr;
|
return *(uint16_t *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ldsw_be_p(const void *ptr)
|
static inline int ldsw_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(int16_t *)ptr;
|
return *(int16_t *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ldl_be_p(const void *ptr)
|
static inline int ldl_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(uint32_t *)ptr;
|
return *(uint32_t *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t ldq_be_p(const void *ptr)
|
static inline uint64_t ldq_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(uint64_t *)ptr;
|
return *(uint64_t *)ptr;
|
||||||
}
|
}
|
||||||
@@ -571,12 +533,12 @@ static inline void stq_be_p(void *ptr, uint64_t v)
|
|||||||
|
|
||||||
/* float access */
|
/* float access */
|
||||||
|
|
||||||
static inline float32 ldfl_be_p(const void *ptr)
|
static inline float32 ldfl_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(float32 *)ptr;
|
return *(float32 *)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline float64 ldfq_be_p(const void *ptr)
|
static inline float64 ldfq_be_p(void *ptr)
|
||||||
{
|
{
|
||||||
return *(float64 *)ptr;
|
return *(float64 *)ptr;
|
||||||
}
|
}
|
||||||
@@ -623,9 +585,6 @@ static inline void stfq_be_p(void *ptr, float64 v)
|
|||||||
/* MMU memory access macros */
|
/* MMU memory access macros */
|
||||||
|
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
#include <assert.h>
|
|
||||||
#include "qemu-types.h"
|
|
||||||
|
|
||||||
/* On some host systems the guest address space is reserved on the host.
|
/* On some host systems the guest address space is reserved on the host.
|
||||||
* This allows the guest address space to be offset to a convenient location.
|
* This allows the guest address space to be offset to a convenient location.
|
||||||
*/
|
*/
|
||||||
@@ -634,16 +593,7 @@ static inline void stfq_be_p(void *ptr, float64 v)
|
|||||||
|
|
||||||
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
|
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
|
||||||
#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
|
#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
|
||||||
#define h2g(x) ({ \
|
#define h2g(x) ((target_ulong)(x - GUEST_BASE))
|
||||||
unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \
|
|
||||||
/* Check if given address fits target address space */ \
|
|
||||||
assert(__ret == (abi_ulong)__ret); \
|
|
||||||
(abi_ulong)__ret; \
|
|
||||||
})
|
|
||||||
#define h2g_valid(x) ({ \
|
|
||||||
unsigned long __guest = (unsigned long)(x) - GUEST_BASE; \
|
|
||||||
(__guest == (abi_ulong)__guest); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define saddr(x) g2h(x)
|
#define saddr(x) g2h(x)
|
||||||
#define laddr(x) g2h(x)
|
#define laddr(x) g2h(x)
|
||||||
@@ -694,14 +644,12 @@ static inline void stfq_be_p(void *ptr, float64 v)
|
|||||||
#define lduw_code(p) lduw_raw(p)
|
#define lduw_code(p) lduw_raw(p)
|
||||||
#define ldsw_code(p) ldsw_raw(p)
|
#define ldsw_code(p) ldsw_raw(p)
|
||||||
#define ldl_code(p) ldl_raw(p)
|
#define ldl_code(p) ldl_raw(p)
|
||||||
#define ldq_code(p) ldq_raw(p)
|
|
||||||
|
|
||||||
#define ldub_kernel(p) ldub_raw(p)
|
#define ldub_kernel(p) ldub_raw(p)
|
||||||
#define ldsb_kernel(p) ldsb_raw(p)
|
#define ldsb_kernel(p) ldsb_raw(p)
|
||||||
#define lduw_kernel(p) lduw_raw(p)
|
#define lduw_kernel(p) lduw_raw(p)
|
||||||
#define ldsw_kernel(p) ldsw_raw(p)
|
#define ldsw_kernel(p) ldsw_raw(p)
|
||||||
#define ldl_kernel(p) ldl_raw(p)
|
#define ldl_kernel(p) ldl_raw(p)
|
||||||
#define ldq_kernel(p) ldq_raw(p)
|
|
||||||
#define ldfl_kernel(p) ldfl_raw(p)
|
#define ldfl_kernel(p) ldfl_raw(p)
|
||||||
#define ldfq_kernel(p) ldfq_raw(p)
|
#define ldfq_kernel(p) ldfq_raw(p)
|
||||||
#define stb_kernel(p, v) stb_raw(p, v)
|
#define stb_kernel(p, v) stb_raw(p, v)
|
||||||
@@ -736,29 +684,77 @@ extern unsigned long qemu_host_page_mask;
|
|||||||
/* original state of the write flag (used when tracking self-modifying
|
/* original state of the write flag (used when tracking self-modifying
|
||||||
code */
|
code */
|
||||||
#define PAGE_WRITE_ORG 0x0010
|
#define PAGE_WRITE_ORG 0x0010
|
||||||
#define PAGE_RESERVED 0x0020
|
|
||||||
|
|
||||||
void page_dump(FILE *f);
|
void page_dump(FILE *f);
|
||||||
int page_get_flags(target_ulong address);
|
int page_get_flags(target_ulong address);
|
||||||
void page_set_flags(target_ulong start, target_ulong end, int flags);
|
void page_set_flags(target_ulong start, target_ulong end, int flags);
|
||||||
int page_check_range(target_ulong start, target_ulong len, int flags);
|
void page_unprotect_range(target_ulong data, target_ulong data_size);
|
||||||
|
|
||||||
void cpu_exec_init_all(unsigned long tb_size);
|
#define SINGLE_CPU_DEFINES
|
||||||
CPUState *cpu_copy(CPUState *env);
|
#ifdef SINGLE_CPU_DEFINES
|
||||||
|
|
||||||
|
#if defined(TARGET_I386)
|
||||||
|
|
||||||
|
#define CPUState CPUX86State
|
||||||
|
#define cpu_init cpu_x86_init
|
||||||
|
#define cpu_exec cpu_x86_exec
|
||||||
|
#define cpu_gen_code cpu_x86_gen_code
|
||||||
|
#define cpu_signal_handler cpu_x86_signal_handler
|
||||||
|
|
||||||
|
#elif defined(TARGET_ARM)
|
||||||
|
|
||||||
|
#define CPUState CPUARMState
|
||||||
|
#define cpu_init cpu_arm_init
|
||||||
|
#define cpu_exec cpu_arm_exec
|
||||||
|
#define cpu_gen_code cpu_arm_gen_code
|
||||||
|
#define cpu_signal_handler cpu_arm_signal_handler
|
||||||
|
|
||||||
|
#elif defined(TARGET_SPARC)
|
||||||
|
|
||||||
|
#define CPUState CPUSPARCState
|
||||||
|
#define cpu_init cpu_sparc_init
|
||||||
|
#define cpu_exec cpu_sparc_exec
|
||||||
|
#define cpu_gen_code cpu_sparc_gen_code
|
||||||
|
#define cpu_signal_handler cpu_sparc_signal_handler
|
||||||
|
|
||||||
|
#elif defined(TARGET_PPC)
|
||||||
|
|
||||||
|
#define CPUState CPUPPCState
|
||||||
|
#define cpu_init cpu_ppc_init
|
||||||
|
#define cpu_exec cpu_ppc_exec
|
||||||
|
#define cpu_gen_code cpu_ppc_gen_code
|
||||||
|
#define cpu_signal_handler cpu_ppc_signal_handler
|
||||||
|
|
||||||
|
#elif defined(TARGET_MIPS)
|
||||||
|
#define CPUState CPUMIPSState
|
||||||
|
#define cpu_init cpu_mips_init
|
||||||
|
#define cpu_exec cpu_mips_exec
|
||||||
|
#define cpu_gen_code cpu_mips_gen_code
|
||||||
|
#define cpu_signal_handler cpu_mips_signal_handler
|
||||||
|
|
||||||
|
#elif defined(TARGET_SH4)
|
||||||
|
#define CPUState CPUSH4State
|
||||||
|
#define cpu_init cpu_sh4_init
|
||||||
|
#define cpu_exec cpu_sh4_exec
|
||||||
|
#define cpu_gen_code cpu_sh4_gen_code
|
||||||
|
#define cpu_signal_handler cpu_sh4_signal_handler
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error unsupported target CPU
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SINGLE_CPU_DEFINES */
|
||||||
|
|
||||||
void cpu_dump_state(CPUState *env, FILE *f,
|
void cpu_dump_state(CPUState *env, FILE *f,
|
||||||
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
|
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
|
||||||
int flags);
|
int flags);
|
||||||
void cpu_dump_statistics (CPUState *env, FILE *f,
|
|
||||||
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
|
|
||||||
int flags);
|
|
||||||
|
|
||||||
void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...)
|
void cpu_abort(CPUState *env, const char *fmt, ...);
|
||||||
__attribute__ ((__format__ (__printf__, 2, 3)));
|
|
||||||
extern CPUState *first_cpu;
|
extern CPUState *first_cpu;
|
||||||
extern CPUState *cpu_single_env;
|
extern CPUState *cpu_single_env;
|
||||||
extern int64_t qemu_icount;
|
extern int code_copy_enabled;
|
||||||
extern int use_icount;
|
|
||||||
|
|
||||||
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
|
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
|
||||||
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
|
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
|
||||||
@@ -766,46 +762,19 @@ extern int use_icount;
|
|||||||
#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */
|
#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */
|
||||||
#define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */
|
#define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */
|
||||||
#define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */
|
#define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */
|
||||||
#define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */
|
|
||||||
#define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */
|
|
||||||
#define CPU_INTERRUPT_VIRQ 0x100 /* virtual interrupt pending. */
|
|
||||||
#define CPU_INTERRUPT_NMI 0x200 /* NMI pending. */
|
|
||||||
|
|
||||||
void cpu_interrupt(CPUState *s, int mask);
|
void cpu_interrupt(CPUState *s, int mask);
|
||||||
void cpu_reset_interrupt(CPUState *env, int mask);
|
void cpu_reset_interrupt(CPUState *env, int mask);
|
||||||
|
|
||||||
/* Breakpoint/watchpoint flags */
|
int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
|
||||||
#define BP_MEM_READ 0x01
|
int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
|
||||||
#define BP_MEM_WRITE 0x02
|
|
||||||
#define BP_MEM_ACCESS (BP_MEM_READ | BP_MEM_WRITE)
|
|
||||||
#define BP_STOP_BEFORE_ACCESS 0x04
|
|
||||||
#define BP_WATCHPOINT_HIT 0x08
|
|
||||||
#define BP_GDB 0x10
|
|
||||||
#define BP_CPU 0x20
|
|
||||||
|
|
||||||
int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
|
|
||||||
CPUBreakpoint **breakpoint);
|
|
||||||
int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags);
|
|
||||||
void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint);
|
|
||||||
void cpu_breakpoint_remove_all(CPUState *env, int mask);
|
|
||||||
int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
|
|
||||||
int flags, CPUWatchpoint **watchpoint);
|
|
||||||
int cpu_watchpoint_remove(CPUState *env, target_ulong addr,
|
|
||||||
target_ulong len, int flags);
|
|
||||||
void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint);
|
|
||||||
void cpu_watchpoint_remove_all(CPUState *env, int mask);
|
|
||||||
|
|
||||||
#define SSTEP_ENABLE 0x1 /* Enable simulated HW single stepping */
|
|
||||||
#define SSTEP_NOIRQ 0x2 /* Do not use IRQ while single stepping */
|
|
||||||
#define SSTEP_NOTIMER 0x4 /* Do not Timers while single stepping */
|
|
||||||
|
|
||||||
void cpu_single_step(CPUState *env, int enabled);
|
void cpu_single_step(CPUState *env, int enabled);
|
||||||
void cpu_reset(CPUState *s);
|
void cpu_reset(CPUState *s);
|
||||||
|
|
||||||
/* Return the physical page corresponding to a virtual one. Use it
|
/* Return the physical page corresponding to a virtual one. Use it
|
||||||
only for debugging because no protection checks are done. Return -1
|
only for debugging because no protection checks are done. Return -1
|
||||||
if no page found. */
|
if no page found. */
|
||||||
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
|
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
|
||||||
|
|
||||||
#define CPU_LOG_TB_OUT_ASM (1 << 0)
|
#define CPU_LOG_TB_OUT_ASM (1 << 0)
|
||||||
#define CPU_LOG_TB_IN_ASM (1 << 1)
|
#define CPU_LOG_TB_IN_ASM (1 << 1)
|
||||||
@@ -816,7 +785,6 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
|
|||||||
#define CPU_LOG_PCALL (1 << 6)
|
#define CPU_LOG_PCALL (1 << 6)
|
||||||
#define CPU_LOG_IOPORT (1 << 7)
|
#define CPU_LOG_IOPORT (1 << 7)
|
||||||
#define CPU_LOG_TB_CPU (1 << 8)
|
#define CPU_LOG_TB_CPU (1 << 8)
|
||||||
#define CPU_LOG_RESET (1 << 9)
|
|
||||||
|
|
||||||
/* define log items */
|
/* define log items */
|
||||||
typedef struct CPULogItem {
|
typedef struct CPULogItem {
|
||||||
@@ -825,7 +793,7 @@ typedef struct CPULogItem {
|
|||||||
const char *help;
|
const char *help;
|
||||||
} CPULogItem;
|
} CPULogItem;
|
||||||
|
|
||||||
extern const CPULogItem cpu_log_items[];
|
extern CPULogItem cpu_log_items[];
|
||||||
|
|
||||||
void cpu_set_log(int log_flags);
|
void cpu_set_log(int log_flags);
|
||||||
void cpu_set_log_filename(const char *filename);
|
void cpu_set_log_filename(const char *filename);
|
||||||
@@ -844,72 +812,37 @@ int cpu_inw(CPUState *env, int addr);
|
|||||||
int cpu_inl(CPUState *env, int addr);
|
int cpu_inl(CPUState *env, int addr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* address in the RAM (different from a physical address) */
|
|
||||||
#ifdef USE_KQEMU
|
|
||||||
typedef uint32_t ram_addr_t;
|
|
||||||
#else
|
|
||||||
typedef unsigned long ram_addr_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* memory API */
|
/* memory API */
|
||||||
|
|
||||||
extern ram_addr_t phys_ram_size;
|
extern int phys_ram_size;
|
||||||
extern int phys_ram_fd;
|
extern int phys_ram_fd;
|
||||||
extern uint8_t *phys_ram_base;
|
extern uint8_t *phys_ram_base;
|
||||||
extern uint8_t *phys_ram_dirty;
|
extern uint8_t *phys_ram_dirty;
|
||||||
extern ram_addr_t ram_size;
|
|
||||||
|
|
||||||
/* physical memory access */
|
/* physical memory access */
|
||||||
|
#define TLB_INVALID_MASK (1 << 3)
|
||||||
/* MMIO pages are identified by a combination of an IO device index and
|
#define IO_MEM_SHIFT 4
|
||||||
3 flags. The ROMD code stores the page ram offset in iotlb entry,
|
|
||||||
so only a limited number of ids are avaiable. */
|
|
||||||
|
|
||||||
#define IO_MEM_SHIFT 3
|
|
||||||
#define IO_MEM_NB_ENTRIES (1 << (TARGET_PAGE_BITS - IO_MEM_SHIFT))
|
#define IO_MEM_NB_ENTRIES (1 << (TARGET_PAGE_BITS - IO_MEM_SHIFT))
|
||||||
|
|
||||||
#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */
|
#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */
|
||||||
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
|
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
|
||||||
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
|
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
|
||||||
#define IO_MEM_NOTDIRTY (3 << IO_MEM_SHIFT)
|
#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
|
||||||
|
/* acts like a ROM when read and like a device when written. As an
|
||||||
/* Acts like a ROM when read and like a device when written. */
|
exception, the write memory callback gets the ram offset instead of
|
||||||
|
the physical address */
|
||||||
#define IO_MEM_ROMD (1)
|
#define IO_MEM_ROMD (1)
|
||||||
#define IO_MEM_SUBPAGE (2)
|
|
||||||
#define IO_MEM_SUBWIDTH (4)
|
|
||||||
|
|
||||||
/* Flags stored in the low bits of the TLB virtual address. These are
|
|
||||||
defined so that fast path ram access is all zeros. */
|
|
||||||
/* Zero if TLB entry is valid. */
|
|
||||||
#define TLB_INVALID_MASK (1 << 3)
|
|
||||||
/* Set if TLB entry references a clean RAM page. The iotlb entry will
|
|
||||||
contain the page physical address. */
|
|
||||||
#define TLB_NOTDIRTY (1 << 4)
|
|
||||||
/* Set if TLB entry is an IO callback. */
|
|
||||||
#define TLB_MMIO (1 << 5)
|
|
||||||
|
|
||||||
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
|
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
|
||||||
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
|
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
|
||||||
|
|
||||||
void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
|
void cpu_register_physical_memory(target_phys_addr_t start_addr,
|
||||||
ram_addr_t size,
|
unsigned long size,
|
||||||
ram_addr_t phys_offset,
|
unsigned long phys_offset);
|
||||||
ram_addr_t region_offset);
|
|
||||||
static inline void cpu_register_physical_memory(target_phys_addr_t start_addr,
|
|
||||||
ram_addr_t size,
|
|
||||||
ram_addr_t phys_offset)
|
|
||||||
{
|
|
||||||
cpu_register_physical_memory_offset(start_addr, size, phys_offset, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr);
|
|
||||||
ram_addr_t qemu_ram_alloc(ram_addr_t);
|
|
||||||
void qemu_ram_free(ram_addr_t addr);
|
|
||||||
int cpu_register_io_memory(int io_index,
|
int cpu_register_io_memory(int io_index,
|
||||||
CPUReadMemoryFunc **mem_read,
|
CPUReadMemoryFunc **mem_read,
|
||||||
CPUWriteMemoryFunc **mem_write,
|
CPUWriteMemoryFunc **mem_write,
|
||||||
void *opaque);
|
void *opaque);
|
||||||
void cpu_unregister_io_memory(int table_address);
|
|
||||||
CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index);
|
CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index);
|
||||||
CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index);
|
CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index);
|
||||||
|
|
||||||
@@ -925,20 +858,11 @@ static inline void cpu_physical_memory_write(target_phys_addr_t addr,
|
|||||||
{
|
{
|
||||||
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
|
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
|
||||||
}
|
}
|
||||||
void *cpu_physical_memory_map(target_phys_addr_t addr,
|
|
||||||
target_phys_addr_t *plen,
|
|
||||||
int is_write);
|
|
||||||
void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
|
|
||||||
int is_write, target_phys_addr_t access_len);
|
|
||||||
void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque));
|
|
||||||
void cpu_unregister_map_client(void *cookie);
|
|
||||||
|
|
||||||
uint32_t ldub_phys(target_phys_addr_t addr);
|
uint32_t ldub_phys(target_phys_addr_t addr);
|
||||||
uint32_t lduw_phys(target_phys_addr_t addr);
|
uint32_t lduw_phys(target_phys_addr_t addr);
|
||||||
uint32_t ldl_phys(target_phys_addr_t addr);
|
uint32_t ldl_phys(target_phys_addr_t addr);
|
||||||
uint64_t ldq_phys(target_phys_addr_t addr);
|
uint64_t ldq_phys(target_phys_addr_t addr);
|
||||||
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
|
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
|
||||||
void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val);
|
|
||||||
void stb_phys(target_phys_addr_t addr, uint32_t val);
|
void stb_phys(target_phys_addr_t addr, uint32_t val);
|
||||||
void stw_phys(target_phys_addr_t addr, uint32_t val);
|
void stw_phys(target_phys_addr_t addr, uint32_t val);
|
||||||
void stl_phys(target_phys_addr_t addr, uint32_t val);
|
void stl_phys(target_phys_addr_t addr, uint32_t val);
|
||||||
@@ -951,8 +875,6 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
|
|||||||
|
|
||||||
#define VGA_DIRTY_FLAG 0x01
|
#define VGA_DIRTY_FLAG 0x01
|
||||||
#define CODE_DIRTY_FLAG 0x02
|
#define CODE_DIRTY_FLAG 0x02
|
||||||
#define KQEMU_DIRTY_FLAG 0x04
|
|
||||||
#define MIGRATION_DIRTY_FLAG 0x08
|
|
||||||
|
|
||||||
/* read dirty bit (return 0 or 1) */
|
/* read dirty bit (return 0 or 1) */
|
||||||
static inline int cpu_physical_memory_is_dirty(ram_addr_t addr)
|
static inline int cpu_physical_memory_is_dirty(ram_addr_t addr)
|
||||||
@@ -975,53 +897,38 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
|
|||||||
int dirty_flags);
|
int dirty_flags);
|
||||||
void cpu_tlb_update_dirty(CPUState *env);
|
void cpu_tlb_update_dirty(CPUState *env);
|
||||||
|
|
||||||
int cpu_physical_memory_set_dirty_tracking(int enable);
|
|
||||||
|
|
||||||
int cpu_physical_memory_get_dirty_tracking(void);
|
|
||||||
|
|
||||||
void cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr);
|
|
||||||
|
|
||||||
void dump_exec_info(FILE *f,
|
void dump_exec_info(FILE *f,
|
||||||
int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
|
int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
|
||||||
|
|
||||||
/* Coalesced MMIO regions are areas where write operations can be reordered.
|
|
||||||
* This usually implies that write operations are side-effect free. This allows
|
|
||||||
* batching which can make a major impact on performance when using
|
|
||||||
* virtualization.
|
|
||||||
*/
|
|
||||||
void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
|
|
||||||
|
|
||||||
void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
|
|
||||||
|
|
||||||
/*******************************************/
|
/*******************************************/
|
||||||
/* host CPU ticks (if available) */
|
/* host CPU ticks (if available) */
|
||||||
|
|
||||||
#if defined(_ARCH_PPC)
|
#if defined(__powerpc__)
|
||||||
|
|
||||||
|
static inline uint32_t get_tbl(void)
|
||||||
|
{
|
||||||
|
uint32_t tbl;
|
||||||
|
asm volatile("mftb %0" : "=r" (tbl));
|
||||||
|
return tbl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t get_tbu(void)
|
||||||
|
{
|
||||||
|
uint32_t tbl;
|
||||||
|
asm volatile("mftbu %0" : "=r" (tbl));
|
||||||
|
return tbl;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int64_t cpu_get_real_ticks(void)
|
static inline int64_t cpu_get_real_ticks(void)
|
||||||
{
|
{
|
||||||
int64_t retval;
|
uint32_t l, h, h1;
|
||||||
#ifdef _ARCH_PPC64
|
/* NOTE: we test if wrapping has occurred */
|
||||||
/* This reads timebase in one 64bit go and includes Cell workaround from:
|
do {
|
||||||
http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027052.html
|
h = get_tbu();
|
||||||
*/
|
l = get_tbl();
|
||||||
__asm__ __volatile__ (
|
h1 = get_tbu();
|
||||||
"mftb %0\n\t"
|
} while (h != h1);
|
||||||
"cmpwi %0,0\n\t"
|
return ((int64_t)h << 32) | l;
|
||||||
"beq- $-8"
|
|
||||||
: "=r" (retval));
|
|
||||||
#else
|
|
||||||
/* http://ozlabs.org/pipermail/linuxppc-dev/1999-October/003889.html */
|
|
||||||
unsigned long junk;
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"mftbu %1\n\t"
|
|
||||||
"mftb %L0\n\t"
|
|
||||||
"mftbu %0\n\t"
|
|
||||||
"cmpw %0,%1\n\t"
|
|
||||||
"bne $-16"
|
|
||||||
: "=r" (retval), "=r" (junk));
|
|
||||||
#endif
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__i386__)
|
#elif defined(__i386__)
|
||||||
@@ -1046,15 +953,6 @@ static inline int64_t cpu_get_real_ticks(void)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__hppa__)
|
|
||||||
|
|
||||||
static inline int64_t cpu_get_real_ticks(void)
|
|
||||||
{
|
|
||||||
int val;
|
|
||||||
asm volatile ("mfctl %%cr16, %0" : "=r"(val));
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(__ia64)
|
#elif defined(__ia64)
|
||||||
|
|
||||||
static inline int64_t cpu_get_real_ticks(void)
|
static inline int64_t cpu_get_real_ticks(void)
|
||||||
@@ -1073,7 +971,7 @@ static inline int64_t cpu_get_real_ticks(void)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
|
#elif defined(__sparc_v9__)
|
||||||
|
|
||||||
static inline int64_t cpu_get_real_ticks (void)
|
static inline int64_t cpu_get_real_ticks (void)
|
||||||
{
|
{
|
||||||
@@ -1094,36 +992,6 @@ static inline int64_t cpu_get_real_ticks (void)
|
|||||||
return rval.i64;
|
return rval.i64;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__mips__)
|
|
||||||
|
|
||||||
static inline int64_t cpu_get_real_ticks(void)
|
|
||||||
{
|
|
||||||
#if __mips_isa_rev >= 2
|
|
||||||
uint32_t count;
|
|
||||||
static uint32_t cyc_per_count = 0;
|
|
||||||
|
|
||||||
if (!cyc_per_count)
|
|
||||||
__asm__ __volatile__("rdhwr %0, $3" : "=r" (cyc_per_count));
|
|
||||||
|
|
||||||
__asm__ __volatile__("rdhwr %1, $2" : "=r" (count));
|
|
||||||
return (int64_t)(count * cyc_per_count);
|
|
||||||
#else
|
|
||||||
/* FIXME */
|
|
||||||
static int64_t ticks = 0;
|
|
||||||
return ticks++;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
/* The host CPU doesn't have an easily accessible cycle counter.
|
|
||||||
Just return a monotonically increasing value. This will be
|
|
||||||
totally wrong, but hopefully better than nothing. */
|
|
||||||
static inline int64_t cpu_get_real_ticks (void)
|
|
||||||
{
|
|
||||||
static int64_t ticks = 0;
|
|
||||||
return ticks++;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* profiling */
|
/* profiling */
|
||||||
@@ -1141,6 +1009,7 @@ extern int64_t dev_time;
|
|||||||
extern int64_t kqemu_ret_int_count;
|
extern int64_t kqemu_ret_int_count;
|
||||||
extern int64_t kqemu_ret_excp_count;
|
extern int64_t kqemu_ret_excp_count;
|
||||||
extern int64_t kqemu_ret_intr_count;
|
extern int64_t kqemu_ret_intr_count;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* CPU_ALL_H */
|
#endif /* CPU_ALL_H */
|
||||||
|
|||||||
132
cpu-defs.h
132
cpu-defs.h
@@ -15,21 +15,15 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#ifndef CPU_DEFS_H
|
#ifndef CPU_DEFS_H
|
||||||
#define CPU_DEFS_H
|
#define CPU_DEFS_H
|
||||||
|
|
||||||
#ifndef NEED_CPU_H
|
|
||||||
#error cpu.h included from common code
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <signal.h>
|
|
||||||
#include "osdep.h"
|
#include "osdep.h"
|
||||||
#include "sys-queue.h"
|
|
||||||
|
|
||||||
#ifndef TARGET_LONG_BITS
|
#ifndef TARGET_LONG_BITS
|
||||||
#error TARGET_LONG_BITS must be defined before including this header
|
#error TARGET_LONG_BITS must be defined before including this header
|
||||||
@@ -50,14 +44,10 @@
|
|||||||
typedef int32_t target_long;
|
typedef int32_t target_long;
|
||||||
typedef uint32_t target_ulong;
|
typedef uint32_t target_ulong;
|
||||||
#define TARGET_FMT_lx "%08x"
|
#define TARGET_FMT_lx "%08x"
|
||||||
#define TARGET_FMT_ld "%d"
|
|
||||||
#define TARGET_FMT_lu "%u"
|
|
||||||
#elif TARGET_LONG_SIZE == 8
|
#elif TARGET_LONG_SIZE == 8
|
||||||
typedef int64_t target_long;
|
typedef int64_t target_long;
|
||||||
typedef uint64_t target_ulong;
|
typedef uint64_t target_ulong;
|
||||||
#define TARGET_FMT_lx "%016" PRIx64
|
#define TARGET_FMT_lx "%016" PRIx64
|
||||||
#define TARGET_FMT_ld "%" PRId64
|
|
||||||
#define TARGET_FMT_lu "%" PRIu64
|
|
||||||
#else
|
#else
|
||||||
#error TARGET_LONG_SIZE undefined
|
#error TARGET_LONG_SIZE undefined
|
||||||
#endif
|
#endif
|
||||||
@@ -70,148 +60,66 @@ typedef uint64_t target_ulong;
|
|||||||
|
|
||||||
#if TARGET_PHYS_ADDR_BITS == 32
|
#if TARGET_PHYS_ADDR_BITS == 32
|
||||||
typedef uint32_t target_phys_addr_t;
|
typedef uint32_t target_phys_addr_t;
|
||||||
#define TARGET_FMT_plx "%08x"
|
|
||||||
#elif TARGET_PHYS_ADDR_BITS == 64
|
#elif TARGET_PHYS_ADDR_BITS == 64
|
||||||
typedef uint64_t target_phys_addr_t;
|
typedef uint64_t target_phys_addr_t;
|
||||||
#define TARGET_FMT_plx "%016" PRIx64
|
|
||||||
#else
|
#else
|
||||||
#error TARGET_PHYS_ADDR_BITS undefined
|
#error TARGET_PHYS_ADDR_BITS undefined
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* address in the RAM (different from a physical address) */
|
||||||
|
typedef unsigned long ram_addr_t;
|
||||||
|
|
||||||
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
|
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
|
||||||
|
|
||||||
#define EXCP_INTERRUPT 0x10000 /* async interruption */
|
#define EXCP_INTERRUPT 0x10000 /* async interruption */
|
||||||
#define EXCP_HLT 0x10001 /* hlt instruction reached */
|
#define EXCP_HLT 0x10001 /* hlt instruction reached */
|
||||||
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
|
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
|
||||||
#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
|
#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
|
||||||
|
#define MAX_BREAKPOINTS 32
|
||||||
|
|
||||||
#define TB_JMP_CACHE_BITS 12
|
#define TB_JMP_CACHE_BITS 12
|
||||||
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
|
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
|
||||||
|
|
||||||
/* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for
|
|
||||||
addresses on the same page. The top bits are the same. This allows
|
|
||||||
TLB invalidation to quickly clear a subset of the hash table. */
|
|
||||||
#define TB_JMP_PAGE_BITS (TB_JMP_CACHE_BITS / 2)
|
|
||||||
#define TB_JMP_PAGE_SIZE (1 << TB_JMP_PAGE_BITS)
|
|
||||||
#define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1)
|
|
||||||
#define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE)
|
|
||||||
|
|
||||||
#define CPU_TLB_BITS 8
|
#define CPU_TLB_BITS 8
|
||||||
#define CPU_TLB_SIZE (1 << CPU_TLB_BITS)
|
#define CPU_TLB_SIZE (1 << CPU_TLB_BITS)
|
||||||
|
|
||||||
#if TARGET_PHYS_ADDR_BITS == 32 && TARGET_LONG_BITS == 32
|
|
||||||
#define CPU_TLB_ENTRY_BITS 4
|
|
||||||
#else
|
|
||||||
#define CPU_TLB_ENTRY_BITS 5
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct CPUTLBEntry {
|
typedef struct CPUTLBEntry {
|
||||||
/* bit TARGET_LONG_BITS to TARGET_PAGE_BITS : virtual address
|
/* bit 31 to TARGET_PAGE_BITS : virtual address
|
||||||
bit TARGET_PAGE_BITS-1..4 : Nonzero for accesses that should not
|
bit TARGET_PAGE_BITS-1..IO_MEM_SHIFT : if non zero, memory io
|
||||||
go directly to ram.
|
zone number
|
||||||
bit 3 : indicates that the entry is invalid
|
bit 3 : indicates that the entry is invalid
|
||||||
bit 2..0 : zero
|
bit 2..0 : zero
|
||||||
*/
|
*/
|
||||||
target_ulong addr_read;
|
target_ulong addr_read;
|
||||||
target_ulong addr_write;
|
target_ulong addr_write;
|
||||||
target_ulong addr_code;
|
target_ulong addr_code;
|
||||||
/* Addend to virtual address to get physical address. IO accesses
|
/* addend to virtual address to get physical address */
|
||||||
use the corresponding iotlb value. */
|
|
||||||
#if TARGET_PHYS_ADDR_BITS == 64
|
|
||||||
/* on i386 Linux make sure it is aligned */
|
|
||||||
target_phys_addr_t addend __attribute__((aligned(8)));
|
|
||||||
#else
|
|
||||||
target_phys_addr_t addend;
|
target_phys_addr_t addend;
|
||||||
#endif
|
|
||||||
/* padding to get a power of two size */
|
|
||||||
uint8_t dummy[(1 << CPU_TLB_ENTRY_BITS) -
|
|
||||||
(sizeof(target_ulong) * 3 +
|
|
||||||
((-sizeof(target_ulong) * 3) & (sizeof(target_phys_addr_t) - 1)) +
|
|
||||||
sizeof(target_phys_addr_t))];
|
|
||||||
} CPUTLBEntry;
|
} CPUTLBEntry;
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
typedef struct icount_decr_u16 {
|
|
||||||
uint16_t high;
|
|
||||||
uint16_t low;
|
|
||||||
} icount_decr_u16;
|
|
||||||
#else
|
|
||||||
typedef struct icount_decr_u16 {
|
|
||||||
uint16_t low;
|
|
||||||
uint16_t high;
|
|
||||||
} icount_decr_u16;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct kvm_run;
|
|
||||||
struct KVMState;
|
|
||||||
|
|
||||||
typedef struct CPUBreakpoint {
|
|
||||||
target_ulong pc;
|
|
||||||
int flags; /* BP_* */
|
|
||||||
TAILQ_ENTRY(CPUBreakpoint) entry;
|
|
||||||
} CPUBreakpoint;
|
|
||||||
|
|
||||||
typedef struct CPUWatchpoint {
|
|
||||||
target_ulong vaddr;
|
|
||||||
target_ulong len_mask;
|
|
||||||
int flags; /* BP_* */
|
|
||||||
TAILQ_ENTRY(CPUWatchpoint) entry;
|
|
||||||
} CPUWatchpoint;
|
|
||||||
|
|
||||||
#define CPU_TEMP_BUF_NLONGS 128
|
|
||||||
#define CPU_COMMON \
|
#define CPU_COMMON \
|
||||||
struct TranslationBlock *current_tb; /* currently executing TB */ \
|
struct TranslationBlock *current_tb; /* currently executing TB */ \
|
||||||
/* soft mmu support */ \
|
/* soft mmu support */ \
|
||||||
/* in order to avoid passing too many arguments to the MMIO \
|
/* in order to avoid passing too many arguments to the memory \
|
||||||
helpers, we store some rarely used information in the CPU \
|
write helpers, we store some rarely used information in the CPU \
|
||||||
context) */ \
|
context) */ \
|
||||||
unsigned long mem_io_pc; /* host pc at which the memory was \
|
unsigned long mem_write_pc; /* host pc at which the memory was \
|
||||||
accessed */ \
|
written */ \
|
||||||
target_ulong mem_io_vaddr; /* target virtual addr at which the \
|
target_ulong mem_write_vaddr; /* target virtual addr at which the \
|
||||||
memory was accessed */ \
|
memory was written */ \
|
||||||
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
|
/* 0 = kernel, 1 = user */ \
|
||||||
uint32_t interrupt_request; \
|
CPUTLBEntry tlb_table[2][CPU_TLB_SIZE]; \
|
||||||
volatile sig_atomic_t exit_request; \
|
|
||||||
/* The meaning of the MMU modes is defined in the target code. */ \
|
|
||||||
CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \
|
|
||||||
target_phys_addr_t iotlb[NB_MMU_MODES][CPU_TLB_SIZE]; \
|
|
||||||
struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
|
struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
|
||||||
/* buffer for temporaries in the code generator */ \
|
|
||||||
long temp_buf[CPU_TEMP_BUF_NLONGS]; \
|
|
||||||
\
|
|
||||||
int64_t icount_extra; /* Instructions until next timer event. */ \
|
|
||||||
/* Number of cycles left, with interrupt flag in high bit. \
|
|
||||||
This allows a single read-compare-cbranch-write sequence to test \
|
|
||||||
for both decrementer underflow and exceptions. */ \
|
|
||||||
union { \
|
|
||||||
uint32_t u32; \
|
|
||||||
icount_decr_u16 u16; \
|
|
||||||
} icount_decr; \
|
|
||||||
uint32_t can_do_io; /* nonzero if memory mapped IO is safe. */ \
|
|
||||||
\
|
\
|
||||||
/* from this point: preserved by CPU reset */ \
|
/* from this point: preserved by CPU reset */ \
|
||||||
/* ice debug support */ \
|
/* ice debug support */ \
|
||||||
TAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints; \
|
target_ulong breakpoints[MAX_BREAKPOINTS]; \
|
||||||
|
int nb_breakpoints; \
|
||||||
int singlestep_enabled; \
|
int singlestep_enabled; \
|
||||||
\
|
\
|
||||||
TAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints; \
|
|
||||||
CPUWatchpoint *watchpoint_hit; \
|
|
||||||
\
|
|
||||||
struct GDBRegisterState *gdb_regs; \
|
|
||||||
\
|
|
||||||
/* Core interrupt code */ \
|
|
||||||
jmp_buf jmp_env; \
|
|
||||||
int exception_index; \
|
|
||||||
\
|
|
||||||
void *next_cpu; /* next CPU sharing TB cache */ \
|
void *next_cpu; /* next CPU sharing TB cache */ \
|
||||||
int cpu_index; /* CPU index (informative) */ \
|
int cpu_index; /* CPU index (informative) */ \
|
||||||
int running; /* Nonzero if cpu is currently running(usermode). */ \
|
|
||||||
/* user data */ \
|
/* user data */ \
|
||||||
void *opaque; \
|
void *opaque;
|
||||||
\
|
|
||||||
const char *cpu_model_str; \
|
|
||||||
struct KVMState *kvm_state; \
|
|
||||||
struct kvm_run *kvm_run; \
|
|
||||||
int kvm_fd;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
1160
cpu-exec.c
1160
cpu-exec.c
File diff suppressed because it is too large
Load Diff
2895
cris-dis.c
2895
cris-dis.c
File diff suppressed because it is too large
Load Diff
376
curses.c
376
curses.c
@@ -1,376 +0,0 @@
|
|||||||
/*
|
|
||||||
* QEMU curses/ncurses display driver
|
|
||||||
*
|
|
||||||
* Copyright (c) 2005 Andrzej Zaborowski <balrog@zabor.org>
|
|
||||||
*
|
|
||||||
* 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 "console.h"
|
|
||||||
#include "sysemu.h"
|
|
||||||
|
|
||||||
#include <curses.h>
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
|
||||||
#define resize_term resizeterm
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FONT_HEIGHT 16
|
|
||||||
#define FONT_WIDTH 8
|
|
||||||
|
|
||||||
static console_ch_t screen[160 * 100];
|
|
||||||
static WINDOW *screenpad = NULL;
|
|
||||||
static int width, height, gwidth, gheight, invalidate;
|
|
||||||
static int px, py, sminx, sminy, smaxx, smaxy;
|
|
||||||
|
|
||||||
static void curses_update(DisplayState *ds, int x, int y, int w, int h)
|
|
||||||
{
|
|
||||||
chtype *line;
|
|
||||||
|
|
||||||
line = ((chtype *) screen) + y * width;
|
|
||||||
for (h += y; y < h; y ++, line += width)
|
|
||||||
mvwaddchnstr(screenpad, y, 0, line, width);
|
|
||||||
|
|
||||||
pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void curses_calc_pad(void)
|
|
||||||
{
|
|
||||||
if (is_fixedsize_console()) {
|
|
||||||
width = gwidth;
|
|
||||||
height = gheight;
|
|
||||||
} else {
|
|
||||||
width = COLS;
|
|
||||||
height = LINES;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screenpad)
|
|
||||||
delwin(screenpad);
|
|
||||||
|
|
||||||
clear();
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
screenpad = newpad(height, width);
|
|
||||||
|
|
||||||
if (width > COLS) {
|
|
||||||
px = (width - COLS) / 2;
|
|
||||||
sminx = 0;
|
|
||||||
smaxx = COLS;
|
|
||||||
} else {
|
|
||||||
px = 0;
|
|
||||||
sminx = (COLS - width) / 2;
|
|
||||||
smaxx = sminx + width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (height > LINES) {
|
|
||||||
py = (height - LINES) / 2;
|
|
||||||
sminy = 0;
|
|
||||||
smaxy = LINES;
|
|
||||||
} else {
|
|
||||||
py = 0;
|
|
||||||
sminy = (LINES - height) / 2;
|
|
||||||
smaxy = sminy + height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void curses_resize(DisplayState *ds)
|
|
||||||
{
|
|
||||||
if (ds_get_width(ds) == gwidth && ds_get_height(ds) == gheight)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gwidth = ds_get_width(ds);
|
|
||||||
gheight = ds_get_height(ds);
|
|
||||||
|
|
||||||
curses_calc_pad();
|
|
||||||
ds->surface->width = width * FONT_WIDTH;
|
|
||||||
ds->surface->height = height * FONT_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#if defined(SIGWINCH) && defined(KEY_RESIZE)
|
|
||||||
static void curses_winch_handler(int signum)
|
|
||||||
{
|
|
||||||
struct winsize {
|
|
||||||
unsigned short ws_row;
|
|
||||||
unsigned short ws_col;
|
|
||||||
unsigned short ws_xpixel; /* unused */
|
|
||||||
unsigned short ws_ypixel; /* unused */
|
|
||||||
} ws;
|
|
||||||
|
|
||||||
/* terminal size changed */
|
|
||||||
if (ioctl(1, TIOCGWINSZ, &ws) == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
resize_term(ws.ws_row, ws.ws_col);
|
|
||||||
curses_calc_pad();
|
|
||||||
invalidate = 1;
|
|
||||||
|
|
||||||
/* some systems require this */
|
|
||||||
signal(SIGWINCH, curses_winch_handler);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void curses_cursor_position(DisplayState *ds, int x, int y)
|
|
||||||
{
|
|
||||||
if (x >= 0) {
|
|
||||||
x = sminx + x - px;
|
|
||||||
y = sminy + y - py;
|
|
||||||
|
|
||||||
if (x >= 0 && y >= 0 && x < COLS && y < LINES) {
|
|
||||||
move(y, x);
|
|
||||||
curs_set(1);
|
|
||||||
/* it seems that curs_set(1) must always be called before
|
|
||||||
* curs_set(2) for the latter to have effect */
|
|
||||||
if (!is_graphic_console())
|
|
||||||
curs_set(2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
curs_set(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* generic keyboard conversion */
|
|
||||||
|
|
||||||
#include "curses_keys.h"
|
|
||||||
#include "keymaps.c"
|
|
||||||
|
|
||||||
static kbd_layout_t *kbd_layout = 0;
|
|
||||||
static int keycode2keysym[CURSES_KEYS];
|
|
||||||
|
|
||||||
static void curses_refresh(DisplayState *ds)
|
|
||||||
{
|
|
||||||
int chr, nextchr, keysym, keycode;
|
|
||||||
|
|
||||||
if (invalidate) {
|
|
||||||
clear();
|
|
||||||
refresh();
|
|
||||||
curses_calc_pad();
|
|
||||||
ds->surface->width = FONT_WIDTH * width;
|
|
||||||
ds->surface->height = FONT_HEIGHT * height;
|
|
||||||
vga_hw_invalidate();
|
|
||||||
invalidate = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vga_hw_text_update(screen);
|
|
||||||
|
|
||||||
nextchr = ERR;
|
|
||||||
while (1) {
|
|
||||||
/* while there are any pending key strokes to process */
|
|
||||||
if (nextchr == ERR)
|
|
||||||
chr = getch();
|
|
||||||
else {
|
|
||||||
chr = nextchr;
|
|
||||||
nextchr = ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chr == ERR)
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef KEY_RESIZE
|
|
||||||
/* this shouldn't occur when we use a custom SIGWINCH handler */
|
|
||||||
if (chr == KEY_RESIZE) {
|
|
||||||
clear();
|
|
||||||
refresh();
|
|
||||||
curses_calc_pad();
|
|
||||||
curses_update(ds, 0, 0, width, height);
|
|
||||||
ds->surface->width = FONT_WIDTH * width;
|
|
||||||
ds->surface->height = FONT_HEIGHT * height;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
keycode = curses2keycode[chr];
|
|
||||||
if (keycode == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* alt key */
|
|
||||||
if (keycode == 1) {
|
|
||||||
nextchr = getch();
|
|
||||||
|
|
||||||
if (nextchr != ERR) {
|
|
||||||
keycode = curses2keycode[nextchr];
|
|
||||||
nextchr = ERR;
|
|
||||||
if (keycode == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
keycode |= ALT;
|
|
||||||
|
|
||||||
/* process keys reserved for qemu */
|
|
||||||
if (keycode >= QEMU_KEY_CONSOLE0 &&
|
|
||||||
keycode < QEMU_KEY_CONSOLE0 + 9) {
|
|
||||||
erase();
|
|
||||||
wnoutrefresh(stdscr);
|
|
||||||
console_select(keycode - QEMU_KEY_CONSOLE0);
|
|
||||||
|
|
||||||
invalidate = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kbd_layout && !(keycode & GREY)) {
|
|
||||||
keysym = keycode2keysym[keycode & KEY_MASK];
|
|
||||||
if (keysym == -1)
|
|
||||||
keysym = chr;
|
|
||||||
|
|
||||||
keycode &= ~KEY_MASK;
|
|
||||||
keycode |= keysym2scancode(kbd_layout, keysym);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_graphic_console()) {
|
|
||||||
/* since terminals don't know about key press and release
|
|
||||||
* events, we need to emit both for each key received */
|
|
||||||
if (keycode & SHIFT)
|
|
||||||
kbd_put_keycode(SHIFT_CODE);
|
|
||||||
if (keycode & CNTRL)
|
|
||||||
kbd_put_keycode(CNTRL_CODE);
|
|
||||||
if (keycode & ALT)
|
|
||||||
kbd_put_keycode(ALT_CODE);
|
|
||||||
if (keycode & GREY)
|
|
||||||
kbd_put_keycode(GREY_CODE);
|
|
||||||
kbd_put_keycode(keycode & KEY_MASK);
|
|
||||||
if (keycode & GREY)
|
|
||||||
kbd_put_keycode(GREY_CODE);
|
|
||||||
kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE);
|
|
||||||
if (keycode & ALT)
|
|
||||||
kbd_put_keycode(ALT_CODE | KEY_RELEASE);
|
|
||||||
if (keycode & CNTRL)
|
|
||||||
kbd_put_keycode(CNTRL_CODE | KEY_RELEASE);
|
|
||||||
if (keycode & SHIFT)
|
|
||||||
kbd_put_keycode(SHIFT_CODE | KEY_RELEASE);
|
|
||||||
} else {
|
|
||||||
keysym = curses2keysym[chr];
|
|
||||||
if (keysym == -1)
|
|
||||||
keysym = chr;
|
|
||||||
|
|
||||||
kbd_put_keysym(keysym);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void curses_cleanup(void *opaque)
|
|
||||||
{
|
|
||||||
endwin();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void curses_atexit(void)
|
|
||||||
{
|
|
||||||
curses_cleanup(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void curses_setup(void)
|
|
||||||
{
|
|
||||||
int i, colour_default[8] = {
|
|
||||||
COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
|
|
||||||
COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* input as raw as possible, let everything be interpreted
|
|
||||||
* by the guest system */
|
|
||||||
initscr(); noecho(); intrflush(stdscr, FALSE);
|
|
||||||
nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
|
|
||||||
start_color(); raw(); scrollok(stdscr, FALSE);
|
|
||||||
|
|
||||||
for (i = 0; i < 64; i ++)
|
|
||||||
init_pair(i, colour_default[i & 7], colour_default[i >> 3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void curses_keyboard_setup(void)
|
|
||||||
{
|
|
||||||
int i, keycode, keysym;
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
/* always use generic keymaps */
|
|
||||||
if (!keyboard_layout)
|
|
||||||
keyboard_layout = "en-us";
|
|
||||||
#endif
|
|
||||||
if(keyboard_layout) {
|
|
||||||
kbd_layout = init_keyboard_layout(keyboard_layout);
|
|
||||||
if (!kbd_layout)
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < CURSES_KEYS; i ++)
|
|
||||||
keycode2keysym[i] = -1;
|
|
||||||
|
|
||||||
for (i = 0; i < CURSES_KEYS; i ++) {
|
|
||||||
if (curses2keycode[i] == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
keycode = curses2keycode[i] & KEY_MASK;
|
|
||||||
if (keycode2keysym[keycode] >= 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (keysym = 0; keysym < CURSES_KEYS; keysym ++)
|
|
||||||
if (curses2keycode[keysym] == keycode) {
|
|
||||||
keycode2keysym[keycode] = keysym;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keysym >= CURSES_KEYS)
|
|
||||||
keycode2keysym[keycode] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void curses_display_init(DisplayState *ds, int full_screen)
|
|
||||||
{
|
|
||||||
DisplayChangeListener *dcl;
|
|
||||||
#ifndef _WIN32
|
|
||||||
if (!isatty(1)) {
|
|
||||||
fprintf(stderr, "We need a terminal output\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
curses_setup();
|
|
||||||
curses_keyboard_setup();
|
|
||||||
atexit(curses_atexit);
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#if defined(SIGWINCH) && defined(KEY_RESIZE)
|
|
||||||
/* some curses implementations provide a handler, but we
|
|
||||||
* want to be sure this is handled regardless of the library */
|
|
||||||
signal(SIGWINCH, curses_winch_handler);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
|
|
||||||
dcl->dpy_update = curses_update;
|
|
||||||
dcl->dpy_resize = curses_resize;
|
|
||||||
dcl->dpy_refresh = curses_refresh;
|
|
||||||
dcl->dpy_text_cursor = curses_cursor_position;
|
|
||||||
register_displaychangelistener(ds, dcl);
|
|
||||||
qemu_free_displaysurface(ds->surface);
|
|
||||||
ds->surface = qemu_create_displaysurface_from(640, 400, 0, 0, (uint8_t*) screen);
|
|
||||||
|
|
||||||
invalidate = 1;
|
|
||||||
|
|
||||||
/* Standard VGA initial text mode dimensions */
|
|
||||||
curses_resize(ds);
|
|
||||||
}
|
|
||||||
484
curses_keys.h
484
curses_keys.h
@@ -1,484 +0,0 @@
|
|||||||
/*
|
|
||||||
* Keycode and keysyms conversion tables for curses
|
|
||||||
*
|
|
||||||
* Copyright (c) 2005 Andrzej Zaborowski <balrog@zabor.org>
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
#define KEY_RELEASE 0x80
|
|
||||||
#define KEY_MASK 0x7f
|
|
||||||
#define SHIFT_CODE 0x2a
|
|
||||||
#define SHIFT 0x0080
|
|
||||||
#define GREY_CODE 0xe0
|
|
||||||
#define GREY 0x0100
|
|
||||||
#define CNTRL_CODE 0x1d
|
|
||||||
#define CNTRL 0x0200
|
|
||||||
#define ALT_CODE 0x38
|
|
||||||
#define ALT 0x0400
|
|
||||||
|
|
||||||
/* curses won't detect a Control + Alt + 1, so use Alt + 1 */
|
|
||||||
#define QEMU_KEY_CONSOLE0 (2 | ALT) /* (curses2keycode['1'] | ALT) */
|
|
||||||
|
|
||||||
#define CURSES_KEYS KEY_MAX /* KEY_MAX defined in <curses.h> */
|
|
||||||
|
|
||||||
static const int curses2keycode[CURSES_KEYS] = {
|
|
||||||
[0 ... (CURSES_KEYS - 1)] = -1,
|
|
||||||
|
|
||||||
[0x01b] = 1, /* Escape */
|
|
||||||
['1'] = 2,
|
|
||||||
['2'] = 3,
|
|
||||||
['3'] = 4,
|
|
||||||
['4'] = 5,
|
|
||||||
['5'] = 6,
|
|
||||||
['6'] = 7,
|
|
||||||
['7'] = 8,
|
|
||||||
['8'] = 9,
|
|
||||||
['9'] = 10,
|
|
||||||
['0'] = 11,
|
|
||||||
['-'] = 12,
|
|
||||||
['='] = 13,
|
|
||||||
[0x07f] = 14, /* Backspace */
|
|
||||||
[0x107] = 14, /* Backspace */
|
|
||||||
|
|
||||||
['\t'] = 15, /* Tab */
|
|
||||||
['q'] = 16,
|
|
||||||
['w'] = 17,
|
|
||||||
['e'] = 18,
|
|
||||||
['r'] = 19,
|
|
||||||
['t'] = 20,
|
|
||||||
['y'] = 21,
|
|
||||||
['u'] = 22,
|
|
||||||
['i'] = 23,
|
|
||||||
['o'] = 24,
|
|
||||||
['p'] = 25,
|
|
||||||
['['] = 26,
|
|
||||||
[']'] = 27,
|
|
||||||
['\n'] = 28, /* Return */
|
|
||||||
['\r'] = 28, /* Return */
|
|
||||||
[0x157] = 28, /* Return */
|
|
||||||
|
|
||||||
['a'] = 30,
|
|
||||||
['s'] = 31,
|
|
||||||
['d'] = 32,
|
|
||||||
['f'] = 33,
|
|
||||||
['g'] = 34,
|
|
||||||
['h'] = 35,
|
|
||||||
['j'] = 36,
|
|
||||||
['k'] = 37,
|
|
||||||
['l'] = 38,
|
|
||||||
[';'] = 39,
|
|
||||||
['\''] = 40, /* Single quote */
|
|
||||||
['`'] = 41,
|
|
||||||
['\\'] = 43, /* Backslash */
|
|
||||||
|
|
||||||
['z'] = 44,
|
|
||||||
['x'] = 45,
|
|
||||||
['c'] = 46,
|
|
||||||
['v'] = 47,
|
|
||||||
['b'] = 48,
|
|
||||||
['n'] = 49,
|
|
||||||
['m'] = 50,
|
|
||||||
[','] = 51,
|
|
||||||
['.'] = 52,
|
|
||||||
['/'] = 53,
|
|
||||||
|
|
||||||
[' '] = 57,
|
|
||||||
|
|
||||||
[0x109] = 59, /* Function Key 1 */
|
|
||||||
[0x10a] = 60, /* Function Key 2 */
|
|
||||||
[0x10b] = 61, /* Function Key 3 */
|
|
||||||
[0x10c] = 62, /* Function Key 4 */
|
|
||||||
[0x10d] = 63, /* Function Key 5 */
|
|
||||||
[0x10e] = 64, /* Function Key 6 */
|
|
||||||
[0x10f] = 65, /* Function Key 7 */
|
|
||||||
[0x110] = 66, /* Function Key 8 */
|
|
||||||
[0x111] = 67, /* Function Key 9 */
|
|
||||||
[0x112] = 68, /* Function Key 10 */
|
|
||||||
[0x113] = 87, /* Function Key 11 */
|
|
||||||
[0x114] = 88, /* Function Key 12 */
|
|
||||||
|
|
||||||
[0x106] = 71 | GREY, /* Home */
|
|
||||||
[0x103] = 72 | GREY, /* Up Arrow */
|
|
||||||
[0x153] = 73 | GREY, /* Page Up */
|
|
||||||
[0x104] = 75 | GREY, /* Left Arrow */
|
|
||||||
[0x105] = 77 | GREY, /* Right Arrow */
|
|
||||||
[0x168] = 79 | GREY, /* End */
|
|
||||||
[0x102] = 80 | GREY, /* Down Arrow */
|
|
||||||
[0x152] = 81 | GREY, /* Page Down */
|
|
||||||
[0x14b] = 82 | GREY, /* Insert */
|
|
||||||
[0x14a] = 83 | GREY, /* Delete */
|
|
||||||
|
|
||||||
['!'] = 2 | SHIFT,
|
|
||||||
['@'] = 3 | SHIFT,
|
|
||||||
['#'] = 4 | SHIFT,
|
|
||||||
['$'] = 5 | SHIFT,
|
|
||||||
['%'] = 6 | SHIFT,
|
|
||||||
['^'] = 7 | SHIFT,
|
|
||||||
['&'] = 8 | SHIFT,
|
|
||||||
['*'] = 9 | SHIFT,
|
|
||||||
['('] = 10 | SHIFT,
|
|
||||||
[')'] = 11 | SHIFT,
|
|
||||||
['_'] = 12 | SHIFT,
|
|
||||||
['+'] = 13 | SHIFT,
|
|
||||||
|
|
||||||
[0x161] = 15 | SHIFT, /* Shift + Tab */
|
|
||||||
['Q'] = 16 | SHIFT,
|
|
||||||
['W'] = 17 | SHIFT,
|
|
||||||
['E'] = 18 | SHIFT,
|
|
||||||
['R'] = 19 | SHIFT,
|
|
||||||
['T'] = 20 | SHIFT,
|
|
||||||
['Y'] = 21 | SHIFT,
|
|
||||||
['U'] = 22 | SHIFT,
|
|
||||||
['I'] = 23 | SHIFT,
|
|
||||||
['O'] = 24 | SHIFT,
|
|
||||||
['P'] = 25 | SHIFT,
|
|
||||||
['{'] = 26 | SHIFT,
|
|
||||||
['}'] = 27 | SHIFT,
|
|
||||||
|
|
||||||
['A'] = 30 | SHIFT,
|
|
||||||
['S'] = 31 | SHIFT,
|
|
||||||
['D'] = 32 | SHIFT,
|
|
||||||
['F'] = 33 | SHIFT,
|
|
||||||
['G'] = 34 | SHIFT,
|
|
||||||
['H'] = 35 | SHIFT,
|
|
||||||
['J'] = 36 | SHIFT,
|
|
||||||
['K'] = 37 | SHIFT,
|
|
||||||
['L'] = 38 | SHIFT,
|
|
||||||
[':'] = 39 | SHIFT,
|
|
||||||
['"'] = 40 | SHIFT,
|
|
||||||
['~'] = 41 | SHIFT,
|
|
||||||
['|'] = 43 | SHIFT,
|
|
||||||
|
|
||||||
['Z'] = 44 | SHIFT,
|
|
||||||
['X'] = 45 | SHIFT,
|
|
||||||
['C'] = 46 | SHIFT,
|
|
||||||
['V'] = 47 | SHIFT,
|
|
||||||
['B'] = 48 | SHIFT,
|
|
||||||
['N'] = 49 | SHIFT,
|
|
||||||
['M'] = 50 | SHIFT,
|
|
||||||
['<'] = 51 | SHIFT,
|
|
||||||
['>'] = 52 | SHIFT,
|
|
||||||
['?'] = 53 | SHIFT,
|
|
||||||
|
|
||||||
[0x115] = 59 | SHIFT, /* Shift + Function Key 1 */
|
|
||||||
[0x116] = 60 | SHIFT, /* Shift + Function Key 2 */
|
|
||||||
[0x117] = 61 | SHIFT, /* Shift + Function Key 3 */
|
|
||||||
[0x118] = 62 | SHIFT, /* Shift + Function Key 4 */
|
|
||||||
[0x119] = 63 | SHIFT, /* Shift + Function Key 5 */
|
|
||||||
[0x11a] = 64 | SHIFT, /* Shift + Function Key 6 */
|
|
||||||
[0x11b] = 65 | SHIFT, /* Shift + Function Key 7 */
|
|
||||||
[0x11c] = 66 | SHIFT, /* Shift + Function Key 8 */
|
|
||||||
|
|
||||||
[0x011] = 16 | CNTRL, /* Control + q */
|
|
||||||
[0x017] = 17 | CNTRL, /* Control + w */
|
|
||||||
[0x005] = 18 | CNTRL, /* Control + e */
|
|
||||||
[0x012] = 19 | CNTRL, /* Control + r */
|
|
||||||
[0x014] = 20 | CNTRL, /* Control + t */
|
|
||||||
[0x019] = 21 | CNTRL, /* Control + y */
|
|
||||||
[0x015] = 22 | CNTRL, /* Control + u */
|
|
||||||
/* Control + i collides with Tab */
|
|
||||||
[0x00f] = 24 | CNTRL, /* Control + o */
|
|
||||||
[0x010] = 25 | CNTRL, /* Control + p */
|
|
||||||
|
|
||||||
[0x001] = 30 | CNTRL, /* Control + a */
|
|
||||||
[0x013] = 31 | CNTRL, /* Control + s */
|
|
||||||
[0x004] = 32 | CNTRL, /* Control + d */
|
|
||||||
[0x006] = 33 | CNTRL, /* Control + f */
|
|
||||||
[0x007] = 34 | CNTRL, /* Control + g */
|
|
||||||
[0x008] = 35 | CNTRL, /* Control + h */
|
|
||||||
[0x00a] = 36 | CNTRL, /* Control + j */
|
|
||||||
[0x00b] = 37 | CNTRL, /* Control + k */
|
|
||||||
[0x00c] = 38 | CNTRL, /* Control + l */
|
|
||||||
|
|
||||||
[0x01a] = 44 | CNTRL, /* Control + z */
|
|
||||||
[0x018] = 45 | CNTRL, /* Control + x */
|
|
||||||
[0x003] = 46 | CNTRL, /* Control + c */
|
|
||||||
[0x016] = 47 | CNTRL, /* Control + v */
|
|
||||||
[0x002] = 48 | CNTRL, /* Control + b */
|
|
||||||
[0x00e] = 49 | CNTRL, /* Control + n */
|
|
||||||
/* Control + m collides with the keycode for Enter */
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static const int curses2keysym[CURSES_KEYS] = {
|
|
||||||
[0 ... (CURSES_KEYS - 1)] = -1,
|
|
||||||
|
|
||||||
['\n'] = '\n',
|
|
||||||
['\r'] = '\n',
|
|
||||||
|
|
||||||
[0x07f] = QEMU_KEY_BACKSPACE,
|
|
||||||
|
|
||||||
[0x102] = QEMU_KEY_DOWN,
|
|
||||||
[0x103] = QEMU_KEY_UP,
|
|
||||||
[0x104] = QEMU_KEY_LEFT,
|
|
||||||
[0x105] = QEMU_KEY_RIGHT,
|
|
||||||
[0x106] = QEMU_KEY_HOME,
|
|
||||||
[0x107] = QEMU_KEY_BACKSPACE,
|
|
||||||
|
|
||||||
[0x14a] = QEMU_KEY_DELETE,
|
|
||||||
[0x152] = QEMU_KEY_PAGEDOWN,
|
|
||||||
[0x153] = QEMU_KEY_PAGEUP,
|
|
||||||
[0x157] = '\n',
|
|
||||||
[0x168] = QEMU_KEY_END,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char* name;
|
|
||||||
int keysym;
|
|
||||||
} name2keysym_t;
|
|
||||||
|
|
||||||
static const name2keysym_t name2keysym[] = {
|
|
||||||
/* Plain ASCII */
|
|
||||||
{ "space", 0x020 },
|
|
||||||
{ "exclam", 0x021 },
|
|
||||||
{ "quotedbl", 0x022 },
|
|
||||||
{ "numbersign", 0x023 },
|
|
||||||
{ "dollar", 0x024 },
|
|
||||||
{ "percent", 0x025 },
|
|
||||||
{ "ampersand", 0x026 },
|
|
||||||
{ "apostrophe", 0x027 },
|
|
||||||
{ "parenleft", 0x028 },
|
|
||||||
{ "parenright", 0x029 },
|
|
||||||
{ "asterisk", 0x02a },
|
|
||||||
{ "plus", 0x02b },
|
|
||||||
{ "comma", 0x02c },
|
|
||||||
{ "minus", 0x02d },
|
|
||||||
{ "period", 0x02e },
|
|
||||||
{ "slash", 0x02f },
|
|
||||||
{ "0", 0x030 },
|
|
||||||
{ "1", 0x031 },
|
|
||||||
{ "2", 0x032 },
|
|
||||||
{ "3", 0x033 },
|
|
||||||
{ "4", 0x034 },
|
|
||||||
{ "5", 0x035 },
|
|
||||||
{ "6", 0x036 },
|
|
||||||
{ "7", 0x037 },
|
|
||||||
{ "8", 0x038 },
|
|
||||||
{ "9", 0x039 },
|
|
||||||
{ "colon", 0x03a },
|
|
||||||
{ "semicolon", 0x03b },
|
|
||||||
{ "less", 0x03c },
|
|
||||||
{ "equal", 0x03d },
|
|
||||||
{ "greater", 0x03e },
|
|
||||||
{ "question", 0x03f },
|
|
||||||
{ "at", 0x040 },
|
|
||||||
{ "A", 0x041 },
|
|
||||||
{ "B", 0x042 },
|
|
||||||
{ "C", 0x043 },
|
|
||||||
{ "D", 0x044 },
|
|
||||||
{ "E", 0x045 },
|
|
||||||
{ "F", 0x046 },
|
|
||||||
{ "G", 0x047 },
|
|
||||||
{ "H", 0x048 },
|
|
||||||
{ "I", 0x049 },
|
|
||||||
{ "J", 0x04a },
|
|
||||||
{ "K", 0x04b },
|
|
||||||
{ "L", 0x04c },
|
|
||||||
{ "M", 0x04d },
|
|
||||||
{ "N", 0x04e },
|
|
||||||
{ "O", 0x04f },
|
|
||||||
{ "P", 0x050 },
|
|
||||||
{ "Q", 0x051 },
|
|
||||||
{ "R", 0x052 },
|
|
||||||
{ "S", 0x053 },
|
|
||||||
{ "T", 0x054 },
|
|
||||||
{ "U", 0x055 },
|
|
||||||
{ "V", 0x056 },
|
|
||||||
{ "W", 0x057 },
|
|
||||||
{ "X", 0x058 },
|
|
||||||
{ "Y", 0x059 },
|
|
||||||
{ "Z", 0x05a },
|
|
||||||
{ "bracketleft", 0x05b },
|
|
||||||
{ "backslash", 0x05c },
|
|
||||||
{ "bracketright", 0x05d },
|
|
||||||
{ "asciicircum", 0x05e },
|
|
||||||
{ "underscore", 0x05f },
|
|
||||||
{ "grave", 0x060 },
|
|
||||||
{ "a", 0x061 },
|
|
||||||
{ "b", 0x062 },
|
|
||||||
{ "c", 0x063 },
|
|
||||||
{ "d", 0x064 },
|
|
||||||
{ "e", 0x065 },
|
|
||||||
{ "f", 0x066 },
|
|
||||||
{ "g", 0x067 },
|
|
||||||
{ "h", 0x068 },
|
|
||||||
{ "i", 0x069 },
|
|
||||||
{ "j", 0x06a },
|
|
||||||
{ "k", 0x06b },
|
|
||||||
{ "l", 0x06c },
|
|
||||||
{ "m", 0x06d },
|
|
||||||
{ "n", 0x06e },
|
|
||||||
{ "o", 0x06f },
|
|
||||||
{ "p", 0x070 },
|
|
||||||
{ "q", 0x071 },
|
|
||||||
{ "r", 0x072 },
|
|
||||||
{ "s", 0x073 },
|
|
||||||
{ "t", 0x074 },
|
|
||||||
{ "u", 0x075 },
|
|
||||||
{ "v", 0x076 },
|
|
||||||
{ "w", 0x077 },
|
|
||||||
{ "x", 0x078 },
|
|
||||||
{ "y", 0x079 },
|
|
||||||
{ "z", 0x07a },
|
|
||||||
{ "braceleft", 0x07b },
|
|
||||||
{ "bar", 0x07c },
|
|
||||||
{ "braceright", 0x07d },
|
|
||||||
{ "asciitilde", 0x07e },
|
|
||||||
|
|
||||||
/* Latin-1 extensions */
|
|
||||||
{ "nobreakspace", 0x0a0 },
|
|
||||||
{ "exclamdown", 0x0a1 },
|
|
||||||
{ "cent", 0x0a2 },
|
|
||||||
{ "sterling", 0x0a3 },
|
|
||||||
{ "currency", 0x0a4 },
|
|
||||||
{ "yen", 0x0a5 },
|
|
||||||
{ "brokenbar", 0x0a6 },
|
|
||||||
{ "section", 0x0a7 },
|
|
||||||
{ "diaeresis", 0x0a8 },
|
|
||||||
{ "copyright", 0x0a9 },
|
|
||||||
{ "ordfeminine", 0x0aa },
|
|
||||||
{ "guillemotleft", 0x0ab },
|
|
||||||
{ "notsign", 0x0ac },
|
|
||||||
{ "hyphen", 0x0ad },
|
|
||||||
{ "registered", 0x0ae },
|
|
||||||
{ "macron", 0x0af },
|
|
||||||
{ "degree", 0x0b0 },
|
|
||||||
{ "plusminus", 0x0b1 },
|
|
||||||
{ "twosuperior", 0x0b2 },
|
|
||||||
{ "threesuperior", 0x0b3 },
|
|
||||||
{ "acute", 0x0b4 },
|
|
||||||
{ "mu", 0x0b5 },
|
|
||||||
{ "paragraph", 0x0b6 },
|
|
||||||
{ "periodcentered", 0x0b7 },
|
|
||||||
{ "cedilla", 0x0b8 },
|
|
||||||
{ "onesuperior", 0x0b9 },
|
|
||||||
{ "masculine", 0x0ba },
|
|
||||||
{ "guillemotright", 0x0bb },
|
|
||||||
{ "onequarter", 0x0bc },
|
|
||||||
{ "onehalf", 0x0bd },
|
|
||||||
{ "threequarters", 0x0be },
|
|
||||||
{ "questiondown", 0x0bf },
|
|
||||||
{ "Agrave", 0x0c0 },
|
|
||||||
{ "Aacute", 0x0c1 },
|
|
||||||
{ "Acircumflex", 0x0c2 },
|
|
||||||
{ "Atilde", 0x0c3 },
|
|
||||||
{ "Adiaeresis", 0x0c4 },
|
|
||||||
{ "Aring", 0x0c5 },
|
|
||||||
{ "AE", 0x0c6 },
|
|
||||||
{ "Ccedilla", 0x0c7 },
|
|
||||||
{ "Egrave", 0x0c8 },
|
|
||||||
{ "Eacute", 0x0c9 },
|
|
||||||
{ "Ecircumflex", 0x0ca },
|
|
||||||
{ "Ediaeresis", 0x0cb },
|
|
||||||
{ "Igrave", 0x0cc },
|
|
||||||
{ "Iacute", 0x0cd },
|
|
||||||
{ "Icircumflex", 0x0ce },
|
|
||||||
{ "Idiaeresis", 0x0cf },
|
|
||||||
{ "ETH", 0x0d0 },
|
|
||||||
{ "Eth", 0x0d0 },
|
|
||||||
{ "Ntilde", 0x0d1 },
|
|
||||||
{ "Ograve", 0x0d2 },
|
|
||||||
{ "Oacute", 0x0d3 },
|
|
||||||
{ "Ocircumflex", 0x0d4 },
|
|
||||||
{ "Otilde", 0x0d5 },
|
|
||||||
{ "Odiaeresis", 0x0d6 },
|
|
||||||
{ "multiply", 0x0d7 },
|
|
||||||
{ "Ooblique", 0x0d8 },
|
|
||||||
{ "Oslash", 0x0d8 },
|
|
||||||
{ "Ugrave", 0x0d9 },
|
|
||||||
{ "Uacute", 0x0da },
|
|
||||||
{ "Ucircumflex", 0x0db },
|
|
||||||
{ "Udiaeresis", 0x0dc },
|
|
||||||
{ "Yacute", 0x0dd },
|
|
||||||
{ "THORN", 0x0de },
|
|
||||||
{ "Thorn", 0x0de },
|
|
||||||
{ "ssharp", 0x0df },
|
|
||||||
{ "agrave", 0x0e0 },
|
|
||||||
{ "aacute", 0x0e1 },
|
|
||||||
{ "acircumflex", 0x0e2 },
|
|
||||||
{ "atilde", 0x0e3 },
|
|
||||||
{ "adiaeresis", 0x0e4 },
|
|
||||||
{ "aring", 0x0e5 },
|
|
||||||
{ "ae", 0x0e6 },
|
|
||||||
{ "ccedilla", 0x0e7 },
|
|
||||||
{ "egrave", 0x0e8 },
|
|
||||||
{ "eacute", 0x0e9 },
|
|
||||||
{ "ecircumflex", 0x0ea },
|
|
||||||
{ "ediaeresis", 0x0eb },
|
|
||||||
{ "igrave", 0x0ec },
|
|
||||||
{ "iacute", 0x0ed },
|
|
||||||
{ "icircumflex", 0x0ee },
|
|
||||||
{ "idiaeresis", 0x0ef },
|
|
||||||
{ "eth", 0x0f0 },
|
|
||||||
{ "ntilde", 0x0f1 },
|
|
||||||
{ "ograve", 0x0f2 },
|
|
||||||
{ "oacute", 0x0f3 },
|
|
||||||
{ "ocircumflex", 0x0f4 },
|
|
||||||
{ "otilde", 0x0f5 },
|
|
||||||
{ "odiaeresis", 0x0f6 },
|
|
||||||
{ "division", 0x0f7 },
|
|
||||||
{ "oslash", 0x0f8 },
|
|
||||||
{ "ooblique", 0x0f8 },
|
|
||||||
{ "ugrave", 0x0f9 },
|
|
||||||
{ "uacute", 0x0fa },
|
|
||||||
{ "ucircumflex", 0x0fb },
|
|
||||||
{ "udiaeresis", 0x0fc },
|
|
||||||
{ "yacute", 0x0fd },
|
|
||||||
{ "thorn", 0x0fe },
|
|
||||||
{ "ydiaeresis", 0x0ff },
|
|
||||||
|
|
||||||
/* Special keys */
|
|
||||||
{ "BackSpace", 0x07f },
|
|
||||||
{ "Tab", '\t' },
|
|
||||||
{ "Return", '\r' },
|
|
||||||
{ "Right", 0x105 },
|
|
||||||
{ "Left", 0x104 },
|
|
||||||
{ "Up", 0x103 },
|
|
||||||
{ "Down", 0x102 },
|
|
||||||
{ "Page_Down", 0x152 },
|
|
||||||
{ "Page_Up", 0x153 },
|
|
||||||
{ "Insert", 0x14b },
|
|
||||||
{ "Delete", 0x14a },
|
|
||||||
{ "Home", 0x106 },
|
|
||||||
{ "End", 0x168 },
|
|
||||||
{ "F1", 0x109 },
|
|
||||||
{ "F2", 0x10a },
|
|
||||||
{ "F3", 0x10b },
|
|
||||||
{ "F4", 0x10c },
|
|
||||||
{ "F5", 0x10d },
|
|
||||||
{ "F6", 0x10e },
|
|
||||||
{ "F7", 0x10f },
|
|
||||||
{ "F8", 0x110 },
|
|
||||||
{ "F9", 0x111 },
|
|
||||||
{ "F10", 0x112 },
|
|
||||||
{ "F11", 0x113 },
|
|
||||||
{ "F12", 0x114 },
|
|
||||||
{ "F13", 0x115 },
|
|
||||||
{ "F14", 0x116 },
|
|
||||||
{ "F15", 0x117 },
|
|
||||||
{ "F16", 0x118 },
|
|
||||||
{ "F17", 0x119 },
|
|
||||||
{ "F18", 0x11a },
|
|
||||||
{ "F19", 0x11b },
|
|
||||||
{ "F20", 0x11c },
|
|
||||||
{ "Escape", 27 },
|
|
||||||
|
|
||||||
{ 0, 0 },
|
|
||||||
};
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user