Compare commits
341 Commits
v0.13.0-rc
...
v0.12.5-qe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69903f803a | ||
|
|
174f225e9d | ||
|
|
e916448940 | ||
|
|
bb44e0bbce | ||
|
|
191d44fc43 | ||
|
|
a2f0cbaa58 | ||
|
|
a9d9a66f13 | ||
|
|
37060c28e5 | ||
|
|
7205c21e76 | ||
|
|
ceef722d01 | ||
|
|
dfe0bb55ee | ||
|
|
6fd82592ce | ||
|
|
39187b5192 | ||
|
|
729862401d | ||
|
|
34d0d68bdf | ||
|
|
82e9cbeb0d | ||
|
|
2020dd5535 | ||
|
|
0c0f53e25c | ||
|
|
3dbe0714dd | ||
|
|
9067bac11d | ||
|
|
74471f3742 | ||
|
|
370f80376a | ||
|
|
ed3aac289a | ||
|
|
11b52a6536 | ||
|
|
b6185fc79c | ||
|
|
8fd7d5438e | ||
|
|
a513171f80 | ||
|
|
ff9e177617 | ||
|
|
db3519a9ec | ||
|
|
258e351d12 | ||
|
|
cd14f4d346 | ||
|
|
df631629b1 | ||
|
|
af0269b036 | ||
|
|
d37dbf988d | ||
|
|
cc7ed88f28 | ||
|
|
07442ab4a1 | ||
|
|
dbe6a18d82 | ||
|
|
7dd007c2ed | ||
|
|
9c6a8f503d | ||
|
|
0c459361a1 | ||
|
|
72d3457e8d | ||
|
|
e1f0c1d05d | ||
|
|
74bcc51b99 | ||
|
|
7e4f956056 | ||
|
|
1fb9798b69 | ||
|
|
9f6a84bc43 | ||
|
|
8cef921d18 | ||
|
|
b04c3db504 | ||
|
|
d04d7cf158 | ||
|
|
2b8bdd5c7f | ||
|
|
2a44494726 | ||
|
|
8f30db54d9 | ||
|
|
b09ac1abe7 | ||
|
|
012d4869c1 | ||
|
|
3597c9c1d5 | ||
|
|
3b4bef0696 | ||
|
|
d899303743 | ||
|
|
5773685183 | ||
|
|
d40ba77ebf | ||
|
|
a8c46d182c | ||
|
|
d80e20a1c3 | ||
|
|
1ce4fad939 | ||
|
|
9167a242db | ||
|
|
09e96924ec | ||
|
|
69ff4e9dbd | ||
|
|
0434349d6a | ||
|
|
e007221223 | ||
|
|
4622317288 | ||
|
|
ffac613ff9 | ||
|
|
aba5288247 | ||
|
|
4f7cb96931 | ||
|
|
fafc2e4b33 | ||
|
|
83ef70f24a | ||
|
|
de17c16e1f | ||
|
|
9462695b64 | ||
|
|
5eb089588e | ||
|
|
2039f70c23 | ||
|
|
082a9fc256 | ||
|
|
36a013c956 | ||
|
|
c4c4b32b81 | ||
|
|
804b6ab08d | ||
|
|
81b168a702 | ||
|
|
5c6892078a | ||
|
|
18a21890ff | ||
|
|
6629fa6473 | ||
|
|
2a7996ce0e | ||
|
|
8ec131fb59 | ||
|
|
30d061750d | ||
|
|
c5f5dc5bad | ||
|
|
d2df336c58 | ||
|
|
b299b12b17 | ||
|
|
c248df6161 | ||
|
|
7d5625d5f7 | ||
|
|
cc21d131e3 | ||
|
|
41a5bda61f | ||
|
|
5163f6e864 | ||
|
|
6173d56bdc | ||
|
|
f39942d217 | ||
|
|
5dde87088f | ||
|
|
3fa017e24b | ||
|
|
35924dbe8c | ||
|
|
88aa905668 | ||
|
|
b93c5c84c8 | ||
|
|
f203baee5b | ||
|
|
5e3be62385 | ||
|
|
b391493bc6 | ||
|
|
57f9f4c9f5 | ||
|
|
7ebc79037c | ||
|
|
ea299062eb | ||
|
|
e03dd1a6c2 | ||
|
|
535d2eb34a | ||
|
|
beb8eab90c | ||
|
|
8d67694fbf | ||
|
|
02510b2436 | ||
|
|
b57a2297f2 | ||
|
|
43fab08210 | ||
|
|
915080e6b1 | ||
|
|
9f59ddcc4f | ||
|
|
999ceb2c1d | ||
|
|
307331a42a | ||
|
|
6728dd464b | ||
|
|
bb45bcc8de | ||
|
|
096109c804 | ||
|
|
7ae1fcc88c | ||
|
|
299e0bc52a | ||
|
|
74f0529e24 | ||
|
|
614971158c | ||
|
|
afa328b1b2 | ||
|
|
868dab5dc2 | ||
|
|
29bb3bf350 | ||
|
|
dbf45b44b7 | ||
|
|
d0d888bc6d | ||
|
|
19abbad0da | ||
|
|
f48aba6de7 | ||
|
|
cb2ae96bf6 | ||
|
|
848f874ca1 | ||
|
|
a1a86bf902 | ||
|
|
c727a05459 | ||
|
|
eb05143e24 | ||
|
|
0c709e6195 | ||
|
|
dc88aa49b4 | ||
|
|
dc2ffbf6d8 | ||
|
|
d3bf9367f2 | ||
|
|
c502715a74 | ||
|
|
b9a61d2154 | ||
|
|
9525204c5d | ||
|
|
f79d556b4f | ||
|
|
41ae9ece21 | ||
|
|
40480d2bf4 | ||
|
|
e389e937a7 | ||
|
|
73b48d914f | ||
|
|
3999bf3244 | ||
|
|
a3441a43a6 | ||
|
|
49a3aaac4a | ||
|
|
027866ce23 | ||
|
|
04babf6c6f | ||
|
|
d2b8117310 | ||
|
|
0c4b9aef7b | ||
|
|
431c829f33 | ||
|
|
be7398ec06 | ||
|
|
be59ce1f48 | ||
|
|
eacad66dbe | ||
|
|
66dbb62824 | ||
|
|
d47d251286 | ||
|
|
348af56fae | ||
|
|
09866b9baa | ||
|
|
e1daf40e3e | ||
|
|
de3ea06d59 | ||
|
|
fe46a160ce | ||
|
|
8033c42abd | ||
|
|
4713c69fa2 | ||
|
|
d68bf60838 | ||
|
|
57fa5ca551 | ||
|
|
8610774f79 | ||
|
|
76ba04832b | ||
|
|
644f5de21b | ||
|
|
dcc0da8297 | ||
|
|
41193c50fa | ||
|
|
da0266005a | ||
|
|
eacdccbb3e | ||
|
|
65e8c51928 | ||
|
|
e470436f19 | ||
|
|
b60c2c74f3 | ||
|
|
fe1b69708c | ||
|
|
a1678e85db | ||
|
|
8212d18cf5 | ||
|
|
6c412ddf1c | ||
|
|
862ad4be53 | ||
|
|
aac2ad563a | ||
|
|
eb41f58a4e | ||
|
|
5543b41167 | ||
|
|
31d85f6a6b | ||
|
|
9c49a2533c | ||
|
|
c6faf5fd73 | ||
|
|
069def25cb | ||
|
|
3733a1e804 | ||
|
|
5b06a3f785 | ||
|
|
baaf73aaac | ||
|
|
345c22aa80 | ||
|
|
26bb2a0865 | ||
|
|
e6ea832410 | ||
|
|
22d0cc8d38 | ||
|
|
898829d5c7 | ||
|
|
72bb3c7571 | ||
|
|
48c437f0ab | ||
|
|
07d00c2174 | ||
|
|
3243a06f51 | ||
|
|
1c3f96be38 | ||
|
|
df9e7219db | ||
|
|
e83421f511 | ||
|
|
2b311b3cce | ||
|
|
4b5db3749c | ||
|
|
a1497a782c | ||
|
|
3c547d7bb7 | ||
|
|
3b43502e3a | ||
|
|
078517421f | ||
|
|
afc7055619 | ||
|
|
53425683d4 | ||
|
|
ef5a63186a | ||
|
|
4a0e0accd7 | ||
|
|
73e47683de | ||
|
|
115e94a31e | ||
|
|
5fd5f6999d | ||
|
|
602e97b725 | ||
|
|
97b766dfcd | ||
|
|
fb8cf78db6 | ||
|
|
c5238ac21b | ||
|
|
99917a99cd | ||
|
|
55ed56908f | ||
|
|
139e310025 | ||
|
|
bed93b1dcb | ||
|
|
73b4ac5cd8 | ||
|
|
00e8277b83 | ||
|
|
a8ea3a357b | ||
|
|
f8051485c1 | ||
|
|
807c80b259 | ||
|
|
686a3c3dc2 | ||
|
|
a381d8277c | ||
|
|
8647b09bfd | ||
|
|
9153014fa0 | ||
|
|
f6d4446ea8 | ||
|
|
f1e247ee6b | ||
|
|
a49668769d | ||
|
|
97d949d9da | ||
|
|
040093b1a5 | ||
|
|
5d4e53dc81 | ||
|
|
3ebee80226 | ||
|
|
c56651312b | ||
|
|
869ca150e7 | ||
|
|
910628f396 | ||
|
|
251241dc90 | ||
|
|
03a23e5c6e | ||
|
|
a68fc29ceb | ||
|
|
0014803d23 | ||
|
|
5118f7b47c | ||
|
|
1c1d7bda2c | ||
|
|
bdae662c94 | ||
|
|
0108d4e323 | ||
|
|
4305793bad | ||
|
|
d2d51eeff0 | ||
|
|
3be42b28c1 | ||
|
|
ee70ef8771 | ||
|
|
5f9fe0f8d0 | ||
|
|
7589acc9e8 | ||
|
|
94f539bdac | ||
|
|
e637fd2386 | ||
|
|
6e785bee32 | ||
|
|
f883e4f7b8 | ||
|
|
5daa7bb7a4 | ||
|
|
b0a84d0525 | ||
|
|
f1f84ba223 | ||
|
|
db830f26cb | ||
|
|
61a606dade | ||
|
|
2d95575edb | ||
|
|
d707483ce3 | ||
|
|
e2deb622c2 | ||
|
|
6e792a557e | ||
|
|
ea2138cf90 | ||
|
|
992f3cb78e | ||
|
|
828b2ff676 | ||
|
|
a231a8272c | ||
|
|
f2604b35dc | ||
|
|
fc05630f1f | ||
|
|
ad960ddbce | ||
|
|
239a69680c | ||
|
|
f4f1df70f2 | ||
|
|
782e9e6554 | ||
|
|
64de0113f1 | ||
|
|
84db615abc | ||
|
|
7c6a56cc63 | ||
|
|
a20600b917 | ||
|
|
4986fd4111 | ||
|
|
96639424e2 | ||
|
|
6ac733bf09 | ||
|
|
25d82d3311 | ||
|
|
f9800fe5a0 | ||
|
|
542d991b4c | ||
|
|
d1d6963eba | ||
|
|
7058b807cd | ||
|
|
f49d2561cb | ||
|
|
a63e5f1971 | ||
|
|
ebbc8a3d8e | ||
|
|
08b2d3ba9a | ||
|
|
72fbd9f97c | ||
|
|
5b6d0419d9 | ||
|
|
9df9eeeb18 | ||
|
|
5b6321a237 | ||
|
|
5e0c455842 | ||
|
|
4d687b13cf | ||
|
|
d7b8193716 | ||
|
|
2e51813417 | ||
|
|
90f445e1c9 | ||
|
|
143d288cba | ||
|
|
13a2ccc46f | ||
|
|
ea2b7d7079 | ||
|
|
0b52786ce1 | ||
|
|
e36469149a | ||
|
|
e5fc266be5 | ||
|
|
3e4cd634cc | ||
|
|
06976f82e7 | ||
|
|
fe7c6c90a8 | ||
|
|
960a4b537a | ||
|
|
c756b1e762 | ||
|
|
06921ec84f | ||
|
|
8cb1cec656 | ||
|
|
a46657d185 | ||
|
|
28acf422cb | ||
|
|
a7d5da8857 | ||
|
|
931a548be3 | ||
|
|
bcddbd0f6a | ||
|
|
b3dfdb5a3b | ||
|
|
6ccc51fd20 | ||
|
|
0ea5709a32 | ||
|
|
67a2698dac | ||
|
|
eea4acfa5c | ||
|
|
c99d32efe6 | ||
|
|
9fa7591beb | ||
|
|
066263f377 | ||
|
|
20c1a35211 | ||
|
|
ea6112b165 | ||
|
|
e222100afe |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -2,11 +2,11 @@ config-devices.*
|
||||
config-all-devices.*
|
||||
config-host.*
|
||||
config-target.*
|
||||
i386
|
||||
*-softmmu
|
||||
*-darwin-user
|
||||
*-linux-user
|
||||
*-bsd-user
|
||||
libdis*
|
||||
libhw32
|
||||
libhw64
|
||||
libuser
|
||||
@@ -22,13 +22,11 @@ qemu-img
|
||||
qemu-nbd
|
||||
qemu-nbd.8
|
||||
qemu-nbd.pod
|
||||
qemu-options.def
|
||||
qemu-options.texi
|
||||
qemu-img-cmds.texi
|
||||
qemu-img-cmds.h
|
||||
qemu-io
|
||||
qemu-monitor.texi
|
||||
QMP/qmp-commands.txt
|
||||
.gdbinit
|
||||
*.a
|
||||
*.aux
|
||||
@@ -38,7 +36,6 @@ QMP/qmp-commands.txt
|
||||
*.fn
|
||||
*.ky
|
||||
*.log
|
||||
*.pdf
|
||||
*.pg
|
||||
*.toc
|
||||
*.tp
|
||||
@@ -49,8 +46,7 @@ QMP/qmp-commands.txt
|
||||
patches
|
||||
pc-bios/bios-pq/status
|
||||
pc-bios/vgabios-pq/status
|
||||
pc-bios/optionrom/linuxboot.bin
|
||||
pc-bios/optionrom/multiboot.bin
|
||||
pc-bios/optionrom/multiboot.raw
|
||||
pc-bios/optionrom/extboot.bin
|
||||
.stgit-*
|
||||
cscope.*
|
||||
|
||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,6 +1,6 @@
|
||||
[submodule "roms/vgabios"]
|
||||
path = roms/vgabios
|
||||
url = git://git.qemu.org/vgabios.git/
|
||||
url = ../vgabios.git
|
||||
[submodule "roms/seabios"]
|
||||
path = roms/seabios
|
||||
url = git://git.qemu.org/seabios.git/
|
||||
url = ../seabios.git
|
||||
|
||||
@@ -49,9 +49,6 @@ and is therefore likely to be changed.
|
||||
Typedefs are used to eliminate the redundant 'struct' keyword. It is the
|
||||
QEMU coding style.
|
||||
|
||||
When wrapping standard library functions, use the prefix qemu_ to alert
|
||||
readers that they are seeing a wrapped version; otherwise avoid this prefix.
|
||||
|
||||
4. Block structure
|
||||
|
||||
Every indented statement is braced; even if the block contains just one
|
||||
|
||||
187
Changelog
187
Changelog
@@ -1,3 +1,190 @@
|
||||
version 0.12.5
|
||||
- audio/alsa: Handle SND_PCM_STATE_SETUP in alsa_poll_handler
|
||||
- block: Handle multiwrite errors only when all requests have completed
|
||||
- block: Fix early failure in multiwrite
|
||||
- vpc: Use bdrv_(p)write_sync for metadata writes
|
||||
- vmdk: Use bdrv_(p)write_sync for metadata writes
|
||||
- qcow2: Use bdrv_(p)write_sync for metadata writes
|
||||
- qcow: Use bdrv_(p)write_sync for metadata writes
|
||||
- block: Add bdrv_(p)write_sync
|
||||
- qcow2: Restore L1 entry on l2_allocate failure
|
||||
- block/vdi: Fix image opening and creation for odd disk sizes
|
||||
- block/vpc: Fix conversion from size to disk geometry
|
||||
- qcow2: Remove abort on free_clusters failure
|
||||
- vmdk: Fix COW
|
||||
- qcow2: Fix creation of large images
|
||||
- vmdk: fix double free
|
||||
- qemu-options: add documentation for stdio signal=on|off
|
||||
- target-arm : fix parallel saturated subtraction implementation
|
||||
- target-arm : fix thumb2 parallel add/sub opcode decoding
|
||||
- target-arm: fix addsub/subadd implementation
|
||||
- target-i386: fix xchg rax,r8
|
||||
- block/vvfat.c: fix warnings with _FORTIFY_SOURCE
|
||||
- audio/alsa: Spelling typo (paramters)
|
||||
- target-mips: fix DINSU instruction
|
||||
- Correct definitions for FD_CMD_SAVE and FD_CMD_RESTORE
|
||||
- qcow2: Fix corruption after error in update_refcount
|
||||
- qcow2: Fix corruption after refblock allocation
|
||||
- block: Fix multiwrite with overlapping requests
|
||||
- qcow2: Fix error handling in l2_allocate
|
||||
- qcow2: Clear L2 table cache after write error
|
||||
- ide: Fix ide_dma_cancel
|
||||
- usb-bus: fix no params
|
||||
- Avoid crash on '-usbdevice <device>' without parameters
|
||||
- Fix -usbdevice crash
|
||||
- Fix multiboot compilation
|
||||
- Fix missing symbols in .rel/.rela.plt sections
|
||||
- target-ppc: fix RFI by clearing some bits of MSR
|
||||
- Fix typo in balloon help
|
||||
- arm_timer: fix oneshot mode
|
||||
- arm_timer: reload timer when enabled
|
||||
- qemu-sockets: avoid strlen of NULL pointer
|
||||
- block: fix aio_flush segfaults for read-only protocols (e.g. curl)
|
||||
- virtio-blk: fix barrier support
|
||||
- block: fix sector comparism in multiwrite_req_compare
|
||||
- pci: irq_state vmstate breakage
|
||||
- qemu-img: use the heap instead of the huge stack array for win32
|
||||
|
||||
version 0.12.4
|
||||
- Workaround for broken OSS_GETVERSION on FreeBSD, part two (Juergen Lock)
|
||||
- oss: fix fragment setting (malc)
|
||||
- oss: issue OSS_GETVERSION ioctl only when needed (malc)
|
||||
- oss: refactor code around policy setting (malc)
|
||||
- oss: workaround for cases when OSS_GETVERSION is not defined (malc)
|
||||
- block: Free iovec arrays allocated by multiwrite_merge() (Stefan Hajnoczi)
|
||||
- lsi: fix segfault in lsi_command_complete (Gerd Hoffmann)
|
||||
- lsi: pass lsi_request to lsi_reselect (Gerd Hoffmann)
|
||||
- lsi: move dma_len+dma_buf into lsi_request (Gerd Hoffmann)
|
||||
- lsi: move current_dev into lsi_request (Gerd Hoffmann)
|
||||
- lsi: have lsi_request for the whole life time of the request. (Gerd Hoffmann)
|
||||
- lsi: use QTAILQ for lsi_queue (Gerd Hoffmann)
|
||||
- tcp/mips: Change TCG_AREG0 (fp -> s0) (Stefan Weil)
|
||||
- sh_pci: fix memory and I/O access (Aurelien Jarno)
|
||||
- Fix incoming migration with iothread (Marcelo Tosatti)
|
||||
- Fix SIGFPE for vnc display of width/height = 1 (Chris Webb)
|
||||
- net: remove broken net_set_boot_mask() boot device validation (Eduardo Habkost)
|
||||
- qcow2: Remove request from in-flight list after error (Kevin Wolf)
|
||||
- qcow2: Don't ignore immediate read/write failures (Kevin Wolf)
|
||||
- block: Fix multiwrite memory leak in error case (Kevin Wolf)
|
||||
- block: Fix error code in multiwrite for immediate failures (Kevin Wolf)
|
||||
- block: Fix multiwrite error handling (Kevin Wolf)
|
||||
- scsi-disk: fix buffer overflow (Gerd Hoffmann)
|
||||
- qcow2: Rewrite alloc_refcount_block/grow_refcount_table (Kevin Wolf)
|
||||
- qcow2: Factor next_refcount_table_size out (Kevin Wolf)
|
||||
- block: avoid creating too large iovecs in multiwrite_merge (Christoph Hellwig)
|
||||
- json-parser: Fix segfault on malformed input (Kevin Wolf)
|
||||
- linux-user: switch default ppc64 CPU to 970fx from 970 (Aurelien Jarno)
|
||||
- target-sh4: MMU: fix store queue addresses (Aurelien Jarno)
|
||||
- target-sh4: MMU: fix ITLB priviledge check (Aurelien Jarno)
|
||||
- target-sh4: MMU: fix mem_idx computation (Aurelien Jarno)
|
||||
- sh7750: handle MMUCR TI bit (Aurelien Jarno)
|
||||
- UHCI spurious interrut fix (Paul Brook)
|
||||
- tcg/mips: fix branch offset during retranslation (Aurelien Jarno)
|
||||
- tcg/arm: correctly save/restore registers in prologue/epilogue (Aurelien Jarno)
|
||||
- workaround for cmd646 bmdma register access while no dma is active (Igor V. Kovalenko)
|
||||
- Fix corner case in chardev udp: parameter (Jan Kiszka)
|
||||
- Don't set default monitor when there is a mux'ed one (Jan Kiszka)
|
||||
- spelling typo (compatibilty) in hw/fw_cfg.c (Vagrant Cascadian)
|
||||
- fdc: fix drive property handling. (Gerd Hoffmann)
|
||||
- target-i386: fix commit c22549204a6edc431e8e4358e61bd56386ff6957 (TeLeMan)
|
||||
- target-i386: fix SIB decoding with index = 4 (Aurelien Jarno)
|
||||
- Fix segfault with ram_size > 4095M without kvm (Ryan Harper)
|
||||
- target-i386: Fix long jumps/calls in long mode with REX.W set (malc)
|
||||
- target-i386: fix lddqu SSE instruction (Aurelien Jarno)
|
||||
- qemu-char.c: drop debug printfs from qemu_chr_parse_compat (Jan Kiszka)
|
||||
- fix undefined shifts by >32 (Paolo Bonzini)
|
||||
- Fix qemu -net user,hostfwd= example (Aurelien Jarno)
|
||||
|
||||
version 0.12.3
|
||||
- kvm: Fix eflags corruption in kvm mode (Jan Kiszka)
|
||||
- qcow2: Fix access after end of array (Kevin Wolf)
|
||||
- ide save/restore pio/atapi cmd transfer fields and io buffer (Marcelo Tosatti)
|
||||
- net: Monitor command set_link finds only VLAN clients, fix (Markus Armbruster)
|
||||
- net: info network shows only VLAN clients, fix (Markus Armbruster)
|
||||
- net: net_check_clients() checks only VLAN clients, fix (Markus Armbruster)
|
||||
- net: Fix bogus "Warning: vlan 0 with no nics" with -device (Markus Armbruster)
|
||||
- net: net_check_clients() runs too early to see -device, fix (Markus Armbruster)
|
||||
- net: Remove unused net_client_uninit() (Markus Armbruster)
|
||||
- don't dereference NULL after failed strdup (Jim Meyering)
|
||||
- virtio-net: fix network stall under load (Tom Lendacky)
|
||||
- json: fix PRId64 on Win32 (Roy Tam)
|
||||
- fix inet_parse typo (Marcelo Tosatti)
|
||||
- iothread: fix vcpu stop with smp tcg (Marcelo Tosatti)
|
||||
- segfault due to buffer overrun in usb-serial (David S. Ahern)
|
||||
- qcow2: Fix signedness bugs (Kevin Wolf)
|
||||
- Do not ignore error, if open file failed (-serial /dev/tty) (Evgeniy Dushistov)
|
||||
- pc-bios: update to newer version of (stable) seabios (Anthony Liguori)
|
||||
- target-mips: fix ROTR and DROTR by zero (Aurelien Jarno)
|
||||
- target-mips: fix CpU exception for coprocessor 0 (Nathan Froyd)
|
||||
- tcg/mips: fix crash in tcg_out_qemu_ld() (Aurelien Jarno)
|
||||
- target-mips: don't call cpu_loop_exit() from helper.c (Aurelien Jarno)
|
||||
- virtio-blk: Fix error cases which ignored rerror/werror (Kevin Wolf)
|
||||
- virtio-blk: Fix restart after read error (Kevin Wolf)
|
||||
- virtio_blk: Factor virtio_blk_handle_request out (Kevin Wolf)
|
||||
- cirrus: Properly re-register cirrus_linear_io_addr on vram unmap (Jan Kiszka)
|
||||
- qcow2: Don't ignore qcow2_alloc_clusters return value (Kevin Wolf)
|
||||
- qcow2: Don't ignore update_refcount return value (Kevin Wolf)
|
||||
- qcow2: Allow updating no refcounts (Kevin Wolf)
|
||||
- qcow2: Improve error handling in update_refcount (Kevin Wolf)
|
||||
- qcow2: Fix error handling in grow_refcount_table (Kevin Wolf)
|
||||
- block: Return original error codes in bdrv_pread/write (Kevin Wolf)
|
||||
- qcow2: Return 0/-errno in qcow2_alloc_cluster_offset (Kevin Wolf)
|
||||
- qcow2: Return 0/-errno in get_cluster_table (Kevin Wolf)
|
||||
- qcow2: Fix error handling in qcow_save_vmstate (Kevin Wolf)
|
||||
- qcow2: Fix error handling in qcow2_grow_l1_table (Kevin Wolf)
|
||||
- win32/sdl: Fix toggle full screen (Herve Poussineau)
|
||||
- win32: pair qemu_memalign() with qemu_vfree() (Herve Poussineau)
|
||||
- vnc_refresh: calling vnc_update_client might free vs (Stefano Stabellini)
|
||||
- Musicpal: Fix descriptor walk in eth_send (Jan Kiszka)
|
||||
- Musicpal: Fix wm8750 I2C address (Jan Kiszka)
|
||||
- fix savevm command without id or tag (Marcelo Tosatti)
|
||||
- reduce number of reinjects on ACK (Gleb Natapov)
|
||||
- QMP: Fix asynchronous events delivery (Luiz Capitulino)
|
||||
- Documentation: Add missing documentation for qdev related command line options (Stefan Weil)
|
||||
- pc: add driver version compat properties (Gerd Hoffmann)
|
||||
- scsi: device version property (Gerd Hoffmann)
|
||||
- ide: device version property (Gerd Hoffmann)
|
||||
- QMP: Emit asynchronous events on all QMP monitors (Adam Litke)
|
||||
- Fix QEMU_WARN_UNUSED_RESULT (Kevin Wolf)
|
||||
|
||||
version 0.12.2:
|
||||
- Qemu's internal TFTP server breaks lock-step-iness of TFTP (Milan Plzik)
|
||||
- osdep.c: Fix accept4 fallback (Kevin Wolf)
|
||||
- pc: add rombar to compat properties for pc-0.10 and pc-0.11 (Gerd Hoffmann)
|
||||
- pci: allow loading roms via fw_cfg. (Gerd Hoffmann)
|
||||
- roms: rework rom loading via fw (Gerd Hoffmann)
|
||||
- fw_cfg: rom loader tweaks. (Gerd Hoffmann)
|
||||
- roms: minor fixes and cleanups. (Gerd Hoffmann)
|
||||
- pc: add machine type for 0.12 (Gerd Hoffmann)
|
||||
- loader: more ignores for rom intended to be loaded by the bios (Aurelien Jarno)
|
||||
- vnc_refresh: return if vd->timer is NULL (Stefano Stabellini)
|
||||
- QMP: Don't free async event's 'data' (Luiz Capitulino)
|
||||
- Handle TFTP ERROR from client (Thomas Horsten)
|
||||
- dmg: fix ->open failure (Christoph Hellwig)
|
||||
- virtio-pci: thinko fix (Michael S. Tsirkin)
|
||||
- pc-bios: Update README (SeaBIOS) (Stefan Weil)
|
||||
- vmware_vga: Check cursor dimensions passed from guest to avoid buffer overflow (Roland Dreier)
|
||||
- remove pending exception on vcpu reset. (Gleb Natapov)
|
||||
- Fix CPU topology initialization (Jiri Denemark)
|
||||
- MCE: Fix bug of IA32_MCG_STATUS after system reset (Huang Ying)
|
||||
- linuxboot: fix gdt address calculation (Avi Kivity)
|
||||
- QMP: Drop wrong assert() (Luiz Capitulino)
|
||||
- vnc: Fix artifacts in hextile decoding (Anthony Liguori)
|
||||
- target-i386: Fix "call im" on x86_64 when executing 32-bit code (Aurelien Jarno)
|
||||
- Add missing newline at the end of options list (Michael Tokarev)
|
||||
- Don't load options roms intended to be loaded by the bios in qemu (Avi Kivity)
|
||||
- USB: Improve usbdevice error messages (Scott Tsai)
|
||||
- cpu-all.h: fix cpu_get_real_ticks() #ifdef (Aurelien Jarno)
|
||||
- alpha: fix compile (Blue Swirl)
|
||||
- user_only: compile everything with -fpie (Kirill A. Shutemov)
|
||||
- fdc/sparc32: don't hang on detection under OBP (Artyom Tarasenko)
|
||||
- scsi-disk: Inquiry with allocation length of CDB < 36 (v4) (Artyom Tarasenko)
|
||||
- e1000: fix init values for command register (Michael S. Tsirkin)
|
||||
|
||||
version 0.12.1:
|
||||
- loader: fix rom loading at address 0 (fixes target-arm) (Aurelien Jarno)
|
||||
- loader: fix rom_copy (fixes multiboot) (Kevin Wolf)
|
||||
|
||||
version 0.12.0:
|
||||
|
||||
- Update to SeaBIOS 0.5.0
|
||||
|
||||
2
EXTERNAL_DEPENDENCIES
Normal file
2
EXTERNAL_DEPENDENCIES
Normal file
@@ -0,0 +1,2 @@
|
||||
seabios 9fb3f4d950744e97cc655b7d7b523d8bf101e4a0
|
||||
vgabios 6e62666cfc19e7fd45dd0d7c3ad62fd8d0b5f67a
|
||||
1
KVM_VERSION
Normal file
1
KVM_VERSION
Normal file
@@ -0,0 +1 @@
|
||||
qemu-kvm-0.12.5
|
||||
@@ -13,7 +13,7 @@ CPU cores:
|
||||
x86 Fabrice Bellard
|
||||
ARM Paul Brook
|
||||
SPARC Blue Swirl
|
||||
MIPS ?
|
||||
MIPS Thiemo Seufer
|
||||
PowerPC ?
|
||||
M68K Paul Brook
|
||||
SH4 ?
|
||||
@@ -45,7 +45,7 @@ MIPS
|
||||
mips_r4k.c Aurelien Jarno
|
||||
mips_malta.c Aurelien Jarno
|
||||
mips_jazz.c Hervé Poussineau
|
||||
mips_mipssim.c ?
|
||||
mips_mipssim.c Thiemo Seufer
|
||||
PowerPC
|
||||
ppc_prep.c ?
|
||||
ppc_oldworld.c Fabrice Bellard
|
||||
@@ -75,7 +75,7 @@ Main loop Fabrice Bellard (new maintainer needed)
|
||||
TCG Fabrice Bellard
|
||||
IDE device ?
|
||||
SCSI device Paul Brook
|
||||
PCI layer Michael S. Tsirkin
|
||||
PCI layer ?
|
||||
USB layer ?
|
||||
Block layer ?
|
||||
Graphic layer ?
|
||||
|
||||
319
Makefile
319
Makefile
@@ -1,5 +1,6 @@
|
||||
# Makefile for QEMU.
|
||||
|
||||
# This needs to be defined before rules.mak
|
||||
GENERATED_HEADERS = config-host.h
|
||||
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
@@ -7,7 +8,7 @@ ifneq ($(wildcard config-host.mak),)
|
||||
all: build-all
|
||||
include config-host.mak
|
||||
include $(SRC_PATH)/rules.mak
|
||||
config-host.mak: $(SRC_PATH)/configure
|
||||
config-host.mak: configure
|
||||
@echo $@ is out-of-date, running configure
|
||||
@sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh
|
||||
else
|
||||
@@ -22,14 +23,14 @@ Makefile: ;
|
||||
configure: ;
|
||||
|
||||
.PHONY: all clean cscope distclean dvi html info install install-doc \
|
||||
pdf recurse-all speed tar tarbin test build-all
|
||||
recurse-all speed tar tarbin test build-all
|
||||
|
||||
$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
|
||||
VPATH=$(SRC_PATH):$(SRC_PATH)/hw
|
||||
|
||||
LIBS+=-lz $(LIBS_TOOLS)
|
||||
|
||||
ifdef BUILD_DOCS
|
||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
|
||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8
|
||||
else
|
||||
DOCS=
|
||||
endif
|
||||
@@ -42,22 +43,12 @@ config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
|
||||
|
||||
%/config-devices.mak: default-configs/%.mak
|
||||
$(call quiet-command,cat $< > $@.tmp, " GEN $@")
|
||||
@if test -f $@; then \
|
||||
if cmp -s $@.old $@ || cmp -s $@ $@.tmp; then \
|
||||
mv $@.tmp $@; \
|
||||
cp -p $@ $@.old; \
|
||||
else \
|
||||
if test -f $@.old; then \
|
||||
echo "WARNING: $@ (user modified) out of date.";\
|
||||
else \
|
||||
echo "WARNING: $@ out of date.";\
|
||||
fi; \
|
||||
echo "Run \"make defconfig\" to regenerate."; \
|
||||
rm $@.tmp; \
|
||||
fi; \
|
||||
@if test -f $@ ; then \
|
||||
echo "WARNING: $@ out of date." ;\
|
||||
echo "Run \"make defconfig\" to regenerate." ; \
|
||||
rm $@.tmp ; \
|
||||
else \
|
||||
mv $@.tmp $@; \
|
||||
cp -p $@ $@.old; \
|
||||
mv $@.tmp $@ ; \
|
||||
fi
|
||||
|
||||
defconfig:
|
||||
@@ -72,17 +63,27 @@ config-host.h-timestamp: config-host.mak
|
||||
|
||||
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
|
||||
|
||||
ifeq ($(KVM_KMOD),yes)
|
||||
|
||||
.PHONEY: kvm-kmod
|
||||
|
||||
all: kvm-kmod
|
||||
|
||||
kvm-kmod:
|
||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C kvm/kernel V="$(V)" )
|
||||
|
||||
|
||||
endif
|
||||
|
||||
subdir-%: $(GENERATED_HEADERS)
|
||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
|
||||
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
endif
|
||||
$(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.a
|
||||
|
||||
$(common-obj-y): $(GENERATED_HEADERS)
|
||||
$(filter %-softmmu,$(SUBDIR_RULES)): $(common-obj-y) subdir-libdis
|
||||
$(filter %-user,$(SUBDIR_RULES)): libuser.a
|
||||
|
||||
$(filter %-user,$(SUBDIR_RULES)): $(GENERATED_HEADERS) subdir-libdis-user subdir-libuser
|
||||
libuser.a: $(GENERATED_HEADERS)
|
||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libuser V="$(V)" TARGET_DIR="libuser/" all,)
|
||||
|
||||
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
|
||||
romsubdir-%:
|
||||
@@ -92,37 +93,173 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
|
||||
|
||||
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
|
||||
|
||||
#######################################################################
|
||||
# QObject
|
||||
qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
|
||||
qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
|
||||
qobject-obj-y += qerror.o
|
||||
|
||||
#######################################################################
|
||||
# block-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
|
||||
block-obj-y += nbd.o block.o aio.o aes.o osdep.o
|
||||
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += compatfd.o
|
||||
|
||||
block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
|
||||
block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
|
||||
block-nested-y += parallels.o nbd.o
|
||||
block-nested-$(CONFIG_WIN32) += raw-win32.o
|
||||
block-nested-$(CONFIG_POSIX) += raw-posix.o
|
||||
block-nested-$(CONFIG_CURL) += curl.o
|
||||
|
||||
block-obj-y += $(addprefix block/, $(block-nested-y))
|
||||
|
||||
net-obj-y = net.o
|
||||
net-nested-y = queue.o checksum.o util.o
|
||||
net-nested-y += socket.o
|
||||
net-nested-y += dump.o
|
||||
net-nested-$(CONFIG_POSIX) += tap.o
|
||||
net-nested-$(CONFIG_LINUX) += tap-linux.o
|
||||
net-nested-$(CONFIG_WIN32) += tap-win32.o
|
||||
net-nested-$(CONFIG_BSD) += tap-bsd.o
|
||||
net-nested-$(CONFIG_SOLARIS) += tap-solaris.o
|
||||
net-nested-$(CONFIG_AIX) += tap-aix.o
|
||||
net-nested-$(CONFIG_SLIRP) += slirp.o
|
||||
net-nested-$(CONFIG_VDE) += vde.o
|
||||
net-obj-y += $(addprefix net/, $(net-nested-y))
|
||||
|
||||
######################################################################
|
||||
# libqemu_common.a: Target independent part of system emulation. The
|
||||
# long term path is to suppress *all* target specific code in case of
|
||||
# system emulation, i.e. a single QEMU executable should support all
|
||||
# CPUs and machines.
|
||||
|
||||
obj-y = $(block-obj-y)
|
||||
obj-y += $(net-obj-y)
|
||||
obj-y += $(qobject-obj-y)
|
||||
obj-y += readline.o console.o
|
||||
|
||||
obj-y += tcg-runtime.o host-utils.o
|
||||
obj-y += irq.o ioport.o
|
||||
obj-$(CONFIG_PTIMER) += ptimer.o
|
||||
obj-$(CONFIG_MAX7310) += max7310.o
|
||||
obj-$(CONFIG_WM8750) += wm8750.o
|
||||
obj-$(CONFIG_TWL92230) += twl92230.o
|
||||
obj-$(CONFIG_TSC2005) += tsc2005.o
|
||||
obj-$(CONFIG_LM832X) += lm832x.o
|
||||
obj-$(CONFIG_TMP105) += tmp105.o
|
||||
obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
|
||||
obj-$(CONFIG_SSD0303) += ssd0303.o
|
||||
obj-$(CONFIG_SSD0323) += ssd0323.o
|
||||
obj-$(CONFIG_ADS7846) += ads7846.o
|
||||
obj-$(CONFIG_MAX111X) += max111x.o
|
||||
obj-$(CONFIG_DS1338) += ds1338.o
|
||||
obj-y += i2c.o smbus.o smbus_eeprom.o
|
||||
obj-y += eeprom93xx.o
|
||||
obj-y += scsi-disk.o cdrom.o
|
||||
obj-y += scsi-generic.o scsi-bus.o
|
||||
obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
|
||||
obj-y += usb-serial.o usb-net.o usb-bus.o
|
||||
obj-$(CONFIG_SSI) += ssi.o
|
||||
obj-$(CONFIG_SSI_SD) += ssi-sd.o
|
||||
obj-$(CONFIG_SD) += sd.o
|
||||
obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
|
||||
obj-y += bt-hci-csr.o
|
||||
obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
|
||||
obj-y += qemu-char.o aio.o savevm.o
|
||||
obj-y += msmouse.o ps2.o
|
||||
obj-y += qdev.o qdev-properties.o
|
||||
obj-y += qemu-config.o block-migration.o
|
||||
|
||||
obj-$(CONFIG_BRLAPI) += baum.o
|
||||
obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
|
||||
|
||||
audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
|
||||
|
||||
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
|
||||
audio-obj-$(CONFIG_SDL) += sdlaudio.o
|
||||
audio-obj-$(CONFIG_OSS) += ossaudio.o
|
||||
audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
|
||||
audio-obj-$(CONFIG_ALSA) += alsaaudio.o
|
||||
audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
|
||||
audio-obj-$(CONFIG_FMOD) += fmodaudio.o
|
||||
audio-obj-$(CONFIG_ESD) += esdaudio.o
|
||||
audio-obj-$(CONFIG_PA) += paaudio.o
|
||||
audio-obj-$(CONFIG_WINWAVE) += winwaveaudio.o
|
||||
audio-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
|
||||
audio-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
|
||||
audio-obj-y += wavcapture.o
|
||||
obj-y += $(addprefix audio/, $(audio-obj-y))
|
||||
|
||||
obj-y += keymaps.o
|
||||
obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
|
||||
obj-$(CONFIG_CURSES) += curses.o
|
||||
obj-y += vnc.o acl.o d3des.o
|
||||
obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
|
||||
obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
|
||||
obj-$(CONFIG_COCOA) += cocoa.o
|
||||
obj-$(CONFIG_IOTHREAD) += qemu-thread.o
|
||||
|
||||
slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
|
||||
slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
|
||||
slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o
|
||||
obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y))
|
||||
|
||||
# xen backend driver support
|
||||
obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o
|
||||
obj-$(CONFIG_XEN) += xen_console.o xenfb.o xen_disk.o xen_nic.o
|
||||
|
||||
QEMU_CFLAGS+=$(CURL_CFLAGS)
|
||||
|
||||
ui/cocoa.o: ui/cocoa.m
|
||||
cocoa.o: cocoa.m
|
||||
|
||||
ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
|
||||
keymaps.o: keymaps.c keymaps.h
|
||||
|
||||
ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
|
||||
sdl_zoom.o: sdl_zoom.c sdl_zoom.h sdl_zoom_template.h
|
||||
|
||||
sdl.o: sdl.c keymaps.h sdl_keysym.h sdl_zoom.h
|
||||
|
||||
sdl.o audio/sdlaudio.o sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
|
||||
|
||||
acl.o: acl.h acl.c
|
||||
|
||||
vnc.h: vnc-tls.h vnc-auth-vencrypt.h vnc-auth-sasl.h keymaps.h
|
||||
|
||||
vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h acl.h
|
||||
|
||||
vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
|
||||
|
||||
vnc-tls.o: vnc-tls.c vnc.h
|
||||
|
||||
vnc-auth-vencrypt.o: vnc-auth-vencrypt.c vnc.h
|
||||
|
||||
vnc-auth-sasl.o: vnc-auth-sasl.c vnc.h
|
||||
|
||||
curses.o: curses.c keymaps.h curses_keys.h
|
||||
|
||||
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
|
||||
|
||||
libqemu_common.a: $(obj-y)
|
||||
|
||||
######################################################################
|
||||
|
||||
qemu-img.o: qemu-img-cmds.h
|
||||
qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS)
|
||||
|
||||
qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y)
|
||||
qemu-img$(EXESUF): qemu-img.o qemu-tool.o $(block-obj-y) $(qobject-obj-y)
|
||||
|
||||
qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y)
|
||||
qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o $(block-obj-y) $(qobject-obj-y)
|
||||
|
||||
qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y)
|
||||
qemu-io$(EXESUF): qemu-io.o qemu-tool.o cmd.o $(block-obj-y) $(qobject-obj-y)
|
||||
|
||||
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
|
||||
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $@")
|
||||
|
||||
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
|
||||
|
||||
check-qint: check-qint.o qint.o qemu-malloc.o
|
||||
check-qstring: check-qstring.o qstring.o qemu-malloc.o
|
||||
check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o
|
||||
check-qdict: check-qdict.o qdict.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o
|
||||
check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o
|
||||
check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o
|
||||
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o
|
||||
@@ -131,21 +268,19 @@ clean:
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
|
||||
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
|
||||
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d
|
||||
rm -f qemu-img-cmds.h
|
||||
$(MAKE) -C tests clean
|
||||
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
|
||||
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser; do \
|
||||
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
|
||||
done
|
||||
|
||||
distclean: clean
|
||||
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
|
||||
rm -f qemu-options.def
|
||||
rm -f config-all-devices.mak
|
||||
rm -f roms/seabios/config.mak roms/vgabios/config.mak
|
||||
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.dvi qemu-doc.fn qemu-doc.info qemu-doc.ky qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp qemu-doc.vr
|
||||
rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
|
||||
for d in $(TARGET_DIRS) libhw32 libhw64 libuser libdis libdis-user; do \
|
||||
rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
|
||||
for d in $(TARGET_DIRS) libhw32 libhw64 libuser; do \
|
||||
rm -rf $$d || exit 1 ; \
|
||||
done
|
||||
|
||||
@@ -156,14 +291,13 @@ 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 \
|
||||
gpxe-eepro100-80861209.rom \
|
||||
gpxe-eepro100-80861229.rom \
|
||||
pxe-e1000.bin \
|
||||
pxe-e1000.bin pxe-i82559er.bin \
|
||||
pxe-ne2k_pci.bin pxe-pcnet.bin \
|
||||
pxe-rtl8139.bin pxe-virtio.bin \
|
||||
bamboo.dtb petalogix-s3adsp1800.dtb \
|
||||
multiboot.bin linuxboot.bin \
|
||||
s390-zipl.rom
|
||||
multiboot.bin linuxboot.bin
|
||||
BLOBS += extboot.bin
|
||||
BLOBS += vapic.bin
|
||||
else
|
||||
BLOBS=
|
||||
endif
|
||||
@@ -178,11 +312,7 @@ ifdef CONFIG_POSIX
|
||||
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
|
||||
endif
|
||||
|
||||
install-sysconfig:
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)/qemu"
|
||||
$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(sysconfdir)/qemu"
|
||||
|
||||
install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
|
||||
install: all $(if $(BUILD_DOCS),install-doc)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
|
||||
ifneq ($(TOOLS),)
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
|
||||
@@ -190,7 +320,12 @@ endif
|
||||
ifneq ($(BLOBS),)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
|
||||
set -e; for x in $(BLOBS); do \
|
||||
if [ -f $(SRC_PATH)/pc-bios/$$x ];then \
|
||||
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
|
||||
fi \
|
||||
; if [ -f pc-bios/optionrom/$$x ];then \
|
||||
$(INSTALL_DATA) pc-bios/optionrom/$$x "$(DESTDIR)$(datadir)"; \
|
||||
fi \
|
||||
done
|
||||
endif
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
|
||||
@@ -200,6 +335,9 @@ endif
|
||||
for d in $(TARGET_DIRS); do \
|
||||
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
ifeq ($(KVM_KMOD),yes)
|
||||
$(MAKE) -C kvm/kernel $@
|
||||
endif
|
||||
|
||||
# various test targets
|
||||
test speed: all
|
||||
@@ -215,21 +353,14 @@ cscope:
|
||||
cscope -b
|
||||
|
||||
# documentation
|
||||
MAKEINFO=makeinfo
|
||||
MAKEINFOFLAGS=--no-headers --no-split --number-sections
|
||||
TEXIFLAG=$(if $(V),,--quiet)
|
||||
%.dvi: %.texi
|
||||
$(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<," GEN $@")
|
||||
|
||||
%.html: %.texi
|
||||
$(call quiet-command,$(MAKEINFO) $(MAKEINFOFLAGS) --html $< -o $@, \
|
||||
" GEN $@")
|
||||
$(call quiet-command,texi2html -I=. -monolithic -number $<," GEN $@")
|
||||
|
||||
%.info: %.texi
|
||||
$(call quiet-command,$(MAKEINFO) $< -o $@," GEN $@")
|
||||
$(call quiet-command,makeinfo -I . $< -o $@," GEN $@")
|
||||
|
||||
%.pdf: %.texi
|
||||
$(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<," GEN $@")
|
||||
%.dvi: %.texi
|
||||
$(call quiet-command,texi2dvi -I . $<," GEN $@")
|
||||
|
||||
qemu-options.texi: $(SRC_PATH)/qemu-options.hx
|
||||
$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
|
||||
@@ -237,9 +368,6 @@ qemu-options.texi: $(SRC_PATH)/qemu-options.hx
|
||||
qemu-monitor.texi: $(SRC_PATH)/qemu-monitor.hx
|
||||
$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
|
||||
|
||||
QMP/qmp-commands.txt: $(SRC_PATH)/qemu-monitor.hx
|
||||
$(call quiet-command,sh $(SRC_PATH)/hxtool -q < $< > $@," GEN $@")
|
||||
|
||||
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
|
||||
$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
|
||||
|
||||
@@ -261,14 +389,13 @@ qemu-nbd.8: qemu-nbd.texi
|
||||
pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
|
||||
" GEN $@")
|
||||
|
||||
dvi: qemu-doc.dvi qemu-tech.dvi
|
||||
html: qemu-doc.html qemu-tech.html
|
||||
info: qemu-doc.info qemu-tech.info
|
||||
pdf: qemu-doc.pdf qemu-tech.pdf
|
||||
|
||||
qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
|
||||
qemu-img.texi qemu-nbd.texi qemu-options.texi \
|
||||
qemu-monitor.texi qemu-img-cmds.texi
|
||||
dvi: qemu-doc.dvi qemu-tech.dvi
|
||||
|
||||
html: qemu-doc.html qemu-tech.html
|
||||
|
||||
qemu-doc.dvi qemu-doc.html qemu-doc.info: qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-monitor.texi qemu-img-cmds.texi
|
||||
|
||||
VERSION ?= $(shell cat VERSION)
|
||||
FILE = qemu-$(VERSION)
|
||||
@@ -280,22 +407,43 @@ tar:
|
||||
cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn
|
||||
rm -rf /tmp/$(FILE)
|
||||
|
||||
SYSTEM_TARGETS=$(filter %-softmmu,$(TARGET_DIRS))
|
||||
SYSTEM_PROGS=$(patsubst qemu-system-i386,qemu, \
|
||||
$(patsubst %-softmmu,qemu-system-%, \
|
||||
$(SYSTEM_TARGETS)))
|
||||
|
||||
USER_TARGETS=$(filter %-user,$(TARGET_DIRS))
|
||||
USER_PROGS=$(patsubst %-bsd-user,qemu-%, \
|
||||
$(patsubst %-darwin-user,qemu-%, \
|
||||
$(patsubst %-linux-user,qemu-%, \
|
||||
$(USER_TARGETS))))
|
||||
|
||||
# generate a binary distribution
|
||||
tarbin:
|
||||
cd / && tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \
|
||||
$(patsubst %,$(bindir)/%, $(SYSTEM_PROGS)) \
|
||||
$(patsubst %,$(bindir)/%, $(USER_PROGS)) \
|
||||
$(bindir)/qemu \
|
||||
$(bindir)/qemu-system-x86_64 \
|
||||
$(bindir)/qemu-system-arm \
|
||||
$(bindir)/qemu-system-cris \
|
||||
$(bindir)/qemu-system-m68k \
|
||||
$(bindir)/qemu-system-microblaze \
|
||||
$(bindir)/qemu-system-mips \
|
||||
$(bindir)/qemu-system-mipsel \
|
||||
$(bindir)/qemu-system-mips64 \
|
||||
$(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-x86_64 \
|
||||
$(bindir)/qemu-alpha \
|
||||
$(bindir)/qemu-arm \
|
||||
$(bindir)/qemu-armeb \
|
||||
$(bindir)/qemu-cris \
|
||||
$(bindir)/qemu-m68k \
|
||||
$(bindir)/qemu-microblaze \
|
||||
$(bindir)/qemu-mips \
|
||||
$(bindir)/qemu-mipsel \
|
||||
$(bindir)/qemu-ppc \
|
||||
$(bindir)/qemu-ppc64 \
|
||||
$(bindir)/qemu-ppc64abi32 \
|
||||
$(bindir)/qemu-sh4 \
|
||||
$(bindir)/qemu-sh4eb \
|
||||
$(bindir)/qemu-sparc \
|
||||
$(bindir)/qemu-sparc64 \
|
||||
$(bindir)/qemu-sparc32plus \
|
||||
$(bindir)/qemu-img \
|
||||
$(bindir)/qemu-nbd \
|
||||
$(datadir)/bios.bin \
|
||||
@@ -310,6 +458,7 @@ tarbin:
|
||||
$(datadir)/pxe-rtl8139.bin \
|
||||
$(datadir)/pxe-pcnet.bin \
|
||||
$(datadir)/pxe-e1000.bin \
|
||||
$(datadir)/extboot.bin \
|
||||
$(docdir)/qemu-doc.html \
|
||||
$(docdir)/qemu-tech.html \
|
||||
$(mandir)/man1/qemu.1 \
|
||||
@@ -317,4 +466,4 @@ tarbin:
|
||||
$(mandir)/man8/qemu-nbd.8
|
||||
|
||||
# Include automatically generated dependency files
|
||||
-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d)
|
||||
-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d)
|
||||
|
||||
23
Makefile.dis
23
Makefile.dis
@@ -1,23 +0,0 @@
|
||||
# Makefile for disassemblers.
|
||||
|
||||
include ../config-host.mak
|
||||
include config.mak
|
||||
include $(SRC_PATH)/rules.mak
|
||||
|
||||
.PHONY: all
|
||||
|
||||
$(call set-vpath, $(SRC_PATH))
|
||||
|
||||
QEMU_CFLAGS+=-I..
|
||||
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
|
||||
all: $(libdis-y)
|
||||
# Dummy command so that make thinks it has done something
|
||||
@true
|
||||
|
||||
clean:
|
||||
rm -f *.o *.d *.a *~
|
||||
|
||||
# Include automatically generated dependency files
|
||||
-include $(wildcard *.d */*.d)
|
||||
39
Makefile.hw
39
Makefile.hw
@@ -7,18 +7,49 @@ include $(SRC_PATH)/rules.mak
|
||||
|
||||
.PHONY: all
|
||||
|
||||
$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
|
||||
VPATH=$(SRC_PATH):$(SRC_PATH)/hw
|
||||
|
||||
QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu
|
||||
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
obj-y =
|
||||
obj-y += loader.o
|
||||
obj-y += virtio.o
|
||||
obj-y += fw_cfg.o
|
||||
obj-y += watchdog.o
|
||||
obj-$(CONFIG_ECC) += ecc.o
|
||||
obj-$(CONFIG_NAND) += nand.o
|
||||
|
||||
all: $(hw-obj-y)
|
||||
obj-$(CONFIG_M48T59) += m48t59.o
|
||||
obj-$(CONFIG_ESCC) += escc.o
|
||||
|
||||
# PCI watchdog devices
|
||||
obj-y += wdt_i6300esb.o
|
||||
|
||||
# MSI-X depends on kvm for interrupt injection,
|
||||
# so moved it from Makefile.hw to Makefile.target for now
|
||||
# obj-y += msix.o
|
||||
|
||||
# PCI network cards
|
||||
obj-y += ne2000.o
|
||||
|
||||
obj-$(CONFIG_SMC91C111) += smc91c111.o
|
||||
obj-$(CONFIG_LAN9118) += lan9118.o
|
||||
|
||||
# SCSI layer
|
||||
obj-y += lsi53c895a.o
|
||||
obj-$(CONFIG_ESP) += esp.o
|
||||
|
||||
obj-y += dma-helpers.o sysbus.o isa-bus.o
|
||||
obj-$(CONFIG_QDEV_ADDR) += qdev-addr.o
|
||||
|
||||
all: $(HWLIB)
|
||||
# Dummy command so that make thinks it has done something
|
||||
@true
|
||||
|
||||
$(HWLIB): $(obj-y)
|
||||
|
||||
clean:
|
||||
rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~
|
||||
rm -f *.o *.d *.a *~
|
||||
|
||||
# Include automatically generated dependency files
|
||||
-include $(wildcard *.d */*.d)
|
||||
|
||||
278
Makefile.objs
278
Makefile.objs
@@ -1,278 +0,0 @@
|
||||
#######################################################################
|
||||
# QObject
|
||||
qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
|
||||
qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
|
||||
qobject-obj-y += qerror.o
|
||||
|
||||
#######################################################################
|
||||
# block-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
|
||||
block-obj-y += nbd.o block.o aio.o aes.o osdep.o qemu-config.o
|
||||
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
|
||||
block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
|
||||
block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
|
||||
block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o
|
||||
block-nested-$(CONFIG_WIN32) += raw-win32.o
|
||||
block-nested-$(CONFIG_POSIX) += raw-posix.o
|
||||
block-nested-$(CONFIG_CURL) += curl.o
|
||||
|
||||
block-obj-y += $(addprefix block/, $(block-nested-y))
|
||||
|
||||
net-obj-y = net.o
|
||||
net-nested-y = queue.o checksum.o util.o
|
||||
net-nested-y += socket.o
|
||||
net-nested-y += dump.o
|
||||
net-nested-$(CONFIG_POSIX) += tap.o
|
||||
net-nested-$(CONFIG_LINUX) += tap-linux.o
|
||||
net-nested-$(CONFIG_WIN32) += tap-win32.o
|
||||
net-nested-$(CONFIG_BSD) += tap-bsd.o
|
||||
net-nested-$(CONFIG_SOLARIS) += tap-solaris.o
|
||||
net-nested-$(CONFIG_AIX) += tap-aix.o
|
||||
net-nested-$(CONFIG_SLIRP) += slirp.o
|
||||
net-nested-$(CONFIG_VDE) += vde.o
|
||||
net-obj-y += $(addprefix net/, $(net-nested-y))
|
||||
|
||||
fsdev-nested-$(CONFIG_VIRTFS) = qemu-fsdev.o
|
||||
fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
|
||||
|
||||
######################################################################
|
||||
# libqemu_common.a: Target independent part of system emulation. The
|
||||
# long term path is to suppress *all* target specific code in case of
|
||||
# system emulation, i.e. a single QEMU executable should support all
|
||||
# CPUs and machines.
|
||||
|
||||
common-obj-y = $(block-obj-y) blockdev.o
|
||||
common-obj-y += $(net-obj-y)
|
||||
common-obj-y += $(qobject-obj-y)
|
||||
common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
|
||||
common-obj-y += readline.o console.o cursor.o async.o qemu-error.o
|
||||
common-obj-$(CONFIG_WIN32) += os-win32.o
|
||||
common-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
|
||||
common-obj-y += tcg-runtime.o host-utils.o
|
||||
common-obj-y += irq.o ioport.o input.o
|
||||
common-obj-$(CONFIG_PTIMER) += ptimer.o
|
||||
common-obj-$(CONFIG_MAX7310) += max7310.o
|
||||
common-obj-$(CONFIG_WM8750) += wm8750.o
|
||||
common-obj-$(CONFIG_TWL92230) += twl92230.o
|
||||
common-obj-$(CONFIG_TSC2005) += tsc2005.o
|
||||
common-obj-$(CONFIG_LM832X) += lm832x.o
|
||||
common-obj-$(CONFIG_TMP105) += tmp105.o
|
||||
common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
|
||||
common-obj-$(CONFIG_SSD0303) += ssd0303.o
|
||||
common-obj-$(CONFIG_SSD0323) += ssd0323.o
|
||||
common-obj-$(CONFIG_ADS7846) += ads7846.o
|
||||
common-obj-$(CONFIG_MAX111X) += max111x.o
|
||||
common-obj-$(CONFIG_DS1338) += ds1338.o
|
||||
common-obj-y += i2c.o smbus.o smbus_eeprom.o
|
||||
common-obj-y += eeprom93xx.o
|
||||
common-obj-y += scsi-disk.o cdrom.o
|
||||
common-obj-y += scsi-generic.o scsi-bus.o
|
||||
common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
|
||||
common-obj-y += usb-serial.o usb-net.o usb-bus.o
|
||||
common-obj-$(CONFIG_SSI) += ssi.o
|
||||
common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
|
||||
common-obj-$(CONFIG_SD) += sd.o
|
||||
common-obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
|
||||
common-obj-y += bt-hci-csr.o
|
||||
common-obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
|
||||
common-obj-y += qemu-char.o savevm.o #aio.o
|
||||
common-obj-y += msmouse.o ps2.o
|
||||
common-obj-y += qdev.o qdev-properties.o
|
||||
common-obj-y += block-migration.o
|
||||
|
||||
common-obj-$(CONFIG_BRLAPI) += baum.o
|
||||
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
|
||||
|
||||
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
|
||||
audio-obj-$(CONFIG_SDL) += sdlaudio.o
|
||||
audio-obj-$(CONFIG_OSS) += ossaudio.o
|
||||
audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
|
||||
audio-obj-$(CONFIG_ALSA) += alsaaudio.o
|
||||
audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
|
||||
audio-obj-$(CONFIG_FMOD) += fmodaudio.o
|
||||
audio-obj-$(CONFIG_ESD) += esdaudio.o
|
||||
audio-obj-$(CONFIG_PA) += paaudio.o
|
||||
audio-obj-$(CONFIG_WINWAVE) += winwaveaudio.o
|
||||
audio-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
|
||||
audio-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
|
||||
audio-obj-y += wavcapture.o
|
||||
common-obj-y += $(addprefix audio/, $(audio-obj-y))
|
||||
|
||||
ui-obj-y += keymaps.o
|
||||
ui-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
|
||||
ui-obj-$(CONFIG_CURSES) += curses.o
|
||||
ui-obj-y += vnc.o d3des.o
|
||||
ui-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
|
||||
ui-obj-y += vnc-enc-tight.o vnc-palette.o
|
||||
ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
|
||||
ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
|
||||
ui-obj-$(CONFIG_COCOA) += cocoa.o
|
||||
ifdef CONFIG_VNC_THREAD
|
||||
ui-obj-y += vnc-jobs-async.o
|
||||
else
|
||||
ui-obj-y += vnc-jobs-sync.o
|
||||
endif
|
||||
common-obj-y += $(addprefix ui/, $(ui-obj-y))
|
||||
|
||||
common-obj-y += iov.o acl.o
|
||||
common-obj-$(CONFIG_THREAD) += qemu-thread.o
|
||||
common-obj-y += notify.o event_notifier.o
|
||||
common-obj-y += qemu-timer.o
|
||||
|
||||
slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
|
||||
slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
|
||||
slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o
|
||||
common-obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y))
|
||||
|
||||
# xen backend driver support
|
||||
common-obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o
|
||||
common-obj-$(CONFIG_XEN) += xen_console.o xenfb.o xen_disk.o xen_nic.o
|
||||
|
||||
######################################################################
|
||||
# libuser
|
||||
|
||||
user-obj-y =
|
||||
user-obj-y += envlist.o path.o
|
||||
user-obj-y += tcg-runtime.o host-utils.o
|
||||
user-obj-y += cutils.o cache-utils.o
|
||||
|
||||
######################################################################
|
||||
# libhw
|
||||
|
||||
hw-obj-y =
|
||||
hw-obj-y += vl.o loader.o
|
||||
hw-obj-y += virtio.o virtio-console.o
|
||||
hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o
|
||||
hw-obj-y += watchdog.o
|
||||
hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
|
||||
hw-obj-$(CONFIG_ECC) += ecc.o
|
||||
hw-obj-$(CONFIG_NAND) += nand.o
|
||||
hw-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o
|
||||
hw-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
|
||||
|
||||
hw-obj-$(CONFIG_M48T59) += m48t59.o
|
||||
hw-obj-$(CONFIG_ESCC) += escc.o
|
||||
hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
|
||||
|
||||
hw-obj-$(CONFIG_SERIAL) += serial.o
|
||||
hw-obj-$(CONFIG_PARALLEL) += parallel.o
|
||||
hw-obj-$(CONFIG_I8254) += i8254.o
|
||||
hw-obj-$(CONFIG_PCSPK) += pcspk.o
|
||||
hw-obj-$(CONFIG_PCKBD) += pckbd.o
|
||||
hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
|
||||
hw-obj-$(CONFIG_FDC) += fdc.o
|
||||
hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
|
||||
hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
|
||||
hw-obj-$(CONFIG_DMA) += dma.o
|
||||
|
||||
# PPC devices
|
||||
hw-obj-$(CONFIG_OPENPIC) += openpic.o
|
||||
hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
|
||||
# Mac shared devices
|
||||
hw-obj-$(CONFIG_MACIO) += macio.o
|
||||
hw-obj-$(CONFIG_CUDA) += cuda.o
|
||||
hw-obj-$(CONFIG_ADB) += adb.o
|
||||
hw-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
|
||||
hw-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o
|
||||
# OldWorld PowerMac
|
||||
hw-obj-$(CONFIG_HEATHROW_PIC) += heathrow_pic.o
|
||||
hw-obj-$(CONFIG_GRACKLE_PCI) += grackle_pci.o
|
||||
# NewWorld PowerMac
|
||||
hw-obj-$(CONFIG_UNIN_PCI) += unin_pci.o
|
||||
hw-obj-$(CONFIG_DEC_PCI) += dec_pci.o
|
||||
# PowerPC E500 boards
|
||||
hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
|
||||
|
||||
# MIPS devices
|
||||
hw-obj-$(CONFIG_PIIX4) += piix4.o
|
||||
|
||||
# PCI watchdog devices
|
||||
hw-obj-y += wdt_i6300esb.o
|
||||
|
||||
hw-obj-y += msix.o
|
||||
|
||||
# PCI network cards
|
||||
hw-obj-y += ne2000.o
|
||||
hw-obj-y += eepro100.o
|
||||
hw-obj-y += pcnet.o
|
||||
|
||||
hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
|
||||
hw-obj-$(CONFIG_LAN9118) += lan9118.o
|
||||
hw-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o
|
||||
|
||||
# IDE
|
||||
hw-obj-$(CONFIG_IDE_CORE) += ide/core.o
|
||||
hw-obj-$(CONFIG_IDE_QDEV) += ide/qdev.o
|
||||
hw-obj-$(CONFIG_IDE_PCI) += ide/pci.o
|
||||
hw-obj-$(CONFIG_IDE_ISA) += ide/isa.o
|
||||
hw-obj-$(CONFIG_IDE_PIIX) += ide/piix.o
|
||||
hw-obj-$(CONFIG_IDE_CMD646) += ide/cmd646.o
|
||||
hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o
|
||||
hw-obj-$(CONFIG_IDE_VIA) += ide/via.o
|
||||
|
||||
# SCSI layer
|
||||
hw-obj-y += lsi53c895a.o
|
||||
hw-obj-$(CONFIG_ESP) += esp.o
|
||||
|
||||
hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
|
||||
hw-obj-y += qdev-addr.o
|
||||
|
||||
# VGA
|
||||
hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o
|
||||
hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o
|
||||
hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
|
||||
hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
|
||||
|
||||
hw-obj-$(CONFIG_RC4030) += rc4030.o
|
||||
hw-obj-$(CONFIG_DP8393X) += dp8393x.o
|
||||
hw-obj-$(CONFIG_DS1225Y) += ds1225y.o
|
||||
hw-obj-$(CONFIG_MIPSNET) += mipsnet.o
|
||||
|
||||
# Sound
|
||||
sound-obj-y =
|
||||
sound-obj-$(CONFIG_SB16) += sb16.o
|
||||
sound-obj-$(CONFIG_ES1370) += es1370.o
|
||||
sound-obj-$(CONFIG_AC97) += ac97.o
|
||||
sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
|
||||
sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
|
||||
sound-obj-$(CONFIG_CS4231A) += cs4231a.o
|
||||
|
||||
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
|
||||
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
|
||||
|
||||
hw-obj-$(CONFIG_VIRTFS) += virtio-9p-debug.o virtio-9p-local.o
|
||||
|
||||
######################################################################
|
||||
# libdis
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
|
||||
libdis-y =
|
||||
libdis-$(CONFIG_ALPHA_DIS) += alpha-dis.o
|
||||
libdis-$(CONFIG_ARM_DIS) += arm-dis.o
|
||||
libdis-$(CONFIG_CRIS_DIS) += cris-dis.o
|
||||
libdis-$(CONFIG_HPPA_DIS) += hppa-dis.o
|
||||
libdis-$(CONFIG_I386_DIS) += i386-dis.o
|
||||
libdis-$(CONFIG_IA64_DIS) += ia64-dis.o
|
||||
libdis-$(CONFIG_M68K_DIS) += m68k-dis.o
|
||||
libdis-$(CONFIG_MICROBLAZE_DIS) += microblaze-dis.o
|
||||
libdis-$(CONFIG_MIPS_DIS) += mips-dis.o
|
||||
libdis-$(CONFIG_PPC_DIS) += ppc-dis.o
|
||||
libdis-$(CONFIG_S390_DIS) += s390-dis.o
|
||||
libdis-$(CONFIG_SH4_DIS) += sh4-dis.o
|
||||
libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
|
||||
|
||||
vl.o: qemu-options.def
|
||||
os-posix.o: qemu-options.def
|
||||
os-win32.o: qemu-options.def
|
||||
|
||||
qemu-options.def: $(SRC_PATH)/qemu-options.hx
|
||||
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
|
||||
|
||||
231
Makefile.target
231
Makefile.target
@@ -1,22 +1,17 @@
|
||||
# -*- Mode: makefile -*-
|
||||
|
||||
# This needs to be defined before rules.mak
|
||||
GENERATED_HEADERS = config-target.h
|
||||
CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
|
||||
|
||||
include ../config-host.mak
|
||||
include config-devices.mak
|
||||
include config-target.mak
|
||||
include $(SRC_PATH)/rules.mak
|
||||
ifneq ($(HWDIR),)
|
||||
include $(HWDIR)/config.mak
|
||||
endif
|
||||
|
||||
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
|
||||
$(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw)
|
||||
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
|
||||
QEMU_CFLAGS+= -I.. -I$(TARGET_PATH) -DNEED_CPU_H
|
||||
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
|
||||
ifdef CONFIG_USER_ONLY
|
||||
# user emulator name
|
||||
QEMU_PROG=qemu-$(TARGET_ARCH2)
|
||||
@@ -33,7 +28,9 @@ PROGS=$(QEMU_PROG)
|
||||
|
||||
LIBS+=-lm
|
||||
|
||||
kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
|
||||
kvm.o kvm-all.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
|
||||
|
||||
CFLAGS += $(KVM_CFLAGS)
|
||||
|
||||
config-target.h: config-target.h-timestamp
|
||||
config-target.h-timestamp: config-target.mak
|
||||
@@ -45,23 +42,40 @@ all: $(PROGS)
|
||||
|
||||
#########################################################
|
||||
# cpu emulator library
|
||||
libobj-y = exec.o translate-all.o cpu-exec.o translate.o
|
||||
libobj-y += tcg/tcg.o
|
||||
libobj-y = exec.o cpu-exec.o
|
||||
libobj-$(CONFIG_NO_CPU_EMULATION) += fake-exec.o
|
||||
libobj-$(CONFIG_CPU_EMULATION) += translate-all.o translate.o
|
||||
libobj-$(CONFIG_CPU_EMULATION) += tcg/tcg.o
|
||||
libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o
|
||||
libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o
|
||||
libobj-y += op_helper.o helper.o
|
||||
ifeq ($(TARGET_BASE_ARCH), i386)
|
||||
libobj-y += cpuid.o
|
||||
endif
|
||||
libobj-$(CONFIG_NEED_MMU) += mmu.o
|
||||
|
||||
libobj-$(CONFIG_KVM) += kvm-tpr-opt.o
|
||||
libobj-$(CONFIG_KVM) += qemu-kvm-helper.o
|
||||
|
||||
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
|
||||
libobj-$(TARGET_ALPHA) += alpha_palcode.o
|
||||
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
libobj-y += disas.o
|
||||
|
||||
$(libobj-y): $(GENERATED_HEADERS)
|
||||
libobj-$(CONFIG_ALPHA_DIS) += alpha-dis.o
|
||||
libobj-$(CONFIG_ARM_DIS) += arm-dis.o
|
||||
libobj-$(CONFIG_CRIS_DIS) += cris-dis.o
|
||||
libobj-$(CONFIG_HPPA_DIS) += hppa-dis.o
|
||||
libobj-$(CONFIG_I386_DIS) += i386-dis.o
|
||||
libobj-$(CONFIG_M68K_DIS) += m68k-dis.o
|
||||
libobj-$(CONFIG_MICROBLAZE_DIS) += microblaze-dis.o
|
||||
libobj-$(CONFIG_MIPS_DIS) += mips-dis.o
|
||||
libobj-$(CONFIG_PPC_DIS) += ppc-dis.o
|
||||
libobj-$(CONFIG_S390_DIS) += s390-dis.o
|
||||
libobj-$(CONFIG_SH4_DIS) += sh4-dis.o
|
||||
libobj-$(CONFIG_SPARC_DIS) += sparc-dis.o
|
||||
|
||||
# libqemu
|
||||
|
||||
libqemu.a: $(libobj-y)
|
||||
|
||||
translate.o: translate.c cpu.h
|
||||
|
||||
translate-all.o: translate-all.c cpu.h
|
||||
@@ -76,19 +90,20 @@ op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
|
||||
# cpu_signal_handler() in cpu-exec.c.
|
||||
signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
|
||||
|
||||
qemu-kvm-helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
|
||||
|
||||
#########################################################
|
||||
# Linux user emulator target
|
||||
|
||||
ifdef CONFIG_LINUX_USER
|
||||
|
||||
$(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR))
|
||||
|
||||
VPATH+=:$(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
|
||||
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
|
||||
obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \
|
||||
elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \
|
||||
qemu-malloc.o
|
||||
elfload.o linuxload.o uaccess.o gdbstub.o
|
||||
|
||||
obj-$(TARGET_HAS_BFLT) += flatload.o
|
||||
obj-$(TARGET_HAS_ELFLOAD32) += elfload32.o
|
||||
|
||||
obj-$(TARGET_I386) += vm86.o
|
||||
|
||||
@@ -101,11 +116,7 @@ obj-arm-y += arm-semi.o
|
||||
|
||||
obj-m68k-y += m68k-sim.o m68k-semi.o
|
||||
|
||||
$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
|
||||
|
||||
obj-y += $(addprefix ../libuser/, $(user-obj-y))
|
||||
obj-y += $(addprefix ../libdis-user/, $(libdis-y))
|
||||
obj-y += $(libobj-y)
|
||||
ARLIBS=../libuser/libuser.a libqemu.a
|
||||
|
||||
endif #CONFIG_LINUX_USER
|
||||
|
||||
@@ -114,8 +125,7 @@ endif #CONFIG_LINUX_USER
|
||||
|
||||
ifdef CONFIG_DARWIN_USER
|
||||
|
||||
$(call set-vpath, $(SRC_PATH)/darwin-user)
|
||||
|
||||
VPATH+=:$(SRC_PATH)/darwin-user
|
||||
QEMU_CFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
|
||||
|
||||
# Leave some space for the regular program loading zone
|
||||
@@ -128,11 +138,7 @@ obj-y = main.o commpage.o machload.o mmap.o signal.o syscall.o thunk.o \
|
||||
|
||||
obj-i386-y += ioport-user.o
|
||||
|
||||
$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
|
||||
|
||||
obj-y += $(addprefix ../libuser/, $(user-obj-y))
|
||||
obj-y += $(addprefix ../libdis-user/, $(libdis-y))
|
||||
obj-y += $(libobj-y)
|
||||
ARLIBS=../libuser/libuser.a libqemu.a
|
||||
|
||||
endif #CONFIG_DARWIN_USER
|
||||
|
||||
@@ -141,8 +147,7 @@ endif #CONFIG_DARWIN_USER
|
||||
|
||||
ifdef CONFIG_BSD_USER
|
||||
|
||||
$(call set-vpath, $(SRC_PATH)/bsd-user)
|
||||
|
||||
VPATH+=:$(SRC_PATH)/bsd-user
|
||||
QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
|
||||
|
||||
obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
|
||||
@@ -150,11 +155,7 @@ obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
|
||||
|
||||
obj-i386-y += ioport-user.o
|
||||
|
||||
$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
|
||||
|
||||
obj-y += $(addprefix ../libuser/, $(user-obj-y))
|
||||
obj-y += $(addprefix ../libdis-user/, $(libdis-y))
|
||||
obj-y += $(libobj-y)
|
||||
ARLIBS=../libuser/libuser.a libqemu.a
|
||||
|
||||
endif #CONFIG_BSD_USER
|
||||
|
||||
@@ -162,23 +163,30 @@ endif #CONFIG_BSD_USER
|
||||
# System emulator target
|
||||
ifdef CONFIG_SOFTMMU
|
||||
|
||||
obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
|
||||
obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
|
||||
# virtio has to be here due to weird dependency between PCI and virtio-net.
|
||||
# need to fix this properly
|
||||
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
|
||||
obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
|
||||
obj-y += vhost_net.o
|
||||
obj-$(CONFIG_VHOST_NET) += vhost.o
|
||||
obj-$(CONFIG_VIRTFS) += virtio-9p.o
|
||||
obj-y += rwhandler.o
|
||||
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o
|
||||
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
|
||||
obj-$(CONFIG_NO_KVM) += kvm-stub.o
|
||||
# MSI-X depends on kvm for interrupt injection,
|
||||
# so moved it from Makefile.hw to Makefile.target for now
|
||||
obj-y += msix.o
|
||||
|
||||
obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
|
||||
LIBS+=-lz
|
||||
|
||||
sound-obj-y =
|
||||
sound-obj-$(CONFIG_SB16) += sb16.o
|
||||
sound-obj-$(CONFIG_ES1370) += es1370.o
|
||||
sound-obj-$(CONFIG_AC97) += ac97.o
|
||||
sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
|
||||
sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
|
||||
sound-obj-$(CONFIG_CS4231A) += cs4231a.o
|
||||
|
||||
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
|
||||
|
||||
QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
|
||||
QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
|
||||
QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
|
||||
QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
|
||||
|
||||
# xen backend driver support
|
||||
obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
|
||||
@@ -187,43 +195,65 @@ obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
|
||||
obj-$(CONFIG_USB_OHCI) += usb-ohci.o
|
||||
|
||||
# PCI network cards
|
||||
obj-y += eepro100.o
|
||||
obj-y += pcnet.o
|
||||
obj-y += rtl8139.o
|
||||
obj-y += e1000.o
|
||||
|
||||
# Hardware support
|
||||
obj-i386-y += vga.o
|
||||
obj-i386-y += mc146818rtc.o i8259.o pc.o
|
||||
obj-i386-y += cirrus_vga.o apic.o ioapic.o piix_pci.o
|
||||
obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o
|
||||
obj-i386-y = ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/piix.o
|
||||
obj-i386-y += pckbd.o $(sound-obj-y) dma.o
|
||||
obj-i386-y += vga.o vga-pci.o vga-isa.o
|
||||
obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
|
||||
obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
|
||||
obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
|
||||
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
|
||||
obj-i386-y += debugcon.o multiboot.o
|
||||
obj-i386-y += pc_piix.o
|
||||
obj-i386-y += extboot.o
|
||||
obj-i386-y += ne2000-isa.o
|
||||
obj-i386-y += testdev.o
|
||||
|
||||
obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
|
||||
obj-i386-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
|
||||
|
||||
# Hardware support
|
||||
obj-ia64-y += ide.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
|
||||
obj-ia64-y += fdc.o mc146818rtc.o serial.o i8259.o ipf.o
|
||||
obj-ia64-y += cirrus_vga.o parallel.o acpi.o piix_pci.o
|
||||
obj-ia64-y += usb-uhci.o
|
||||
obj-ia64-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
|
||||
|
||||
# shared objects
|
||||
obj-ppc-y = ppc.o
|
||||
obj-ppc-y += vga.o
|
||||
obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o
|
||||
obj-ppc-y += ide/cmd646.o
|
||||
obj-ppc-y += vga.o vga-pci.o $(sound-obj-y) dma.o openpic.o
|
||||
obj-ppc-y += cirrus_vga.o
|
||||
# PREP target
|
||||
obj-ppc-y += i8259.o mc146818rtc.o
|
||||
obj-ppc-y += ppc_prep.o
|
||||
obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o
|
||||
obj-ppc-y += prep_pci.o ppc_prep.o ne2000-isa.o
|
||||
# Mac shared devices
|
||||
obj-ppc-y += macio.o cuda.o adb.o mac_nvram.o mac_dbdma.o
|
||||
# OldWorld PowerMac
|
||||
obj-ppc-y += ppc_oldworld.o
|
||||
obj-ppc-y += heathrow_pic.o grackle_pci.o ppc_oldworld.o
|
||||
# NewWorld PowerMac
|
||||
obj-ppc-y += ppc_newworld.o
|
||||
obj-ppc-y += unin_pci.o ppc_newworld.o
|
||||
# PowerPC 4xx boards
|
||||
obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
|
||||
obj-ppc-y += pflash_cfi02.o ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
|
||||
obj-ppc-y += ppc440.o ppc440_bamboo.o
|
||||
# PowerPC E500 boards
|
||||
obj-ppc-y += ppce500_mpc8544ds.o
|
||||
obj-ppc-y += ppce500_pci.o ppce500_mpc8544ds.o
|
||||
obj-ppc-$(CONFIG_KVM) += kvm_ppc.o
|
||||
obj-ppc-$(CONFIG_FDT) += device_tree.o
|
||||
|
||||
obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
|
||||
obj-mips-y += mips_addr.o mips_timer.o mips_int.o
|
||||
obj-mips-y += vga.o i8259.o
|
||||
obj-mips-y += g364fb.o jazz_led.o
|
||||
obj-mips-y += gt64xxx.o mc146818rtc.o
|
||||
obj-mips-y += cirrus_vga.o
|
||||
obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
|
||||
obj-mips-y += mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o
|
||||
obj-mips-y += vga-pci.o vga-isa.o vga-isa-mm.o
|
||||
obj-mips-y += g364fb.o jazz_led.o dp8393x.o
|
||||
obj-mips-y += ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/piix.o
|
||||
obj-mips-y += gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
|
||||
obj-mips-y += piix4.o parallel.o cirrus_vga.o pcspk.o $(sound-obj-y)
|
||||
obj-mips-y += mipsnet.o ne2000-isa.o
|
||||
obj-mips-y += pflash_cfi01.o
|
||||
obj-mips-y += vmware_vga.o
|
||||
|
||||
obj-microblaze-y = petalogix_s3adsp1800_mmu.o
|
||||
|
||||
@@ -233,13 +263,12 @@ obj-microblaze-y += xilinx_timer.o
|
||||
obj-microblaze-y += xilinx_uartlite.o
|
||||
obj-microblaze-y += xilinx_ethlite.o
|
||||
|
||||
obj-microblaze-y += pflash_cfi02.o
|
||||
|
||||
obj-microblaze-$(CONFIG_FDT) += device_tree.o
|
||||
|
||||
# Boards
|
||||
obj-cris-y = cris_pic_cpu.o
|
||||
obj-cris-y += cris-boot.o
|
||||
obj-cris-y += etraxfs.o axis_dev88.o
|
||||
obj-cris-y += axis_dev88.o
|
||||
obj-cris-y = cris_pic_cpu.o etraxfs.o axis_dev88.o
|
||||
|
||||
# IO blocks
|
||||
obj-cris-y += etraxfs_dma.o
|
||||
@@ -248,14 +277,17 @@ obj-cris-y += etraxfs_eth.o
|
||||
obj-cris-y += etraxfs_timer.o
|
||||
obj-cris-y += etraxfs_ser.o
|
||||
|
||||
obj-cris-y += pflash_cfi02.o
|
||||
|
||||
ifeq ($(TARGET_ARCH), sparc64)
|
||||
obj-sparc-y = sun4u.o apb_pci.o
|
||||
obj-sparc-y += vga.o
|
||||
obj-sparc-y += mc146818rtc.o
|
||||
obj-sparc-y += cirrus_vga.o
|
||||
obj-sparc-y = sun4u.o pckbd.o apb_pci.o
|
||||
obj-sparc-y += ide/core.o ide/qdev.o ide/pci.o ide/cmd646.o
|
||||
obj-sparc-y += vga.o vga-pci.o
|
||||
obj-sparc-y += fdc.o mc146818rtc.o serial.o
|
||||
obj-sparc-y += cirrus_vga.o parallel.o
|
||||
else
|
||||
obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
|
||||
obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
|
||||
obj-sparc-y = sun4m.o lance.o tcx.o iommu.o slavio_intctl.o
|
||||
obj-sparc-y += slavio_timer.o slavio_misc.o fdc.o sparc32_dma.o
|
||||
obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
|
||||
endif
|
||||
|
||||
@@ -268,61 +300,64 @@ obj-arm-y += pl061.o
|
||||
obj-arm-y += arm-semi.o
|
||||
obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
|
||||
obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
|
||||
obj-arm-y += gumstix.o
|
||||
obj-arm-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o
|
||||
obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
|
||||
omap_gpio.o omap_intc.o omap_uart.o
|
||||
obj-arm-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
|
||||
omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
|
||||
obj-arm-y += pflash_cfi01.o gumstix.o
|
||||
obj-arm-y += zaurus.o ide/core.o ide/microdrive.o serial.o spitz.o tosa.o tc6393xb.o
|
||||
obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
|
||||
obj-arm-y += omap2.o omap_dss.o soc_dma.o
|
||||
obj-arm-y += omap_sx1.o palm.o tsc210x.o
|
||||
obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
|
||||
obj-arm-y += mst_fpga.o mainstone.o
|
||||
obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
|
||||
obj-arm-y += musicpal.o pflash_cfi02.o bitbang_i2c.o marvell_88w8618_audio.o
|
||||
obj-arm-y += framebuffer.o
|
||||
obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
|
||||
obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
|
||||
obj-arm-y += syborg_virtio.o
|
||||
|
||||
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
|
||||
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
|
||||
obj-sh4-y += ide/mmio.o
|
||||
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
|
||||
obj-sh4-y += ide/core.o ide/mmio.o
|
||||
|
||||
obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
|
||||
obj-m68k-y += m68k-semi.o dummy_m68k.o
|
||||
|
||||
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
|
||||
|
||||
obj-alpha-y = alpha_palcode.o
|
||||
ifeq ($(TARGET_ARCH), ia64)
|
||||
firmware.o: firmware.c
|
||||
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
endif
|
||||
|
||||
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
|
||||
main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
|
||||
|
||||
vl.o: qemu-options.h
|
||||
|
||||
monitor.o: qemu-monitor.h
|
||||
|
||||
$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
|
||||
|
||||
obj-y += $(addprefix ../, $(common-obj-y))
|
||||
obj-y += $(addprefix ../libdis/, $(libdis-y))
|
||||
obj-y += $(libobj-y)
|
||||
obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
|
||||
ARLIBS=../libqemu_common.a libqemu.a $(HWLIB)
|
||||
|
||||
endif # CONFIG_SOFTMMU
|
||||
|
||||
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
|
||||
|
||||
$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
|
||||
$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) $(ARLIBS)
|
||||
$(call LINK,$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y))
|
||||
|
||||
|
||||
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/feature_to_c.sh
|
||||
gdbstub-xml.c: $(TARGET_XML_FILES) feature_to_c.sh
|
||||
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@")
|
||||
|
||||
qemu-options.h: $(SRC_PATH)/qemu-options.hx
|
||||
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
|
||||
|
||||
qemu-monitor.h: $(SRC_PATH)/qemu-monitor.hx
|
||||
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
|
||||
rm -f *.d */*.d tcg/*.o ide/*.o
|
||||
rm -f qemu-monitor.h gdbstub-xml.c
|
||||
rm -f qemu-options.h qemu-monitor.h gdbstub-xml.c
|
||||
|
||||
install: all
|
||||
ifneq ($(PROGS),)
|
||||
|
||||
@@ -6,16 +6,25 @@ include $(SRC_PATH)/rules.mak
|
||||
|
||||
.PHONY: all
|
||||
|
||||
$(call set-vpath, $(SRC_PATH))
|
||||
# Do not take %.o from $(SRC_PATH), only %.c and %.h
|
||||
# All %.o for user targets should be built with -fpie, when
|
||||
# configured with --enable-user-pie, so we don't want to
|
||||
# take %.o from $(SRC_PATH), since they built without -fpie
|
||||
vpath %.c %.h $(SRC_PATH)
|
||||
|
||||
QEMU_CFLAGS+=-I..
|
||||
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
obj-y =
|
||||
obj-y += envlist.o path.o
|
||||
obj-y += tcg-runtime.o host-utils.o
|
||||
obj-y += cutils.o cache-utils.o
|
||||
|
||||
all: $(user-obj-y)
|
||||
all: libuser.a
|
||||
# Dummy command so that make thinks it has done something
|
||||
@true
|
||||
|
||||
libuser.a: $(obj-y)
|
||||
|
||||
clean:
|
||||
rm -f *.o *.d *.a *~
|
||||
|
||||
|
||||
11
QMP/README
11
QMP/README
@@ -15,9 +15,8 @@ QMP is JSON[1] based and has the following features:
|
||||
|
||||
For more information, please, refer to the following files:
|
||||
|
||||
o qmp-spec.txt QEMU Monitor Protocol current specification
|
||||
o qmp-commands.txt QMP supported commands
|
||||
o qmp-events.txt List of available asynchronous events
|
||||
o qmp-spec.txt QEMU Monitor Protocol current specification
|
||||
o qmp-events.txt List of available asynchronous events
|
||||
|
||||
There are also two simple Python scripts available:
|
||||
|
||||
@@ -53,11 +52,9 @@ $ telnet localhost 4444
|
||||
Trying 127.0.0.1...
|
||||
Connected to localhost.
|
||||
Escape character is '^]'.
|
||||
{"QMP": {"version": {"qemu": "0.12.50", "package": ""}, "capabilities": []}}
|
||||
{ "execute": "qmp_capabilities" }
|
||||
{"return": {}}
|
||||
{"QMP": {"capabilities": []}}
|
||||
{ "execute": "query-version" }
|
||||
{"return": {"qemu": "0.12.50", "package": ""}}
|
||||
{"return": {"qemu": "0.11.50", "package": ""}}
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
@@ -1,202 +1,26 @@
|
||||
QEMU Monitor Protocol Events
|
||||
============================
|
||||
QEMU Monitor Protocol: Events
|
||||
=============================
|
||||
|
||||
BLOCK_IO_ERROR
|
||||
--------------
|
||||
|
||||
Emitted when a disk I/O error occurs.
|
||||
|
||||
Data:
|
||||
|
||||
- "device": device name (json-string)
|
||||
- "operation": I/O operation (json-string, "read" or "write")
|
||||
- "action": action that has been taken, it's one of the following (json-string):
|
||||
"ignore": error has been ignored
|
||||
"report": error has been reported to the device
|
||||
"stop": error caused VM to be stopped
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "BLOCK_IO_ERROR",
|
||||
"data": { "device": "ide0-hd1",
|
||||
"operation": "write",
|
||||
"action": "stop" },
|
||||
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
||||
|
||||
Note: If action is "stop", a STOP event will eventually follow the
|
||||
BLOCK_IO_ERROR event.
|
||||
|
||||
RESET
|
||||
-----
|
||||
|
||||
Emitted when the Virtual Machine is reseted.
|
||||
1 SHUTDOWN
|
||||
-----------
|
||||
|
||||
Description: Issued when the Virtual Machine is powered down.
|
||||
Data: None.
|
||||
|
||||
Example:
|
||||
2 RESET
|
||||
-------
|
||||
|
||||
{ "event": "RESET",
|
||||
"timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
|
||||
Description: Issued when the Virtual Machine is reseted.
|
||||
Data: None.
|
||||
|
||||
RESUME
|
||||
3 STOP
|
||||
------
|
||||
|
||||
Emitted when the Virtual Machine resumes execution.
|
||||
|
||||
Description: Issued when the Virtual Machine is stopped.
|
||||
Data: None.
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "RESUME",
|
||||
"timestamp": { "seconds": 1271770767, "microseconds": 582542 } }
|
||||
|
||||
RTC_CHANGE
|
||||
----------
|
||||
|
||||
Emitted when the guest changes the RTC time.
|
||||
|
||||
Data:
|
||||
|
||||
- "offset": delta against the host UTC in seconds (json-number)
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "RTC_CHANGE",
|
||||
"data": { "offset": 78 },
|
||||
"timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
|
||||
|
||||
SHUTDOWN
|
||||
--------
|
||||
|
||||
Emitted when the Virtual Machine is powered down.
|
||||
4 DEBUG
|
||||
-------
|
||||
|
||||
Description: Issued when the Virtual Machine enters debug mode.
|
||||
Data: None.
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "SHUTDOWN",
|
||||
"timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
|
||||
|
||||
Note: If the command-line option "-no-shutdown" has been specified, a STOP
|
||||
event will eventually follow the SHUTDOWN event.
|
||||
|
||||
STOP
|
||||
----
|
||||
|
||||
Emitted when the Virtual Machine is stopped.
|
||||
|
||||
Data: None.
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "SHUTDOWN",
|
||||
"timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
|
||||
|
||||
VNC_CONNECTED
|
||||
-------------
|
||||
|
||||
Emitted when a VNC client establishes a connection.
|
||||
|
||||
Data:
|
||||
|
||||
- "server": Server information (json-object)
|
||||
- "host": IP address (json-string)
|
||||
- "service": port number (json-string)
|
||||
- "family": address family (json-string, "ipv4" or "ipv6")
|
||||
- "auth": authentication method (json-string, optional)
|
||||
- "client": Client information (json-object)
|
||||
- "host": IP address (json-string)
|
||||
- "service": port number (json-string)
|
||||
- "family": address family (json-string, "ipv4" or "ipv6")
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "VNC_CONNECTED",
|
||||
"data": {
|
||||
"server": { "auth": "sasl", "family": "ipv4",
|
||||
"service": "5901", "host": "0.0.0.0" },
|
||||
"client": { "family": "ipv4", "service": "58425",
|
||||
"host": "127.0.0.1" } },
|
||||
"timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
|
||||
|
||||
|
||||
Note: This event is emitted before any authentication takes place, thus
|
||||
the authentication ID is not provided.
|
||||
|
||||
VNC_DISCONNECTED
|
||||
----------------
|
||||
|
||||
Emitted when the conection is closed.
|
||||
|
||||
Data:
|
||||
|
||||
- "server": Server information (json-object)
|
||||
- "host": IP address (json-string)
|
||||
- "service": port number (json-string)
|
||||
- "family": address family (json-string, "ipv4" or "ipv6")
|
||||
- "auth": authentication method (json-string, optional)
|
||||
- "client": Client information (json-object)
|
||||
- "host": IP address (json-string)
|
||||
- "service": port number (json-string)
|
||||
- "family": address family (json-string, "ipv4" or "ipv6")
|
||||
- "x509_dname": TLS dname (json-string, optional)
|
||||
- "sasl_username": SASL username (json-string, optional)
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "VNC_DISCONNECTED",
|
||||
"data": {
|
||||
"server": { "auth": "sasl", "family": "ipv4",
|
||||
"service": "5901", "host": "0.0.0.0" },
|
||||
"client": { "family": "ipv4", "service": "58425",
|
||||
"host": "127.0.0.1", "sasl_username": "luiz" } },
|
||||
"timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
|
||||
|
||||
VNC_INITIALIZED
|
||||
---------------
|
||||
|
||||
Emitted after authentication takes place (if any) and the VNC session is
|
||||
made active.
|
||||
|
||||
Data:
|
||||
|
||||
- "server": Server information (json-object)
|
||||
- "host": IP address (json-string)
|
||||
- "service": port number (json-string)
|
||||
- "family": address family (json-string, "ipv4" or "ipv6")
|
||||
- "auth": authentication method (json-string, optional)
|
||||
- "client": Client information (json-object)
|
||||
- "host": IP address (json-string)
|
||||
- "service": port number (json-string)
|
||||
- "family": address family (json-string, "ipv4" or "ipv6")
|
||||
- "x509_dname": TLS dname (json-string, optional)
|
||||
- "sasl_username": SASL username (json-string, optional)
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "VNC_INITIALIZED",
|
||||
"data": {
|
||||
"server": { "auth": "sasl", "family": "ipv4",
|
||||
"service": "5901", "host": "0.0.0.0"},
|
||||
"client": { "family": "ipv4", "service": "46089",
|
||||
"host": "127.0.0.1", "sasl_username": "luiz" } },
|
||||
"timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
|
||||
|
||||
WATCHDOG
|
||||
--------
|
||||
|
||||
Emitted when the watchdog device's timer is expired.
|
||||
|
||||
Data:
|
||||
|
||||
- "action": Action that has been taken, it's one of the following (json-string):
|
||||
"reset", "shutdown", "poweroff", "pause", "debug", or "none"
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "WATCHDOG",
|
||||
"data": { "action": "reset" },
|
||||
"timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
|
||||
|
||||
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
|
||||
followed respectively by the RESET, SHUTDOWN, or STOP events.
|
||||
|
||||
@@ -42,7 +42,6 @@ def main():
|
||||
|
||||
qemu = qmp.QEMUMonitorProtocol(argv[1])
|
||||
qemu.connect()
|
||||
qemu.send("qmp_capabilities")
|
||||
|
||||
print 'Connected!'
|
||||
|
||||
|
||||
@@ -44,17 +44,14 @@ they can be in ANY order, thus no particular order should be assumed.
|
||||
|
||||
Right when connected the Server will issue a greeting message, which signals
|
||||
that the connection has been successfully established and that the Server is
|
||||
ready for capabilities negotiation (for more information refer to section
|
||||
'4. Capabilities Negotiation').
|
||||
waiting for commands.
|
||||
|
||||
The format is:
|
||||
|
||||
{ "QMP": { "version": json-object, "capabilities": json-array } }
|
||||
{ "QMP": { "capabilities": json-array } }
|
||||
|
||||
Where,
|
||||
|
||||
- The "version" member contains the Server's version information (the format
|
||||
is the same of the 'query-version' command)
|
||||
- The "capabilities" member specify the availability of features beyond the
|
||||
baseline specification
|
||||
|
||||
@@ -155,7 +152,7 @@ This section provides some examples of real QMP usage, in all of them
|
||||
3.1 Server greeting
|
||||
-------------------
|
||||
|
||||
S: {"QMP": {"version": {"qemu": "0.12.50", "package": ""}, "capabilities": []}}
|
||||
S: {"QMP": {"capabilities": []}}
|
||||
|
||||
3.2 Simple 'stop' execution
|
||||
---------------------------
|
||||
@@ -182,91 +179,25 @@ S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
|
||||
S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
|
||||
"POWERDOWN"}
|
||||
|
||||
4. Capabilities Negotiation
|
||||
----------------------------
|
||||
4. Compatibility Considerations
|
||||
--------------------------------
|
||||
|
||||
When a Client successfully establishes a connection, the Server is in
|
||||
Capabilities Negotiation mode.
|
||||
|
||||
In this mode only the 'qmp_capabilities' command is allowed to run, all
|
||||
other commands will return the CommandNotFound error. Asynchronous messages
|
||||
are not delivered either.
|
||||
|
||||
Clients should use the 'qmp_capabilities' command to enable capabilities
|
||||
advertised in the Server's greeting (section '2.2 Server Greeting') they
|
||||
support.
|
||||
|
||||
When the 'qmp_capabilities' command is issued, and if it does not return an
|
||||
error, the Server enters in Command mode where capabilities changes take
|
||||
effect, all commands (except 'qmp_capabilities') are allowed and asynchronous
|
||||
messages are delivered.
|
||||
|
||||
5 Compatibility Considerations
|
||||
------------------------------
|
||||
|
||||
All protocol changes or new features which modify the protocol format in an
|
||||
incompatible way are disabled by default and will be advertised by the
|
||||
capabilities array (section '2.2 Server Greeting'). Thus, Clients can check
|
||||
that array and enable the capabilities they support.
|
||||
|
||||
Additionally, Clients must not assume any particular:
|
||||
In order to achieve maximum compatibility between versions, Clients must not
|
||||
assume any particular:
|
||||
|
||||
- Size of json-objects or length of json-arrays
|
||||
- Order of json-object members or json-array elements
|
||||
- Amount of errors generated by a command, that is, new errors can be added
|
||||
to any existing command in newer versions of the Server
|
||||
|
||||
6. Downstream extension of QMP
|
||||
------------------------------
|
||||
Additionally, Clients should always:
|
||||
|
||||
We recommend that downstream consumers of QEMU do *not* modify QMP.
|
||||
Management tools should be able to support both upstream and downstream
|
||||
versions of QMP without special logic, and downstream extensions are
|
||||
inherently at odds with that.
|
||||
- Check the capabilities json-array at connection time
|
||||
- Check the availability of commands with 'query-commands' before issuing them
|
||||
|
||||
However, we recognize that it is sometimes impossible for downstreams to
|
||||
avoid modifying QMP. Both upstream and downstream need to take care to
|
||||
preserve long-term compatibility and interoperability.
|
||||
5. Recommendations to Client implementors
|
||||
-----------------------------------------
|
||||
|
||||
To help with that, QMP reserves JSON object member names beginning with
|
||||
'__' (double underscore) for downstream use ("downstream names"). This
|
||||
means upstream will never use any downstream names for its commands,
|
||||
arguments, errors, asynchronous events, and so forth.
|
||||
|
||||
Any new names downstream wishes to add must begin with '__'. To
|
||||
ensure compatibility with other downstreams, it is strongly
|
||||
recommended that you prefix your downstram names with '__RFQDN_' where
|
||||
RFQDN is a valid, reverse fully qualified domain name which you
|
||||
control. For example, a qemu-kvm specific monitor command would be:
|
||||
|
||||
(qemu) __org.linux-kvm_enable_irqchip
|
||||
|
||||
Downstream must not change the server greeting (section 2.2) other than
|
||||
to offer additional capabilities. But see below for why even that is
|
||||
discouraged.
|
||||
|
||||
Section '5 Compatibility Considerations' applies to downstream as well
|
||||
as to upstream, obviously. It follows that downstream must behave
|
||||
exactly like upstream for any input not containing members with
|
||||
downstream names ("downstream members"), except it may add members
|
||||
with downstream names to its output.
|
||||
|
||||
Thus, a client should not be able to distinguish downstream from
|
||||
upstream as long as it doesn't send input with downstream members, and
|
||||
properly ignores any downstream members in the output it receives.
|
||||
|
||||
Advice on downstream modifications:
|
||||
|
||||
1. Introducing new commands is okay. If you want to extend an existing
|
||||
command, consider introducing a new one with the new behaviour
|
||||
instead.
|
||||
|
||||
2. Introducing new asynchronous messages is okay. If you want to extend
|
||||
an existing message, consider adding a new one instead.
|
||||
|
||||
3. Introducing new errors for use in new commands is okay. Adding new
|
||||
errors to existing commands counts as extension, so 1. applies.
|
||||
|
||||
4. New capabilities are strongly discouraged. Capabilities are for
|
||||
evolving the basic protocol, and multiple diverging basic protocol
|
||||
dialects are most undesirable.
|
||||
5.1 The Server should be always started in pause mode, thus the Client is
|
||||
able to perform any setup procedure without the risk of race conditions
|
||||
and related problems
|
||||
|
||||
@@ -63,14 +63,10 @@ class QEMUMonitorProtocol:
|
||||
|
||||
def __json_read(self):
|
||||
try:
|
||||
while True:
|
||||
line = json.loads(self.sockfile.readline())
|
||||
if not 'event' in line:
|
||||
return line
|
||||
return json.loads(self.sock.recv(1024))
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
self.sockfile = self.sock.makefile()
|
||||
|
||||
@@ -24,9 +24,8 @@ def main():
|
||||
|
||||
qemu = qmp.QEMUMonitorProtocol(argv[1])
|
||||
qemu.connect()
|
||||
qemu.send("qmp_capabilities")
|
||||
|
||||
for cmd in [ 'version', 'kvm', 'status', 'uuid', 'balloon' ]:
|
||||
for cmd in [ 'version', 'hpet', 'kvm', 'status', 'uuid', 'balloon' ]:
|
||||
print cmd + ': ' + str(qemu.send('query-' + cmd))
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
642
arch_init.c
642
arch_init.c
@@ -1,642 +0,0 @@
|
||||
/*
|
||||
* QEMU System Emulator
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include "config.h"
|
||||
#include "monitor.h"
|
||||
#include "sysemu.h"
|
||||
#include "arch_init.h"
|
||||
#include "audio/audio.h"
|
||||
#include "hw/pc.h"
|
||||
#include "hw/pci.h"
|
||||
#include "hw/audiodev.h"
|
||||
#include "kvm.h"
|
||||
#include "migration.h"
|
||||
#include "net.h"
|
||||
#include "gdbstub.h"
|
||||
#include "hw/smbios.h"
|
||||
|
||||
#ifdef TARGET_SPARC
|
||||
int graphic_width = 1024;
|
||||
int graphic_height = 768;
|
||||
int graphic_depth = 8;
|
||||
#else
|
||||
int graphic_width = 800;
|
||||
int graphic_height = 600;
|
||||
int graphic_depth = 15;
|
||||
#endif
|
||||
|
||||
const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf";
|
||||
|
||||
#if defined(TARGET_ALPHA)
|
||||
#define QEMU_ARCH QEMU_ARCH_ALPHA
|
||||
#elif defined(TARGET_ARM)
|
||||
#define QEMU_ARCH QEMU_ARCH_ARM
|
||||
#elif defined(TARGET_CRIS)
|
||||
#define QEMU_ARCH QEMU_ARCH_CRIS
|
||||
#elif defined(TARGET_I386)
|
||||
#define QEMU_ARCH QEMU_ARCH_I386
|
||||
#elif defined(TARGET_M68K)
|
||||
#define QEMU_ARCH QEMU_ARCH_M68K
|
||||
#elif defined(TARGET_MICROBLAZE)
|
||||
#define QEMU_ARCH QEMU_ARCH_MICROBLAZE
|
||||
#elif defined(TARGET_MIPS)
|
||||
#define QEMU_ARCH QEMU_ARCH_MIPS
|
||||
#elif defined(TARGET_PPC)
|
||||
#define QEMU_ARCH QEMU_ARCH_PPC
|
||||
#elif defined(TARGET_S390X)
|
||||
#define QEMU_ARCH QEMU_ARCH_S390X
|
||||
#elif defined(TARGET_SH4)
|
||||
#define QEMU_ARCH QEMU_ARCH_SH4
|
||||
#elif defined(TARGET_SPARC)
|
||||
#define QEMU_ARCH QEMU_ARCH_SPARC
|
||||
#endif
|
||||
|
||||
const uint32_t arch_type = QEMU_ARCH;
|
||||
|
||||
/***********************************************************/
|
||||
/* ram save/restore */
|
||||
|
||||
#define RAM_SAVE_FLAG_FULL 0x01 /* Obsolete, not used anymore */
|
||||
#define RAM_SAVE_FLAG_COMPRESS 0x02
|
||||
#define RAM_SAVE_FLAG_MEM_SIZE 0x04
|
||||
#define RAM_SAVE_FLAG_PAGE 0x08
|
||||
#define RAM_SAVE_FLAG_EOS 0x10
|
||||
#define RAM_SAVE_FLAG_CONTINUE 0x20
|
||||
|
||||
static int is_dup_page(uint8_t *page, uint8_t ch)
|
||||
{
|
||||
uint32_t val = ch << 24 | ch << 16 | ch << 8 | ch;
|
||||
uint32_t *array = (uint32_t *)page;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (TARGET_PAGE_SIZE / 4); i++) {
|
||||
if (array[i] != val) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ram_save_block(QEMUFile *f)
|
||||
{
|
||||
static RAMBlock *last_block = NULL;
|
||||
static ram_addr_t last_offset = 0;
|
||||
RAMBlock *block = last_block;
|
||||
ram_addr_t offset = last_offset;
|
||||
ram_addr_t current_addr;
|
||||
int bytes_sent = 0;
|
||||
|
||||
if (!block)
|
||||
block = QLIST_FIRST(&ram_list.blocks);
|
||||
|
||||
current_addr = block->offset + offset;
|
||||
|
||||
do {
|
||||
if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) {
|
||||
uint8_t *p;
|
||||
int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
|
||||
|
||||
cpu_physical_memory_reset_dirty(current_addr,
|
||||
current_addr + TARGET_PAGE_SIZE,
|
||||
MIGRATION_DIRTY_FLAG);
|
||||
|
||||
p = block->host + offset;
|
||||
|
||||
if (is_dup_page(p, *p)) {
|
||||
qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_COMPRESS);
|
||||
if (!cont) {
|
||||
qemu_put_byte(f, strlen(block->idstr));
|
||||
qemu_put_buffer(f, (uint8_t *)block->idstr,
|
||||
strlen(block->idstr));
|
||||
}
|
||||
qemu_put_byte(f, *p);
|
||||
bytes_sent = 1;
|
||||
} else {
|
||||
qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_PAGE);
|
||||
if (!cont) {
|
||||
qemu_put_byte(f, strlen(block->idstr));
|
||||
qemu_put_buffer(f, (uint8_t *)block->idstr,
|
||||
strlen(block->idstr));
|
||||
}
|
||||
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
|
||||
bytes_sent = TARGET_PAGE_SIZE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
offset += TARGET_PAGE_SIZE;
|
||||
if (offset >= block->length) {
|
||||
offset = 0;
|
||||
block = QLIST_NEXT(block, next);
|
||||
if (!block)
|
||||
block = QLIST_FIRST(&ram_list.blocks);
|
||||
}
|
||||
|
||||
current_addr = block->offset + offset;
|
||||
|
||||
} while (current_addr != last_block->offset + last_offset);
|
||||
|
||||
last_block = block;
|
||||
last_offset = offset;
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
static uint64_t bytes_transferred;
|
||||
|
||||
static ram_addr_t ram_save_remaining(void)
|
||||
{
|
||||
RAMBlock *block;
|
||||
ram_addr_t count = 0;
|
||||
|
||||
QLIST_FOREACH(block, &ram_list.blocks, next) {
|
||||
ram_addr_t addr;
|
||||
for (addr = block->offset; addr < block->offset + block->length;
|
||||
addr += TARGET_PAGE_SIZE) {
|
||||
if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint64_t ram_bytes_remaining(void)
|
||||
{
|
||||
return ram_save_remaining() * TARGET_PAGE_SIZE;
|
||||
}
|
||||
|
||||
uint64_t ram_bytes_transferred(void)
|
||||
{
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
uint64_t ram_bytes_total(void)
|
||||
{
|
||||
RAMBlock *block;
|
||||
uint64_t total = 0;
|
||||
|
||||
QLIST_FOREACH(block, &ram_list.blocks, next)
|
||||
total += block->length;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
|
||||
{
|
||||
ram_addr_t addr;
|
||||
uint64_t bytes_transferred_last;
|
||||
double bwidth = 0;
|
||||
uint64_t expected_time = 0;
|
||||
|
||||
if (stage < 0) {
|
||||
cpu_physical_memory_set_dirty_tracking(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) {
|
||||
qemu_file_set_error(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stage == 1) {
|
||||
RAMBlock *block;
|
||||
bytes_transferred = 0;
|
||||
|
||||
/* Make sure all dirty bits are set */
|
||||
QLIST_FOREACH(block, &ram_list.blocks, next) {
|
||||
for (addr = block->offset; addr < block->offset + block->length;
|
||||
addr += TARGET_PAGE_SIZE) {
|
||||
if (!cpu_physical_memory_get_dirty(addr,
|
||||
MIGRATION_DIRTY_FLAG)) {
|
||||
cpu_physical_memory_set_dirty(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable dirty memory tracking */
|
||||
cpu_physical_memory_set_dirty_tracking(1);
|
||||
|
||||
qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
|
||||
|
||||
QLIST_FOREACH(block, &ram_list.blocks, next) {
|
||||
qemu_put_byte(f, strlen(block->idstr));
|
||||
qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr));
|
||||
qemu_put_be64(f, block->length);
|
||||
}
|
||||
}
|
||||
|
||||
bytes_transferred_last = bytes_transferred;
|
||||
bwidth = qemu_get_clock_ns(rt_clock);
|
||||
|
||||
while (!qemu_file_rate_limit(f)) {
|
||||
int bytes_sent;
|
||||
|
||||
bytes_sent = ram_save_block(f);
|
||||
bytes_transferred += bytes_sent;
|
||||
if (bytes_sent == 0) { /* no more blocks */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bwidth = qemu_get_clock_ns(rt_clock) - bwidth;
|
||||
bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;
|
||||
|
||||
/* if we haven't transferred anything this round, force expected_time to a
|
||||
* a very high value, but without crashing */
|
||||
if (bwidth == 0) {
|
||||
bwidth = 0.000001;
|
||||
}
|
||||
|
||||
/* try transferring iterative blocks of memory */
|
||||
if (stage == 3) {
|
||||
int bytes_sent;
|
||||
|
||||
/* flush all remaining blocks regardless of rate limiting */
|
||||
while ((bytes_sent = ram_save_block(f)) != 0) {
|
||||
bytes_transferred += bytes_sent;
|
||||
}
|
||||
cpu_physical_memory_set_dirty_tracking(0);
|
||||
}
|
||||
|
||||
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
|
||||
|
||||
expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
|
||||
|
||||
return (stage == 2) && (expected_time <= migrate_max_downtime());
|
||||
}
|
||||
|
||||
static inline void *host_from_stream_offset(QEMUFile *f,
|
||||
ram_addr_t offset,
|
||||
int flags)
|
||||
{
|
||||
static RAMBlock *block = NULL;
|
||||
char id[256];
|
||||
uint8_t len;
|
||||
|
||||
if (flags & RAM_SAVE_FLAG_CONTINUE) {
|
||||
if (!block) {
|
||||
fprintf(stderr, "Ack, bad migration stream!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return block->host + offset;
|
||||
}
|
||||
|
||||
len = qemu_get_byte(f);
|
||||
qemu_get_buffer(f, (uint8_t *)id, len);
|
||||
id[len] = 0;
|
||||
|
||||
QLIST_FOREACH(block, &ram_list.blocks, next) {
|
||||
if (!strncmp(id, block->idstr, sizeof(id)))
|
||||
return block->host + offset;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Can't find block %s!\n", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
ram_addr_t addr;
|
||||
int flags;
|
||||
|
||||
if (version_id < 3 || version_id > 4) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
do {
|
||||
addr = qemu_get_be64(f);
|
||||
|
||||
flags = addr & ~TARGET_PAGE_MASK;
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
|
||||
if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
|
||||
if (version_id == 3) {
|
||||
if (addr != ram_bytes_total()) {
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
/* Synchronize RAM block list */
|
||||
char id[256];
|
||||
ram_addr_t length;
|
||||
ram_addr_t total_ram_bytes = addr;
|
||||
|
||||
while (total_ram_bytes) {
|
||||
RAMBlock *block;
|
||||
uint8_t len;
|
||||
|
||||
len = qemu_get_byte(f);
|
||||
qemu_get_buffer(f, (uint8_t *)id, len);
|
||||
id[len] = 0;
|
||||
length = qemu_get_be64(f);
|
||||
|
||||
QLIST_FOREACH(block, &ram_list.blocks, next) {
|
||||
if (!strncmp(id, block->idstr, sizeof(id))) {
|
||||
if (block->length != length)
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!block) {
|
||||
fprintf(stderr, "Unknown ramblock \"%s\", cannot "
|
||||
"accept migration\n", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
total_ram_bytes -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & RAM_SAVE_FLAG_COMPRESS) {
|
||||
void *host;
|
||||
uint8_t ch;
|
||||
|
||||
if (version_id == 3)
|
||||
host = qemu_get_ram_ptr(addr);
|
||||
else
|
||||
host = host_from_stream_offset(f, addr, flags);
|
||||
|
||||
ch = qemu_get_byte(f);
|
||||
memset(host, ch, TARGET_PAGE_SIZE);
|
||||
#ifndef _WIN32
|
||||
if (ch == 0 &&
|
||||
(!kvm_enabled() || kvm_has_sync_mmu())) {
|
||||
madvise(host, TARGET_PAGE_SIZE, MADV_DONTNEED);
|
||||
}
|
||||
#endif
|
||||
} else if (flags & RAM_SAVE_FLAG_PAGE) {
|
||||
void *host;
|
||||
|
||||
if (version_id == 3)
|
||||
host = qemu_get_ram_ptr(addr);
|
||||
else
|
||||
host = host_from_stream_offset(f, addr, flags);
|
||||
|
||||
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
|
||||
}
|
||||
if (qemu_file_has_error(f)) {
|
||||
return -EIO;
|
||||
}
|
||||
} while (!(flags & RAM_SAVE_FLAG_EOS));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qemu_service_io(void)
|
||||
{
|
||||
qemu_notify_event();
|
||||
}
|
||||
|
||||
#ifdef HAS_AUDIO
|
||||
struct soundhw soundhw[] = {
|
||||
#ifdef HAS_AUDIO_CHOICE
|
||||
#if defined(TARGET_I386) || defined(TARGET_MIPS)
|
||||
{
|
||||
"pcspk",
|
||||
"PC speaker",
|
||||
0,
|
||||
1,
|
||||
{ .init_isa = pcspk_audio_init }
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SB16
|
||||
{
|
||||
"sb16",
|
||||
"Creative Sound Blaster 16",
|
||||
0,
|
||||
1,
|
||||
{ .init_isa = SB16_init }
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CS4231A
|
||||
{
|
||||
"cs4231a",
|
||||
"CS4231A",
|
||||
0,
|
||||
1,
|
||||
{ .init_isa = cs4231a_init }
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ADLIB
|
||||
{
|
||||
"adlib",
|
||||
#ifdef HAS_YMF262
|
||||
"Yamaha YMF262 (OPL3)",
|
||||
#else
|
||||
"Yamaha YM3812 (OPL2)",
|
||||
#endif
|
||||
0,
|
||||
1,
|
||||
{ .init_isa = Adlib_init }
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GUS
|
||||
{
|
||||
"gus",
|
||||
"Gravis Ultrasound GF1",
|
||||
0,
|
||||
1,
|
||||
{ .init_isa = GUS_init }
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AC97
|
||||
{
|
||||
"ac97",
|
||||
"Intel 82801AA AC97 Audio",
|
||||
0,
|
||||
0,
|
||||
{ .init_pci = ac97_init }
|
||||
},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ES1370
|
||||
{
|
||||
"es1370",
|
||||
"ENSONIQ AudioPCI ES1370",
|
||||
0,
|
||||
0,
|
||||
{ .init_pci = es1370_init }
|
||||
},
|
||||
#endif
|
||||
|
||||
#endif /* HAS_AUDIO_CHOICE */
|
||||
|
||||
{ NULL, NULL, 0, 0, { NULL } }
|
||||
};
|
||||
|
||||
void select_soundhw(const char *optarg)
|
||||
{
|
||||
struct soundhw *c;
|
||||
|
||||
if (*optarg == '?') {
|
||||
show_valid_cards:
|
||||
|
||||
printf("Valid sound card names (comma separated):\n");
|
||||
for (c = soundhw; c->name; ++c) {
|
||||
printf ("%-11s %s\n", c->name, c->descr);
|
||||
}
|
||||
printf("\n-soundhw all will enable all of the above\n");
|
||||
exit(*optarg != '?');
|
||||
}
|
||||
else {
|
||||
size_t l;
|
||||
const char *p;
|
||||
char *e;
|
||||
int bad_card = 0;
|
||||
|
||||
if (!strcmp(optarg, "all")) {
|
||||
for (c = soundhw; c->name; ++c) {
|
||||
c->enabled = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
p = optarg;
|
||||
while (*p) {
|
||||
e = strchr(p, ',');
|
||||
l = !e ? strlen(p) : (size_t) (e - p);
|
||||
|
||||
for (c = soundhw; c->name; ++c) {
|
||||
if (!strncmp(c->name, p, l) && !c->name[l]) {
|
||||
c->enabled = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!c->name) {
|
||||
if (l > 80) {
|
||||
fprintf(stderr,
|
||||
"Unknown sound card name (too big to show)\n");
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Unknown sound card name `%.*s'\n",
|
||||
(int) l, p);
|
||||
}
|
||||
bad_card = 1;
|
||||
}
|
||||
p += l + (e != NULL);
|
||||
}
|
||||
|
||||
if (bad_card) {
|
||||
goto show_valid_cards;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void select_soundhw(const char *optarg)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
int qemu_uuid_parse(const char *str, uint8_t *uuid)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (strlen(str) != 36) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3],
|
||||
&uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9],
|
||||
&uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14],
|
||||
&uuid[15]);
|
||||
|
||||
if (ret != 16) {
|
||||
return -1;
|
||||
}
|
||||
#ifdef TARGET_I386
|
||||
smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 16, uuid);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void do_acpitable_option(const char *optarg)
|
||||
{
|
||||
#ifdef TARGET_I386
|
||||
if (acpi_table_add(optarg) < 0) {
|
||||
fprintf(stderr, "Wrong acpi table provided\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void do_smbios_option(const char *optarg)
|
||||
{
|
||||
#ifdef TARGET_I386
|
||||
if (smbios_entry_add(optarg) < 0) {
|
||||
fprintf(stderr, "Wrong smbios provided\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void cpudef_init(void)
|
||||
{
|
||||
#if defined(cpudef_setup)
|
||||
cpudef_setup(); /* parse cpu definitions in target config file */
|
||||
#endif
|
||||
}
|
||||
|
||||
int audio_available(void)
|
||||
{
|
||||
#ifdef HAS_AUDIO
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int kvm_available(void)
|
||||
{
|
||||
#ifdef CONFIG_KVM
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int xen_available(void)
|
||||
{
|
||||
#ifdef CONFIG_XEN
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
33
arch_init.h
33
arch_init.h
@@ -1,33 +0,0 @@
|
||||
#ifndef QEMU_ARCH_INIT_H
|
||||
#define QEMU_ARCH_INIT_H
|
||||
|
||||
extern const char arch_config_name[];
|
||||
|
||||
enum {
|
||||
QEMU_ARCH_ALL = -1,
|
||||
QEMU_ARCH_ALPHA = 1,
|
||||
QEMU_ARCH_ARM = 2,
|
||||
QEMU_ARCH_CRIS = 4,
|
||||
QEMU_ARCH_I386 = 8,
|
||||
QEMU_ARCH_M68K = 16,
|
||||
QEMU_ARCH_MICROBLAZE = 32,
|
||||
QEMU_ARCH_MIPS = 64,
|
||||
QEMU_ARCH_PPC = 128,
|
||||
QEMU_ARCH_S390X = 256,
|
||||
QEMU_ARCH_SH4 = 512,
|
||||
QEMU_ARCH_SPARC = 1024,
|
||||
};
|
||||
|
||||
extern const uint32_t arch_type;
|
||||
|
||||
void select_soundhw(const char *optarg);
|
||||
int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque);
|
||||
int ram_load(QEMUFile *f, void *opaque, int version_id);
|
||||
void do_acpitable_option(const char *optarg);
|
||||
void do_smbios_option(const char *optarg);
|
||||
void cpudef_init(void);
|
||||
int audio_available(void);
|
||||
int kvm_available(void);
|
||||
int xen_available(void);
|
||||
|
||||
#endif
|
||||
17
arm-dis.c
17
arm-dis.c
@@ -60,8 +60,10 @@
|
||||
#define FPU_VFP_EXT_V3 0
|
||||
#define FPU_NEON_EXT_V1 0
|
||||
|
||||
int floatformat_ieee_single_little;
|
||||
/* Assume host uses ieee float. */
|
||||
static void floatformat_to_double (unsigned char *data, double *dest)
|
||||
static void floatformat_to_double (int *ignored, unsigned char *data,
|
||||
double *dest)
|
||||
{
|
||||
union {
|
||||
uint32_t i;
|
||||
@@ -2515,6 +2517,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
|
||||
{
|
||||
func (stream, "<illegal constant %.8x:%x:%x>",
|
||||
bits, cmode, op);
|
||||
size = 32;
|
||||
break;
|
||||
}
|
||||
switch (size)
|
||||
@@ -2540,7 +2543,9 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
|
||||
valbytes[2] = (value >> 16) & 0xff;
|
||||
valbytes[3] = (value >> 24) & 0xff;
|
||||
|
||||
floatformat_to_double (valbytes, &fvalue);
|
||||
floatformat_to_double
|
||||
(&floatformat_ieee_single_little, valbytes,
|
||||
&fvalue);
|
||||
|
||||
func (stream, "#%.7g\t; 0x%.8lx", fvalue,
|
||||
value);
|
||||
@@ -3148,14 +3153,14 @@ print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given)
|
||||
if (started)
|
||||
func (stream, ", ");
|
||||
started = 1;
|
||||
func (stream, "%s", arm_regnames[14] /* "lr" */);
|
||||
func (stream, arm_regnames[14] /* "lr" */);
|
||||
}
|
||||
|
||||
if (domaskpc)
|
||||
{
|
||||
if (started)
|
||||
func (stream, ", ");
|
||||
func (stream, "%s", arm_regnames[15] /* "pc" */);
|
||||
func (stream, arm_regnames[15] /* "pc" */);
|
||||
}
|
||||
|
||||
func (stream, "}");
|
||||
@@ -3698,7 +3703,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
|
||||
}
|
||||
else
|
||||
{
|
||||
func (stream, "%s", psr_name (given & 0xff));
|
||||
func (stream, psr_name (given & 0xff));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3706,7 +3711,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
|
||||
if ((given & 0xff) == 0)
|
||||
func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C');
|
||||
else
|
||||
func (stream, "%s", psr_name (given & 0xff));
|
||||
func (stream, psr_name (given & 0xff));
|
||||
break;
|
||||
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
|
||||
@@ -459,7 +459,6 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
return 0;
|
||||
}
|
||||
case SYS_EXIT:
|
||||
gdb_exit(env, 0);
|
||||
exit(0);
|
||||
default:
|
||||
fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
|
||||
|
||||
@@ -411,11 +411,10 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
|
||||
}
|
||||
|
||||
static void alsa_dump_info (struct alsa_params_req *req,
|
||||
struct alsa_params_obt *obt,
|
||||
snd_pcm_format_t obtfmt)
|
||||
struct alsa_params_obt *obt)
|
||||
{
|
||||
dolog ("parameter | requested value | obtained value\n");
|
||||
dolog ("format | %10d | %10d\n", req->fmt, obtfmt);
|
||||
dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
|
||||
dolog ("channels | %10d | %10d\n",
|
||||
req->nchannels, obt->nchannels);
|
||||
dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
|
||||
@@ -667,15 +666,15 @@ static int alsa_open (int in, struct alsa_params_req *req,
|
||||
*handlep = handle;
|
||||
|
||||
if (conf.verbose &&
|
||||
(obtfmt != req->fmt ||
|
||||
(obt->fmt != req->fmt ||
|
||||
obt->nchannels != req->nchannels ||
|
||||
obt->freq != req->freq)) {
|
||||
dolog ("Audio parameters for %s\n", typ);
|
||||
alsa_dump_info (req, obt, obtfmt);
|
||||
alsa_dump_info (req, obt);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
alsa_dump_info (req, obt, obtfmt);
|
||||
alsa_dump_info (req, obt);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -115,9 +115,6 @@ struct mixeng_volume nominal_volume = {
|
||||
#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
|
||||
#error No its not
|
||||
#else
|
||||
static void audio_print_options (const char *prefix,
|
||||
struct audio_option *opt);
|
||||
|
||||
int audio_bug (const char *funcname, int cond)
|
||||
{
|
||||
if (cond) {
|
||||
@@ -125,16 +122,10 @@ int audio_bug (const char *funcname, int cond)
|
||||
|
||||
AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
|
||||
if (!shown) {
|
||||
struct audio_driver *d;
|
||||
|
||||
shown = 1;
|
||||
AUD_log (NULL, "Save all your work and restart without audio\n");
|
||||
AUD_log (NULL, "Please send bug report to av1474@comtv.ru\n");
|
||||
AUD_log (NULL, "I am sorry\n");
|
||||
d = glob_audio_state.drv;
|
||||
if (d) {
|
||||
audio_print_options (d->name, d->options);
|
||||
}
|
||||
}
|
||||
AUD_log (NULL, "Context:\n");
|
||||
|
||||
@@ -330,10 +321,10 @@ void AUD_vlog (const char *cap, const char *fmt, va_list ap)
|
||||
{
|
||||
if (conf.log_to_monitor) {
|
||||
if (cap) {
|
||||
monitor_printf(default_mon, "%s: ", cap);
|
||||
monitor_printf(cur_mon, "%s: ", cap);
|
||||
}
|
||||
|
||||
monitor_vprintf(default_mon, fmt, ap);
|
||||
monitor_vprintf(cur_mon, fmt, ap);
|
||||
}
|
||||
else {
|
||||
if (cap) {
|
||||
@@ -1901,7 +1892,7 @@ static void audio_init (void)
|
||||
}
|
||||
|
||||
QLIST_INIT (&s->card_head);
|
||||
vmstate_register (NULL, 0, &vmstate_audio, s);
|
||||
vmstate_register (0, &vmstate_audio, s);
|
||||
}
|
||||
|
||||
void AUD_register_card (const char *name, QEMUSoundCard *card)
|
||||
|
||||
@@ -541,7 +541,7 @@ uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
|
||||
|
||||
cur_ts = sw->hw->ts_helper;
|
||||
old_ts = ts->old_ts;
|
||||
/* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */
|
||||
/* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
|
||||
|
||||
if (cur_ts >= old_ts) {
|
||||
delta = cur_ts - old_ts;
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
#undef IN_T
|
||||
#undef SHIFT
|
||||
|
||||
/* Unsigned 32 bit */
|
||||
/* Unsigned 16 bit */
|
||||
#define IN_T uint32_t
|
||||
#define IN_MIN 0
|
||||
#define IN_MAX UINT32_MAX
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
typedef struct SDLVoiceOut {
|
||||
HWVoiceOut hw;
|
||||
int live;
|
||||
int rpos;
|
||||
int decr;
|
||||
int pending;
|
||||
} SDLVoiceOut;
|
||||
|
||||
static struct {
|
||||
@@ -115,19 +115,23 @@ static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
|
||||
return sdl_post (s, forfn);
|
||||
}
|
||||
|
||||
static int aud_to_sdlfmt (audfmt_e fmt)
|
||||
static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
|
||||
{
|
||||
switch (fmt) {
|
||||
case AUD_FMT_S8:
|
||||
*shift = 0;
|
||||
return AUDIO_S8;
|
||||
|
||||
case AUD_FMT_U8:
|
||||
*shift = 0;
|
||||
return AUDIO_U8;
|
||||
|
||||
case AUD_FMT_S16:
|
||||
*shift = 1;
|
||||
return AUDIO_S16LSB;
|
||||
|
||||
case AUD_FMT_U16:
|
||||
*shift = 1;
|
||||
return AUDIO_U16LSB;
|
||||
|
||||
default:
|
||||
@@ -221,6 +225,10 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||
HWVoiceOut *hw = &sdl->hw;
|
||||
int samples = len >> hw->info.shift;
|
||||
|
||||
if (sdl_lock (s, "sdl_callback")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->exit) {
|
||||
return;
|
||||
}
|
||||
@@ -228,49 +236,34 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||
while (samples) {
|
||||
int to_mix, decr;
|
||||
|
||||
/* dolog ("in callback samples=%d\n", samples); */
|
||||
sdl_wait (s, "sdl_callback");
|
||||
if (s->exit) {
|
||||
return;
|
||||
while (!sdl->pending) {
|
||||
if (sdl_unlock (s, "sdl_callback")) {
|
||||
return;
|
||||
}
|
||||
|
||||
sdl_wait (s, "sdl_callback");
|
||||
if (s->exit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sdl_lock (s, "sdl_callback")) {
|
||||
return;
|
||||
}
|
||||
sdl->pending += sdl->live;
|
||||
sdl->live = 0;
|
||||
}
|
||||
|
||||
if (sdl_lock (s, "sdl_callback")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
|
||||
dolog ("sdl->live=%d hw->samples=%d\n",
|
||||
sdl->live, hw->samples);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sdl->live) {
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* dolog ("in callback live=%d\n", live); */
|
||||
to_mix = audio_MIN (samples, sdl->live);
|
||||
decr = to_mix;
|
||||
while (to_mix) {
|
||||
int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
|
||||
struct st_sample *src = hw->mix_buf + hw->rpos;
|
||||
|
||||
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
|
||||
hw->clip (buf, src, chunk);
|
||||
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
|
||||
to_mix -= chunk;
|
||||
buf += chunk << hw->info.shift;
|
||||
}
|
||||
to_mix = audio_MIN (samples, sdl->pending);
|
||||
decr = audio_pcm_hw_clip_out (hw, buf, to_mix, 0);
|
||||
buf += decr << hw->info.shift;
|
||||
samples -= decr;
|
||||
sdl->live -= decr;
|
||||
sdl->decr += decr;
|
||||
|
||||
again:
|
||||
if (sdl_unlock (s, "sdl_callback")) {
|
||||
return;
|
||||
}
|
||||
sdl->pending -= decr;
|
||||
}
|
||||
|
||||
if (sdl_unlock (s, "sdl_callback")) {
|
||||
return;
|
||||
}
|
||||
/* dolog ("done len=%d\n", len); */
|
||||
}
|
||||
|
||||
static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
|
||||
@@ -288,18 +281,9 @@ static int sdl_run_out (HWVoiceOut *hw, int live)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sdl->decr > live) {
|
||||
ldebug ("sdl->decr %d live %d sdl->live %d\n",
|
||||
sdl->decr,
|
||||
live,
|
||||
sdl->live);
|
||||
}
|
||||
|
||||
decr = audio_MIN (sdl->decr, live);
|
||||
sdl->decr -= decr;
|
||||
|
||||
sdl->live = live - decr;
|
||||
hw->rpos = sdl->rpos;
|
||||
sdl->live = live;
|
||||
decr = sdl->decr;
|
||||
sdl->decr = 0;
|
||||
|
||||
if (sdl->live > 0) {
|
||||
sdl_unlock_and_post (s, "sdl_run_out");
|
||||
@@ -322,13 +306,16 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
|
||||
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
|
||||
SDLAudioState *s = &glob_sdl;
|
||||
SDL_AudioSpec req, obt;
|
||||
int shift;
|
||||
int endianess;
|
||||
int err;
|
||||
audfmt_e effective_fmt;
|
||||
struct audsettings obt_as;
|
||||
|
||||
shift <<= as->nchannels == 2;
|
||||
|
||||
req.freq = as->freq;
|
||||
req.format = aud_to_sdlfmt (as->fmt);
|
||||
req.format = aud_to_sdlfmt (as->fmt, &shift);
|
||||
req.channels = as->nchannels;
|
||||
req.samples = conf.nb_samples;
|
||||
req.callback = sdl_callback;
|
||||
|
||||
146
balloon.c
146
balloon.c
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* QEMU System Emulator
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "sysemu.h"
|
||||
#include "monitor.h"
|
||||
#include "qjson.h"
|
||||
#include "qint.h"
|
||||
#include "cpu-common.h"
|
||||
#include "kvm.h"
|
||||
#include "balloon.h"
|
||||
|
||||
|
||||
static QEMUBalloonEvent *qemu_balloon_event;
|
||||
void *qemu_balloon_event_opaque;
|
||||
|
||||
void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
|
||||
{
|
||||
qemu_balloon_event = func;
|
||||
qemu_balloon_event_opaque = opaque;
|
||||
}
|
||||
|
||||
int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
|
||||
{
|
||||
if (qemu_balloon_event) {
|
||||
qemu_balloon_event(qemu_balloon_event_opaque, target, cb, opaque);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int qemu_balloon_status(MonitorCompletion cb, void *opaque)
|
||||
{
|
||||
if (qemu_balloon_event) {
|
||||
qemu_balloon_event(qemu_balloon_event_opaque, 0, cb, opaque);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
|
||||
{
|
||||
Monitor *mon = opaque;
|
||||
|
||||
if (strcmp(key, "actual"))
|
||||
monitor_printf(mon, ",%s=%" PRId64, key,
|
||||
qint_get_int(qobject_to_qint(obj)));
|
||||
}
|
||||
|
||||
void monitor_print_balloon(Monitor *mon, const QObject *data)
|
||||
{
|
||||
QDict *qdict;
|
||||
|
||||
qdict = qobject_to_qdict(data);
|
||||
if (!qdict_haskey(qdict, "actual"))
|
||||
return;
|
||||
|
||||
monitor_printf(mon, "balloon: actual=%" PRId64,
|
||||
qdict_get_int(qdict, "actual") >> 20);
|
||||
qdict_iter(qdict, print_balloon_stat, mon);
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* do_info_balloon(): Balloon information
|
||||
*
|
||||
* Make an asynchronous request for balloon info. When the request completes
|
||||
* a QDict will be returned according to the following specification:
|
||||
*
|
||||
* - "actual": current balloon value in bytes
|
||||
* The following fields may or may not be present:
|
||||
* - "mem_swapped_in": Amount of memory swapped in (bytes)
|
||||
* - "mem_swapped_out": Amount of memory swapped out (bytes)
|
||||
* - "major_page_faults": Number of major faults
|
||||
* - "minor_page_faults": Number of minor faults
|
||||
* - "free_mem": Total amount of free and unused memory (bytes)
|
||||
* - "total_mem": Total amount of available memory (bytes)
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0,
|
||||
* "major_page_faults": 142, "minor_page_faults": 239245,
|
||||
* "free_mem": 1014185984, "total_mem": 1044668416 }
|
||||
*/
|
||||
int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (kvm_enabled() && !kvm_has_sync_mmu()) {
|
||||
qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = qemu_balloon_status(cb, opaque);
|
||||
if (!ret) {
|
||||
qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_balloon(): Request VM to change its memory allocation
|
||||
*/
|
||||
int do_balloon(Monitor *mon, const QDict *params,
|
||||
MonitorCompletion cb, void *opaque)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (kvm_enabled() && !kvm_has_sync_mmu()) {
|
||||
qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque);
|
||||
if (ret == 0) {
|
||||
qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cb(opaque, NULL);
|
||||
return 0;
|
||||
}
|
||||
14
balloon.h
14
balloon.h
@@ -14,20 +14,14 @@
|
||||
#ifndef _QEMU_BALLOON_H
|
||||
#define _QEMU_BALLOON_H
|
||||
|
||||
#include "monitor.h"
|
||||
#include "cpu-defs.h"
|
||||
|
||||
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target,
|
||||
MonitorCompletion cb, void *cb_data);
|
||||
typedef ram_addr_t (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
|
||||
|
||||
void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
|
||||
|
||||
int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque);
|
||||
void qemu_balloon(ram_addr_t target);
|
||||
|
||||
int qemu_balloon_status(MonitorCompletion cb, void *opaque);
|
||||
|
||||
void monitor_print_balloon(Monitor *mon, const QObject *data);
|
||||
int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
|
||||
int do_balloon(Monitor *mon, const QDict *params,
|
||||
MonitorCompletion cb, void *opaque);
|
||||
ram_addr_t qemu_balloon_status(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
#include "block_int.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "monitor.h"
|
||||
#include "block-migration.h"
|
||||
#include "migration.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS)
|
||||
@@ -28,14 +26,17 @@
|
||||
#define BLK_MIG_FLAG_PROGRESS 0x04
|
||||
|
||||
#define MAX_IS_ALLOCATED_SEARCH 65536
|
||||
#define MAX_BLOCKS_READ 10000
|
||||
#define BLOCKS_READ_CHANGE 100
|
||||
#define INITIAL_BLOCKS_READ 100
|
||||
|
||||
//#define DEBUG_BLK_MIGRATION
|
||||
|
||||
#ifdef DEBUG_BLK_MIGRATION
|
||||
#define DPRINTF(fmt, ...) \
|
||||
#define dprintf(fmt, ...) \
|
||||
do { printf("blk_migration: " fmt, ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) \
|
||||
#define dprintf(fmt, ...) \
|
||||
do { } while (0)
|
||||
#endif
|
||||
|
||||
@@ -44,7 +45,6 @@ typedef struct BlkMigDevState {
|
||||
int bulk_completed;
|
||||
int shared_base;
|
||||
int64_t cur_sector;
|
||||
int64_t cur_dirty;
|
||||
int64_t completed_sectors;
|
||||
int64_t total_sectors;
|
||||
int64_t dirty;
|
||||
@@ -59,7 +59,6 @@ typedef struct BlkMigBlock {
|
||||
QEMUIOVector qiov;
|
||||
BlockDriverAIOCB *aiocb;
|
||||
int ret;
|
||||
int64_t time;
|
||||
QSIMPLEQ_ENTRY(BlkMigBlock) entry;
|
||||
} BlkMigBlock;
|
||||
|
||||
@@ -73,9 +72,6 @@ typedef struct BlkMigState {
|
||||
int transferred;
|
||||
int64_t total_sector_sum;
|
||||
int prev_progress;
|
||||
int bulk_completed;
|
||||
long double total_time;
|
||||
int reads;
|
||||
} BlkMigState;
|
||||
|
||||
static BlkMigState block_mig_state;
|
||||
@@ -128,28 +124,12 @@ uint64_t blk_mig_bytes_total(void)
|
||||
return sum << BDRV_SECTOR_BITS;
|
||||
}
|
||||
|
||||
static inline void add_avg_read_time(int64_t time)
|
||||
{
|
||||
block_mig_state.reads++;
|
||||
block_mig_state.total_time += time;
|
||||
}
|
||||
|
||||
static inline long double compute_read_bwidth(void)
|
||||
{
|
||||
assert(block_mig_state.total_time != 0);
|
||||
return (block_mig_state.reads * BLOCK_SIZE)/ block_mig_state.total_time;
|
||||
}
|
||||
|
||||
static void blk_mig_read_cb(void *opaque, int ret)
|
||||
{
|
||||
BlkMigBlock *blk = opaque;
|
||||
|
||||
blk->ret = ret;
|
||||
|
||||
blk->time = qemu_get_clock_ns(rt_clock) - blk->time;
|
||||
|
||||
add_avg_read_time(blk->time);
|
||||
|
||||
QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
|
||||
|
||||
block_mig_state.submitted--;
|
||||
@@ -158,7 +138,7 @@ static void blk_mig_read_cb(void *opaque, int ret)
|
||||
}
|
||||
|
||||
static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
|
||||
BlkMigDevState *bmds)
|
||||
BlkMigDevState *bmds, int is_async)
|
||||
{
|
||||
int64_t total_sectors = bmds->total_sectors;
|
||||
int64_t cur_sector = bmds->cur_sector;
|
||||
@@ -195,18 +175,26 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
|
||||
blk->bmds = bmds;
|
||||
blk->sector = cur_sector;
|
||||
|
||||
blk->iov.iov_base = blk->buf;
|
||||
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
|
||||
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
|
||||
if (is_async) {
|
||||
blk->iov.iov_base = blk->buf;
|
||||
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
|
||||
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
|
||||
|
||||
blk->time = qemu_get_clock_ns(rt_clock);
|
||||
blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
|
||||
nr_sectors, blk_mig_read_cb, blk);
|
||||
if (!blk->aiocb) {
|
||||
goto error;
|
||||
}
|
||||
block_mig_state.submitted++;
|
||||
} else {
|
||||
if (bdrv_read(bs, cur_sector, blk->buf, nr_sectors) < 0) {
|
||||
goto error;
|
||||
}
|
||||
blk_send(f, blk);
|
||||
|
||||
blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
|
||||
nr_sectors, blk_mig_read_cb, blk);
|
||||
if (!blk->aiocb) {
|
||||
goto error;
|
||||
qemu_free(blk->buf);
|
||||
qemu_free(blk);
|
||||
}
|
||||
block_mig_state.submitted++;
|
||||
|
||||
bdrv_reset_dirty(bs, cur_sector, nr_sectors);
|
||||
bmds->cur_sector = cur_sector + nr_sectors;
|
||||
@@ -230,55 +218,49 @@ static void set_dirty_tracking(int enable)
|
||||
}
|
||||
}
|
||||
|
||||
static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
|
||||
{
|
||||
Monitor *mon = opaque;
|
||||
BlkMigDevState *bmds;
|
||||
int64_t sectors;
|
||||
|
||||
if (!bdrv_is_read_only(bs)) {
|
||||
sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
|
||||
if (sectors <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bmds = qemu_mallocz(sizeof(BlkMigDevState));
|
||||
bmds->bs = bs;
|
||||
bmds->bulk_completed = 0;
|
||||
bmds->total_sectors = sectors;
|
||||
bmds->completed_sectors = 0;
|
||||
bmds->shared_base = block_mig_state.shared_base;
|
||||
|
||||
block_mig_state.total_sector_sum += sectors;
|
||||
|
||||
if (bmds->shared_base) {
|
||||
monitor_printf(mon, "Start migration for %s with shared base "
|
||||
"image\n",
|
||||
bs->device_name);
|
||||
} else {
|
||||
monitor_printf(mon, "Start full migration for %s\n",
|
||||
bs->device_name);
|
||||
}
|
||||
|
||||
QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_blk_migration(Monitor *mon, QEMUFile *f)
|
||||
{
|
||||
BlkMigDevState *bmds;
|
||||
BlockDriverState *bs;
|
||||
int64_t sectors;
|
||||
|
||||
block_mig_state.submitted = 0;
|
||||
block_mig_state.read_done = 0;
|
||||
block_mig_state.transferred = 0;
|
||||
block_mig_state.total_sector_sum = 0;
|
||||
block_mig_state.prev_progress = -1;
|
||||
block_mig_state.bulk_completed = 0;
|
||||
block_mig_state.total_time = 0;
|
||||
block_mig_state.reads = 0;
|
||||
|
||||
bdrv_iterate(init_blk_migration_it, mon);
|
||||
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
|
||||
if (bs->type == BDRV_TYPE_HD) {
|
||||
sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
|
||||
if (sectors == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bmds = qemu_mallocz(sizeof(BlkMigDevState));
|
||||
bmds->bs = bs;
|
||||
bmds->bulk_completed = 0;
|
||||
bmds->total_sectors = sectors;
|
||||
bmds->completed_sectors = 0;
|
||||
bmds->shared_base = block_mig_state.shared_base;
|
||||
|
||||
block_mig_state.total_sector_sum += sectors;
|
||||
|
||||
if (bmds->shared_base) {
|
||||
monitor_printf(mon, "Start migration for %s with shared base "
|
||||
"image\n",
|
||||
bs->device_name);
|
||||
} else {
|
||||
monitor_printf(mon, "Start full migration for %s\n",
|
||||
bs->device_name);
|
||||
}
|
||||
|
||||
QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f)
|
||||
static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f, int is_async)
|
||||
{
|
||||
int64_t completed_sector_sum = 0;
|
||||
BlkMigDevState *bmds;
|
||||
@@ -287,7 +269,7 @@ static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f)
|
||||
|
||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||
if (bmds->bulk_completed == 0) {
|
||||
if (mig_save_device_bulk(mon, f, bmds) == 1) {
|
||||
if (mig_save_device_bulk(mon, f, bmds, is_async) == 1) {
|
||||
/* completed bulk section for this device */
|
||||
bmds->bulk_completed = 1;
|
||||
}
|
||||
@@ -311,97 +293,46 @@ static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void blk_mig_reset_dirty_cursor(void)
|
||||
#define MAX_NUM_BLOCKS 4
|
||||
|
||||
static void blk_mig_save_dirty_blocks(Monitor *mon, QEMUFile *f)
|
||||
{
|
||||
BlkMigDevState *bmds;
|
||||
|
||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||
bmds->cur_dirty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
|
||||
BlkMigDevState *bmds, int is_async)
|
||||
{
|
||||
BlkMigBlock *blk;
|
||||
int64_t total_sectors = bmds->total_sectors;
|
||||
BlkMigBlock blk;
|
||||
int64_t sector;
|
||||
int nr_sectors;
|
||||
|
||||
for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
|
||||
if (bdrv_get_dirty(bmds->bs, sector)) {
|
||||
|
||||
if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
|
||||
nr_sectors = total_sectors - sector;
|
||||
} else {
|
||||
nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
|
||||
}
|
||||
blk = qemu_malloc(sizeof(BlkMigBlock));
|
||||
blk->buf = qemu_malloc(BLOCK_SIZE);
|
||||
blk->bmds = bmds;
|
||||
blk->sector = sector;
|
||||
|
||||
if (is_async) {
|
||||
blk->iov.iov_base = blk->buf;
|
||||
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
|
||||
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
|
||||
|
||||
blk->time = qemu_get_clock_ns(rt_clock);
|
||||
|
||||
blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov,
|
||||
nr_sectors, blk_mig_read_cb, blk);
|
||||
if (!blk->aiocb) {
|
||||
goto error;
|
||||
}
|
||||
block_mig_state.submitted++;
|
||||
} else {
|
||||
if (bdrv_read(bmds->bs, sector, blk->buf,
|
||||
nr_sectors) < 0) {
|
||||
goto error;
|
||||
}
|
||||
blk_send(f, blk);
|
||||
|
||||
qemu_free(blk->buf);
|
||||
qemu_free(blk);
|
||||
}
|
||||
|
||||
bdrv_reset_dirty(bmds->bs, sector, nr_sectors);
|
||||
break;
|
||||
}
|
||||
sector += BDRV_SECTORS_PER_DIRTY_CHUNK;
|
||||
bmds->cur_dirty = sector;
|
||||
}
|
||||
|
||||
return (bmds->cur_dirty >= bmds->total_sectors);
|
||||
|
||||
error:
|
||||
monitor_printf(mon, "Error reading sector %" PRId64 "\n", sector);
|
||||
qemu_file_set_error(f);
|
||||
qemu_free(blk->buf);
|
||||
qemu_free(blk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blk_mig_save_dirty_block(Monitor *mon, QEMUFile *f, int is_async)
|
||||
{
|
||||
BlkMigDevState *bmds;
|
||||
int ret = 0;
|
||||
blk.buf = qemu_malloc(BLOCK_SIZE);
|
||||
|
||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||
if (mig_save_device_dirty(mon, f, bmds, is_async) == 0) {
|
||||
ret = 1;
|
||||
break;
|
||||
for (sector = 0; sector < bmds->cur_sector;) {
|
||||
if (bdrv_get_dirty(bmds->bs, sector)) {
|
||||
if (bdrv_read(bmds->bs, sector, blk.buf,
|
||||
BDRV_SECTORS_PER_DIRTY_CHUNK) < 0) {
|
||||
monitor_printf(mon, "Error reading sector %" PRId64 "\n",
|
||||
sector);
|
||||
qemu_file_set_error(f);
|
||||
qemu_free(blk.buf);
|
||||
return;
|
||||
}
|
||||
blk.bmds = bmds;
|
||||
blk.sector = sector;
|
||||
blk_send(f, &blk);
|
||||
|
||||
bdrv_reset_dirty(bmds->bs, sector,
|
||||
BDRV_SECTORS_PER_DIRTY_CHUNK);
|
||||
}
|
||||
sector += BDRV_SECTORS_PER_DIRTY_CHUNK;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
qemu_free(blk.buf);
|
||||
}
|
||||
|
||||
static void flush_blks(QEMUFile* f)
|
||||
{
|
||||
BlkMigBlock *blk;
|
||||
|
||||
DPRINTF("%s Enter submitted %d read_done %d transferred %d\n",
|
||||
dprintf("%s Enter submitted %d read_done %d transferred %d\n",
|
||||
__FUNCTION__, block_mig_state.submitted, block_mig_state.read_done,
|
||||
block_mig_state.transferred);
|
||||
|
||||
@@ -424,47 +355,26 @@ static void flush_blks(QEMUFile* f)
|
||||
assert(block_mig_state.read_done >= 0);
|
||||
}
|
||||
|
||||
DPRINTF("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__,
|
||||
dprintf("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__,
|
||||
block_mig_state.submitted, block_mig_state.read_done,
|
||||
block_mig_state.transferred);
|
||||
}
|
||||
|
||||
static int64_t get_remaining_dirty(void)
|
||||
{
|
||||
BlkMigDevState *bmds;
|
||||
int64_t dirty = 0;
|
||||
|
||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||
dirty += bdrv_get_dirty_count(bmds->bs);
|
||||
}
|
||||
|
||||
return dirty * BLOCK_SIZE;
|
||||
}
|
||||
|
||||
static int is_stage2_completed(void)
|
||||
{
|
||||
int64_t remaining_dirty;
|
||||
long double bwidth;
|
||||
BlkMigDevState *bmds;
|
||||
|
||||
if (block_mig_state.bulk_completed == 1) {
|
||||
if (block_mig_state.submitted > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
remaining_dirty = get_remaining_dirty();
|
||||
if (remaining_dirty == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bwidth = compute_read_bwidth();
|
||||
|
||||
if ((remaining_dirty / bwidth) <=
|
||||
migrate_max_downtime()) {
|
||||
/* finish stage2 because we think that we can finish remaing work
|
||||
below max_downtime */
|
||||
|
||||
return 1;
|
||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||
if (bmds->bulk_completed == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void blk_mig_cleanup(Monitor *mon)
|
||||
@@ -490,7 +400,7 @@ static void blk_mig_cleanup(Monitor *mon)
|
||||
|
||||
static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
|
||||
{
|
||||
DPRINTF("Enter save live stage %d submitted %d transferred %d\n",
|
||||
dprintf("Enter save live stage %d submitted %d transferred %d\n",
|
||||
stage, block_mig_state.submitted, block_mig_state.transferred);
|
||||
|
||||
if (stage < 0) {
|
||||
@@ -518,41 +428,29 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
blk_mig_reset_dirty_cursor();
|
||||
|
||||
if (stage == 2) {
|
||||
/* control the rate of transfer */
|
||||
while ((block_mig_state.submitted +
|
||||
block_mig_state.read_done) * BLOCK_SIZE <
|
||||
qemu_file_get_rate_limit(f)) {
|
||||
if (block_mig_state.bulk_completed == 0) {
|
||||
/* first finish the bulk phase */
|
||||
if (blk_mig_save_bulked_block(mon, f) == 0) {
|
||||
/* finished saving bulk on all devices */
|
||||
block_mig_state.bulk_completed = 1;
|
||||
}
|
||||
} else {
|
||||
if (blk_mig_save_dirty_block(mon, f, 1) == 0) {
|
||||
/* no more dirty blocks */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flush_blks(f);
|
||||
|
||||
if (qemu_file_has_error(f)) {
|
||||
blk_mig_cleanup(mon);
|
||||
return 0;
|
||||
/* control the rate of transfer */
|
||||
while ((block_mig_state.submitted +
|
||||
block_mig_state.read_done) * BLOCK_SIZE <
|
||||
qemu_file_get_rate_limit(f)) {
|
||||
if (blk_mig_save_bulked_block(mon, f, 1) == 0) {
|
||||
/* no more bulk blocks for now */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stage == 3) {
|
||||
/* we know for sure that save bulk is completed and
|
||||
all async read completed */
|
||||
assert(block_mig_state.submitted == 0);
|
||||
flush_blks(f);
|
||||
|
||||
while (blk_mig_save_dirty_block(mon, f, 0) != 0);
|
||||
if (qemu_file_has_error(f)) {
|
||||
blk_mig_cleanup(mon);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stage == 3) {
|
||||
while (blk_mig_save_bulked_block(mon, f, 0) != 0) {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
blk_mig_save_dirty_blocks(mon, f);
|
||||
blk_mig_cleanup(mon);
|
||||
|
||||
/* report completion */
|
||||
@@ -586,7 +484,6 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
|
||||
addr >>= BDRV_SECTOR_BITS;
|
||||
|
||||
if (flags & BLK_MIG_FLAG_DEVICE_BLOCK) {
|
||||
int ret;
|
||||
/* get device name */
|
||||
len = qemu_get_byte(f);
|
||||
qemu_get_buffer(f, (uint8_t *)device_name, len);
|
||||
@@ -602,12 +499,9 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
|
||||
buf = qemu_malloc(BLOCK_SIZE);
|
||||
|
||||
qemu_get_buffer(f, buf, BLOCK_SIZE);
|
||||
ret = bdrv_write(bs, addr, buf, BDRV_SECTORS_PER_DIRTY_CHUNK);
|
||||
bdrv_write(bs, addr, buf, BDRV_SECTORS_PER_DIRTY_CHUNK);
|
||||
|
||||
qemu_free(buf);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
} else if (flags & BLK_MIG_FLAG_PROGRESS) {
|
||||
if (!banner_printed) {
|
||||
printf("Receiving block device images\n");
|
||||
@@ -642,6 +536,6 @@ void blk_mig_init(void)
|
||||
QSIMPLEQ_INIT(&block_mig_state.bmds_list);
|
||||
QSIMPLEQ_INIT(&block_mig_state.blk_list);
|
||||
|
||||
register_savevm_live(NULL, "block", 0, 1, block_set_params,
|
||||
block_save_live, NULL, block_load, &block_mig_state);
|
||||
register_savevm_live("block", 0, 1, block_set_params, block_save_live,
|
||||
NULL, block_load, &block_mig_state);
|
||||
}
|
||||
|
||||
116
block.h
116
block.h
@@ -27,31 +27,25 @@ typedef struct QEMUSnapshotInfo {
|
||||
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_NATIVE_AIO 0x0080 /* use native AIO instead of the thread pool */
|
||||
#define BDRV_O_NO_BACKING 0x0100 /* don't open the backing file */
|
||||
#define BDRV_O_NO_FLUSH 0x0200 /* disable flushing on this disk */
|
||||
|
||||
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB)
|
||||
|
||||
#define BDRV_SECTOR_BITS 9
|
||||
#define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS)
|
||||
#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1)
|
||||
#define BDRV_SECTOR_SIZE (1 << BDRV_SECTOR_BITS)
|
||||
#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1);
|
||||
|
||||
typedef enum {
|
||||
BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC,
|
||||
BLOCK_ERR_STOP_ANY
|
||||
} BlockErrorAction;
|
||||
|
||||
typedef enum {
|
||||
BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
|
||||
} BlockMonEventAction;
|
||||
|
||||
void bdrv_mon_event(const BlockDriverState *bdrv,
|
||||
BlockMonEventAction action, int is_read);
|
||||
void bdrv_info_print(Monitor *mon, const QObject *data);
|
||||
void bdrv_info(Monitor *mon, QObject **ret_data);
|
||||
void bdrv_stats_print(Monitor *mon, const QObject *data);
|
||||
@@ -59,21 +53,22 @@ void bdrv_info_stats(Monitor *mon, QObject **ret_data);
|
||||
|
||||
void bdrv_init(void);
|
||||
void bdrv_init_with_whitelist(void);
|
||||
BlockDriver *bdrv_find_protocol(const char *filename);
|
||||
BlockDriver *bdrv_find_format(const char *format_name);
|
||||
BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
|
||||
int bdrv_create(BlockDriver *drv, const char* filename,
|
||||
QEMUOptionParameter *options);
|
||||
int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
|
||||
int bdrv_create2(BlockDriver *drv,
|
||||
const char *filename, int64_t size_in_sectors,
|
||||
const char *backing_file, const char *backing_format,
|
||||
int flags);
|
||||
BlockDriverState *bdrv_new(const char *device_name);
|
||||
void bdrv_delete(BlockDriverState *bs);
|
||||
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
|
||||
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
||||
BlockDriver *drv);
|
||||
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_attach(BlockDriverState *bs, DeviceState *qdev);
|
||||
void bdrv_detach(BlockDriverState *bs, DeviceState *qdev);
|
||||
DeviceState *bdrv_get_attached(BlockDriverState *bs);
|
||||
int bdrv_check(BlockDriverState *bs);
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
@@ -91,20 +86,8 @@ int64_t bdrv_getlength(BlockDriverState *bs);
|
||||
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
|
||||
void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
|
||||
int bdrv_commit(BlockDriverState *bs);
|
||||
void bdrv_commit_all(void);
|
||||
int bdrv_change_backing_file(BlockDriverState *bs,
|
||||
const char *backing_file, const char *backing_fmt);
|
||||
void bdrv_register(BlockDriver *bdrv);
|
||||
|
||||
|
||||
typedef struct BdrvCheckResult {
|
||||
int corruptions;
|
||||
int leaks;
|
||||
int check_errors;
|
||||
} BdrvCheckResult;
|
||||
|
||||
int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res);
|
||||
|
||||
/* async block I/O */
|
||||
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
|
||||
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
|
||||
@@ -144,9 +127,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
|
||||
/* Ensure contents are flushed to disk. */
|
||||
void bdrv_flush(BlockDriverState *bs);
|
||||
void bdrv_flush_all(void);
|
||||
void bdrv_close_all(void);
|
||||
|
||||
int bdrv_has_zero_init(BlockDriverState *bs);
|
||||
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
int *pnum);
|
||||
|
||||
@@ -167,12 +148,9 @@ 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);
|
||||
void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
|
||||
BlockErrorAction on_write_error);
|
||||
BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read);
|
||||
void bdrv_set_removable(BlockDriverState *bs, int removable);
|
||||
int bdrv_is_removable(BlockDriverState *bs);
|
||||
int bdrv_is_read_only(BlockDriverState *bs);
|
||||
int bdrv_set_read_only(BlockDriverState *bs, int read_only);
|
||||
int bdrv_is_sg(BlockDriverState *bs);
|
||||
int bdrv_enable_write_cache(BlockDriverState *bs);
|
||||
int bdrv_is_inserted(BlockDriverState *bs);
|
||||
@@ -184,7 +162,6 @@ 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);
|
||||
BlockDriverState *bdrv_next(BlockDriverState *bs);
|
||||
void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs),
|
||||
void *opaque);
|
||||
int bdrv_is_encrypted(BlockDriverState *bs);
|
||||
@@ -201,9 +178,6 @@ 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_can_snapshot(BlockDriverState *bs);
|
||||
int bdrv_is_snapshot(BlockDriverState *bs);
|
||||
BlockDriverState *bdrv_snapshots(void);
|
||||
int bdrv_snapshot_create(BlockDriverState *bs,
|
||||
QEMUSnapshotInfo *sn_info);
|
||||
int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||
@@ -231,58 +205,4 @@ void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
|
||||
int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
|
||||
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors);
|
||||
int64_t bdrv_get_dirty_count(BlockDriverState *bs);
|
||||
|
||||
|
||||
typedef enum {
|
||||
BLKDBG_L1_UPDATE,
|
||||
|
||||
BLKDBG_L1_GROW_ALLOC_TABLE,
|
||||
BLKDBG_L1_GROW_WRITE_TABLE,
|
||||
BLKDBG_L1_GROW_ACTIVATE_TABLE,
|
||||
|
||||
BLKDBG_L2_LOAD,
|
||||
BLKDBG_L2_UPDATE,
|
||||
BLKDBG_L2_UPDATE_COMPRESSED,
|
||||
BLKDBG_L2_ALLOC_COW_READ,
|
||||
BLKDBG_L2_ALLOC_WRITE,
|
||||
|
||||
BLKDBG_READ,
|
||||
BLKDBG_READ_AIO,
|
||||
BLKDBG_READ_BACKING,
|
||||
BLKDBG_READ_BACKING_AIO,
|
||||
BLKDBG_READ_COMPRESSED,
|
||||
|
||||
BLKDBG_WRITE_AIO,
|
||||
BLKDBG_WRITE_COMPRESSED,
|
||||
|
||||
BLKDBG_VMSTATE_LOAD,
|
||||
BLKDBG_VMSTATE_SAVE,
|
||||
|
||||
BLKDBG_COW_READ,
|
||||
BLKDBG_COW_WRITE,
|
||||
|
||||
BLKDBG_REFTABLE_LOAD,
|
||||
BLKDBG_REFTABLE_GROW,
|
||||
|
||||
BLKDBG_REFBLOCK_LOAD,
|
||||
BLKDBG_REFBLOCK_UPDATE,
|
||||
BLKDBG_REFBLOCK_UPDATE_PART,
|
||||
BLKDBG_REFBLOCK_ALLOC,
|
||||
BLKDBG_REFBLOCK_ALLOC_HOOKUP,
|
||||
BLKDBG_REFBLOCK_ALLOC_WRITE,
|
||||
BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS,
|
||||
BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE,
|
||||
BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE,
|
||||
|
||||
BLKDBG_CLUSTER_ALLOC,
|
||||
BLKDBG_CLUSTER_ALLOC_BYTES,
|
||||
BLKDBG_CLUSTER_FREE,
|
||||
|
||||
BLKDBG_EVENT_MAX,
|
||||
} BlkDebugEvent;
|
||||
|
||||
#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
|
||||
void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
|
||||
|
||||
#endif
|
||||
|
||||
473
block/blkdebug.c
473
block/blkdebug.c
@@ -1,473 +0,0 @@
|
||||
/*
|
||||
* Block protocol for I/O error injection
|
||||
*
|
||||
* Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
|
||||
typedef struct BlkdebugVars {
|
||||
int state;
|
||||
|
||||
/* If inject_errno != 0, an error is injected for requests */
|
||||
int inject_errno;
|
||||
|
||||
/* Decides if all future requests fail (false) or only the next one and
|
||||
* after the next request inject_errno is reset to 0 (true) */
|
||||
bool inject_once;
|
||||
|
||||
/* Decides if aio_readv/writev fails right away (true) or returns an error
|
||||
* return value only in the callback (false) */
|
||||
bool inject_immediately;
|
||||
} BlkdebugVars;
|
||||
|
||||
typedef struct BDRVBlkdebugState {
|
||||
BlkdebugVars vars;
|
||||
QLIST_HEAD(list, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
|
||||
} BDRVBlkdebugState;
|
||||
|
||||
typedef struct BlkdebugAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
QEMUBH *bh;
|
||||
int ret;
|
||||
} BlkdebugAIOCB;
|
||||
|
||||
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
|
||||
|
||||
static AIOPool blkdebug_aio_pool = {
|
||||
.aiocb_size = sizeof(BlkdebugAIOCB),
|
||||
.cancel = blkdebug_aio_cancel,
|
||||
};
|
||||
|
||||
enum {
|
||||
ACTION_INJECT_ERROR,
|
||||
ACTION_SET_STATE,
|
||||
};
|
||||
|
||||
typedef struct BlkdebugRule {
|
||||
BlkDebugEvent event;
|
||||
int action;
|
||||
int state;
|
||||
union {
|
||||
struct {
|
||||
int error;
|
||||
int immediately;
|
||||
int once;
|
||||
} inject;
|
||||
struct {
|
||||
int new_state;
|
||||
} set_state;
|
||||
} options;
|
||||
QLIST_ENTRY(BlkdebugRule) next;
|
||||
} BlkdebugRule;
|
||||
|
||||
static QemuOptsList inject_error_opts = {
|
||||
.name = "inject-error",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "event",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{
|
||||
.name = "state",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
},
|
||||
{
|
||||
.name = "errno",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
},
|
||||
{
|
||||
.name = "once",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
{
|
||||
.name = "immediately",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static QemuOptsList set_state_opts = {
|
||||
.name = "set-state",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "event",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{
|
||||
.name = "state",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
},
|
||||
{
|
||||
.name = "new_state",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static QemuOptsList *config_groups[] = {
|
||||
&inject_error_opts,
|
||||
&set_state_opts,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *event_names[BLKDBG_EVENT_MAX] = {
|
||||
[BLKDBG_L1_UPDATE] = "l1_update",
|
||||
[BLKDBG_L1_GROW_ALLOC_TABLE] = "l1_grow.alloc_table",
|
||||
[BLKDBG_L1_GROW_WRITE_TABLE] = "l1_grow.write_table",
|
||||
[BLKDBG_L1_GROW_ACTIVATE_TABLE] = "l1_grow.activate_table",
|
||||
|
||||
[BLKDBG_L2_LOAD] = "l2_load",
|
||||
[BLKDBG_L2_UPDATE] = "l2_update",
|
||||
[BLKDBG_L2_UPDATE_COMPRESSED] = "l2_update_compressed",
|
||||
[BLKDBG_L2_ALLOC_COW_READ] = "l2_alloc.cow_read",
|
||||
[BLKDBG_L2_ALLOC_WRITE] = "l2_alloc.write",
|
||||
|
||||
[BLKDBG_READ] = "read",
|
||||
[BLKDBG_READ_AIO] = "read_aio",
|
||||
[BLKDBG_READ_BACKING] = "read_backing",
|
||||
[BLKDBG_READ_BACKING_AIO] = "read_backing_aio",
|
||||
[BLKDBG_READ_COMPRESSED] = "read_compressed",
|
||||
|
||||
[BLKDBG_WRITE_AIO] = "write_aio",
|
||||
[BLKDBG_WRITE_COMPRESSED] = "write_compressed",
|
||||
|
||||
[BLKDBG_VMSTATE_LOAD] = "vmstate_load",
|
||||
[BLKDBG_VMSTATE_SAVE] = "vmstate_save",
|
||||
|
||||
[BLKDBG_COW_READ] = "cow_read",
|
||||
[BLKDBG_COW_WRITE] = "cow_write",
|
||||
|
||||
[BLKDBG_REFTABLE_LOAD] = "reftable_load",
|
||||
[BLKDBG_REFTABLE_GROW] = "reftable_grow",
|
||||
|
||||
[BLKDBG_REFBLOCK_LOAD] = "refblock_load",
|
||||
[BLKDBG_REFBLOCK_UPDATE] = "refblock_update",
|
||||
[BLKDBG_REFBLOCK_UPDATE_PART] = "refblock_update_part",
|
||||
[BLKDBG_REFBLOCK_ALLOC] = "refblock_alloc",
|
||||
[BLKDBG_REFBLOCK_ALLOC_HOOKUP] = "refblock_alloc.hookup",
|
||||
[BLKDBG_REFBLOCK_ALLOC_WRITE] = "refblock_alloc.write",
|
||||
[BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS] = "refblock_alloc.write_blocks",
|
||||
[BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE] = "refblock_alloc.write_table",
|
||||
[BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE] = "refblock_alloc.switch_table",
|
||||
|
||||
[BLKDBG_CLUSTER_ALLOC] = "cluster_alloc",
|
||||
[BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes",
|
||||
[BLKDBG_CLUSTER_FREE] = "cluster_free",
|
||||
};
|
||||
|
||||
static int get_event_by_name(const char *name, BlkDebugEvent *event)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
|
||||
if (!strcmp(event_names[i], name)) {
|
||||
*event = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct add_rule_data {
|
||||
BDRVBlkdebugState *s;
|
||||
int action;
|
||||
};
|
||||
|
||||
static int add_rule(QemuOpts *opts, void *opaque)
|
||||
{
|
||||
struct add_rule_data *d = opaque;
|
||||
BDRVBlkdebugState *s = d->s;
|
||||
const char* event_name;
|
||||
BlkDebugEvent event;
|
||||
struct BlkdebugRule *rule;
|
||||
|
||||
/* Find the right event for the rule */
|
||||
event_name = qemu_opt_get(opts, "event");
|
||||
if (!event_name || get_event_by_name(event_name, &event) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set attributes common for all actions */
|
||||
rule = qemu_mallocz(sizeof(*rule));
|
||||
*rule = (struct BlkdebugRule) {
|
||||
.event = event,
|
||||
.action = d->action,
|
||||
.state = qemu_opt_get_number(opts, "state", 0),
|
||||
};
|
||||
|
||||
/* Parse action-specific options */
|
||||
switch (d->action) {
|
||||
case ACTION_INJECT_ERROR:
|
||||
rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
|
||||
rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0);
|
||||
rule->options.inject.immediately =
|
||||
qemu_opt_get_bool(opts, "immediately", 0);
|
||||
break;
|
||||
|
||||
case ACTION_SET_STATE:
|
||||
rule->options.set_state.new_state =
|
||||
qemu_opt_get_number(opts, "new_state", 0);
|
||||
break;
|
||||
};
|
||||
|
||||
/* Add the rule */
|
||||
QLIST_INSERT_HEAD(&s->rules[event], rule, next);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_config(BDRVBlkdebugState *s, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
int ret;
|
||||
struct add_rule_data d;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ret = qemu_config_parse(f, config_groups, filename);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
d.s = s;
|
||||
d.action = ACTION_INJECT_ERROR;
|
||||
qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
|
||||
|
||||
d.action = ACTION_SET_STATE;
|
||||
qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_opts_reset(&inject_error_opts);
|
||||
qemu_opts_reset(&set_state_opts);
|
||||
fclose(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
|
||||
static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
int ret;
|
||||
char *config, *c;
|
||||
|
||||
/* Parse the blkdebug: prefix */
|
||||
if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
filename += strlen("blkdebug:");
|
||||
|
||||
/* Read rules from config file */
|
||||
c = strchr(filename, ':');
|
||||
if (c == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
config = strdup(filename);
|
||||
config[c - filename] = '\0';
|
||||
ret = read_config(s, config);
|
||||
free(config);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
filename = c + 1;
|
||||
|
||||
/* Set initial state */
|
||||
s->vars.state = 1;
|
||||
|
||||
/* Open the backing file */
|
||||
ret = bdrv_file_open(&bs->file, filename, flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void error_callback_bh(void *opaque)
|
||||
{
|
||||
struct BlkdebugAIOCB *acb = opaque;
|
||||
qemu_bh_delete(acb->bh);
|
||||
acb->common.cb(acb->common.opaque, acb->ret);
|
||||
qemu_aio_release(acb);
|
||||
}
|
||||
|
||||
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
|
||||
qemu_aio_release(acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
int error = s->vars.inject_errno;
|
||||
struct BlkdebugAIOCB *acb;
|
||||
QEMUBH *bh;
|
||||
|
||||
if (s->vars.inject_once) {
|
||||
s->vars.inject_errno = 0;
|
||||
}
|
||||
|
||||
if (s->vars.inject_immediately) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque);
|
||||
acb->ret = -error;
|
||||
|
||||
bh = qemu_bh_new(error_callback_bh, acb);
|
||||
acb->bh = bh;
|
||||
qemu_bh_schedule(bh);
|
||||
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
|
||||
if (s->vars.inject_errno) {
|
||||
return inject_error(bs, cb, opaque);
|
||||
}
|
||||
|
||||
BlockDriverAIOCB *acb =
|
||||
bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
|
||||
return acb;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
|
||||
if (s->vars.inject_errno) {
|
||||
return inject_error(bs, cb, opaque);
|
||||
}
|
||||
|
||||
BlockDriverAIOCB *acb =
|
||||
bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
|
||||
return acb;
|
||||
}
|
||||
|
||||
static void blkdebug_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugRule *rule, *next;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
|
||||
QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
|
||||
QLIST_REMOVE(rule, next);
|
||||
qemu_free(rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blkdebug_flush(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_flush(bs->file);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_flush(bs->file, cb, opaque);
|
||||
}
|
||||
|
||||
static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
|
||||
BlkdebugVars *old_vars)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugVars *vars = &s->vars;
|
||||
|
||||
/* Only process rules for the current state */
|
||||
if (rule->state && rule->state != old_vars->state) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Take the action */
|
||||
switch (rule->action) {
|
||||
case ACTION_INJECT_ERROR:
|
||||
vars->inject_errno = rule->options.inject.error;
|
||||
vars->inject_once = rule->options.inject.once;
|
||||
vars->inject_immediately = rule->options.inject.immediately;
|
||||
break;
|
||||
|
||||
case ACTION_SET_STATE:
|
||||
vars->state = rule->options.set_state.new_state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
struct BlkdebugRule *rule;
|
||||
BlkdebugVars old_vars = s->vars;
|
||||
|
||||
if (event < 0 || event >= BLKDBG_EVENT_MAX) {
|
||||
return;
|
||||
}
|
||||
|
||||
QLIST_FOREACH(rule, &s->rules[event], next) {
|
||||
process_rule(bs, rule, &old_vars);
|
||||
}
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_blkdebug = {
|
||||
.format_name = "blkdebug",
|
||||
.protocol_name = "blkdebug",
|
||||
|
||||
.instance_size = sizeof(BDRVBlkdebugState),
|
||||
|
||||
.bdrv_file_open = blkdebug_open,
|
||||
.bdrv_close = blkdebug_close,
|
||||
.bdrv_flush = blkdebug_flush,
|
||||
|
||||
.bdrv_aio_readv = blkdebug_aio_readv,
|
||||
.bdrv_aio_writev = blkdebug_aio_writev,
|
||||
.bdrv_aio_flush = blkdebug_aio_flush,
|
||||
|
||||
.bdrv_debug_event = blkdebug_debug_event,
|
||||
};
|
||||
|
||||
static void bdrv_blkdebug_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_blkdebug);
|
||||
}
|
||||
|
||||
block_init(bdrv_blkdebug_init);
|
||||
@@ -80,6 +80,8 @@ struct bochs_header {
|
||||
};
|
||||
|
||||
typedef struct BDRVBochsState {
|
||||
int fd;
|
||||
|
||||
uint32_t *catalog_bitmap;
|
||||
int catalog_size;
|
||||
|
||||
@@ -107,16 +109,25 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bochs_open(BlockDriverState *bs, int flags)
|
||||
static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
int i;
|
||||
int fd, i;
|
||||
struct bochs_header bochs;
|
||||
struct bochs_header_v1 header_v1;
|
||||
|
||||
fd = open(filename, O_RDWR | O_BINARY);
|
||||
if (fd < 0) {
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bs->read_only = 1; // no write support yet
|
||||
|
||||
if (bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)) != sizeof(bochs)) {
|
||||
s->fd = fd;
|
||||
|
||||
if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -135,10 +146,12 @@ static int bochs_open(BlockDriverState *bs, int flags)
|
||||
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
||||
}
|
||||
|
||||
lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
|
||||
|
||||
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
|
||||
s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
|
||||
if (bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
|
||||
s->catalog_size * 4) != 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]);
|
||||
@@ -152,53 +165,68 @@ static int bochs_open(BlockDriverState *bs, int flags)
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
int64_t offset = sector_num * 512;
|
||||
int64_t extent_index, extent_offset, bitmap_offset;
|
||||
int64_t extent_index, extent_offset, bitmap_offset, block_offset;
|
||||
char bitmap_entry;
|
||||
|
||||
// seek to sector
|
||||
extent_index = offset / s->extent_size;
|
||||
extent_offset = (offset % s->extent_size) / 512;
|
||||
|
||||
if (s->catalog_bitmap[extent_index] == 0xffffffff) {
|
||||
return -1; /* not allocated */
|
||||
if (s->catalog_bitmap[extent_index] == 0xffffffff)
|
||||
{
|
||||
// fprintf(stderr, "page not allocated [%x - %x:%x]\n",
|
||||
// sector_num, extent_index, extent_offset);
|
||||
return -1; // not allocated
|
||||
}
|
||||
|
||||
bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
|
||||
(s->extent_blocks + s->bitmap_blocks));
|
||||
block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
|
||||
|
||||
/* read in bitmap for current extent */
|
||||
if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
||||
&bitmap_entry, 1) != 1) {
|
||||
return -1;
|
||||
// fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n",
|
||||
// sector_num, extent_index, extent_offset,
|
||||
// le32_to_cpu(s->catalog_bitmap[extent_index]),
|
||||
// bitmap_offset, block_offset);
|
||||
|
||||
// read in bitmap for current extent
|
||||
lseek(s->fd, bitmap_offset + (extent_offset / 8), SEEK_SET);
|
||||
|
||||
read(s->fd, &bitmap_entry, 1);
|
||||
|
||||
if (!((bitmap_entry >> (extent_offset % 8)) & 1))
|
||||
{
|
||||
// fprintf(stderr, "sector (%x) in bitmap not allocated\n",
|
||||
// sector_num);
|
||||
return -1; // not allocated
|
||||
}
|
||||
|
||||
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
|
||||
return -1; /* not allocated */
|
||||
}
|
||||
lseek(s->fd, block_offset, SEEK_SET);
|
||||
|
||||
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bochs_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
int64_t block_offset = seek_to_sector(bs, sector_num);
|
||||
if (block_offset >= 0) {
|
||||
ret = bdrv_pread(bs->file, block_offset, buf, 512);
|
||||
if (ret != 512) {
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
if (!seek_to_sector(bs, sector_num))
|
||||
{
|
||||
ret = read(s->fd, buf, 512);
|
||||
if (ret != 512)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
memset(buf, 0, 512);
|
||||
nb_sectors--;
|
||||
sector_num++;
|
||||
@@ -211,6 +239,7 @@ static void bochs_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
qemu_free(s->catalog_bitmap);
|
||||
close(s->fd);
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_bochs = {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <zlib.h>
|
||||
|
||||
typedef struct BDRVCloopState {
|
||||
int fd;
|
||||
uint32_t block_size;
|
||||
uint32_t n_blocks;
|
||||
uint64_t* offsets;
|
||||
@@ -50,31 +51,34 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cloop_open(BlockDriverState *bs, int flags)
|
||||
static int cloop_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVCloopState *s = bs->opaque;
|
||||
uint32_t offsets_size,max_compressed_block_size=1,i;
|
||||
|
||||
s->fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (s->fd < 0)
|
||||
return -errno;
|
||||
bs->read_only = 1;
|
||||
|
||||
/* read header */
|
||||
if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) {
|
||||
goto cloop_close;
|
||||
if(lseek(s->fd,128,SEEK_SET)<0) {
|
||||
cloop_close:
|
||||
close(s->fd);
|
||||
return -1;
|
||||
}
|
||||
s->block_size = be32_to_cpu(s->block_size);
|
||||
|
||||
if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) {
|
||||
goto cloop_close;
|
||||
}
|
||||
s->n_blocks = be32_to_cpu(s->n_blocks);
|
||||
if(read(s->fd,&s->block_size,4)<4)
|
||||
goto cloop_close;
|
||||
s->block_size=be32_to_cpu(s->block_size);
|
||||
if(read(s->fd,&s->n_blocks,4)<4)
|
||||
goto cloop_close;
|
||||
s->n_blocks=be32_to_cpu(s->n_blocks);
|
||||
|
||||
/* read offsets */
|
||||
offsets_size = s->n_blocks * sizeof(uint64_t);
|
||||
s->offsets = qemu_malloc(offsets_size);
|
||||
if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) <
|
||||
offsets_size) {
|
||||
offsets_size=s->n_blocks*sizeof(uint64_t);
|
||||
s->offsets=(uint64_t*)qemu_malloc(offsets_size);
|
||||
if(read(s->fd,s->offsets,offsets_size)<offsets_size)
|
||||
goto cloop_close;
|
||||
}
|
||||
for(i=0;i<s->n_blocks;i++) {
|
||||
s->offsets[i]=be64_to_cpu(s->offsets[i]);
|
||||
if(i>0) {
|
||||
@@ -94,21 +98,16 @@ static int cloop_open(BlockDriverState *bs, int flags)
|
||||
s->sectors_per_block = s->block_size/512;
|
||||
bs->total_sectors = s->n_blocks*s->sectors_per_block;
|
||||
return 0;
|
||||
|
||||
cloop_close:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int cloop_read_block(BlockDriverState *bs, int block_num)
|
||||
static inline int cloop_read_block(BDRVCloopState *s,int block_num)
|
||||
{
|
||||
BDRVCloopState *s = bs->opaque;
|
||||
|
||||
if(s->current_block != block_num) {
|
||||
int ret;
|
||||
uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
|
||||
|
||||
ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
|
||||
bytes);
|
||||
lseek(s->fd, s->offsets[block_num], SEEK_SET);
|
||||
ret = read(s->fd, s->compressed_block, bytes);
|
||||
if (ret != bytes)
|
||||
return -1;
|
||||
|
||||
@@ -137,7 +136,7 @@ static int cloop_read(BlockDriverState *bs, int64_t sector_num,
|
||||
for(i=0;i<nb_sectors;i++) {
|
||||
uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block),
|
||||
block_num=(sector_num+i)/s->sectors_per_block;
|
||||
if(cloop_read_block(bs, block_num) != 0)
|
||||
if(cloop_read_block(s, block_num) != 0)
|
||||
return -1;
|
||||
memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512);
|
||||
}
|
||||
@@ -147,6 +146,7 @@ static int cloop_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static void cloop_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVCloopState *s = bs->opaque;
|
||||
close(s->fd);
|
||||
if(s->n_blocks>0)
|
||||
free(s->offsets);
|
||||
free(s->compressed_block);
|
||||
|
||||
147
block/cow.c
147
block/cow.c
@@ -21,9 +21,11 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _WIN32
|
||||
#include "qemu-common.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
#include <sys/mman.h>
|
||||
|
||||
/**************************************************************/
|
||||
/* COW block driver using file system holes */
|
||||
@@ -42,6 +44,10 @@ struct cow_header_v2 {
|
||||
};
|
||||
|
||||
typedef struct BDRVCowState {
|
||||
int fd;
|
||||
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
|
||||
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
|
||||
int cow_bitmap_size;
|
||||
int64_t cow_sectors_offset;
|
||||
} BDRVCowState;
|
||||
|
||||
@@ -57,16 +63,22 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cow_open(BlockDriverState *bs, int flags)
|
||||
static int cow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVCowState *s = bs->opaque;
|
||||
int fd;
|
||||
struct cow_header_v2 cow_header;
|
||||
int bitmap_size;
|
||||
int64_t size;
|
||||
|
||||
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
}
|
||||
s->fd = fd;
|
||||
/* see if it is a cow image */
|
||||
if (bdrv_pread(bs->file, 0, &cow_header, sizeof(cow_header)) !=
|
||||
sizeof(cow_header)) {
|
||||
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -82,91 +94,61 @@ static int cow_open(BlockDriverState *bs, int flags)
|
||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
|
||||
cow_header.backing_file);
|
||||
|
||||
bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
|
||||
s->cow_sectors_offset = (bitmap_size + 511) & ~511;
|
||||
/* mmap the bitmap */
|
||||
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
|
||||
s->cow_bitmap_addr = (void *)mmap(get_mmap_addr(s->cow_bitmap_size),
|
||||
s->cow_bitmap_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, s->fd, 0);
|
||||
if (s->cow_bitmap_addr == MAP_FAILED)
|
||||
goto fail;
|
||||
s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
|
||||
s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511;
|
||||
return 0;
|
||||
fail:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX(hch): right now these functions are extremly ineffcient.
|
||||
* We should just read the whole bitmap we'll need in one go instead.
|
||||
*/
|
||||
static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
|
||||
static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum)
|
||||
{
|
||||
uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
|
||||
uint8_t bitmap;
|
||||
int ret;
|
||||
|
||||
ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bitmap |= (1 << (bitnum % 8));
|
||||
|
||||
ret = bdrv_pwrite_sync(bs->file, offset, &bitmap, sizeof(bitmap));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
bitmap[bitnum / 8] |= (1 << (bitnum%8));
|
||||
}
|
||||
|
||||
static inline int is_bit_set(BlockDriverState *bs, int64_t bitnum)
|
||||
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
|
||||
{
|
||||
uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
|
||||
uint8_t bitmap;
|
||||
int ret;
|
||||
|
||||
ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return !!(bitmap & (1 << (bitnum % 8)));
|
||||
return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
|
||||
}
|
||||
|
||||
|
||||
/* Return true if first block has been changed (ie. current version is
|
||||
* in COW file). Set the number of continuous blocks for which that
|
||||
* is true. */
|
||||
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *num_same)
|
||||
static inline int is_changed(uint8_t *bitmap,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
int *num_same)
|
||||
{
|
||||
int changed;
|
||||
|
||||
if (nb_sectors == 0) {
|
||||
if (!bitmap || nb_sectors == 0) {
|
||||
*num_same = nb_sectors;
|
||||
return 0;
|
||||
}
|
||||
|
||||
changed = is_bit_set(bs, sector_num);
|
||||
if (changed < 0) {
|
||||
return 0; /* XXX: how to return I/O errors? */
|
||||
}
|
||||
|
||||
changed = is_bit_set(bitmap, sector_num);
|
||||
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
|
||||
if (is_bit_set(bs, sector_num + *num_same) != changed)
|
||||
if (is_bit_set(bitmap, sector_num + *num_same) != changed)
|
||||
break;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_sectors; i++) {
|
||||
error = cow_set_bit(bs, sector_num + i);
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
BDRVCowState *s = bs->opaque;
|
||||
return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
|
||||
}
|
||||
|
||||
static int cow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
@@ -176,10 +158,9 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
int ret, n;
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
if (cow_is_allocated(bs, sector_num, nb_sectors, &n)) {
|
||||
ret = bdrv_pread(bs->file,
|
||||
s->cow_sectors_offset + sector_num * 512,
|
||||
buf, n * 512);
|
||||
if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
|
||||
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
|
||||
ret = read(s->fd, buf, n * 512);
|
||||
if (ret != n * 512)
|
||||
return -1;
|
||||
} else {
|
||||
@@ -203,18 +184,22 @@ static int cow_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVCowState *s = bs->opaque;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
ret = bdrv_pwrite(bs->file, s->cow_sectors_offset + sector_num * 512,
|
||||
buf, nb_sectors * 512);
|
||||
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
|
||||
ret = write(s->fd, buf, nb_sectors * 512);
|
||||
if (ret != nb_sectors * 512)
|
||||
return -1;
|
||||
|
||||
return cow_update_bitmap(bs, sector_num, nb_sectors);
|
||||
for (i = 0; i < nb_sectors; i++)
|
||||
cow_set_bit(s->cow_bitmap, sector_num + i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cow_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVCowState *s = bs->opaque;
|
||||
munmap((void *)s->cow_bitmap_addr, s->cow_bitmap_size);
|
||||
close(s->fd);
|
||||
}
|
||||
|
||||
static int cow_create(const char *filename, QEMUOptionParameter *options)
|
||||
@@ -224,7 +209,6 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
|
||||
struct stat st;
|
||||
int64_t image_sectors = 0;
|
||||
const char *image_filename = NULL;
|
||||
int ret;
|
||||
|
||||
/* Read out options */
|
||||
while (options && options->name) {
|
||||
@@ -239,7 +223,7 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
|
||||
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
||||
0644);
|
||||
if (cow_fd < 0)
|
||||
return -errno;
|
||||
return -1;
|
||||
memset(&cow_header, 0, sizeof(cow_header));
|
||||
cow_header.magic = cpu_to_be32(COW_MAGIC);
|
||||
cow_header.version = cpu_to_be32(COW_VERSION);
|
||||
@@ -264,27 +248,17 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
|
||||
}
|
||||
cow_header.sectorsize = cpu_to_be32(512);
|
||||
cow_header.size = cpu_to_be64(image_sectors * 512);
|
||||
ret = qemu_write_full(cow_fd, &cow_header, sizeof(cow_header));
|
||||
if (ret != sizeof(cow_header)) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
write(cow_fd, &cow_header, sizeof(cow_header));
|
||||
/* resize to include at least all the bitmap */
|
||||
ret = ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
|
||||
if (ret) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
|
||||
close(cow_fd);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cow_flush(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_flush(bs->file);
|
||||
BDRVCowState *s = bs->opaque;
|
||||
qemu_fdatasync(s->fd);
|
||||
}
|
||||
|
||||
static QEMUOptionParameter cow_create_options[] = {
|
||||
@@ -322,3 +296,4 @@ static void bdrv_cow_init(void)
|
||||
}
|
||||
|
||||
block_init(bdrv_cow_init);
|
||||
#endif
|
||||
|
||||
36
block/curl.c
36
block/curl.c
@@ -29,9 +29,9 @@
|
||||
// #define DEBUG_VERBOSE
|
||||
|
||||
#ifdef DEBUG_CURL
|
||||
#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
|
||||
#define dprintf(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) do { } while (0)
|
||||
#define dprintf(fmt, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define CURL_NUM_STATES 8
|
||||
@@ -80,7 +80,7 @@ static void curl_multi_do(void *arg);
|
||||
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||
void *s, void *sp)
|
||||
{
|
||||
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
||||
dprintf("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
||||
switch (action) {
|
||||
case CURL_POLL_IN:
|
||||
qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, NULL, NULL, s);
|
||||
@@ -104,11 +104,10 @@ static size_t curl_size_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||
{
|
||||
CURLState *s = ((CURLState*)opaque);
|
||||
size_t realsize = size * nmemb;
|
||||
size_t fsize;
|
||||
long long fsize;
|
||||
|
||||
if(sscanf(ptr, "Content-Length: %zd", &fsize) == 1) {
|
||||
if(sscanf(ptr, "Content-Length: %lld", &fsize) == 1)
|
||||
s->s->len = fsize;
|
||||
}
|
||||
|
||||
return realsize;
|
||||
}
|
||||
@@ -119,7 +118,7 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||
size_t realsize = size * nmemb;
|
||||
int i;
|
||||
|
||||
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
|
||||
dprintf("CURL: Just reading %lld bytes\n", (unsigned long long)realsize);
|
||||
|
||||
if (!s || !s->orig_buf)
|
||||
goto read_end;
|
||||
@@ -340,7 +339,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
}
|
||||
|
||||
if ((s->readahead_size & 0x1ff) != 0) {
|
||||
fprintf(stderr, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512\n",
|
||||
fprintf(stderr, "HTTP_READAHEAD_SIZE %Zd is not a multiple of 512\n",
|
||||
s->readahead_size);
|
||||
goto out_noclean;
|
||||
}
|
||||
@@ -350,7 +349,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
inited = 1;
|
||||
}
|
||||
|
||||
DPRINTF("CURL: Opening %s\n", file);
|
||||
dprintf("CURL: Opening %s\n", file);
|
||||
s->url = file;
|
||||
state = curl_init_state(s);
|
||||
if (!state)
|
||||
@@ -369,7 +368,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
s->len = (size_t)d;
|
||||
else if(!s->len)
|
||||
goto out;
|
||||
DPRINTF("CURL: Size = %zd\n", s->len);
|
||||
dprintf("CURL: Size = %lld\n", (long long)s->len);
|
||||
|
||||
curl_clean_state(state);
|
||||
curl_easy_cleanup(state->curl);
|
||||
@@ -451,9 +450,8 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
||||
state->orig_buf = qemu_malloc(state->buf_len);
|
||||
state->acb[0] = acb;
|
||||
|
||||
snprintf(state->range, 127, "%zd-%zd", start, end);
|
||||
DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
|
||||
(nb_sectors * SECTOR_SIZE), start, state->range);
|
||||
snprintf(state->range, 127, "%lld-%lld", (long long)start, (long long)end);
|
||||
dprintf("CURL (AIO): Reading %d at %lld (%s)\n", (nb_sectors * SECTOR_SIZE), start, state->range);
|
||||
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
|
||||
|
||||
curl_multi_add_handle(s->multi, state->curl);
|
||||
@@ -467,7 +465,7 @@ static void curl_close(BlockDriverState *bs)
|
||||
BDRVCURLState *s = bs->opaque;
|
||||
int i;
|
||||
|
||||
DPRINTF("CURL: Close\n");
|
||||
dprintf("CURL: Close\n");
|
||||
for (i=0; i<CURL_NUM_STATES; i++) {
|
||||
if (s->states[i].in_use)
|
||||
curl_clean_state(&s->states[i]);
|
||||
@@ -497,7 +495,7 @@ static BlockDriver bdrv_http = {
|
||||
.protocol_name = "http",
|
||||
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
|
||||
@@ -509,7 +507,7 @@ static BlockDriver bdrv_https = {
|
||||
.protocol_name = "https",
|
||||
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
|
||||
@@ -521,7 +519,7 @@ static BlockDriver bdrv_ftp = {
|
||||
.protocol_name = "ftp",
|
||||
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
|
||||
@@ -533,7 +531,7 @@ static BlockDriver bdrv_ftps = {
|
||||
.protocol_name = "ftps",
|
||||
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
|
||||
@@ -545,7 +543,7 @@ static BlockDriver bdrv_tftp = {
|
||||
.protocol_name = "tftp",
|
||||
|
||||
.instance_size = sizeof(BDRVCURLState),
|
||||
.bdrv_file_open = curl_open,
|
||||
.bdrv_open = curl_open,
|
||||
.bdrv_close = curl_close,
|
||||
.bdrv_getlength = curl_getlength,
|
||||
|
||||
|
||||
107
block/dmg.c
107
block/dmg.c
@@ -28,6 +28,8 @@
|
||||
#include <zlib.h>
|
||||
|
||||
typedef struct BDRVDMGState {
|
||||
int fd;
|
||||
|
||||
/* each chunk contains a certain number of sectors,
|
||||
* offsets[i] is the offset in the .dmg file,
|
||||
* lengths[i] is the length of the compressed chunk,
|
||||
@@ -56,75 +58,69 @@ static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static off_t read_off(BlockDriverState *bs, int64_t offset)
|
||||
static off_t read_off(int fd)
|
||||
{
|
||||
uint64_t buffer;
|
||||
if (bdrv_pread(bs->file, offset, &buffer, 8) < 8)
|
||||
if(read(fd,&buffer,8)<8)
|
||||
return 0;
|
||||
return be64_to_cpu(buffer);
|
||||
}
|
||||
|
||||
static off_t read_uint32(BlockDriverState *bs, int64_t offset)
|
||||
static off_t read_uint32(int fd)
|
||||
{
|
||||
uint32_t buffer;
|
||||
if (bdrv_pread(bs->file, offset, &buffer, 4) < 4)
|
||||
if(read(fd,&buffer,4)<4)
|
||||
return 0;
|
||||
return be32_to_cpu(buffer);
|
||||
}
|
||||
|
||||
static int dmg_open(BlockDriverState *bs, int flags)
|
||||
static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
off_t info_begin,info_end,last_in_offset,last_out_offset;
|
||||
uint32_t count;
|
||||
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
|
||||
int64_t offset;
|
||||
|
||||
s->fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (s->fd < 0)
|
||||
return -errno;
|
||||
bs->read_only = 1;
|
||||
s->n_chunks = 0;
|
||||
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
|
||||
|
||||
/* read offset of info blocks */
|
||||
offset = bdrv_getlength(bs->file);
|
||||
if (offset < 0) {
|
||||
if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
|
||||
goto fail;
|
||||
}
|
||||
offset -= 0x1d8;
|
||||
|
||||
info_begin = read_off(bs, offset);
|
||||
if (info_begin == 0) {
|
||||
info_begin=read_off(s->fd);
|
||||
if(info_begin==0)
|
||||
goto fail;
|
||||
if(lseek(s->fd,info_begin,SEEK_SET)<0)
|
||||
goto fail;
|
||||
if(read_uint32(s->fd)!=0x100)
|
||||
goto fail;
|
||||
if((count = read_uint32(s->fd))==0)
|
||||
goto fail;
|
||||
info_end = info_begin+count;
|
||||
if(lseek(s->fd,0xf8,SEEK_CUR)<0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (read_uint32(bs, info_begin) != 0x100) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
count = read_uint32(bs, info_begin + 4);
|
||||
if (count == 0) {
|
||||
goto fail;
|
||||
}
|
||||
info_end = info_begin + count;
|
||||
|
||||
offset = info_begin + 0x100;
|
||||
|
||||
/* read offsets */
|
||||
last_in_offset = last_out_offset = 0;
|
||||
while (offset < info_end) {
|
||||
while(lseek(s->fd,0,SEEK_CUR)<info_end) {
|
||||
uint32_t type;
|
||||
|
||||
count = read_uint32(bs, offset);
|
||||
count = read_uint32(s->fd);
|
||||
if(count==0)
|
||||
goto fail;
|
||||
offset += 4;
|
||||
|
||||
type = read_uint32(bs, offset);
|
||||
if (type == 0x6d697368 && count >= 244) {
|
||||
type = read_uint32(s->fd);
|
||||
if(type!=0x6d697368 || count<244)
|
||||
lseek(s->fd,count-4,SEEK_CUR);
|
||||
else {
|
||||
int new_size, chunk_count;
|
||||
|
||||
offset += 4;
|
||||
offset += 200;
|
||||
|
||||
if(lseek(s->fd,200,SEEK_CUR)<0)
|
||||
goto fail;
|
||||
chunk_count = (count-204)/40;
|
||||
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
|
||||
s->types = qemu_realloc(s->types, new_size/2);
|
||||
@@ -134,8 +130,7 @@ static int dmg_open(BlockDriverState *bs, int flags)
|
||||
s->sectorcounts = qemu_realloc(s->sectorcounts, new_size);
|
||||
|
||||
for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
|
||||
s->types[i] = read_uint32(bs, offset);
|
||||
offset += 4;
|
||||
s->types[i] = read_uint32(s->fd);
|
||||
if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
|
||||
if(s->types[i]==0xffffffff) {
|
||||
last_in_offset = s->offsets[i-1]+s->lengths[i-1];
|
||||
@@ -143,23 +138,15 @@ static int dmg_open(BlockDriverState *bs, int flags)
|
||||
}
|
||||
chunk_count--;
|
||||
i--;
|
||||
offset += 36;
|
||||
if(lseek(s->fd,36,SEEK_CUR)<0)
|
||||
goto fail;
|
||||
continue;
|
||||
}
|
||||
offset += 4;
|
||||
|
||||
s->sectors[i] = last_out_offset+read_off(bs, offset);
|
||||
offset += 8;
|
||||
|
||||
s->sectorcounts[i] = read_off(bs, offset);
|
||||
offset += 8;
|
||||
|
||||
s->offsets[i] = last_in_offset+read_off(bs, offset);
|
||||
offset += 8;
|
||||
|
||||
s->lengths[i] = read_off(bs, offset);
|
||||
offset += 8;
|
||||
|
||||
read_uint32(s->fd);
|
||||
s->sectors[i] = last_out_offset+read_off(s->fd);
|
||||
s->sectorcounts[i] = read_off(s->fd);
|
||||
s->offsets[i] = last_in_offset+read_off(s->fd);
|
||||
s->lengths[i] = read_off(s->fd);
|
||||
if(s->lengths[i]>max_compressed_size)
|
||||
max_compressed_size = s->lengths[i];
|
||||
if(s->sectorcounts[i]>max_sectors_per_chunk)
|
||||
@@ -179,6 +166,7 @@ static int dmg_open(BlockDriverState *bs, int flags)
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
close(s->fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -208,10 +196,8 @@ static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
|
||||
return s->n_chunks; /* error */
|
||||
}
|
||||
|
||||
static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
|
||||
static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num)
|
||||
{
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
|
||||
if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) {
|
||||
int ret;
|
||||
uint32_t chunk = search_chunk(s,sector_num);
|
||||
@@ -224,12 +210,15 @@ static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
|
||||
case 0x80000005: { /* zlib compressed */
|
||||
int i;
|
||||
|
||||
ret = lseek(s->fd, s->offsets[chunk], SEEK_SET);
|
||||
if(ret<0)
|
||||
return -1;
|
||||
|
||||
/* we need to buffer, because only the chunk as whole can be
|
||||
* inflated. */
|
||||
i=0;
|
||||
do {
|
||||
ret = bdrv_pread(bs->file, s->offsets[chunk] + i,
|
||||
s->compressed_chunk+i, s->lengths[chunk]-i);
|
||||
ret = read(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i);
|
||||
if(ret<0 && errno==EINTR)
|
||||
ret=0;
|
||||
i+=ret;
|
||||
@@ -250,8 +239,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
|
||||
return -1;
|
||||
break; }
|
||||
case 1: /* copy */
|
||||
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||
s->uncompressed_chunk, s->lengths[chunk]);
|
||||
ret = read(s->fd, s->uncompressed_chunk, s->lengths[chunk]);
|
||||
if (ret != s->lengths[chunk])
|
||||
return -1;
|
||||
break;
|
||||
@@ -272,7 +260,7 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
for(i=0;i<nb_sectors;i++) {
|
||||
uint32_t sector_offset_in_chunk;
|
||||
if(dmg_read_chunk(bs, sector_num+i) != 0)
|
||||
if(dmg_read_chunk(s, sector_num+i) != 0)
|
||||
return -1;
|
||||
sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk];
|
||||
memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512);
|
||||
@@ -283,6 +271,7 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static void dmg_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
close(s->fd);
|
||||
if(s->n_chunks>0) {
|
||||
free(s->types);
|
||||
free(s->offsets);
|
||||
|
||||
@@ -49,6 +49,9 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
|
||||
size_t blocksize;
|
||||
int ret;
|
||||
|
||||
if ((flags & BDRV_O_CREAT))
|
||||
return -EINVAL;
|
||||
|
||||
if (!strstart(filename, "nbd:", &host))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -177,7 +180,7 @@ static int64_t nbd_getlength(BlockDriverState *bs)
|
||||
static BlockDriver bdrv_nbd = {
|
||||
.format_name = "nbd",
|
||||
.instance_size = sizeof(BDRVNBDState),
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_open = nbd_open,
|
||||
.bdrv_read = nbd_read,
|
||||
.bdrv_write = nbd_write,
|
||||
.bdrv_close = nbd_close,
|
||||
|
||||
@@ -46,6 +46,7 @@ struct parallels_header {
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct BDRVParallelsState {
|
||||
int fd;
|
||||
|
||||
uint32_t *catalog_bitmap;
|
||||
int catalog_size;
|
||||
@@ -67,15 +68,24 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parallels_open(BlockDriverState *bs, int flags)
|
||||
static int parallels_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVParallelsState *s = bs->opaque;
|
||||
int i;
|
||||
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
|
||||
|
||||
if (bdrv_pread(bs->file, 0, &ph, sizeof(ph)) != sizeof(ph))
|
||||
s->fd = fd;
|
||||
|
||||
if (read(fd, &ph, sizeof(ph)) != sizeof(ph))
|
||||
goto fail;
|
||||
|
||||
if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
|
||||
@@ -85,11 +95,14 @@ static int parallels_open(BlockDriverState *bs, int flags)
|
||||
|
||||
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 (bdrv_pread(bs->file, 64, s->catalog_bitmap, 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++)
|
||||
@@ -99,34 +112,45 @@ static int parallels_open(BlockDriverState *bs, int flags)
|
||||
fail:
|
||||
if (s->catalog_bitmap)
|
||||
qemu_free(s->catalog_bitmap);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
{
|
||||
BDRVParallelsState *s = bs->opaque;
|
||||
uint32_t index, offset;
|
||||
uint64_t position;
|
||||
|
||||
index = sector_num / s->tracks;
|
||||
offset = sector_num % s->tracks;
|
||||
|
||||
/* not allocated */
|
||||
// not allocated
|
||||
if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0))
|
||||
return -1;
|
||||
return (uint64_t)(s->catalog_bitmap[index] + offset) * 512;
|
||||
|
||||
position = (uint64_t)(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) {
|
||||
int64_t position = seek_to_sector(bs, sector_num);
|
||||
if (position >= 0) {
|
||||
if (bdrv_pread(bs->file, position, buf, 512) != 512)
|
||||
return -1;
|
||||
} else {
|
||||
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;
|
||||
@@ -138,6 +162,7 @@ static void parallels_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVParallelsState *s = bs->opaque;
|
||||
qemu_free(s->catalog_bitmap);
|
||||
close(s->fd);
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_parallels = {
|
||||
|
||||
100
block/qcow.c
100
block/qcow.c
@@ -76,7 +76,7 @@ typedef struct BDRVQcowState {
|
||||
AES_KEY aes_decrypt_key;
|
||||
} BDRVQcowState;
|
||||
|
||||
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
|
||||
static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
|
||||
|
||||
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
@@ -90,13 +90,16 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcow_open(BlockDriverState *bs, int flags)
|
||||
static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int len, i, shift;
|
||||
int len, i, shift, ret;
|
||||
QCowHeader header;
|
||||
|
||||
if (bdrv_pread(bs->file, 0, &header, sizeof(header)) != sizeof(header))
|
||||
ret = bdrv_file_open(&s->hd, filename, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
|
||||
goto fail;
|
||||
be32_to_cpus(&header.magic);
|
||||
be32_to_cpus(&header.version);
|
||||
@@ -132,7 +135,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
|
||||
s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
|
||||
if (!s->l1_table)
|
||||
goto fail;
|
||||
if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
|
||||
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
|
||||
s->l1_size * sizeof(uint64_t))
|
||||
goto fail;
|
||||
for(i = 0;i < s->l1_size; i++) {
|
||||
@@ -155,7 +158,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
|
||||
len = header.backing_file_size;
|
||||
if (len > 1023)
|
||||
len = 1023;
|
||||
if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len)
|
||||
if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
|
||||
goto fail;
|
||||
bs->backing_file[len] = '\0';
|
||||
}
|
||||
@@ -166,6 +169,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
|
||||
qemu_free(s->l2_cache);
|
||||
qemu_free(s->cluster_cache);
|
||||
qemu_free(s->cluster_data);
|
||||
bdrv_delete(s->hd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -267,13 +271,13 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
if (!allocate)
|
||||
return 0;
|
||||
/* allocate a new l2 entry */
|
||||
l2_offset = bdrv_getlength(bs->file);
|
||||
l2_offset = bdrv_getlength(s->hd);
|
||||
/* round to cluster size */
|
||||
l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
|
||||
/* update the L1 entry */
|
||||
s->l1_table[l1_index] = l2_offset;
|
||||
tmp = cpu_to_be64(l2_offset);
|
||||
if (bdrv_pwrite_sync(bs->file,
|
||||
if (bdrv_pwrite_sync(s->hd,
|
||||
s->l1_table_offset + l1_index * sizeof(tmp),
|
||||
&tmp, sizeof(tmp)) < 0)
|
||||
return 0;
|
||||
@@ -303,11 +307,11 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
l2_table = s->l2_cache + (min_index << s->l2_bits);
|
||||
if (new_l2_table) {
|
||||
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
||||
if (bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
|
||||
if (bdrv_pwrite_sync(s->hd, l2_offset, l2_table,
|
||||
s->l2_size * sizeof(uint64_t)) < 0)
|
||||
return 0;
|
||||
} else {
|
||||
if (bdrv_pread(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
s->l2_size * sizeof(uint64_t))
|
||||
return 0;
|
||||
}
|
||||
@@ -326,22 +330,22 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
/* if the cluster is already compressed, we must
|
||||
decompress it in the case it is not completely
|
||||
overwritten */
|
||||
if (decompress_cluster(bs, cluster_offset) < 0)
|
||||
if (decompress_cluster(s, cluster_offset) < 0)
|
||||
return 0;
|
||||
cluster_offset = bdrv_getlength(bs->file);
|
||||
cluster_offset = bdrv_getlength(s->hd);
|
||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||
~(s->cluster_size - 1);
|
||||
/* write the cluster content */
|
||||
if (bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache, s->cluster_size) !=
|
||||
if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) !=
|
||||
s->cluster_size)
|
||||
return -1;
|
||||
} else {
|
||||
cluster_offset = bdrv_getlength(bs->file);
|
||||
cluster_offset = bdrv_getlength(s->hd);
|
||||
if (allocate == 1) {
|
||||
/* round to cluster size */
|
||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||
~(s->cluster_size - 1);
|
||||
bdrv_truncate(bs->file, cluster_offset + s->cluster_size);
|
||||
bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
|
||||
/* if encrypted, we must initialize the cluster
|
||||
content which won't be written */
|
||||
if (s->crypt_method &&
|
||||
@@ -355,7 +359,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
s->cluster_data,
|
||||
s->cluster_data + 512, 1, 1,
|
||||
&s->aes_encrypt_key);
|
||||
if (bdrv_pwrite(bs->file, cluster_offset + i * 512,
|
||||
if (bdrv_pwrite(s->hd, cluster_offset + i * 512,
|
||||
s->cluster_data, 512) != 512)
|
||||
return -1;
|
||||
}
|
||||
@@ -369,7 +373,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
/* update L2 table */
|
||||
tmp = cpu_to_be64(cluster_offset);
|
||||
l2_table[l2_index] = tmp;
|
||||
if (bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
|
||||
if (bdrv_pwrite_sync(s->hd, l2_offset + l2_index * sizeof(tmp),
|
||||
&tmp, sizeof(tmp)) < 0)
|
||||
return 0;
|
||||
}
|
||||
@@ -419,9 +423,8 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
||||
static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int ret, csize;
|
||||
uint64_t coffset;
|
||||
|
||||
@@ -429,7 +432,7 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
||||
if (s->cluster_cache_offset != coffset) {
|
||||
csize = cluster_offset >> (63 - s->cluster_bits);
|
||||
csize &= (s->cluster_size - 1);
|
||||
ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize);
|
||||
ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize);
|
||||
if (ret != csize)
|
||||
return -1;
|
||||
if (decompress_buffer(s->cluster_cache, s->cluster_size,
|
||||
@@ -466,11 +469,11 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
memset(buf, 0, 512 * n);
|
||||
}
|
||||
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
||||
if (decompress_cluster(bs, cluster_offset) < 0)
|
||||
if (decompress_cluster(s, cluster_offset) < 0)
|
||||
return -1;
|
||||
memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
|
||||
} else {
|
||||
ret = bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512);
|
||||
ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
|
||||
if (ret != n * 512)
|
||||
return -1;
|
||||
if (s->crypt_method) {
|
||||
@@ -503,7 +506,7 @@ typedef struct QCowAIOCB {
|
||||
|
||||
static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common);
|
||||
QCowAIOCB *acb = (QCowAIOCB *)blockacb;
|
||||
if (acb->hd_aiocb)
|
||||
bdrv_aio_cancel(acb->hd_aiocb);
|
||||
qemu_aio_release(acb);
|
||||
@@ -599,7 +602,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
|
||||
}
|
||||
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
||||
/* add AIO support for compressed blocks ? */
|
||||
if (decompress_cluster(bs, acb->cluster_offset) < 0)
|
||||
if (decompress_cluster(s, acb->cluster_offset) < 0)
|
||||
goto done;
|
||||
memcpy(acb->buf,
|
||||
s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
|
||||
@@ -612,7 +615,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
|
||||
acb->hd_iov.iov_base = (void *)acb->buf;
|
||||
acb->hd_iov.iov_len = acb->n * 512;
|
||||
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
|
||||
acb->hd_aiocb = bdrv_aio_readv(bs->file,
|
||||
acb->hd_aiocb = bdrv_aio_readv(s->hd,
|
||||
(acb->cluster_offset >> 9) + index_in_cluster,
|
||||
&acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
|
||||
if (acb->hd_aiocb == NULL)
|
||||
@@ -697,7 +700,7 @@ static void qcow_aio_write_cb(void *opaque, int ret)
|
||||
acb->hd_iov.iov_base = (void *)src_buf;
|
||||
acb->hd_iov.iov_len = acb->n * 512;
|
||||
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
|
||||
acb->hd_aiocb = bdrv_aio_writev(bs->file,
|
||||
acb->hd_aiocb = bdrv_aio_writev(s->hd,
|
||||
(cluster_offset >> 9) + index_in_cluster,
|
||||
&acb->hd_qiov, acb->n,
|
||||
qcow_aio_write_cb, acb);
|
||||
@@ -737,6 +740,7 @@ static void qcow_close(BlockDriverState *bs)
|
||||
qemu_free(s->l2_cache);
|
||||
qemu_free(s->cluster_cache);
|
||||
qemu_free(s->cluster_data);
|
||||
bdrv_delete(s->hd);
|
||||
}
|
||||
|
||||
static int qcow_create(const char *filename, QEMUOptionParameter *options)
|
||||
@@ -747,7 +751,6 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
|
||||
int64_t total_size = 0;
|
||||
const char *backing_file = NULL;
|
||||
int flags = 0;
|
||||
int ret;
|
||||
|
||||
/* Read out options */
|
||||
while (options && options->name) {
|
||||
@@ -763,7 +766,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
return -1;
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.magic = cpu_to_be32(QCOW_MAGIC);
|
||||
header.version = cpu_to_be32(QCOW_VERSION);
|
||||
@@ -799,34 +802,17 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
|
||||
}
|
||||
|
||||
/* write all the data */
|
||||
ret = qemu_write_full(fd, &header, sizeof(header));
|
||||
if (ret != sizeof(header)) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
write(fd, &header, sizeof(header));
|
||||
if (backing_file) {
|
||||
ret = qemu_write_full(fd, backing_file, backing_filename_len);
|
||||
if (ret != backing_filename_len) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
write(fd, backing_file, backing_filename_len);
|
||||
}
|
||||
lseek(fd, header_size, SEEK_SET);
|
||||
tmp = 0;
|
||||
for(i = 0;i < l1_size; i++) {
|
||||
ret = qemu_write_full(fd, &tmp, sizeof(tmp));
|
||||
if (ret != sizeof(tmp)) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
write(fd, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
exit:
|
||||
close(fd);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcow_make_empty(BlockDriverState *bs)
|
||||
@@ -836,10 +822,10 @@ static int qcow_make_empty(BlockDriverState *bs)
|
||||
int ret;
|
||||
|
||||
memset(s->l1_table, 0, l1_length);
|
||||
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
|
||||
if (bdrv_pwrite_sync(s->hd, s->l1_table_offset, s->l1_table,
|
||||
l1_length) < 0)
|
||||
return -1;
|
||||
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
|
||||
ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -900,7 +886,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
|
||||
out_len, 0, 0);
|
||||
cluster_offset &= s->cluster_offset_mask;
|
||||
if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) {
|
||||
if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
|
||||
qemu_free(out_buf);
|
||||
return -1;
|
||||
}
|
||||
@@ -912,13 +898,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
static void qcow_flush(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_flush(bs->file);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_flush(bs->file, cb, opaque);
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
bdrv_flush(s->hd);
|
||||
}
|
||||
|
||||
static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
@@ -961,7 +942,6 @@ static BlockDriver bdrv_qcow = {
|
||||
.bdrv_make_empty = qcow_make_empty,
|
||||
.bdrv_aio_readv = qcow_aio_readv,
|
||||
.bdrv_aio_writev = qcow_aio_writev,
|
||||
.bdrv_aio_flush = qcow_aio_flush,
|
||||
.bdrv_write_compressed = qcow_write_compressed,
|
||||
.bdrv_get_info = qcow_get_info,
|
||||
|
||||
|
||||
@@ -54,27 +54,24 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
|
||||
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
|
||||
|
||||
/* write new table (align to cluster) */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ALLOC_TABLE);
|
||||
new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
|
||||
if (new_l1_table_offset < 0) {
|
||||
qemu_free(new_l1_table);
|
||||
return new_l1_table_offset;
|
||||
}
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
|
||||
for(i = 0; i < s->l1_size; i++)
|
||||
new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
|
||||
ret = bdrv_pwrite_sync(bs->file, new_l1_table_offset, new_l1_table, new_l1_size2);
|
||||
ret = bdrv_pwrite_sync(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
for(i = 0; i < s->l1_size; i++)
|
||||
new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
|
||||
|
||||
/* set new table */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE);
|
||||
cpu_to_be32w((uint32_t*)data, new_l1_size);
|
||||
cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
|
||||
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size), data,sizeof(data));
|
||||
ret = bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, l1_size), data,sizeof(data));
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -157,36 +154,29 @@ static uint64_t *seek_l2_table(BDRVQcowState *s, uint64_t l2_offset)
|
||||
* the image file failed.
|
||||
*/
|
||||
|
||||
static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
|
||||
uint64_t **l2_table)
|
||||
static uint64_t *l2_load(BlockDriverState *bs, uint64_t l2_offset)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int min_index;
|
||||
int ret;
|
||||
uint64_t *l2_table;
|
||||
|
||||
/* seek if the table for the given offset is in the cache */
|
||||
|
||||
*l2_table = seek_l2_table(s, l2_offset);
|
||||
if (*l2_table != NULL) {
|
||||
return 0;
|
||||
}
|
||||
l2_table = seek_l2_table(s, l2_offset);
|
||||
if (l2_table != NULL)
|
||||
return l2_table;
|
||||
|
||||
/* not found: load a new entry in the least used one */
|
||||
|
||||
min_index = l2_cache_new_entry(bs);
|
||||
*l2_table = s->l2_cache + (min_index << s->l2_bits);
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
|
||||
ret = bdrv_pread(bs->file, l2_offset, *l2_table,
|
||||
s->l2_size * sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
l2_table = s->l2_cache + (min_index << s->l2_bits);
|
||||
if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
s->l2_size * sizeof(uint64_t))
|
||||
return NULL;
|
||||
s->l2_cache_offsets[min_index] = l2_offset;
|
||||
s->l2_cache_counts[min_index] = 1;
|
||||
|
||||
return 0;
|
||||
return l2_table;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -194,9 +184,8 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
|
||||
* and we really don't want bdrv_pread to perform a read-modify-write)
|
||||
*/
|
||||
#define L1_ENTRIES_PER_SECTOR (512 / 8)
|
||||
static int write_l1_entry(BlockDriverState *bs, int l1_index)
|
||||
static int write_l1_entry(BDRVQcowState *s, int l1_index)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t buf[L1_ENTRIES_PER_SECTOR];
|
||||
int l1_start_index;
|
||||
int i, ret;
|
||||
@@ -206,8 +195,7 @@ static int write_l1_entry(BlockDriverState *bs, int l1_index)
|
||||
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
|
||||
}
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
|
||||
ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset + 8 * l1_start_index,
|
||||
ret = bdrv_pwrite_sync(s->hd, s->l1_table_offset + 8 * l1_start_index,
|
||||
buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@@ -226,7 +214,7 @@ static int write_l1_entry(BlockDriverState *bs, int l1_index)
|
||||
*
|
||||
*/
|
||||
|
||||
static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
|
||||
static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int min_index;
|
||||
@@ -241,7 +229,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
|
||||
|
||||
l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
|
||||
if (l2_offset < 0) {
|
||||
return l2_offset;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* allocate a new entry in the l2 cache */
|
||||
@@ -254,16 +242,13 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
|
||||
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
||||
} else {
|
||||
/* if there was an old l2 table, read it from the disk */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
|
||||
ret = bdrv_pread(bs->file, old_l2_offset, l2_table,
|
||||
s->l2_size * sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
if (bdrv_pread(s->hd, old_l2_offset,
|
||||
l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
s->l2_size * sizeof(uint64_t))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
/* write the l2 table to the file */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
|
||||
ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
|
||||
ret = bdrv_pwrite_sync(s->hd, l2_offset, l2_table,
|
||||
s->l2_size * sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
@@ -271,8 +256,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
|
||||
|
||||
/* update the L1 entry */
|
||||
s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
|
||||
ret = write_l1_entry(bs, l1_index);
|
||||
if (ret < 0) {
|
||||
if (write_l1_entry(s, l1_index) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -281,13 +265,12 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
|
||||
s->l2_cache_offsets[min_index] = l2_offset;
|
||||
s->l2_cache_counts[min_index] = 1;
|
||||
|
||||
*table = l2_table;
|
||||
return 0;
|
||||
return l2_table;
|
||||
|
||||
fail:
|
||||
s->l1_table[l1_index] = old_l2_offset;
|
||||
qcow2_l2_cache_reset(bs);
|
||||
return ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
|
||||
@@ -351,20 +334,13 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
n = nb_sectors;
|
||||
|
||||
ret = qcow2_get_cluster_offset(bs, sector_num << 9, &n,
|
||||
&cluster_offset);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
cluster_offset = qcow2_get_cluster_offset(bs, sector_num << 9, &n);
|
||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||
if (!cluster_offset) {
|
||||
if (bs->backing_hd) {
|
||||
/* read from the base image */
|
||||
n1 = qcow2_backing_read1(bs->backing_hd, sector_num, buf, n);
|
||||
if (n1 > 0) {
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING);
|
||||
ret = bdrv_read(bs->backing_hd, sector_num, buf, n1);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
@@ -373,12 +349,11 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
memset(buf, 0, 512 * n);
|
||||
}
|
||||
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
||||
if (qcow2_decompress_cluster(bs, cluster_offset) < 0)
|
||||
if (qcow2_decompress_cluster(s, cluster_offset) < 0)
|
||||
return -1;
|
||||
memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
|
||||
} else {
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_READ);
|
||||
ret = bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512);
|
||||
ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
|
||||
if (ret != n * 512)
|
||||
return -1;
|
||||
if (s->crypt_method) {
|
||||
@@ -402,7 +377,6 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
|
||||
n = n_end - n_start;
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
|
||||
ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -412,8 +386,7 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
|
||||
s->cluster_data, n, 1,
|
||||
&s->aes_encrypt_key);
|
||||
}
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
|
||||
ret = bdrv_write_sync(bs->file, (cluster_offset >> 9) + n_start,
|
||||
ret = bdrv_write_sync(s->hd, (cluster_offset >> 9) + n_start,
|
||||
s->cluster_data, n);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -424,29 +397,28 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
|
||||
/*
|
||||
* get_cluster_offset
|
||||
*
|
||||
* For a given offset of the disk image, find the cluster offset in
|
||||
* qcow2 file. The offset is stored in *cluster_offset.
|
||||
* For a given offset of the disk image, return cluster offset in
|
||||
* qcow2 file.
|
||||
*
|
||||
* on entry, *num is the number of contiguous clusters we'd like to
|
||||
* access following offset.
|
||||
*
|
||||
* on exit, *num is the number of contiguous clusters we can read.
|
||||
*
|
||||
* Return 0, if the offset is found
|
||||
* Return -errno, otherwise.
|
||||
* Return 1, if the offset is found
|
||||
* Return 0, otherwise.
|
||||
*
|
||||
*/
|
||||
|
||||
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int *num, uint64_t *cluster_offset)
|
||||
uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int *num)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
unsigned int l1_index, l2_index;
|
||||
uint64_t l2_offset, *l2_table;
|
||||
uint64_t l2_offset, *l2_table, cluster_offset;
|
||||
int l1_bits, c;
|
||||
unsigned int index_in_cluster, nb_clusters;
|
||||
uint64_t nb_available, nb_needed;
|
||||
int ret;
|
||||
|
||||
index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1);
|
||||
nb_needed = *num + index_in_cluster;
|
||||
@@ -467,7 +439,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
nb_needed = nb_available;
|
||||
}
|
||||
|
||||
*cluster_offset = 0;
|
||||
cluster_offset = 0;
|
||||
|
||||
/* seek the the l2 offset in the l1 table */
|
||||
|
||||
@@ -485,18 +457,17 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
/* load the l2 table in memory */
|
||||
|
||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
||||
ret = l2_load(bs, l2_offset, &l2_table);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
l2_table = l2_load(bs, l2_offset);
|
||||
if (l2_table == NULL)
|
||||
return 0;
|
||||
|
||||
/* find the cluster offset for the given disk offset */
|
||||
|
||||
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
|
||||
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
||||
cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
||||
nb_clusters = size_to_clusters(s, nb_needed << 9);
|
||||
|
||||
if (!*cluster_offset) {
|
||||
if (!cluster_offset) {
|
||||
/* how many empty clusters ? */
|
||||
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
|
||||
} else {
|
||||
@@ -512,8 +483,7 @@ out:
|
||||
|
||||
*num = nb_available - index_in_cluster;
|
||||
|
||||
*cluster_offset &=~QCOW_OFLAG_COPIED;
|
||||
return 0;
|
||||
return cluster_offset & ~QCOW_OFLAG_COPIED;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -534,8 +504,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
unsigned int l1_index, l2_index;
|
||||
uint64_t l2_offset;
|
||||
uint64_t *l2_table = NULL;
|
||||
uint64_t l2_offset, *l2_table;
|
||||
int ret;
|
||||
|
||||
/* seek the the l2 offset in the l1 table */
|
||||
@@ -554,16 +523,16 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
||||
if (l2_offset & QCOW_OFLAG_COPIED) {
|
||||
/* load the l2 table in memory */
|
||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
||||
ret = l2_load(bs, l2_offset, &l2_table);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
l2_table = l2_load(bs, l2_offset);
|
||||
if (l2_table == NULL) {
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
if (l2_offset)
|
||||
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
|
||||
ret = l2_allocate(bs, l1_index, &l2_table);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
l2_table = l2_allocate(bs, l1_index);
|
||||
if (l2_table == NULL) {
|
||||
return -EIO;
|
||||
}
|
||||
l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
|
||||
}
|
||||
@@ -629,9 +598,8 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
|
||||
/* compressed clusters never have the copied flag */
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
|
||||
l2_table[l2_index] = cpu_to_be64(cluster_offset);
|
||||
if (bdrv_pwrite_sync(bs->file,
|
||||
if (bdrv_pwrite_sync(s->hd,
|
||||
l2_offset + l2_index * sizeof(uint64_t),
|
||||
l2_table + l2_index,
|
||||
sizeof(uint64_t)) < 0)
|
||||
@@ -645,7 +613,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
* read-modify-write in bdrv_pwrite
|
||||
*/
|
||||
#define L2_ENTRIES_PER_SECTOR (512 / 8)
|
||||
static int write_l2_entries(BlockDriverState *bs, uint64_t *l2_table,
|
||||
static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table,
|
||||
uint64_t l2_offset, int l2_index, int num)
|
||||
{
|
||||
int l2_start_index = l2_index & ~(L1_ENTRIES_PER_SECTOR - 1);
|
||||
@@ -654,8 +622,7 @@ static int write_l2_entries(BlockDriverState *bs, uint64_t *l2_table,
|
||||
size_t len = end_offset - start_offset;
|
||||
int ret;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
|
||||
ret = bdrv_pwrite_sync(bs->file, l2_offset + start_offset,
|
||||
ret = bdrv_pwrite_sync(s->hd, l2_offset + start_offset,
|
||||
&l2_table[l2_start_index], len);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@@ -712,7 +679,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
||||
(i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
|
||||
}
|
||||
|
||||
ret = write_l2_entries(bs, l2_table, l2_offset, l2_index, m->nb_clusters);
|
||||
ret = write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters);
|
||||
if (ret < 0) {
|
||||
qcow2_l2_cache_reset(bs);
|
||||
goto err;
|
||||
@@ -897,9 +864,8 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
||||
int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int ret, csize, nb_csectors, sector_offset;
|
||||
uint64_t coffset;
|
||||
|
||||
@@ -908,8 +874,7 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
||||
nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
|
||||
sector_offset = coffset & 511;
|
||||
csize = nb_csectors * 512 - sector_offset;
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
|
||||
ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data, nb_csectors);
|
||||
ret = bdrv_read(s->hd, coffset >> 9, s->cluster_data, nb_csectors);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -34,17 +34,15 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
|
||||
static int cache_refcount_updates = 0;
|
||||
|
||||
static int write_refcount_block(BlockDriverState *bs)
|
||||
static int write_refcount_block(BDRVQcowState *s)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
size_t size = s->cluster_size;
|
||||
|
||||
if (s->refcount_block_cache_offset == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE);
|
||||
if (bdrv_pwrite_sync(bs->file, s->refcount_block_cache_offset,
|
||||
if (bdrv_pwrite_sync(s->hd, s->refcount_block_cache_offset,
|
||||
s->refcount_block_cache, size) < 0)
|
||||
{
|
||||
return -EIO;
|
||||
@@ -65,8 +63,7 @@ int qcow2_refcount_init(BlockDriverState *bs)
|
||||
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
|
||||
s->refcount_table = qemu_malloc(refcount_table_size2);
|
||||
if (s->refcount_table_size > 0) {
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
|
||||
ret = bdrv_pread(bs->file, s->refcount_table_offset,
|
||||
ret = bdrv_pread(s->hd, s->refcount_table_offset,
|
||||
s->refcount_table, refcount_table_size2);
|
||||
if (ret != refcount_table_size2)
|
||||
goto fail;
|
||||
@@ -93,34 +90,22 @@ static int load_refcount_block(BlockDriverState *bs,
|
||||
int ret;
|
||||
|
||||
if (cache_refcount_updates) {
|
||||
ret = write_refcount_block(bs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
write_refcount_block(s);
|
||||
}
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_LOAD);
|
||||
ret = bdrv_pread(bs->file, refcount_block_offset, s->refcount_block_cache,
|
||||
ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache,
|
||||
s->cluster_size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret != s->cluster_size)
|
||||
return -EIO;
|
||||
s->refcount_block_cache_offset = refcount_block_offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the refcount of the cluster given by its index. Any non-negative
|
||||
* return value is the refcount of the cluster, negative values are -errno
|
||||
* and indicate an error.
|
||||
*/
|
||||
static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int refcount_table_index, block_index;
|
||||
int64_t refcount_block_offset;
|
||||
int ret;
|
||||
|
||||
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
|
||||
if (refcount_table_index >= s->refcount_table_size)
|
||||
@@ -130,10 +115,8 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
||||
return 0;
|
||||
if (refcount_block_offset != s->refcount_block_cache_offset) {
|
||||
/* better than nothing: return allocated if read error */
|
||||
ret = load_refcount_block(bs, refcount_block_offset);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (load_refcount_block(bs, refcount_block_offset) < 0)
|
||||
return 1;
|
||||
}
|
||||
block_index = cluster_index &
|
||||
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
|
||||
@@ -181,8 +164,6 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
|
||||
unsigned int refcount_table_index;
|
||||
int ret;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC);
|
||||
|
||||
/* Find the refcount block for the given cluster */
|
||||
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
|
||||
|
||||
@@ -226,17 +207,14 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
|
||||
*/
|
||||
|
||||
if (cache_refcount_updates) {
|
||||
ret = write_refcount_block(bs);
|
||||
ret = write_refcount_block(s);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate the refcount block itself and mark it as used */
|
||||
int64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
|
||||
if (new_block < 0) {
|
||||
return new_block;
|
||||
}
|
||||
uint64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
|
||||
|
||||
#ifdef DEBUG_ALLOC2
|
||||
fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64
|
||||
@@ -268,8 +246,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
|
||||
}
|
||||
|
||||
/* Now the new refcount block needs to be written to disk */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
|
||||
ret = bdrv_pwrite_sync(bs->file, new_block, s->refcount_block_cache,
|
||||
ret = bdrv_pwrite_sync(s->hd, new_block, s->refcount_block_cache,
|
||||
s->cluster_size);
|
||||
if (ret < 0) {
|
||||
goto fail_block;
|
||||
@@ -278,8 +255,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
|
||||
/* If the refcount table is big enough, just hook the block up there */
|
||||
if (refcount_table_index < s->refcount_table_size) {
|
||||
uint64_t data64 = cpu_to_be64(new_block);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
|
||||
ret = bdrv_pwrite_sync(bs->file,
|
||||
ret = bdrv_pwrite_sync(s->hd,
|
||||
s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
|
||||
&data64, sizeof(data64));
|
||||
if (ret < 0) {
|
||||
@@ -301,8 +277,6 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
|
||||
* refcount table at once without producing an inconsistent state in
|
||||
* between.
|
||||
*/
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_GROW);
|
||||
|
||||
/* Calculate the number of refcount blocks needed so far */
|
||||
uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
|
||||
uint64_t blocks_used = (s->free_cluster_index +
|
||||
@@ -358,8 +332,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
|
||||
}
|
||||
|
||||
/* Write refcount blocks to disk */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
|
||||
ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
|
||||
ret = bdrv_pwrite_sync(s->hd, meta_offset, new_blocks,
|
||||
blocks_clusters * s->cluster_size);
|
||||
qemu_free(new_blocks);
|
||||
if (ret < 0) {
|
||||
@@ -371,8 +344,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
|
||||
cpu_to_be64s(&new_table[i]);
|
||||
}
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
|
||||
ret = bdrv_pwrite_sync(bs->file, table_offset, new_table,
|
||||
ret = bdrv_pwrite_sync(s->hd, table_offset, new_table,
|
||||
table_size * sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
goto fail_table;
|
||||
@@ -386,8 +358,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
|
||||
uint8_t data[12];
|
||||
cpu_to_be64w((uint64_t*)data, table_offset);
|
||||
cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE);
|
||||
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, refcount_table_offset),
|
||||
ret = bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, refcount_table_offset),
|
||||
data, sizeof(data));
|
||||
if (ret < 0) {
|
||||
goto fail_table;
|
||||
@@ -422,10 +393,9 @@ fail_block:
|
||||
}
|
||||
|
||||
#define REFCOUNTS_PER_SECTOR (512 >> REFCOUNT_SHIFT)
|
||||
static int write_refcount_block_entries(BlockDriverState *bs,
|
||||
static int write_refcount_block_entries(BDRVQcowState *s,
|
||||
int64_t refcount_block_offset, int first_index, int last_index)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
@@ -442,9 +412,7 @@ static int write_refcount_block_entries(BlockDriverState *bs,
|
||||
& ~(REFCOUNTS_PER_SECTOR - 1);
|
||||
|
||||
size = (last_index - first_index) << REFCOUNT_SHIFT;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
|
||||
ret = bdrv_pwrite_sync(bs->file,
|
||||
ret = bdrv_pwrite_sync(s->hd,
|
||||
refcount_block_offset + (first_index << REFCOUNT_SHIFT),
|
||||
&s->refcount_block_cache[first_index], size);
|
||||
if (ret < 0) {
|
||||
@@ -489,10 +457,10 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
|
||||
if ((old_table_index >= 0) && (table_index != old_table_index)) {
|
||||
|
||||
ret = write_refcount_block_entries(bs, refcount_block_offset,
|
||||
first_index, last_index);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
if (write_refcount_block_entries(s, refcount_block_offset,
|
||||
first_index, last_index) < 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
first_index = -1;
|
||||
@@ -534,11 +502,10 @@ fail:
|
||||
|
||||
/* Write last changed block to disk */
|
||||
if (refcount_block_offset != 0) {
|
||||
int wret;
|
||||
wret = write_refcount_block_entries(bs, refcount_block_offset,
|
||||
first_index, last_index);
|
||||
if (wret < 0) {
|
||||
return ret < 0 ? ret : wret;
|
||||
if (write_refcount_block_entries(s, refcount_block_offset,
|
||||
first_index, last_index) < 0)
|
||||
{
|
||||
return ret < 0 ? ret : -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,13 +521,7 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increases or decreases the refcount of a given cluster by one.
|
||||
* addend must be 1 or -1.
|
||||
*
|
||||
* If the return value is non-negative, it is the new refcount of the cluster.
|
||||
* If it is negative, it is -errno and indicates an error.
|
||||
*/
|
||||
/* addend must be 1 or -1 */
|
||||
static int update_cluster_refcount(BlockDriverState *bs,
|
||||
int64_t cluster_index,
|
||||
int addend)
|
||||
@@ -587,19 +548,14 @@ static int update_cluster_refcount(BlockDriverState *bs,
|
||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int i, nb_clusters, refcount;
|
||||
int i, nb_clusters;
|
||||
|
||||
nb_clusters = size_to_clusters(s, size);
|
||||
retry:
|
||||
for(i = 0; i < nb_clusters; i++) {
|
||||
int64_t next_cluster_index = s->free_cluster_index++;
|
||||
refcount = get_refcount(bs, next_cluster_index);
|
||||
|
||||
if (refcount < 0) {
|
||||
return refcount;
|
||||
} else if (refcount != 0) {
|
||||
int64_t i = s->free_cluster_index++;
|
||||
if (get_refcount(bs, i) != 0)
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_ALLOC2
|
||||
printf("alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
|
||||
@@ -614,12 +570,7 @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
|
||||
int64_t offset;
|
||||
int ret;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
|
||||
offset = alloc_clusters_noref(bs, size);
|
||||
if (offset < 0) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
ret = update_refcount(bs, offset, size, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@@ -635,7 +586,6 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
||||
int64_t offset, cluster_offset;
|
||||
int free_in_cluster;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_BYTES);
|
||||
assert(size > 0 && size <= s->cluster_size);
|
||||
if (s->free_byte_offset == 0) {
|
||||
s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size);
|
||||
@@ -679,7 +629,6 @@ void qcow2_free_clusters(BlockDriverState *bs,
|
||||
{
|
||||
int ret;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_FREE);
|
||||
ret = update_refcount(bs, offset, size, -1);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
|
||||
@@ -756,6 +705,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
l2_table = NULL;
|
||||
l1_table = NULL;
|
||||
l1_size2 = l1_size * sizeof(uint64_t);
|
||||
l1_allocated = 0;
|
||||
if (l1_table_offset != s->l1_table_offset) {
|
||||
if (l1_size2 != 0) {
|
||||
l1_table = qemu_mallocz(align_offset(l1_size2, 512));
|
||||
@@ -763,7 +713,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
l1_table = NULL;
|
||||
}
|
||||
l1_allocated = 1;
|
||||
if (bdrv_pread(bs->file, l1_table_offset,
|
||||
if (bdrv_pread(s->hd, l1_table_offset,
|
||||
l1_table, l1_size2) != l1_size2)
|
||||
goto fail;
|
||||
for(i = 0;i < l1_size; i++)
|
||||
@@ -783,7 +733,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
old_l2_offset = l2_offset;
|
||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
||||
l2_modified = 0;
|
||||
if (bdrv_pread(bs->file, l2_offset, l2_table, l2_size) != l2_size)
|
||||
if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
|
||||
goto fail;
|
||||
for(j = 0; j < s->l2_size; j++) {
|
||||
offset = be64_to_cpu(l2_table[j]);
|
||||
@@ -810,10 +760,6 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
} else {
|
||||
refcount = get_refcount(bs, offset >> s->cluster_bits);
|
||||
}
|
||||
|
||||
if (refcount < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (refcount == 1) {
|
||||
@@ -826,7 +772,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
if (l2_modified) {
|
||||
if (bdrv_pwrite_sync(bs->file,
|
||||
if (bdrv_pwrite_sync(s->hd,
|
||||
l2_offset, l2_table, l2_size) < 0)
|
||||
goto fail;
|
||||
}
|
||||
@@ -836,9 +782,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
} else {
|
||||
refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
|
||||
}
|
||||
if (refcount < 0) {
|
||||
goto fail;
|
||||
} else if (refcount == 1) {
|
||||
if (refcount == 1) {
|
||||
l2_offset |= QCOW_OFLAG_COPIED;
|
||||
}
|
||||
if (l2_offset != old_l2_offset) {
|
||||
@@ -850,7 +794,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
if (l1_modified) {
|
||||
for(i = 0; i < l1_size; i++)
|
||||
cpu_to_be64s(&l1_table[i]);
|
||||
if (bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table,
|
||||
if (bdrv_pwrite_sync(s->hd, l1_table_offset, l1_table,
|
||||
l1_size2) < 0)
|
||||
goto fail;
|
||||
for(i = 0; i < l1_size; i++)
|
||||
@@ -860,14 +804,14 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
qemu_free(l1_table);
|
||||
qemu_free(l2_table);
|
||||
cache_refcount_updates = 0;
|
||||
write_refcount_block(bs);
|
||||
write_refcount_block(s);
|
||||
return 0;
|
||||
fail:
|
||||
if (l1_allocated)
|
||||
qemu_free(l1_table);
|
||||
qemu_free(l2_table);
|
||||
cache_refcount_updates = 0;
|
||||
write_refcount_block(bs);
|
||||
write_refcount_block(s);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -884,10 +828,9 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
* This is used to construct a temporary refcount table out of L1 and L2 tables
|
||||
* which can be compared the the refcount table saved in the image.
|
||||
*
|
||||
* Modifies the number of errors in res.
|
||||
* Returns the number of errors in the image that were found
|
||||
*/
|
||||
static void inc_refcounts(BlockDriverState *bs,
|
||||
BdrvCheckResult *res,
|
||||
static int inc_refcounts(BlockDriverState *bs,
|
||||
uint16_t *refcount_table,
|
||||
int refcount_table_size,
|
||||
int64_t offset, int64_t size)
|
||||
@@ -895,32 +838,30 @@ static void inc_refcounts(BlockDriverState *bs,
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int64_t start, last, cluster_offset;
|
||||
int k;
|
||||
int errors = 0;
|
||||
|
||||
if (size <= 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
start = offset & ~(s->cluster_size - 1);
|
||||
last = (offset + size - 1) & ~(s->cluster_size - 1);
|
||||
for(cluster_offset = start; cluster_offset <= last;
|
||||
cluster_offset += s->cluster_size) {
|
||||
k = cluster_offset >> s->cluster_bits;
|
||||
if (k < 0) {
|
||||
if (k < 0 || k >= refcount_table_size) {
|
||||
fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
|
||||
cluster_offset);
|
||||
res->corruptions++;
|
||||
} else if (k >= refcount_table_size) {
|
||||
fprintf(stderr, "Warning: cluster offset=0x%" PRIx64 " is after "
|
||||
"the end of the image file, can't properly check refcounts.\n",
|
||||
cluster_offset);
|
||||
res->check_errors++;
|
||||
errors++;
|
||||
} else {
|
||||
if (++refcount_table[k] == 0) {
|
||||
fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64
|
||||
"\n", cluster_offset);
|
||||
res->corruptions++;
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -931,19 +872,20 @@ static void inc_refcounts(BlockDriverState *bs,
|
||||
* Returns the number of errors found by the checks or -errno if an internal
|
||||
* error occurred.
|
||||
*/
|
||||
static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
static int check_refcounts_l2(BlockDriverState *bs,
|
||||
uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset,
|
||||
int check_copied)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t *l2_table, offset;
|
||||
int i, l2_size, nb_csectors, refcount;
|
||||
int errors = 0;
|
||||
|
||||
/* Read L2 table from disk */
|
||||
l2_size = s->l2_size * sizeof(uint64_t);
|
||||
l2_table = qemu_malloc(l2_size);
|
||||
|
||||
if (bdrv_pread(bs->file, l2_offset, l2_table, l2_size) != l2_size)
|
||||
if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
|
||||
goto fail;
|
||||
|
||||
/* Do the actual checks */
|
||||
@@ -957,53 +899,50 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
"copied flag must never be set for compressed "
|
||||
"clusters\n", offset >> s->cluster_bits);
|
||||
offset &= ~QCOW_OFLAG_COPIED;
|
||||
res->corruptions++;
|
||||
errors++;
|
||||
}
|
||||
|
||||
/* Mark cluster as used */
|
||||
nb_csectors = ((offset >> s->csize_shift) &
|
||||
s->csize_mask) + 1;
|
||||
offset &= s->cluster_offset_mask;
|
||||
inc_refcounts(bs, res, refcount_table, refcount_table_size,
|
||||
offset & ~511, nb_csectors * 512);
|
||||
errors += inc_refcounts(bs, refcount_table,
|
||||
refcount_table_size,
|
||||
offset & ~511, nb_csectors * 512);
|
||||
} else {
|
||||
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
|
||||
if (check_copied) {
|
||||
uint64_t entry = offset;
|
||||
offset &= ~QCOW_OFLAG_COPIED;
|
||||
refcount = get_refcount(bs, offset >> s->cluster_bits);
|
||||
if (refcount < 0) {
|
||||
fprintf(stderr, "Can't get refcount for offset %"
|
||||
PRIx64 ": %s\n", entry, strerror(-refcount));
|
||||
goto fail;
|
||||
}
|
||||
if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) {
|
||||
fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
|
||||
PRIx64 " refcount=%d\n", entry, refcount);
|
||||
res->corruptions++;
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark cluster as used */
|
||||
offset &= ~QCOW_OFLAG_COPIED;
|
||||
inc_refcounts(bs, res, refcount_table,refcount_table_size,
|
||||
offset, s->cluster_size);
|
||||
errors += inc_refcounts(bs, refcount_table,
|
||||
refcount_table_size,
|
||||
offset, s->cluster_size);
|
||||
|
||||
/* Correct offsets are cluster aligned */
|
||||
if (offset & (s->cluster_size - 1)) {
|
||||
fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
|
||||
"properly aligned; L2 entry corrupted.\n", offset);
|
||||
res->corruptions++;
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qemu_free(l2_table);
|
||||
return 0;
|
||||
return errors;
|
||||
|
||||
fail:
|
||||
fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
|
||||
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
|
||||
qemu_free(l2_table);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -1017,7 +956,6 @@ fail:
|
||||
* error occurred.
|
||||
*/
|
||||
static int check_refcounts_l1(BlockDriverState *bs,
|
||||
BdrvCheckResult *res,
|
||||
uint16_t *refcount_table,
|
||||
int refcount_table_size,
|
||||
int64_t l1_table_offset, int l1_size,
|
||||
@@ -1026,19 +964,20 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t *l1_table, l2_offset, l1_size2;
|
||||
int i, refcount, ret;
|
||||
int errors = 0;
|
||||
|
||||
l1_size2 = l1_size * sizeof(uint64_t);
|
||||
|
||||
/* Mark L1 table as used */
|
||||
inc_refcounts(bs, res, refcount_table, refcount_table_size,
|
||||
l1_table_offset, l1_size2);
|
||||
errors += inc_refcounts(bs, refcount_table, refcount_table_size,
|
||||
l1_table_offset, l1_size2);
|
||||
|
||||
/* Read L1 table entries from disk */
|
||||
if (l1_size2 == 0) {
|
||||
l1_table = NULL;
|
||||
} else {
|
||||
l1_table = qemu_malloc(l1_size2);
|
||||
if (bdrv_pread(bs->file, l1_table_offset,
|
||||
if (bdrv_pread(s->hd, l1_table_offset,
|
||||
l1_table, l1_size2) != l1_size2)
|
||||
goto fail;
|
||||
for(i = 0;i < l1_size; i++)
|
||||
@@ -1053,44 +992,41 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||
if (check_copied) {
|
||||
refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED)
|
||||
>> s->cluster_bits);
|
||||
if (refcount < 0) {
|
||||
fprintf(stderr, "Can't get refcount for l2_offset %"
|
||||
PRIx64 ": %s\n", l2_offset, strerror(-refcount));
|
||||
goto fail;
|
||||
}
|
||||
if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
|
||||
fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64
|
||||
" refcount=%d\n", l2_offset, refcount);
|
||||
res->corruptions++;
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark L2 table as used */
|
||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
||||
inc_refcounts(bs, res, refcount_table, refcount_table_size,
|
||||
l2_offset, s->cluster_size);
|
||||
errors += inc_refcounts(bs, refcount_table,
|
||||
refcount_table_size,
|
||||
l2_offset,
|
||||
s->cluster_size);
|
||||
|
||||
/* L2 tables are cluster aligned */
|
||||
if (l2_offset & (s->cluster_size - 1)) {
|
||||
fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
|
||||
"cluster aligned; L1 entry corrupted\n", l2_offset);
|
||||
res->corruptions++;
|
||||
errors++;
|
||||
}
|
||||
|
||||
/* Process and check L2 entries */
|
||||
ret = check_refcounts_l2(bs, res, refcount_table,
|
||||
refcount_table_size, l2_offset, check_copied);
|
||||
ret = check_refcounts_l2(bs, refcount_table, refcount_table_size,
|
||||
l2_offset, check_copied);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
errors += ret;
|
||||
}
|
||||
}
|
||||
qemu_free(l1_table);
|
||||
return 0;
|
||||
return errors;
|
||||
|
||||
fail:
|
||||
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
|
||||
res->check_errors++;
|
||||
qemu_free(l1_table);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -1101,102 +1037,66 @@ fail:
|
||||
* Returns 0 if no errors are found, the number of errors in case the image is
|
||||
* detected as corrupted, and -errno when an internal error occured.
|
||||
*/
|
||||
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
|
||||
int qcow2_check_refcounts(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int64_t size;
|
||||
int nb_clusters, refcount1, refcount2, i;
|
||||
QCowSnapshot *sn;
|
||||
uint16_t *refcount_table;
|
||||
int ret;
|
||||
int ret, errors = 0;
|
||||
|
||||
size = bdrv_getlength(bs->file);
|
||||
size = bdrv_getlength(s->hd);
|
||||
nb_clusters = size_to_clusters(s, size);
|
||||
refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
|
||||
|
||||
/* header */
|
||||
inc_refcounts(bs, res, refcount_table, nb_clusters,
|
||||
0, s->cluster_size);
|
||||
errors += inc_refcounts(bs, refcount_table, nb_clusters,
|
||||
0, s->cluster_size);
|
||||
|
||||
/* current L1 table */
|
||||
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
|
||||
ret = check_refcounts_l1(bs, refcount_table, nb_clusters,
|
||||
s->l1_table_offset, s->l1_size, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
errors += ret;
|
||||
|
||||
/* snapshots */
|
||||
for(i = 0; i < s->nb_snapshots; i++) {
|
||||
sn = s->snapshots + i;
|
||||
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
|
||||
sn->l1_table_offset, sn->l1_size, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
check_refcounts_l1(bs, refcount_table, nb_clusters,
|
||||
sn->l1_table_offset, sn->l1_size, 0);
|
||||
}
|
||||
inc_refcounts(bs, res, refcount_table, nb_clusters,
|
||||
s->snapshots_offset, s->snapshots_size);
|
||||
errors += inc_refcounts(bs, refcount_table, nb_clusters,
|
||||
s->snapshots_offset, s->snapshots_size);
|
||||
|
||||
/* refcount data */
|
||||
inc_refcounts(bs, res, refcount_table, nb_clusters,
|
||||
s->refcount_table_offset,
|
||||
s->refcount_table_size * sizeof(uint64_t));
|
||||
|
||||
errors += inc_refcounts(bs, refcount_table, nb_clusters,
|
||||
s->refcount_table_offset,
|
||||
s->refcount_table_size * sizeof(uint64_t));
|
||||
for(i = 0; i < s->refcount_table_size; i++) {
|
||||
uint64_t offset, cluster;
|
||||
int64_t offset;
|
||||
offset = s->refcount_table[i];
|
||||
cluster = offset >> s->cluster_bits;
|
||||
|
||||
/* Refcount blocks are cluster aligned */
|
||||
if (offset & (s->cluster_size - 1)) {
|
||||
fprintf(stderr, "ERROR refcount block %d is not "
|
||||
"cluster aligned; refcount table entry corrupted\n", i);
|
||||
res->corruptions++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cluster >= nb_clusters) {
|
||||
fprintf(stderr, "ERROR refcount block %d is outside image\n", i);
|
||||
res->corruptions++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (offset != 0) {
|
||||
inc_refcounts(bs, res, refcount_table, nb_clusters,
|
||||
offset, s->cluster_size);
|
||||
if (refcount_table[cluster] != 1) {
|
||||
fprintf(stderr, "ERROR refcount block %d refcount=%d\n",
|
||||
i, refcount_table[cluster]);
|
||||
res->corruptions++;
|
||||
}
|
||||
errors += inc_refcounts(bs, refcount_table, nb_clusters,
|
||||
offset, s->cluster_size);
|
||||
}
|
||||
}
|
||||
|
||||
/* compare ref counts */
|
||||
for(i = 0; i < nb_clusters; i++) {
|
||||
refcount1 = get_refcount(bs, i);
|
||||
if (refcount1 < 0) {
|
||||
fprintf(stderr, "Can't get refcount for cluster %d: %s\n",
|
||||
i, strerror(-refcount1));
|
||||
res->check_errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
refcount2 = refcount_table[i];
|
||||
if (refcount1 != refcount2) {
|
||||
fprintf(stderr, "%s cluster %d refcount=%d reference=%d\n",
|
||||
refcount1 < refcount2 ? "ERROR" : "Leaked",
|
||||
fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n",
|
||||
i, refcount1, refcount2);
|
||||
if (refcount1 < refcount2) {
|
||||
res->corruptions++;
|
||||
} else {
|
||||
res->leaks++;
|
||||
}
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
qemu_free(refcount_table);
|
||||
|
||||
return 0;
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
|
||||
s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
|
||||
for(i = 0; i < s->nb_snapshots; i++) {
|
||||
offset = align_offset(offset, 8);
|
||||
if (bdrv_pread(bs->file, offset, &h, sizeof(h)) != sizeof(h))
|
||||
if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
|
||||
goto fail;
|
||||
offset += sizeof(h);
|
||||
sn = s->snapshots + i;
|
||||
@@ -97,13 +97,13 @@ int qcow2_read_snapshots(BlockDriverState *bs)
|
||||
offset += extra_data_size;
|
||||
|
||||
sn->id_str = qemu_malloc(id_str_size + 1);
|
||||
if (bdrv_pread(bs->file, offset, sn->id_str, id_str_size) != id_str_size)
|
||||
if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
|
||||
goto fail;
|
||||
offset += id_str_size;
|
||||
sn->id_str[id_str_size] = '\0';
|
||||
|
||||
sn->name = qemu_malloc(name_size + 1);
|
||||
if (bdrv_pread(bs->file, offset, sn->name, name_size) != name_size)
|
||||
if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
|
||||
goto fail;
|
||||
offset += name_size;
|
||||
sn->name[name_size] = '\0';
|
||||
@@ -158,24 +158,24 @@ static int qcow_write_snapshots(BlockDriverState *bs)
|
||||
h.id_str_size = cpu_to_be16(id_str_size);
|
||||
h.name_size = cpu_to_be16(name_size);
|
||||
offset = align_offset(offset, 8);
|
||||
if (bdrv_pwrite_sync(bs->file, offset, &h, sizeof(h)) < 0)
|
||||
if (bdrv_pwrite_sync(s->hd, offset, &h, sizeof(h)) < 0)
|
||||
goto fail;
|
||||
offset += sizeof(h);
|
||||
if (bdrv_pwrite_sync(bs->file, offset, sn->id_str, id_str_size) < 0)
|
||||
if (bdrv_pwrite_sync(s->hd, offset, sn->id_str, id_str_size) < 0)
|
||||
goto fail;
|
||||
offset += id_str_size;
|
||||
if (bdrv_pwrite_sync(bs->file, offset, sn->name, name_size) < 0)
|
||||
if (bdrv_pwrite_sync(s->hd, offset, sn->name, name_size) < 0)
|
||||
goto fail;
|
||||
offset += name_size;
|
||||
}
|
||||
|
||||
/* update the various header fields */
|
||||
data64 = cpu_to_be64(snapshots_offset);
|
||||
if (bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, snapshots_offset),
|
||||
if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, snapshots_offset),
|
||||
&data64, sizeof(data64)) < 0)
|
||||
goto fail;
|
||||
data32 = cpu_to_be32(s->nb_snapshots);
|
||||
if (bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
|
||||
if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, nb_snapshots),
|
||||
&data32, sizeof(data32)) < 0)
|
||||
goto fail;
|
||||
|
||||
@@ -284,7 +284,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
for(i = 0; i < s->l1_size; i++) {
|
||||
l1_table[i] = cpu_to_be64(s->l1_table[i]);
|
||||
}
|
||||
if (bdrv_pwrite_sync(bs->file, sn->l1_table_offset,
|
||||
if (bdrv_pwrite_sync(s->hd, sn->l1_table_offset,
|
||||
l1_table, s->l1_size * sizeof(uint64_t)) < 0)
|
||||
goto fail;
|
||||
qemu_free(l1_table);
|
||||
@@ -331,10 +331,10 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
||||
s->l1_size = sn->l1_size;
|
||||
l1_size2 = s->l1_size * sizeof(uint64_t);
|
||||
/* copy the snapshot l1 table to the current l1 table */
|
||||
if (bdrv_pread(bs->file, sn->l1_table_offset,
|
||||
if (bdrv_pread(s->hd, sn->l1_table_offset,
|
||||
s->l1_table, l1_size2) != l1_size2)
|
||||
goto fail;
|
||||
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset,
|
||||
if (bdrv_pwrite_sync(s->hd, s->l1_table_offset,
|
||||
s->l1_table, l1_size2) < 0)
|
||||
goto fail;
|
||||
for(i = 0;i < s->l1_size; i++) {
|
||||
|
||||
374
block/qcow2.c
374
block/qcow2.c
@@ -52,6 +52,8 @@ typedef struct {
|
||||
#define QCOW_EXT_MAGIC_END 0
|
||||
#define QCOW_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
|
||||
|
||||
|
||||
|
||||
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
const QCowHeader *cow_header = (const void *)buf;
|
||||
@@ -75,6 +77,7 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
uint64_t end_offset)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
QCowExtension ext;
|
||||
uint64_t offset;
|
||||
|
||||
@@ -92,10 +95,9 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
printf("attemting to read extended header in offset %lu\n", offset);
|
||||
#endif
|
||||
|
||||
if (bdrv_pread(bs->file, offset, &ext, sizeof(ext)) != sizeof(ext)) {
|
||||
fprintf(stderr, "qcow_handle_extension: ERROR: "
|
||||
"pread fail from offset %" PRIu64 "\n",
|
||||
offset);
|
||||
if (bdrv_pread(s->hd, offset, &ext, sizeof(ext)) != sizeof(ext)) {
|
||||
fprintf(stderr, "qcow_handle_extension: ERROR: pread fail from offset %llu\n",
|
||||
(unsigned long long)offset);
|
||||
return 1;
|
||||
}
|
||||
be32_to_cpus(&ext.magic);
|
||||
@@ -115,7 +117,7 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
ext.len, sizeof(bs->backing_format));
|
||||
return 2;
|
||||
}
|
||||
if (bdrv_pread(bs->file, offset , bs->backing_format,
|
||||
if (bdrv_pread(s->hd, offset , bs->backing_format,
|
||||
ext.len) != ext.len)
|
||||
return 3;
|
||||
bs->backing_format[ext.len] = '\0';
|
||||
@@ -136,14 +138,17 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
}
|
||||
|
||||
|
||||
static int qcow_open(BlockDriverState *bs, int flags)
|
||||
static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int len, i;
|
||||
int len, i, shift, ret;
|
||||
QCowHeader header;
|
||||
uint64_t ext_end;
|
||||
|
||||
if (bdrv_pread(bs->file, 0, &header, sizeof(header)) != sizeof(header))
|
||||
ret = bdrv_file_open(&s->hd, filename, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
|
||||
goto fail;
|
||||
be32_to_cpus(&header.magic);
|
||||
be32_to_cpus(&header.version);
|
||||
@@ -187,7 +192,8 @@ static int qcow_open(BlockDriverState *bs, int flags)
|
||||
|
||||
/* read the level 1 table */
|
||||
s->l1_size = header.l1_size;
|
||||
s->l1_vm_state_index = size_to_l1(s, header.size);
|
||||
shift = s->cluster_bits + s->l2_bits;
|
||||
s->l1_vm_state_index = (header.size + (1LL << shift) - 1) >> shift;
|
||||
/* the L1 table must contain at least enough entries to put
|
||||
header.size bytes */
|
||||
if (s->l1_size < s->l1_vm_state_index)
|
||||
@@ -196,7 +202,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
|
||||
if (s->l1_size > 0) {
|
||||
s->l1_table = qemu_mallocz(
|
||||
align_offset(s->l1_size * sizeof(uint64_t), 512));
|
||||
if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
|
||||
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
|
||||
s->l1_size * sizeof(uint64_t))
|
||||
goto fail;
|
||||
for(i = 0;i < s->l1_size; i++) {
|
||||
@@ -229,7 +235,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
|
||||
len = header.backing_file_size;
|
||||
if (len > 1023)
|
||||
len = 1023;
|
||||
if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len)
|
||||
if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
|
||||
goto fail;
|
||||
bs->backing_file[len] = '\0';
|
||||
}
|
||||
@@ -248,6 +254,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
|
||||
qemu_free(s->l2_cache);
|
||||
qemu_free(s->cluster_cache);
|
||||
qemu_free(s->cluster_data);
|
||||
bdrv_delete(s->hd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -297,15 +304,9 @@ static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
uint64_t cluster_offset;
|
||||
int ret;
|
||||
|
||||
*pnum = nb_sectors;
|
||||
/* FIXME We can get errors here, but the bdrv_is_allocated interface can't
|
||||
* pass them on today */
|
||||
ret = qcow2_get_cluster_offset(bs, sector_num << 9, pnum, &cluster_offset);
|
||||
if (ret < 0) {
|
||||
*pnum = 0;
|
||||
}
|
||||
cluster_offset = qcow2_get_cluster_offset(bs, sector_num << 9, pnum);
|
||||
|
||||
return (cluster_offset != 0);
|
||||
}
|
||||
@@ -331,8 +332,8 @@ typedef struct QCowAIOCB {
|
||||
QEMUIOVector *qiov;
|
||||
uint8_t *buf;
|
||||
void *orig_buf;
|
||||
int remaining_sectors;
|
||||
int cur_nr_sectors; /* number of sectors in current iteration */
|
||||
int nb_sectors;
|
||||
int n;
|
||||
uint64_t cluster_offset;
|
||||
uint8_t *cluster_data;
|
||||
BlockDriverAIOCB *hd_aiocb;
|
||||
@@ -345,7 +346,7 @@ typedef struct QCowAIOCB {
|
||||
|
||||
static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common);
|
||||
QCowAIOCB *acb = (QCowAIOCB *)blockacb;
|
||||
if (acb->hd_aiocb)
|
||||
bdrv_aio_cancel(acb->hd_aiocb);
|
||||
qemu_aio_release(acb);
|
||||
@@ -398,43 +399,38 @@ static void qcow_aio_read_cb(void *opaque, int ret)
|
||||
} else {
|
||||
if (s->crypt_method) {
|
||||
qcow2_encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
|
||||
acb->cur_nr_sectors, 0,
|
||||
acb->n, 0,
|
||||
&s->aes_decrypt_key);
|
||||
}
|
||||
}
|
||||
|
||||
acb->remaining_sectors -= acb->cur_nr_sectors;
|
||||
acb->sector_num += acb->cur_nr_sectors;
|
||||
acb->buf += acb->cur_nr_sectors * 512;
|
||||
acb->nb_sectors -= acb->n;
|
||||
acb->sector_num += acb->n;
|
||||
acb->buf += acb->n * 512;
|
||||
|
||||
if (acb->remaining_sectors == 0) {
|
||||
if (acb->nb_sectors == 0) {
|
||||
/* request completed */
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* prepare next AIO request */
|
||||
acb->cur_nr_sectors = acb->remaining_sectors;
|
||||
ret = qcow2_get_cluster_offset(bs, acb->sector_num << 9,
|
||||
&acb->cur_nr_sectors, &acb->cluster_offset);
|
||||
if (ret < 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
acb->n = acb->nb_sectors;
|
||||
acb->cluster_offset =
|
||||
qcow2_get_cluster_offset(bs, acb->sector_num << 9, &acb->n);
|
||||
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
|
||||
|
||||
if (!acb->cluster_offset) {
|
||||
if (bs->backing_hd) {
|
||||
/* read from the base image */
|
||||
n1 = qcow2_backing_read1(bs->backing_hd, acb->sector_num,
|
||||
acb->buf, acb->cur_nr_sectors);
|
||||
acb->buf, acb->n);
|
||||
if (n1 > 0) {
|
||||
acb->hd_iov.iov_base = (void *)acb->buf;
|
||||
acb->hd_iov.iov_len = acb->cur_nr_sectors * 512;
|
||||
acb->hd_iov.iov_len = acb->n * 512;
|
||||
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
|
||||
acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
|
||||
&acb->hd_qiov, acb->cur_nr_sectors,
|
||||
&acb->hd_qiov, acb->n,
|
||||
qcow_aio_read_cb, acb);
|
||||
if (acb->hd_aiocb == NULL)
|
||||
goto done;
|
||||
@@ -445,17 +441,17 @@ static void qcow_aio_read_cb(void *opaque, int ret)
|
||||
}
|
||||
} else {
|
||||
/* Note: in this case, no need to wait */
|
||||
memset(acb->buf, 0, 512 * acb->cur_nr_sectors);
|
||||
memset(acb->buf, 0, 512 * acb->n);
|
||||
ret = qcow_schedule_bh(qcow_aio_read_bh, acb);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
}
|
||||
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
||||
/* add AIO support for compressed blocks ? */
|
||||
if (qcow2_decompress_cluster(bs, acb->cluster_offset) < 0)
|
||||
if (qcow2_decompress_cluster(s, acb->cluster_offset) < 0)
|
||||
goto done;
|
||||
memcpy(acb->buf, s->cluster_cache + index_in_cluster * 512,
|
||||
512 * acb->cur_nr_sectors);
|
||||
memcpy(acb->buf,
|
||||
s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
|
||||
ret = qcow_schedule_bh(qcow_aio_read_bh, acb);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
@@ -466,13 +462,11 @@ static void qcow_aio_read_cb(void *opaque, int ret)
|
||||
}
|
||||
|
||||
acb->hd_iov.iov_base = (void *)acb->buf;
|
||||
acb->hd_iov.iov_len = acb->cur_nr_sectors * 512;
|
||||
acb->hd_iov.iov_len = acb->n * 512;
|
||||
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
|
||||
acb->hd_aiocb = bdrv_aio_readv(bs->file,
|
||||
acb->hd_aiocb = bdrv_aio_readv(s->hd,
|
||||
(acb->cluster_offset >> 9) + index_in_cluster,
|
||||
&acb->hd_qiov, acb->cur_nr_sectors,
|
||||
qcow_aio_read_cb, acb);
|
||||
&acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
|
||||
if (acb->hd_aiocb == NULL) {
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
@@ -508,8 +502,8 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
|
||||
} else {
|
||||
acb->buf = (uint8_t *)qiov->iov->iov_base;
|
||||
}
|
||||
acb->remaining_sectors = nb_sectors;
|
||||
acb->cur_nr_sectors = 0;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
acb->n = 0;
|
||||
acb->cluster_offset = 0;
|
||||
acb->l2meta.nb_clusters = 0;
|
||||
QLIST_INIT(&acb->l2meta.dependent_requests);
|
||||
@@ -542,8 +536,14 @@ static void run_dependent_requests(QCowL2Meta *m)
|
||||
QLIST_REMOVE(m, next_in_flight);
|
||||
}
|
||||
|
||||
/* Restart all dependent requests */
|
||||
QLIST_FOREACH_SAFE(req, &m->dependent_requests, next_depend, next) {
|
||||
/*
|
||||
* Restart all dependent requests.
|
||||
* Can't use QLIST_FOREACH here - the next link might not be the same
|
||||
* any more after the callback (request could depend on a different
|
||||
* request now)
|
||||
*/
|
||||
for (req = m->dependent_requests.lh_first; req != NULL; req = next) {
|
||||
next = req->next_depend.le_next;
|
||||
qcow_aio_write_cb(req, 0);
|
||||
}
|
||||
|
||||
@@ -571,24 +571,24 @@ static void qcow_aio_write_cb(void *opaque, int ret)
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
acb->remaining_sectors -= acb->cur_nr_sectors;
|
||||
acb->sector_num += acb->cur_nr_sectors;
|
||||
acb->buf += acb->cur_nr_sectors * 512;
|
||||
acb->nb_sectors -= acb->n;
|
||||
acb->sector_num += acb->n;
|
||||
acb->buf += acb->n * 512;
|
||||
|
||||
if (acb->remaining_sectors == 0) {
|
||||
if (acb->nb_sectors == 0) {
|
||||
/* request completed */
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
|
||||
n_end = index_in_cluster + acb->remaining_sectors;
|
||||
n_end = index_in_cluster + acb->nb_sectors;
|
||||
if (s->crypt_method &&
|
||||
n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors)
|
||||
n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
|
||||
|
||||
ret = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
|
||||
index_in_cluster, n_end, &acb->cur_nr_sectors, &acb->l2meta);
|
||||
index_in_cluster, n_end, &acb->n, &acb->l2meta);
|
||||
if (ret < 0) {
|
||||
goto done;
|
||||
}
|
||||
@@ -610,18 +610,17 @@ static void qcow_aio_write_cb(void *opaque, int ret)
|
||||
s->cluster_size);
|
||||
}
|
||||
qcow2_encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
|
||||
acb->cur_nr_sectors, 1, &s->aes_encrypt_key);
|
||||
acb->n, 1, &s->aes_encrypt_key);
|
||||
src_buf = acb->cluster_data;
|
||||
} else {
|
||||
src_buf = acb->buf;
|
||||
}
|
||||
acb->hd_iov.iov_base = (void *)src_buf;
|
||||
acb->hd_iov.iov_len = acb->cur_nr_sectors * 512;
|
||||
acb->hd_iov.iov_len = acb->n * 512;
|
||||
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||
acb->hd_aiocb = bdrv_aio_writev(bs->file,
|
||||
acb->hd_aiocb = bdrv_aio_writev(s->hd,
|
||||
(acb->cluster_offset >> 9) + index_in_cluster,
|
||||
&acb->hd_qiov, acb->cur_nr_sectors,
|
||||
&acb->hd_qiov, acb->n,
|
||||
qcow_aio_write_cb, acb);
|
||||
if (acb->hd_aiocb == NULL) {
|
||||
ret = -EIO;
|
||||
@@ -666,105 +665,7 @@ static void qcow_close(BlockDriverState *bs)
|
||||
qemu_free(s->cluster_cache);
|
||||
qemu_free(s->cluster_data);
|
||||
qcow2_refcount_close(bs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the variable length parts of the qcow2 header, i.e. the backing file
|
||||
* name and all extensions. qcow2 was not designed to allow such changes, so if
|
||||
* we run out of space (we can only use the first cluster) this function may
|
||||
* fail.
|
||||
*
|
||||
* Returns 0 on success, -errno in error cases.
|
||||
*/
|
||||
static int qcow2_update_ext_header(BlockDriverState *bs,
|
||||
const char *backing_file, const char *backing_fmt)
|
||||
{
|
||||
size_t backing_file_len = 0;
|
||||
size_t backing_fmt_len = 0;
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
QCowExtension ext_backing_fmt = {0, 0};
|
||||
int ret;
|
||||
|
||||
/* Backing file format doesn't make sense without a backing file */
|
||||
if (backing_fmt && !backing_file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Prepare the backing file format extension if needed */
|
||||
if (backing_fmt) {
|
||||
ext_backing_fmt.len = cpu_to_be32(strlen(backing_fmt));
|
||||
ext_backing_fmt.magic = cpu_to_be32(QCOW_EXT_MAGIC_BACKING_FORMAT);
|
||||
backing_fmt_len = ((sizeof(ext_backing_fmt)
|
||||
+ strlen(backing_fmt) + 7) & ~7);
|
||||
}
|
||||
|
||||
/* Check if we can fit the new header into the first cluster */
|
||||
if (backing_file) {
|
||||
backing_file_len = strlen(backing_file);
|
||||
}
|
||||
|
||||
size_t header_size = sizeof(QCowHeader) + backing_file_len
|
||||
+ backing_fmt_len;
|
||||
|
||||
if (header_size > s->cluster_size) {
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/* Rewrite backing file name and qcow2 extensions */
|
||||
size_t ext_size = header_size - sizeof(QCowHeader);
|
||||
uint8_t buf[ext_size];
|
||||
size_t offset = 0;
|
||||
size_t backing_file_offset = 0;
|
||||
|
||||
if (backing_file) {
|
||||
if (backing_fmt) {
|
||||
int padding = backing_fmt_len -
|
||||
(sizeof(ext_backing_fmt) + strlen(backing_fmt));
|
||||
|
||||
memcpy(buf + offset, &ext_backing_fmt, sizeof(ext_backing_fmt));
|
||||
offset += sizeof(ext_backing_fmt);
|
||||
|
||||
memcpy(buf + offset, backing_fmt, strlen(backing_fmt));
|
||||
offset += strlen(backing_fmt);
|
||||
|
||||
memset(buf + offset, 0, padding);
|
||||
offset += padding;
|
||||
}
|
||||
|
||||
memcpy(buf + offset, backing_file, backing_file_len);
|
||||
backing_file_offset = sizeof(QCowHeader) + offset;
|
||||
}
|
||||
|
||||
ret = bdrv_pwrite_sync(bs->file, sizeof(QCowHeader), buf, ext_size);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Update header fields */
|
||||
uint64_t be_backing_file_offset = cpu_to_be64(backing_file_offset);
|
||||
uint32_t be_backing_file_size = cpu_to_be32(backing_file_len);
|
||||
|
||||
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, backing_file_offset),
|
||||
&be_backing_file_offset, sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, backing_file_size),
|
||||
&be_backing_file_size, sizeof(uint32_t));
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcow2_change_backing_file(BlockDriverState *bs,
|
||||
const char *backing_file, const char *backing_fmt)
|
||||
{
|
||||
return qcow2_update_ext_header(bs, backing_file, backing_fmt);
|
||||
bdrv_delete(s->hd);
|
||||
}
|
||||
|
||||
static int get_bits_from_size(size_t size)
|
||||
@@ -791,6 +692,7 @@ static int get_bits_from_size(size_t size)
|
||||
|
||||
static int preallocate(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t nb_sectors;
|
||||
uint64_t offset;
|
||||
int num;
|
||||
@@ -805,14 +707,14 @@ static int preallocate(BlockDriverState *bs)
|
||||
while (nb_sectors) {
|
||||
num = MIN(nb_sectors, INT_MAX >> 9);
|
||||
ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num, &meta);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = qcow2_alloc_cluster_link_l2(bs, &meta);
|
||||
if (ret < 0) {
|
||||
if (qcow2_alloc_cluster_link_l2(bs, &meta) < 0) {
|
||||
qcow2_free_any_clusters(bs, meta.cluster_offset, meta.nb_clusters);
|
||||
return ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* There are no dependent requests, but we need to remove our request
|
||||
@@ -833,10 +735,7 @@ static int preallocate(BlockDriverState *bs)
|
||||
if (meta.cluster_offset != 0) {
|
||||
uint8_t buf[512];
|
||||
memset(buf, 0, 512);
|
||||
ret = bdrv_write(bs->file, (meta.cluster_offset >> 9) + num - 1, buf, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
bdrv_write(s->hd, (meta.cluster_offset >> 9) + num - 1, buf, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -855,13 +754,13 @@ static int qcow_create2(const char *filename, int64_t total_size,
|
||||
uint64_t old_ref_clusters;
|
||||
QCowCreateState s1, *s = &s1;
|
||||
QCowExtension ext_bf = {0, 0};
|
||||
int ret;
|
||||
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
return -1;
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.magic = cpu_to_be32(QCOW_MAGIC);
|
||||
header.version = cpu_to_be32(QCOW_VERSION);
|
||||
@@ -959,11 +858,7 @@ static int qcow_create2(const char *filename, int64_t total_size,
|
||||
ref_clusters * s->cluster_size);
|
||||
|
||||
/* write all the data */
|
||||
ret = qemu_write_full(fd, &header, sizeof(header));
|
||||
if (ret != sizeof(header)) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
write(fd, &header, sizeof(header));
|
||||
if (backing_file) {
|
||||
if (backing_format_len) {
|
||||
char zero[16];
|
||||
@@ -972,72 +867,40 @@ static int qcow_create2(const char *filename, int64_t total_size,
|
||||
memset(zero, 0, sizeof(zero));
|
||||
cpu_to_be32s(&ext_bf.magic);
|
||||
cpu_to_be32s(&ext_bf.len);
|
||||
ret = qemu_write_full(fd, &ext_bf, sizeof(ext_bf));
|
||||
if (ret != sizeof(ext_bf)) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
ret = qemu_write_full(fd, backing_format, backing_format_len);
|
||||
if (ret != backing_format_len) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
write(fd, &ext_bf, sizeof(ext_bf));
|
||||
write(fd, backing_format, backing_format_len);
|
||||
if (padding > 0) {
|
||||
ret = qemu_write_full(fd, zero, padding);
|
||||
if (ret != padding) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
write(fd, zero, padding);
|
||||
}
|
||||
}
|
||||
ret = qemu_write_full(fd, backing_file, backing_filename_len);
|
||||
if (ret != backing_filename_len) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
write(fd, backing_file, backing_filename_len);
|
||||
}
|
||||
lseek(fd, s->l1_table_offset, SEEK_SET);
|
||||
tmp = 0;
|
||||
for(i = 0;i < l1_size; i++) {
|
||||
ret = qemu_write_full(fd, &tmp, sizeof(tmp));
|
||||
if (ret != sizeof(tmp)) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
write(fd, &tmp, sizeof(tmp));
|
||||
}
|
||||
lseek(fd, s->refcount_table_offset, SEEK_SET);
|
||||
ret = qemu_write_full(fd, s->refcount_table,
|
||||
write(fd, s->refcount_table,
|
||||
reftable_clusters * s->cluster_size);
|
||||
if (ret != reftable_clusters * s->cluster_size) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
lseek(fd, s->refcount_block_offset, SEEK_SET);
|
||||
ret = qemu_write_full(fd, s->refcount_block,
|
||||
ref_clusters * s->cluster_size);
|
||||
if (ret != ref_clusters * s->cluster_size) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
write(fd, s->refcount_block, ref_clusters * s->cluster_size);
|
||||
|
||||
ret = 0;
|
||||
exit:
|
||||
qemu_free(s->refcount_table);
|
||||
qemu_free(s->refcount_block);
|
||||
close(fd);
|
||||
|
||||
/* Preallocate metadata */
|
||||
if (ret == 0 && prealloc) {
|
||||
if (prealloc) {
|
||||
BlockDriverState *bs;
|
||||
BlockDriver *drv = bdrv_find_format("qcow2");
|
||||
bs = bdrv_new("");
|
||||
bdrv_open(bs, filename, BDRV_O_CACHE_WB | BDRV_O_RDWR, drv);
|
||||
ret = preallocate(bs);
|
||||
bdrv_open(bs, filename, BDRV_O_CACHE_WB);
|
||||
preallocate(bs);
|
||||
bdrv_close(bs);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcow_create(const char *filename, QEMUOptionParameter *options)
|
||||
@@ -1096,9 +959,9 @@ static int qcow_make_empty(BlockDriverState *bs)
|
||||
int ret;
|
||||
|
||||
memset(s->l1_table, 0, l1_length);
|
||||
if (bdrv_pwrite(bs->file, s->l1_table_offset, s->l1_table, l1_length) < 0)
|
||||
if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
|
||||
return -1;
|
||||
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
|
||||
ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1107,43 +970,6 @@ static int qcow_make_empty(BlockDriverState *bs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int ret, new_l1_size;
|
||||
|
||||
if (offset & 511) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* cannot proceed if image has snapshots */
|
||||
if (s->nb_snapshots) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* shrinking is currently not supported */
|
||||
if (offset < bs->total_sectors * 512) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
new_l1_size = size_to_l1(s, offset);
|
||||
ret = qcow2_grow_l1_table(bs, new_l1_size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* write updated header.size */
|
||||
offset = cpu_to_be64(offset);
|
||||
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
|
||||
&offset, sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
s->l1_vm_state_index = new_l1_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: put compressed sectors first, then all the cluster aligned
|
||||
tables to avoid losing bytes in alignment */
|
||||
static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
@@ -1158,9 +984,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
if (nb_sectors == 0) {
|
||||
/* align end of file to a sector boundary to ease reading with
|
||||
sector based I/Os */
|
||||
cluster_offset = bdrv_getlength(bs->file);
|
||||
cluster_offset = bdrv_getlength(s->hd);
|
||||
cluster_offset = (cluster_offset + 511) & ~511;
|
||||
bdrv_truncate(bs->file, cluster_offset);
|
||||
bdrv_truncate(s->hd, cluster_offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1203,8 +1029,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
if (!cluster_offset)
|
||||
return -1;
|
||||
cluster_offset &= s->cluster_offset_mask;
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
|
||||
if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) {
|
||||
if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
|
||||
qemu_free(out_buf);
|
||||
return -1;
|
||||
}
|
||||
@@ -1216,13 +1041,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
static void qcow_flush(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_flush(bs->file);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_flush(bs->file, cb, opaque);
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
bdrv_flush(s->hd);
|
||||
}
|
||||
|
||||
static int64_t qcow_vm_state_offset(BDRVQcowState *s)
|
||||
@@ -1239,9 +1059,9 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
}
|
||||
|
||||
|
||||
static int qcow_check(BlockDriverState *bs, BdrvCheckResult *result)
|
||||
static int qcow_check(BlockDriverState *bs)
|
||||
{
|
||||
return qcow2_check_refcounts(bs, result);
|
||||
return qcow2_check_refcounts(bs);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -1251,7 +1071,7 @@ static void dump_refcounts(BlockDriverState *bs)
|
||||
int64_t nb_clusters, k, k1, size;
|
||||
int refcount;
|
||||
|
||||
size = bdrv_getlength(bs->file);
|
||||
size = bdrv_getlength(s->hd);
|
||||
nb_clusters = size_to_clusters(s, size);
|
||||
for(k = 0; k < nb_clusters;) {
|
||||
k1 = k;
|
||||
@@ -1259,8 +1079,7 @@ static void dump_refcounts(BlockDriverState *bs)
|
||||
k++;
|
||||
while (k < nb_clusters && get_refcount(bs, k) == refcount)
|
||||
k++;
|
||||
printf("%" PRId64 ": refcount=%d nb=%" PRId64 "\n", k, refcount,
|
||||
k - k1);
|
||||
printf("%lld: refcount=%d nb=%lld\n", k, refcount, k - k1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1272,7 +1091,6 @@ static int qcow_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
|
||||
int growable = bs->growable;
|
||||
int ret;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
|
||||
bs->growable = 1;
|
||||
ret = bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size);
|
||||
bs->growable = growable;
|
||||
@@ -1287,7 +1105,6 @@ static int qcow_load_vmstate(BlockDriverState *bs, uint8_t *buf,
|
||||
int growable = bs->growable;
|
||||
int ret;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
|
||||
bs->growable = 1;
|
||||
ret = bdrv_pread(bs, qcow_vm_state_offset(s) + pos, buf, size);
|
||||
bs->growable = growable;
|
||||
@@ -1343,10 +1160,7 @@ static BlockDriver bdrv_qcow2 = {
|
||||
|
||||
.bdrv_aio_readv = qcow_aio_readv,
|
||||
.bdrv_aio_writev = qcow_aio_writev,
|
||||
.bdrv_aio_flush = qcow_aio_flush,
|
||||
|
||||
.bdrv_truncate = qcow2_truncate,
|
||||
.bdrv_write_compressed = qcow_write_compressed,
|
||||
.bdrv_write_compressed = qcow_write_compressed,
|
||||
|
||||
.bdrv_snapshot_create = qcow2_snapshot_create,
|
||||
.bdrv_snapshot_goto = qcow2_snapshot_goto,
|
||||
@@ -1357,8 +1171,6 @@ static BlockDriver bdrv_qcow2 = {
|
||||
.bdrv_save_vmstate = qcow_save_vmstate,
|
||||
.bdrv_load_vmstate = qcow_load_vmstate,
|
||||
|
||||
.bdrv_change_backing_file = qcow2_change_backing_file,
|
||||
|
||||
.create_options = qcow_create_options,
|
||||
.bdrv_check = qcow_check,
|
||||
};
|
||||
|
||||
@@ -150,12 +150,6 @@ static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
|
||||
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
|
||||
}
|
||||
|
||||
static inline int size_to_l1(BDRVQcowState *s, int64_t size)
|
||||
{
|
||||
int shift = s->cluster_bits + s->l2_bits;
|
||||
return (size + (1ULL << shift) - 1) >> shift;
|
||||
}
|
||||
|
||||
static inline int64_t align_offset(int64_t offset, int n)
|
||||
{
|
||||
offset = (offset + n - 1) & ~(n - 1);
|
||||
@@ -185,19 +179,19 @@ void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset,
|
||||
int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
int64_t l1_table_offset, int l1_size, int addend);
|
||||
|
||||
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res);
|
||||
int qcow2_check_refcounts(BlockDriverState *bs);
|
||||
|
||||
/* qcow2-cluster.c functions */
|
||||
int qcow2_grow_l1_table(BlockDriverState *bs, int min_size);
|
||||
void qcow2_l2_cache_reset(BlockDriverState *bs);
|
||||
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
|
||||
int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
|
||||
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
||||
uint8_t *out_buf, const uint8_t *in_buf,
|
||||
int nb_sectors, int enc,
|
||||
const AES_KEY *key);
|
||||
|
||||
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int *num, uint64_t *cluster_offset);
|
||||
uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int *num);
|
||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int n_start, int n_end, int *num, QCowL2Meta *m);
|
||||
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "qemu-log.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
#include "compatfd.h"
|
||||
#include <assert.h>
|
||||
#include "block/raw-posix-aio.h"
|
||||
|
||||
#ifdef CONFIG_COCOA
|
||||
@@ -105,6 +107,7 @@
|
||||
typedef struct BDRVRawState {
|
||||
int fd;
|
||||
int type;
|
||||
unsigned int lseek_err_cnt;
|
||||
int open_flags;
|
||||
#if defined(__linux__)
|
||||
/* linux floppy specific */
|
||||
@@ -133,12 +136,15 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int fd, ret;
|
||||
|
||||
s->lseek_err_cnt = 0;
|
||||
|
||||
s->open_flags = open_flags | O_BINARY;
|
||||
s->open_flags &= ~O_ACCMODE;
|
||||
if (bdrv_flags & BDRV_O_RDWR) {
|
||||
if ((bdrv_flags & BDRV_O_ACCESS) == BDRV_O_RDWR) {
|
||||
s->open_flags |= O_RDWR;
|
||||
} else {
|
||||
s->open_flags |= O_RDONLY;
|
||||
bs->read_only = 1;
|
||||
}
|
||||
|
||||
/* Use O_DSYNC for write-through caching, no flags for write-back caching,
|
||||
@@ -201,9 +207,13 @@ out_close:
|
||||
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int open_flags = 0;
|
||||
|
||||
s->type = FTYPE_FILE;
|
||||
return raw_open_common(bs, filename, flags, 0);
|
||||
if (flags & BDRV_O_CREAT)
|
||||
open_flags = O_CREAT | O_TRUNC;
|
||||
|
||||
return raw_open_common(bs, filename, flags, open_flags);
|
||||
}
|
||||
|
||||
/* XXX: use host sector size if necessary with:
|
||||
@@ -216,7 +226,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_COCOA
|
||||
uint32_t blockSize = 512;
|
||||
u_int32_t blockSize = 512;
|
||||
if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
|
||||
bufsize = blockSize;
|
||||
}
|
||||
@@ -240,16 +250,29 @@ static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = pread(s->fd, buf, count, offset);
|
||||
if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
|
||||
++(s->lseek_err_cnt);
|
||||
if(s->lseek_err_cnt <= 10) {
|
||||
DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
|
||||
"] lseek failed : %d = %s\n",
|
||||
s->fd, bs->filename, offset, buf, count,
|
||||
bs->total_sectors, errno, strerror(errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
s->lseek_err_cnt=0;
|
||||
|
||||
ret = read(s->fd, buf, count);
|
||||
if (ret == count)
|
||||
return ret;
|
||||
goto label__raw_read__success;
|
||||
|
||||
/* Allow reads beyond the end (needed for pwrite) */
|
||||
if ((ret == 0) && bs->growable) {
|
||||
int64_t size = raw_getlength(bs);
|
||||
if (offset >= size) {
|
||||
memset(buf, 0, count);
|
||||
return count;
|
||||
ret = count;
|
||||
goto label__raw_read__success;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,13 +282,15 @@ static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
|
||||
bs->total_sectors, ret, errno, strerror(errno));
|
||||
|
||||
/* Try harder for CDrom. */
|
||||
if (s->type != FTYPE_FILE) {
|
||||
ret = pread(s->fd, buf, count, offset);
|
||||
if (bs->type == BDRV_TYPE_CDROM) {
|
||||
lseek(s->fd, offset, SEEK_SET);
|
||||
ret = read(s->fd, buf, count);
|
||||
if (ret == count)
|
||||
return ret;
|
||||
ret = pread(s->fd, buf, count, offset);
|
||||
goto label__raw_read__success;
|
||||
lseek(s->fd, offset, SEEK_SET);
|
||||
ret = read(s->fd, buf, count);
|
||||
if (ret == count)
|
||||
return ret;
|
||||
goto label__raw_read__success;
|
||||
|
||||
DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
|
||||
"] retry read failed %d : %d = %s\n",
|
||||
@@ -273,6 +298,8 @@ static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
|
||||
bs->total_sectors, ret, errno, strerror(errno));
|
||||
}
|
||||
|
||||
label__raw_read__success:
|
||||
|
||||
return (ret < 0) ? -errno : ret;
|
||||
}
|
||||
|
||||
@@ -293,15 +320,29 @@ static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset,
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
|
||||
ret = pwrite(s->fd, buf, count, offset);
|
||||
if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
|
||||
++(s->lseek_err_cnt);
|
||||
if(s->lseek_err_cnt) {
|
||||
DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%"
|
||||
PRId64 "] lseek failed : %d = %s\n",
|
||||
s->fd, bs->filename, offset, buf, count,
|
||||
bs->total_sectors, errno, strerror(errno));
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
s->lseek_err_cnt = 0;
|
||||
|
||||
ret = write(s->fd, buf, count);
|
||||
if (ret == count)
|
||||
return ret;
|
||||
goto label__raw_write__success;
|
||||
|
||||
DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
|
||||
"] write failed %d : %d = %s\n",
|
||||
s->fd, bs->filename, offset, buf, count,
|
||||
bs->total_sectors, ret, errno, strerror(errno));
|
||||
|
||||
label__raw_write__success:
|
||||
|
||||
return (ret < 0) ? -errno : ret;
|
||||
}
|
||||
|
||||
@@ -356,12 +397,8 @@ static int raw_pread(BlockDriverState *bs, int64_t offset,
|
||||
size = ALIGNED_BUFFER_SIZE;
|
||||
|
||||
ret = raw_pread_aligned(bs, offset, s->aligned_buf, size);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else if (ret == 0) {
|
||||
fprintf(stderr, "raw_pread: read beyond end of file\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
size = ret;
|
||||
if (size > count)
|
||||
@@ -387,9 +424,8 @@ static int raw_read(BlockDriverState *bs, int64_t sector_num,
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = raw_pread(bs, sector_num * BDRV_SECTOR_SIZE, buf,
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
if (ret == (nb_sectors * BDRV_SECTOR_SIZE))
|
||||
ret = raw_pread(bs, sector_num * 512, buf, nb_sectors * 512);
|
||||
if (ret == (nb_sectors * 512))
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
@@ -476,9 +512,8 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret;
|
||||
ret = raw_pwrite(bs, sector_num * BDRV_SECTOR_SIZE, buf,
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
if (ret == (nb_sectors * BDRV_SECTOR_SIZE))
|
||||
ret = raw_pwrite(bs, sector_num * 512, buf, nb_sectors * 512);
|
||||
if (ret == (nb_sectors * 512))
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
@@ -491,7 +526,7 @@ static int qiov_is_aligned(QEMUIOVector *qiov)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < qiov->niov; i++) {
|
||||
if ((uintptr_t) qiov->iov[i].iov_base % BDRV_SECTOR_SIZE) {
|
||||
if ((uintptr_t) qiov->iov[i].iov_base % 512) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -595,41 +630,21 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
||||
} else
|
||||
return st.st_size;
|
||||
}
|
||||
#elif defined(__sun__)
|
||||
static int64_t raw_getlength(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
struct dk_minfo minfo;
|
||||
int ret;
|
||||
|
||||
ret = fd_open(bs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the DKIOCGMEDIAINFO ioctl to read the size.
|
||||
*/
|
||||
ret = ioctl(s->fd, DKIOCGMEDIAINFO, &minfo);
|
||||
if (ret != -1) {
|
||||
return minfo.dki_lbsize * minfo.dki_capacity;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are reports that lseek on some devices fails, but
|
||||
* irc discussion said that contingency on contingency was overkill.
|
||||
*/
|
||||
return lseek(s->fd, 0, SEEK_END);
|
||||
}
|
||||
#elif defined(CONFIG_BSD)
|
||||
static int64_t raw_getlength(BlockDriverState *bs)
|
||||
#else /* !__OpenBSD__ */
|
||||
static int64_t raw_getlength(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int fd = s->fd;
|
||||
int64_t size;
|
||||
#ifdef CONFIG_BSD
|
||||
struct stat sb;
|
||||
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
int reopened = 0;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __sun__
|
||||
struct dk_minfo minfo;
|
||||
int rv;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
@@ -637,6 +652,7 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_BSD
|
||||
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
again:
|
||||
#endif
|
||||
@@ -671,24 +687,24 @@ again:
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
#ifdef __sun__
|
||||
/*
|
||||
* use the DKIOCGMEDIAINFO ioctl to read the size.
|
||||
*/
|
||||
rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
|
||||
if ( rv != -1 ) {
|
||||
size = minfo.dki_lbsize * minfo.dki_capacity;
|
||||
} else /* there are reports that lseek on some devices
|
||||
fails, but irc discussion said that contingency
|
||||
on contingency was overkill */
|
||||
#endif
|
||||
{
|
||||
size = lseek(fd, 0, SEEK_END);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
#else
|
||||
static int64_t raw_getlength(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
ret = fd_open(bs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return lseek(s->fd, 0, SEEK_END);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int raw_create(const char *filename, QEMUOptionParameter *options)
|
||||
@@ -700,7 +716,7 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
|
||||
/* Read out options */
|
||||
while (options && options->name) {
|
||||
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
|
||||
total_size = options->value.n / BDRV_SECTOR_SIZE;
|
||||
total_size = options->value.n / 512;
|
||||
}
|
||||
options++;
|
||||
}
|
||||
@@ -710,7 +726,7 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
|
||||
if (fd < 0) {
|
||||
result = -errno;
|
||||
} else {
|
||||
if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
|
||||
if (ftruncate(fd, total_size * 512) != 0) {
|
||||
result = -errno;
|
||||
}
|
||||
if (close(fd) != 0) {
|
||||
@@ -736,12 +752,11 @@ static QEMUOptionParameter raw_create_options[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_file = {
|
||||
.format_name = "file",
|
||||
.protocol_name = "file",
|
||||
static BlockDriver bdrv_raw = {
|
||||
.format_name = "raw",
|
||||
.instance_size = sizeof(BDRVRawState),
|
||||
.bdrv_probe = NULL, /* no probe for protocols */
|
||||
.bdrv_file_open = raw_open,
|
||||
.bdrv_open = raw_open,
|
||||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_close = raw_close,
|
||||
@@ -973,41 +988,35 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
|
||||
/* Read out options */
|
||||
while (options && options->name) {
|
||||
if (!strcmp(options->name, "size")) {
|
||||
total_size = options->value.n / BDRV_SECTOR_SIZE;
|
||||
total_size = options->value.n / 512;
|
||||
}
|
||||
options++;
|
||||
}
|
||||
|
||||
fd = open(filename, O_WRONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
return -EIO;
|
||||
|
||||
if (fstat(fd, &stat_buf) < 0)
|
||||
ret = -errno;
|
||||
ret = -EIO;
|
||||
else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode))
|
||||
ret = -ENODEV;
|
||||
else if (lseek(fd, 0, SEEK_END) < total_size * BDRV_SECTOR_SIZE)
|
||||
ret = -EIO;
|
||||
else if (lseek(fd, 0, SEEK_END) < total_size * 512)
|
||||
ret = -ENOSPC;
|
||||
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hdev_has_zero_init(BlockDriverState *bs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_host_device = {
|
||||
.format_name = "host_device",
|
||||
.protocol_name = "host_device",
|
||||
.instance_size = sizeof(BDRVRawState),
|
||||
.bdrv_probe_device = hdev_probe_device,
|
||||
.bdrv_file_open = hdev_open,
|
||||
.bdrv_open = hdev_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_create = hdev_create,
|
||||
.create_options = raw_create_options,
|
||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||
.no_zero_init = 1,
|
||||
.bdrv_flush = raw_flush,
|
||||
|
||||
.bdrv_aio_readv = raw_aio_readv,
|
||||
@@ -1048,26 +1057,9 @@ static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
|
||||
static int floppy_probe_device(const char *filename)
|
||||
{
|
||||
int fd, ret;
|
||||
int prio = 0;
|
||||
struct floppy_struct fdparam;
|
||||
|
||||
if (strstart(filename, "/dev/fd", NULL))
|
||||
prio = 50;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Attempt to detect via a floppy specific ioctl */
|
||||
ret = ioctl(fd, FDGETPRM, &fdparam);
|
||||
if (ret >= 0)
|
||||
prio = 100;
|
||||
|
||||
close(fd);
|
||||
out:
|
||||
return prio;
|
||||
return 100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1115,14 +1107,13 @@ static int floppy_eject(BlockDriverState *bs, int eject_flag)
|
||||
|
||||
static BlockDriver bdrv_host_floppy = {
|
||||
.format_name = "host_floppy",
|
||||
.protocol_name = "host_floppy",
|
||||
.instance_size = sizeof(BDRVRawState),
|
||||
.bdrv_probe_device = floppy_probe_device,
|
||||
.bdrv_file_open = floppy_open,
|
||||
.bdrv_open = floppy_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_create = hdev_create,
|
||||
.create_options = raw_create_options,
|
||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||
.no_zero_init = 1,
|
||||
.bdrv_flush = raw_flush,
|
||||
|
||||
.bdrv_aio_readv = raw_aio_readv,
|
||||
@@ -1151,25 +1142,9 @@ static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
|
||||
static int cdrom_probe_device(const char *filename)
|
||||
{
|
||||
int fd, ret;
|
||||
int prio = 0;
|
||||
|
||||
if (strstart(filename, "/dev/cd", NULL))
|
||||
prio = 50;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Attempt to detect via a CDROM specific ioctl */
|
||||
ret = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
|
||||
if (ret >= 0)
|
||||
prio = 100;
|
||||
|
||||
close(fd);
|
||||
out:
|
||||
return prio;
|
||||
return 100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdrom_is_inserted(BlockDriverState *bs)
|
||||
@@ -1215,14 +1190,13 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked)
|
||||
|
||||
static BlockDriver bdrv_host_cdrom = {
|
||||
.format_name = "host_cdrom",
|
||||
.protocol_name = "host_cdrom",
|
||||
.instance_size = sizeof(BDRVRawState),
|
||||
.bdrv_probe_device = cdrom_probe_device,
|
||||
.bdrv_file_open = cdrom_open,
|
||||
.bdrv_open = cdrom_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_create = hdev_create,
|
||||
.create_options = raw_create_options,
|
||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||
.no_zero_init = 1,
|
||||
.bdrv_flush = raw_flush,
|
||||
|
||||
.bdrv_aio_readv = raw_aio_readv,
|
||||
@@ -1338,14 +1312,13 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked)
|
||||
|
||||
static BlockDriver bdrv_host_cdrom = {
|
||||
.format_name = "host_cdrom",
|
||||
.protocol_name = "host_cdrom",
|
||||
.instance_size = sizeof(BDRVRawState),
|
||||
.bdrv_probe_device = cdrom_probe_device,
|
||||
.bdrv_file_open = cdrom_open,
|
||||
.bdrv_open = cdrom_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_create = hdev_create,
|
||||
.create_options = raw_create_options,
|
||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||
.no_zero_init = 1,
|
||||
.bdrv_flush = raw_flush,
|
||||
|
||||
.bdrv_aio_readv = raw_aio_readv,
|
||||
@@ -1363,13 +1336,13 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
};
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
static void bdrv_file_init(void)
|
||||
static void bdrv_raw_init(void)
|
||||
{
|
||||
/*
|
||||
* Register all the drivers. Note that order is important, the driver
|
||||
* registered last will get probed first.
|
||||
*/
|
||||
bdrv_register(&bdrv_file);
|
||||
bdrv_register(&bdrv_raw);
|
||||
bdrv_register(&bdrv_host_device);
|
||||
#ifdef __linux__
|
||||
bdrv_register(&bdrv_host_floppy);
|
||||
@@ -1380,4 +1353,4 @@ static void bdrv_file_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
block_init(bdrv_file_init);
|
||||
block_init(bdrv_raw_init);
|
||||
|
||||
@@ -76,17 +76,21 @@ static int set_sparse(int fd)
|
||||
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int access_flags;
|
||||
int access_flags, create_flags;
|
||||
DWORD overlapped;
|
||||
|
||||
s->type = FTYPE_FILE;
|
||||
|
||||
if (flags & BDRV_O_RDWR) {
|
||||
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||
access_flags = GENERIC_READ | GENERIC_WRITE;
|
||||
} else {
|
||||
access_flags = GENERIC_READ;
|
||||
}
|
||||
|
||||
if (flags & BDRV_O_CREAT) {
|
||||
create_flags = CREATE_ALWAYS;
|
||||
} else {
|
||||
create_flags = OPEN_EXISTING;
|
||||
}
|
||||
overlapped = FILE_ATTRIBUTE_NORMAL;
|
||||
if ((flags & BDRV_O_NOCACHE))
|
||||
overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
|
||||
@@ -94,7 +98,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
overlapped |= FILE_FLAG_WRITE_THROUGH;
|
||||
s->hfile = CreateFile(filename, access_flags,
|
||||
FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, overlapped, NULL);
|
||||
create_flags, overlapped, NULL);
|
||||
if (s->hfile == INVALID_HANDLE_VALUE) {
|
||||
int err = GetLastError();
|
||||
|
||||
@@ -238,11 +242,10 @@ static QEMUOptionParameter raw_create_options[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_file = {
|
||||
.format_name = "file",
|
||||
.protocol_name = "file",
|
||||
static BlockDriver bdrv_raw = {
|
||||
.format_name = "raw",
|
||||
.instance_size = sizeof(BDRVRawState),
|
||||
.bdrv_file_open = raw_open,
|
||||
.bdrv_open = raw_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_create = raw_create,
|
||||
.bdrv_flush = raw_flush,
|
||||
@@ -334,7 +337,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
}
|
||||
s->type = find_device_type(bs, filename);
|
||||
|
||||
if (flags & BDRV_O_RDWR) {
|
||||
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||
access_flags = GENERIC_READ | GENERIC_WRITE;
|
||||
} else {
|
||||
access_flags = GENERIC_READ;
|
||||
@@ -394,30 +397,23 @@ static int raw_set_locked(BlockDriverState *bs, int locked)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int hdev_has_zero_init(BlockDriverState *bs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_host_device = {
|
||||
.format_name = "host_device",
|
||||
.protocol_name = "host_device",
|
||||
.instance_size = sizeof(BDRVRawState),
|
||||
.bdrv_probe_device = hdev_probe_device,
|
||||
.bdrv_file_open = hdev_open,
|
||||
.bdrv_open = hdev_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_flush = raw_flush,
|
||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||
|
||||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
};
|
||||
|
||||
static void bdrv_file_init(void)
|
||||
static void bdrv_raw_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_file);
|
||||
bdrv_register(&bdrv_raw);
|
||||
bdrv_register(&bdrv_host_device);
|
||||
}
|
||||
|
||||
block_init(bdrv_file_init);
|
||||
block_init(bdrv_raw_init);
|
||||
|
||||
280
block/raw.c
280
block/raw.c
@@ -1,280 +0,0 @@
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
|
||||
static int raw_open(BlockDriverState *bs, int flags)
|
||||
{
|
||||
bs->sg = bs->file->sg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check for the user attempting to write something that looks like a
|
||||
block format header to the beginning of the image and fail out.
|
||||
*/
|
||||
static int check_for_block_signature(BlockDriverState *bs, const uint8_t *buf)
|
||||
{
|
||||
static const uint8_t signatures[][4] = {
|
||||
{ 'Q', 'F', 'I', 0xfb }, /* qcow/qcow2 */
|
||||
{ 'C', 'O', 'W', 'D' }, /* VMDK3 */
|
||||
{ 'V', 'M', 'D', 'K' }, /* VMDK4 */
|
||||
{ 'O', 'O', 'O', 'M' }, /* UML COW */
|
||||
{}
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; signatures[i][0] != 0; i++) {
|
||||
if (memcmp(buf, signatures[i], 4) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_write_unsafe(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
/* assume that if the user specifies the format explicitly, then assume
|
||||
that they will continue to do so and provide no safety net */
|
||||
if (!bs->probed) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sector_num == 0 && nb_sectors > 0) {
|
||||
return check_for_block_signature(bs, buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
return bdrv_read(bs->file, sector_num, buf, nb_sectors);
|
||||
}
|
||||
|
||||
static int raw_write_scrubbed_bootsect(BlockDriverState *bs,
|
||||
const uint8_t *buf)
|
||||
{
|
||||
uint8_t bootsect[512];
|
||||
|
||||
/* scrub the dangerous signature */
|
||||
memcpy(bootsect, buf, 512);
|
||||
memset(bootsect, 0, 4);
|
||||
|
||||
return bdrv_write(bs->file, 0, bootsect, 1);
|
||||
}
|
||||
|
||||
static int raw_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
if (check_write_unsafe(bs, sector_num, buf, nb_sectors)) {
|
||||
int ret;
|
||||
|
||||
ret = raw_write_scrubbed_bootsect(bs, buf);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bdrv_write(bs->file, 1, buf + 512, nb_sectors - 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret + 512;
|
||||
}
|
||||
|
||||
return bdrv_write(bs->file, sector_num, buf, nb_sectors);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
|
||||
}
|
||||
|
||||
typedef struct RawScrubberBounce
|
||||
{
|
||||
BlockDriverCompletionFunc *cb;
|
||||
void *opaque;
|
||||
QEMUIOVector qiov;
|
||||
} RawScrubberBounce;
|
||||
|
||||
static void raw_aio_writev_scrubbed(void *opaque, int ret)
|
||||
{
|
||||
RawScrubberBounce *b = opaque;
|
||||
|
||||
if (ret < 0) {
|
||||
b->cb(b->opaque, ret);
|
||||
} else {
|
||||
b->cb(b->opaque, ret + 512);
|
||||
}
|
||||
|
||||
qemu_iovec_destroy(&b->qiov);
|
||||
qemu_free(b);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
const uint8_t *first_buf;
|
||||
int first_buf_index = 0, i;
|
||||
|
||||
/* This is probably being paranoid, but handle cases of zero size
|
||||
vectors. */
|
||||
for (i = 0; i < qiov->niov; i++) {
|
||||
if (qiov->iov[i].iov_len) {
|
||||
assert(qiov->iov[i].iov_len >= 512);
|
||||
first_buf_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
first_buf = qiov->iov[first_buf_index].iov_base;
|
||||
|
||||
if (check_write_unsafe(bs, sector_num, first_buf, nb_sectors)) {
|
||||
RawScrubberBounce *b;
|
||||
int ret;
|
||||
|
||||
/* write the first sector using sync I/O */
|
||||
ret = raw_write_scrubbed_bootsect(bs, first_buf);
|
||||
if (ret < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* adjust request to be everything but first sector */
|
||||
|
||||
b = qemu_malloc(sizeof(*b));
|
||||
b->cb = cb;
|
||||
b->opaque = opaque;
|
||||
|
||||
qemu_iovec_init(&b->qiov, qiov->nalloc);
|
||||
qemu_iovec_concat(&b->qiov, qiov, qiov->size);
|
||||
|
||||
b->qiov.size -= 512;
|
||||
b->qiov.iov[first_buf_index].iov_base += 512;
|
||||
b->qiov.iov[first_buf_index].iov_len -= 512;
|
||||
|
||||
return bdrv_aio_writev(bs->file, sector_num + 1, &b->qiov,
|
||||
nb_sectors - 1, raw_aio_writev_scrubbed, b);
|
||||
}
|
||||
|
||||
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
|
||||
}
|
||||
|
||||
static void raw_close(BlockDriverState *bs)
|
||||
{
|
||||
}
|
||||
|
||||
static void raw_flush(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_flush(bs->file);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_flush(bs->file, cb, opaque);
|
||||
}
|
||||
|
||||
static int64_t raw_getlength(BlockDriverState *bs)
|
||||
{
|
||||
return bdrv_getlength(bs->file);
|
||||
}
|
||||
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
return bdrv_truncate(bs->file, offset);
|
||||
}
|
||||
|
||||
static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
return 1; /* everything can be opened as raw image */
|
||||
}
|
||||
|
||||
static int raw_is_inserted(BlockDriverState *bs)
|
||||
{
|
||||
return bdrv_is_inserted(bs->file);
|
||||
}
|
||||
|
||||
static int raw_eject(BlockDriverState *bs, int eject_flag)
|
||||
{
|
||||
return bdrv_eject(bs->file, eject_flag);
|
||||
}
|
||||
|
||||
static int raw_set_locked(BlockDriverState *bs, int locked)
|
||||
{
|
||||
bdrv_set_locked(bs->file, locked);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||
{
|
||||
return bdrv_ioctl(bs->file, req, buf);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
|
||||
unsigned long int req, void *buf,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque);
|
||||
}
|
||||
|
||||
static int raw_create(const char *filename, QEMUOptionParameter *options)
|
||||
{
|
||||
return bdrv_create_file(filename, options);
|
||||
}
|
||||
|
||||
static QEMUOptionParameter raw_create_options[] = {
|
||||
{
|
||||
.name = BLOCK_OPT_SIZE,
|
||||
.type = OPT_SIZE,
|
||||
.help = "Virtual disk size"
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static int raw_has_zero_init(BlockDriverState *bs)
|
||||
{
|
||||
return bdrv_has_zero_init(bs->file);
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_raw = {
|
||||
.format_name = "raw",
|
||||
|
||||
/* It's really 0, but we need to make qemu_malloc() happy */
|
||||
.instance_size = 1,
|
||||
|
||||
.bdrv_open = raw_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_flush = raw_flush,
|
||||
.bdrv_probe = raw_probe,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_truncate = raw_truncate,
|
||||
|
||||
.bdrv_aio_readv = raw_aio_readv,
|
||||
.bdrv_aio_writev = raw_aio_writev,
|
||||
.bdrv_aio_flush = raw_aio_flush,
|
||||
|
||||
.bdrv_is_inserted = raw_is_inserted,
|
||||
.bdrv_eject = raw_eject,
|
||||
.bdrv_set_locked = raw_set_locked,
|
||||
.bdrv_ioctl = raw_ioctl,
|
||||
.bdrv_aio_ioctl = raw_aio_ioctl,
|
||||
|
||||
.bdrv_create = raw_create,
|
||||
.create_options = raw_create_options,
|
||||
.bdrv_has_zero_init = raw_has_zero_init,
|
||||
};
|
||||
|
||||
static void bdrv_raw_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_raw);
|
||||
}
|
||||
|
||||
block_init(bdrv_raw_init);
|
||||
2036
block/sheepdog.c
2036
block/sheepdog.c
File diff suppressed because it is too large
Load Diff
50
block/vdi.c
50
block/vdi.c
@@ -291,10 +291,11 @@ static void vdi_header_print(VdiHeader *header)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
|
||||
static int vdi_check(BlockDriverState *bs)
|
||||
{
|
||||
/* TODO: additional checks possible. */
|
||||
BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
|
||||
int n_errors = 0;
|
||||
uint32_t blocks_allocated = 0;
|
||||
uint32_t block;
|
||||
uint32_t *bmap;
|
||||
@@ -314,12 +315,11 @@ static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: block index %" PRIu32
|
||||
" also used by %" PRIu32 "\n", bmap[bmap_entry], bmap_entry);
|
||||
res->corruptions++;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: block index %" PRIu32
|
||||
" too large, is %" PRIu32 "\n", block, bmap_entry);
|
||||
res->corruptions++;
|
||||
n_errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,12 +327,12 @@ static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
|
||||
fprintf(stderr, "ERROR: allocated blocks mismatch, is %" PRIu32
|
||||
", should be %" PRIu32 "\n",
|
||||
blocks_allocated, s->header.blocks_allocated);
|
||||
res->corruptions++;
|
||||
n_errors++;
|
||||
}
|
||||
|
||||
qemu_free(bmap);
|
||||
|
||||
return 0;
|
||||
return n_errors;
|
||||
}
|
||||
|
||||
static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
@@ -376,15 +376,21 @@ static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return result;
|
||||
}
|
||||
|
||||
static int vdi_open(BlockDriverState *bs, int flags)
|
||||
static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVVdiState *s = bs->opaque;
|
||||
VdiHeader header;
|
||||
size_t bmap_size;
|
||||
int ret;
|
||||
|
||||
logout("\n");
|
||||
|
||||
if (bdrv_read(bs->file, 0, (uint8_t *)&header, 1) < 0) {
|
||||
ret = bdrv_file_open(&s->hd, filename, flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (bdrv_read(s->hd, 0, (uint8_t *)&header, 1) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -441,10 +447,8 @@ static int vdi_open(BlockDriverState *bs, int flags)
|
||||
|
||||
bmap_size = header.blocks_in_image * sizeof(uint32_t);
|
||||
bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
|
||||
if (bmap_size > 0) {
|
||||
s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
|
||||
}
|
||||
if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
|
||||
s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
|
||||
if (bdrv_read(s->hd, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
|
||||
goto fail_free_bmap;
|
||||
}
|
||||
|
||||
@@ -454,6 +458,7 @@ static int vdi_open(BlockDriverState *bs, int flags)
|
||||
qemu_free(s->bmap);
|
||||
|
||||
fail:
|
||||
bdrv_delete(s->hd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -477,7 +482,7 @@ static int vdi_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
static void vdi_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
/* TODO: This code is untested. How can I get it executed? */
|
||||
VdiAIOCB *acb = container_of(blockacb, VdiAIOCB, common);
|
||||
VdiAIOCB *acb = (VdiAIOCB *)blockacb;
|
||||
logout("\n");
|
||||
if (acb->hd_aiocb) {
|
||||
bdrv_aio_cancel(acb->hd_aiocb);
|
||||
@@ -608,7 +613,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
|
||||
acb->hd_iov.iov_base = (void *)acb->buf;
|
||||
acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
|
||||
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
|
||||
acb->hd_aiocb = bdrv_aio_readv(bs->file, offset, &acb->hd_qiov,
|
||||
acb->hd_aiocb = bdrv_aio_readv(s->hd, offset, &acb->hd_qiov,
|
||||
n_sectors, vdi_aio_read_cb, acb);
|
||||
if (acb->hd_aiocb == NULL) {
|
||||
goto done;
|
||||
@@ -671,7 +676,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
|
||||
acb->hd_iov.iov_base = acb->block_buffer;
|
||||
acb->hd_iov.iov_len = SECTOR_SIZE;
|
||||
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
|
||||
acb->hd_aiocb = bdrv_aio_writev(bs->file, 0, &acb->hd_qiov, 1,
|
||||
acb->hd_aiocb = bdrv_aio_writev(s->hd, 0, &acb->hd_qiov, 1,
|
||||
vdi_aio_write_cb, acb);
|
||||
if (acb->hd_aiocb == NULL) {
|
||||
goto done;
|
||||
@@ -700,7 +705,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
|
||||
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
|
||||
logout("will write %u block map sectors starting from entry %u\n",
|
||||
n_sectors, bmap_first);
|
||||
acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
|
||||
acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov,
|
||||
n_sectors, vdi_aio_write_cb, acb);
|
||||
if (acb->hd_aiocb == NULL) {
|
||||
goto done;
|
||||
@@ -749,7 +754,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
|
||||
acb->hd_iov.iov_base = (void *)block;
|
||||
acb->hd_iov.iov_len = s->block_size;
|
||||
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
|
||||
acb->hd_aiocb = bdrv_aio_writev(bs->file, offset,
|
||||
acb->hd_aiocb = bdrv_aio_writev(s->hd, offset,
|
||||
&acb->hd_qiov, s->block_sectors,
|
||||
vdi_aio_write_cb, acb);
|
||||
if (acb->hd_aiocb == NULL) {
|
||||
@@ -762,7 +767,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
|
||||
acb->hd_iov.iov_base = (void *)acb->buf;
|
||||
acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
|
||||
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
|
||||
acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
|
||||
acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov,
|
||||
n_sectors, vdi_aio_write_cb, acb);
|
||||
if (acb->hd_aiocb == NULL) {
|
||||
goto done;
|
||||
@@ -868,10 +873,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
|
||||
result = -errno;
|
||||
}
|
||||
|
||||
bmap = NULL;
|
||||
if (bmap_size > 0) {
|
||||
bmap = (uint32_t *)qemu_mallocz(bmap_size);
|
||||
}
|
||||
bmap = (uint32_t *)qemu_mallocz(bmap_size);
|
||||
for (i = 0; i < blocks; i++) {
|
||||
if (image_type == VDI_TYPE_STATIC) {
|
||||
bmap[i] = i;
|
||||
@@ -898,12 +900,16 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
|
||||
|
||||
static void vdi_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVdiState *s = bs->opaque;
|
||||
logout("\n");
|
||||
bdrv_delete(s->hd);
|
||||
}
|
||||
|
||||
static void vdi_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVdiState *s = bs->opaque;
|
||||
logout("\n");
|
||||
bdrv_flush(bs->file);
|
||||
bdrv_flush(s->hd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
248
block/vmdk.c
248
block/vmdk.c
@@ -76,6 +76,7 @@ typedef struct BDRVVmdkState {
|
||||
|
||||
unsigned int cluster_sectors;
|
||||
uint32_t parent_cid;
|
||||
int is_parent;
|
||||
} BDRVVmdkState;
|
||||
|
||||
typedef struct VmdkMetaData {
|
||||
@@ -108,13 +109,14 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
|
||||
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(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
|
||||
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
|
||||
return 0;
|
||||
|
||||
if (parent) {
|
||||
@@ -135,11 +137,12 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
|
||||
|
||||
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(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
|
||||
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
|
||||
return -1;
|
||||
|
||||
tmp_str = strstr(desc,"parentCID");
|
||||
@@ -150,7 +153,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
|
||||
pstrcat(desc, sizeof(desc), tmp_desc);
|
||||
}
|
||||
|
||||
if (bdrv_pwrite_sync(bs->file, 0x200, desc, DESC_SIZE) < 0)
|
||||
if (bdrv_pwrite_sync(s->hd, 0x200, desc, DESC_SIZE) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -176,7 +179,6 @@ static int vmdk_is_cid_valid(BlockDriverState *bs)
|
||||
static int vmdk_snapshot_create(const char *filename, const char *backing_file)
|
||||
{
|
||||
int snp_fd, p_fd;
|
||||
int ret;
|
||||
uint32_t p_cid;
|
||||
char *p_name, *gd_buf, *rgd_buf;
|
||||
const char *real_filename, *temp_str;
|
||||
@@ -201,49 +203,34 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file)
|
||||
|
||||
snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
|
||||
if (snp_fd < 0)
|
||||
return -errno;
|
||||
return -1;
|
||||
p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (p_fd < 0) {
|
||||
close(snp_fd);
|
||||
return -errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read the header */
|
||||
if (lseek(p_fd, 0x0, SEEK_SET) == -1) {
|
||||
ret = -errno;
|
||||
if (lseek(p_fd, 0x0, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
}
|
||||
if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE) {
|
||||
ret = -errno;
|
||||
if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* write the header */
|
||||
if (lseek(snp_fd, 0x0, SEEK_SET) == -1) {
|
||||
ret = -errno;
|
||||
if (lseek(snp_fd, 0x0, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
}
|
||||
if (write(snp_fd, hdr, HEADER_SIZE) == -1) {
|
||||
ret = -errno;
|
||||
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
|
||||
|
||||
if (ftruncate(snp_fd, header.grain_offset << 9)) {
|
||||
ret = -errno;
|
||||
goto fail;
|
||||
}
|
||||
ftruncate(snp_fd, header.grain_offset << 9);
|
||||
/* the descriptor offset = 0x200 */
|
||||
if (lseek(p_fd, 0x200, SEEK_SET) == -1) {
|
||||
ret = -errno;
|
||||
if (lseek(p_fd, 0x200, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
}
|
||||
if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE) {
|
||||
ret = -errno;
|
||||
if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((p_name = strstr(p_desc,"CID")) != NULL) {
|
||||
p_name += sizeof("CID");
|
||||
@@ -262,14 +249,10 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file)
|
||||
(uint32_t)header.capacity, real_filename);
|
||||
|
||||
/* write the descriptor */
|
||||
if (lseek(snp_fd, 0x200, SEEK_SET) == -1) {
|
||||
ret = -errno;
|
||||
if (lseek(snp_fd, 0x200, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
}
|
||||
if (write(snp_fd, s_desc, strlen(s_desc)) == -1) {
|
||||
ret = -errno;
|
||||
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
|
||||
@@ -279,73 +262,70 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file)
|
||||
* 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) {
|
||||
ret = -EINVAL;
|
||||
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) {
|
||||
ret = -errno;
|
||||
if (lseek(p_fd, rgd_offset, SEEK_SET) == -1)
|
||||
goto fail_rgd;
|
||||
}
|
||||
if (read(p_fd, rgd_buf, gd_size) != gd_size) {
|
||||
ret = -errno;
|
||||
if (read(p_fd, rgd_buf, gd_size) != gd_size)
|
||||
goto fail_rgd;
|
||||
}
|
||||
if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1) {
|
||||
ret = -errno;
|
||||
if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1)
|
||||
goto fail_rgd;
|
||||
}
|
||||
if (write(snp_fd, rgd_buf, gd_size) == -1) {
|
||||
ret = -errno;
|
||||
if (write(snp_fd, rgd_buf, gd_size) == -1)
|
||||
goto fail_rgd;
|
||||
}
|
||||
|
||||
/* write GD */
|
||||
gd_buf = qemu_malloc(gd_size);
|
||||
if (lseek(p_fd, gd_offset, SEEK_SET) == -1) {
|
||||
ret = -errno;
|
||||
if (lseek(p_fd, gd_offset, SEEK_SET) == -1)
|
||||
goto fail_gd;
|
||||
}
|
||||
if (read(p_fd, gd_buf, gd_size) != gd_size) {
|
||||
ret = -errno;
|
||||
if (read(p_fd, gd_buf, gd_size) != gd_size)
|
||||
goto fail_gd;
|
||||
}
|
||||
if (lseek(snp_fd, gd_offset, SEEK_SET) == -1) {
|
||||
ret = -errno;
|
||||
if (lseek(snp_fd, gd_offset, SEEK_SET) == -1)
|
||||
goto fail_gd;
|
||||
}
|
||||
if (write(snp_fd, gd_buf, gd_size) == -1) {
|
||||
ret = -errno;
|
||||
if (write(snp_fd, gd_buf, gd_size) == -1)
|
||||
goto fail_gd;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
fail_gd:
|
||||
qemu_free(gd_buf);
|
||||
fail_rgd:
|
||||
qemu_free(rgd_buf);
|
||||
fail:
|
||||
|
||||
close(p_fd);
|
||||
close(snp_fd);
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
fail_gd:
|
||||
qemu_free(gd_buf);
|
||||
fail_rgd:
|
||||
qemu_free(rgd_buf);
|
||||
fail:
|
||||
close(p_fd);
|
||||
close(snp_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int vmdk_parent_open(BlockDriverState *bs)
|
||||
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(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
|
||||
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
|
||||
return -1;
|
||||
|
||||
if ((p_name = strstr(desc,"parentFileNameHint")) != NULL) {
|
||||
char *end_name;
|
||||
struct stat file_buf;
|
||||
|
||||
p_name += sizeof("parentFileNameHint") + 1;
|
||||
if ((end_name = strchr(p_name,'\"')) == NULL)
|
||||
@@ -354,25 +334,50 @@ static int vmdk_parent_open(BlockDriverState *bs)
|
||||
return -1;
|
||||
|
||||
pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
|
||||
if (stat(bs->backing_file, &file_buf) != 0) {
|
||||
path_combine(parent_img_name, sizeof(parent_img_name),
|
||||
filename, bs->backing_file);
|
||||
} else {
|
||||
pstrcpy(parent_img_name, sizeof(parent_img_name),
|
||||
bs->backing_file);
|
||||
}
|
||||
|
||||
bs->backing_hd = bdrv_new("");
|
||||
if (!bs->backing_hd) {
|
||||
failure:
|
||||
bdrv_close(s->hd);
|
||||
return -1;
|
||||
}
|
||||
parent_open = 1;
|
||||
if (bdrv_open(bs->backing_hd, parent_img_name, BDRV_O_RDONLY) < 0)
|
||||
goto failure;
|
||||
parent_open = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmdk_open(BlockDriverState *bs, int flags)
|
||||
static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
uint32_t magic;
|
||||
int l1_size, i;
|
||||
int l1_size, i, ret;
|
||||
|
||||
if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic))
|
||||
if (parent_open)
|
||||
// Parent must be opened as RO.
|
||||
flags = BDRV_O_RDONLY;
|
||||
|
||||
ret = bdrv_file_open(&s->hd, filename, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic))
|
||||
goto fail;
|
||||
|
||||
magic = be32_to_cpu(magic);
|
||||
if (magic == VMDK3_MAGIC) {
|
||||
VMDK3Header header;
|
||||
|
||||
if (bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header)) != sizeof(header))
|
||||
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
|
||||
goto fail;
|
||||
s->cluster_sectors = le32_to_cpu(header.granularity);
|
||||
s->l2_size = 1 << 9;
|
||||
@@ -384,7 +389,7 @@ static int vmdk_open(BlockDriverState *bs, int flags)
|
||||
} else if (magic == VMDK4_MAGIC) {
|
||||
VMDK4Header header;
|
||||
|
||||
if (bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header)) != sizeof(header))
|
||||
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
|
||||
goto fail;
|
||||
bs->total_sectors = le64_to_cpu(header.capacity);
|
||||
s->cluster_sectors = le64_to_cpu(header.granularity);
|
||||
@@ -397,8 +402,13 @@ static int vmdk_open(BlockDriverState *bs, int flags)
|
||||
s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
|
||||
s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
|
||||
|
||||
if (parent_open)
|
||||
s->is_parent = 1;
|
||||
else
|
||||
s->is_parent = 0;
|
||||
|
||||
// try to open parent images, if exist
|
||||
if (vmdk_parent_open(bs) != 0)
|
||||
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);
|
||||
@@ -409,7 +419,7 @@ static int vmdk_open(BlockDriverState *bs, int flags)
|
||||
/* read the L1 table */
|
||||
l1_size = s->l1_size * sizeof(uint32_t);
|
||||
s->l1_table = qemu_malloc(l1_size);
|
||||
if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
|
||||
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
|
||||
goto fail;
|
||||
for(i = 0; i < s->l1_size; i++) {
|
||||
le32_to_cpus(&s->l1_table[i]);
|
||||
@@ -417,7 +427,7 @@ static int vmdk_open(BlockDriverState *bs, int flags)
|
||||
|
||||
if (s->l1_backup_table_offset) {
|
||||
s->l1_backup_table = qemu_malloc(l1_size);
|
||||
if (bdrv_pread(bs->file, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size)
|
||||
if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size)
|
||||
goto fail;
|
||||
for(i = 0; i < s->l1_size; i++) {
|
||||
le32_to_cpus(&s->l1_backup_table[i]);
|
||||
@@ -430,6 +440,7 @@ static int vmdk_open(BlockDriverState *bs, int flags)
|
||||
qemu_free(s->l1_backup_table);
|
||||
qemu_free(s->l1_table);
|
||||
qemu_free(s->l2_cache);
|
||||
bdrv_delete(s->hd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -457,7 +468,7 @@ static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
|
||||
}
|
||||
|
||||
//Write grain only into the active image
|
||||
ret = bdrv_write(bs->file, cluster_offset, whole_grain,
|
||||
ret = bdrv_write(s->hd, cluster_offset, whole_grain,
|
||||
s->cluster_sectors);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
@@ -471,13 +482,13 @@ static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data)
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
|
||||
/* update L2 table */
|
||||
if (bdrv_pwrite_sync(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
|
||||
if (bdrv_pwrite_sync(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
|
||||
&(m_data->offset), sizeof(m_data->offset)) < 0)
|
||||
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_sync(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
|
||||
if (bdrv_pwrite_sync(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
|
||||
&(m_data->offset), sizeof(m_data->offset)) < 0)
|
||||
return -1;
|
||||
}
|
||||
@@ -525,7 +536,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
|
||||
}
|
||||
}
|
||||
l2_table = s->l2_cache + (min_index * s->l2_size);
|
||||
if (bdrv_pread(bs->file, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) !=
|
||||
if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) !=
|
||||
s->l2_size * sizeof(uint32_t))
|
||||
return 0;
|
||||
|
||||
@@ -538,15 +549,15 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
|
||||
if (!cluster_offset) {
|
||||
if (!allocate)
|
||||
return 0;
|
||||
|
||||
// Avoid the L2 tables update for the images that have snapshots.
|
||||
cluster_offset = bdrv_getlength(bs->file);
|
||||
bdrv_truncate(bs->file, cluster_offset + (s->cluster_sectors << 9));
|
||||
|
||||
cluster_offset >>= 9;
|
||||
tmp = cpu_to_le32(cluster_offset);
|
||||
l2_table[l2_index] = tmp;
|
||||
if (!s->is_parent) {
|
||||
cluster_offset = bdrv_getlength(s->hd);
|
||||
bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
|
||||
|
||||
cluster_offset >>= 9;
|
||||
tmp = cpu_to_le32(cluster_offset);
|
||||
l2_table[l2_index] = tmp;
|
||||
}
|
||||
/* First of all we write grain itself, to avoid race condition
|
||||
* that may to corrupt the image.
|
||||
* This problem may occur because of insufficient space on host disk
|
||||
@@ -608,7 +619,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
||||
memset(buf, 0, 512 * n);
|
||||
}
|
||||
} else {
|
||||
if(bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
|
||||
if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
|
||||
return -1;
|
||||
}
|
||||
nb_sectors -= n;
|
||||
@@ -644,7 +655,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
if (!cluster_offset)
|
||||
return -1;
|
||||
|
||||
if (bdrv_pwrite(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
|
||||
if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
|
||||
return -1;
|
||||
if (m_data.valid) {
|
||||
/* update L2 tables */
|
||||
@@ -692,7 +703,6 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
|
||||
int64_t total_size = 0;
|
||||
const char *backing_file = NULL;
|
||||
int flags = 0;
|
||||
int ret;
|
||||
|
||||
// Read out options
|
||||
while (options && options->name) {
|
||||
@@ -714,7 +724,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||
0644);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
return -1;
|
||||
magic = cpu_to_be32(VMDK4_MAGIC);
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.version = cpu_to_le32(1);
|
||||
@@ -749,44 +759,22 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
|
||||
header.check_bytes[3] = 0xa;
|
||||
|
||||
/* write all the data */
|
||||
ret = qemu_write_full(fd, &magic, sizeof(magic));
|
||||
if (ret != sizeof(magic)) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
ret = qemu_write_full(fd, &header, sizeof(header));
|
||||
if (ret != sizeof(header)) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
write(fd, &magic, sizeof(magic));
|
||||
write(fd, &header, sizeof(header));
|
||||
|
||||
ret = ftruncate(fd, header.grain_offset << 9);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
ftruncate(fd, header.grain_offset << 9);
|
||||
|
||||
/* write grain directory */
|
||||
lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
|
||||
for (i = 0, tmp = header.rgd_offset + gd_size;
|
||||
i < gt_count; i++, tmp += gt_size) {
|
||||
ret = qemu_write_full(fd, &tmp, sizeof(tmp));
|
||||
if (ret != sizeof(tmp)) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
i < gt_count; i++, tmp += gt_size)
|
||||
write(fd, &tmp, sizeof(tmp));
|
||||
|
||||
/* write backup grain directory */
|
||||
lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
|
||||
for (i = 0, tmp = header.gd_offset + gd_size;
|
||||
i < gt_count; i++, tmp += gt_size) {
|
||||
ret = qemu_write_full(fd, &tmp, sizeof(tmp));
|
||||
if (ret != sizeof(tmp)) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
i < gt_count; i++, tmp += gt_size)
|
||||
write(fd, &tmp, sizeof(tmp));
|
||||
|
||||
/* compose the descriptor */
|
||||
real_filename = filename;
|
||||
@@ -803,16 +791,10 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
|
||||
|
||||
/* write the descriptor */
|
||||
lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
|
||||
ret = qemu_write_full(fd, desc, strlen(desc));
|
||||
if (ret != strlen(desc)) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
write(fd, desc, strlen(desc));
|
||||
|
||||
ret = 0;
|
||||
exit:
|
||||
close(fd);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vmdk_close(BlockDriverState *bs)
|
||||
@@ -821,11 +803,15 @@ static void vmdk_close(BlockDriverState *bs)
|
||||
|
||||
qemu_free(s->l1_table);
|
||||
qemu_free(s->l2_cache);
|
||||
// try to close parent image, if exist
|
||||
vmdk_parent_close(s->hd);
|
||||
bdrv_delete(s->hd);
|
||||
}
|
||||
|
||||
static void vmdk_flush(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_flush(bs->file);
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
bdrv_flush(s->hd);
|
||||
}
|
||||
|
||||
|
||||
@@ -852,7 +838,7 @@ static BlockDriver bdrv_vmdk = {
|
||||
.format_name = "vmdk",
|
||||
.instance_size = sizeof(BDRVVmdkState),
|
||||
.bdrv_probe = vmdk_probe,
|
||||
.bdrv_open = vmdk_open,
|
||||
.bdrv_open = vmdk_open,
|
||||
.bdrv_read = vmdk_read,
|
||||
.bdrv_write = vmdk_write,
|
||||
.bdrv_close = vmdk_close,
|
||||
|
||||
65
block/vpc.c
65
block/vpc.c
@@ -150,16 +150,20 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpc_open(BlockDriverState *bs, int flags)
|
||||
static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
int i;
|
||||
int ret, i;
|
||||
struct vhd_footer* footer;
|
||||
struct vhd_dyndisk_header* dyndisk_header;
|
||||
uint8_t buf[HEADER_SIZE];
|
||||
uint32_t checksum;
|
||||
|
||||
if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
|
||||
ret = bdrv_file_open(&s->hd, filename, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (bdrv_pread(s->hd, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
|
||||
goto fail;
|
||||
|
||||
footer = (struct vhd_footer*) s->footer_buf;
|
||||
@@ -170,7 +174,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
|
||||
footer->checksum = 0;
|
||||
if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum)
|
||||
fprintf(stderr, "block-vpc: The header checksum of '%s' is "
|
||||
"incorrect.\n", bs->filename);
|
||||
"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
|
||||
@@ -178,7 +182,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
|
||||
bs->total_sectors = (int64_t)
|
||||
be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
|
||||
|
||||
if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
|
||||
if (bdrv_pread(s->hd, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
|
||||
!= HEADER_SIZE)
|
||||
goto fail;
|
||||
|
||||
@@ -195,7 +199,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
|
||||
s->pagetable = qemu_malloc(s->max_table_entries * 4);
|
||||
|
||||
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
||||
if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
|
||||
if (bdrv_pread(s->hd, s->bat_offset, s->pagetable,
|
||||
s->max_table_entries * 4) != s->max_table_entries * 4)
|
||||
goto fail;
|
||||
|
||||
@@ -224,6 +228,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
bdrv_delete(s->hd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -261,7 +266,7 @@ static inline int64_t get_sector_offset(BlockDriverState *bs,
|
||||
|
||||
s->last_bitmap_offset = bitmap_offset;
|
||||
memset(bitmap, 0xff, s->bitmap_size);
|
||||
bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
|
||||
bdrv_pwrite_sync(s->hd, bitmap_offset, bitmap, s->bitmap_size);
|
||||
}
|
||||
|
||||
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
|
||||
@@ -311,7 +316,7 @@ static int rewrite_footer(BlockDriverState* bs)
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
int64_t offset = s->free_data_block_offset;
|
||||
|
||||
ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE);
|
||||
ret = bdrv_pwrite_sync(s->hd, offset, s->footer_buf, HEADER_SIZE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -346,7 +351,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
|
||||
|
||||
// Initialize the block's bitmap
|
||||
memset(bitmap, 0xff, s->bitmap_size);
|
||||
bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
|
||||
bdrv_pwrite_sync(s->hd, s->free_data_block_offset, bitmap,
|
||||
s->bitmap_size);
|
||||
|
||||
// Write new footer (the old one will be overwritten)
|
||||
@@ -358,7 +363,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
|
||||
// Write BAT entry to disk
|
||||
bat_offset = s->bat_offset + (4 * index);
|
||||
bat_value = be32_to_cpu(s->pagetable[index]);
|
||||
ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
|
||||
ret = bdrv_pwrite_sync(s->hd, bat_offset, &bat_value, 4);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
@@ -375,30 +380,21 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num,
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
int ret;
|
||||
int64_t offset;
|
||||
int64_t sectors, sectors_per_block;
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
offset = get_sector_offset(bs, sector_num, 0);
|
||||
|
||||
sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
|
||||
sectors = sectors_per_block - (sector_num % sectors_per_block);
|
||||
if (sectors > nb_sectors) {
|
||||
sectors = nb_sectors;
|
||||
}
|
||||
|
||||
if (offset == -1) {
|
||||
memset(buf, 0, sectors * BDRV_SECTOR_SIZE);
|
||||
memset(buf, 0, 512);
|
||||
} else {
|
||||
ret = bdrv_pread(bs->file, offset, buf,
|
||||
sectors * BDRV_SECTOR_SIZE);
|
||||
if (ret != sectors * BDRV_SECTOR_SIZE) {
|
||||
ret = bdrv_pread(s->hd, offset, buf, 512);
|
||||
if (ret != 512)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
nb_sectors -= sectors;
|
||||
sector_num += sectors;
|
||||
buf += sectors * BDRV_SECTOR_SIZE;
|
||||
nb_sectors--;
|
||||
sector_num++;
|
||||
buf += 512;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -408,32 +404,24 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
|
||||
{
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
int64_t offset;
|
||||
int64_t sectors, sectors_per_block;
|
||||
int ret;
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
offset = get_sector_offset(bs, sector_num, 1);
|
||||
|
||||
sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
|
||||
sectors = sectors_per_block - (sector_num % sectors_per_block);
|
||||
if (sectors > nb_sectors) {
|
||||
sectors = nb_sectors;
|
||||
}
|
||||
|
||||
if (offset == -1) {
|
||||
offset = alloc_block(bs, sector_num);
|
||||
if (offset < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = bdrv_pwrite(bs->file, offset, buf, sectors * BDRV_SECTOR_SIZE);
|
||||
if (ret != sectors * BDRV_SECTOR_SIZE) {
|
||||
ret = bdrv_pwrite(s->hd, offset, buf, 512);
|
||||
if (ret != 512)
|
||||
return -1;
|
||||
}
|
||||
|
||||
nb_sectors -= sectors;
|
||||
sector_num += sectors;
|
||||
buf += sectors * BDRV_SECTOR_SIZE;
|
||||
nb_sectors--;
|
||||
sector_num++;
|
||||
buf += 512;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -606,6 +594,7 @@ static void vpc_close(BlockDriverState *bs)
|
||||
#ifdef CACHE
|
||||
qemu_free(s->pageentry_u8);
|
||||
#endif
|
||||
bdrv_delete(s->hd);
|
||||
}
|
||||
|
||||
static QEMUOptionParameter vpc_create_options[] = {
|
||||
|
||||
@@ -512,7 +512,7 @@ static inline uint8_t fat_chksum(const direntry_t* entry)
|
||||
for(i=0;i<11;i++) {
|
||||
unsigned char c;
|
||||
|
||||
c = (i < 8) ? entry->name[i] : entry->extension[i-8];
|
||||
c = (i <= 8) ? entry->name[i] : entry->extension[i-8];
|
||||
chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
|
||||
}
|
||||
|
||||
@@ -1099,8 +1099,8 @@ static inline void vvfat_close_current_file(BDRVVVFATState *s)
|
||||
*/
|
||||
static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
|
||||
{
|
||||
int index3=index1+1;
|
||||
while(1) {
|
||||
int index3;
|
||||
mapping_t* mapping;
|
||||
index3=(index1+index2)/2;
|
||||
mapping=array_get(&(s->mapping),index3);
|
||||
@@ -1244,7 +1244,7 @@ static void print_direntry(const direntry_t* direntry)
|
||||
int j = 0;
|
||||
char buffer[1024];
|
||||
|
||||
fprintf(stderr, "direntry %p: ", direntry);
|
||||
fprintf(stderr, "direntry 0x%x: ", (int)direntry);
|
||||
if(!direntry)
|
||||
return;
|
||||
if(is_long_name(direntry)) {
|
||||
@@ -1273,11 +1273,7 @@ static void print_direntry(const direntry_t* direntry)
|
||||
|
||||
static void print_mapping(const mapping_t* mapping)
|
||||
{
|
||||
fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
|
||||
"first_mapping_index = %d, name = %s, mode = 0x%x, " ,
|
||||
mapping, mapping->begin, mapping->end, mapping->dir_index,
|
||||
mapping->first_mapping_index, mapping->path, mapping->mode);
|
||||
|
||||
fprintf(stderr, "mapping (0x%x): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , (int)mapping, mapping->begin, mapping->end, mapping->dir_index, mapping->first_mapping_index, mapping->path, mapping->mode);
|
||||
if (mapping->mode & MODE_DIRECTORY)
|
||||
fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
|
||||
else
|
||||
@@ -1642,7 +1638,7 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
|
||||
/* new file */
|
||||
schedule_new_file(s, qemu_strdup(path), cluster_num);
|
||||
else {
|
||||
abort();
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1663,7 +1659,7 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
|
||||
if (offset != mapping->info.file.offset + s->cluster_size
|
||||
* (cluster_num - mapping->begin)) {
|
||||
/* offset of this cluster in file chain has changed */
|
||||
abort();
|
||||
assert(0);
|
||||
copy_it = 1;
|
||||
} else if (offset == 0) {
|
||||
const char* basename = get_basename(mapping->path);
|
||||
@@ -1675,7 +1671,7 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
|
||||
|
||||
if (mapping->first_mapping_index != first_mapping_index
|
||||
&& mapping->info.file.offset > 0) {
|
||||
abort();
|
||||
assert(0);
|
||||
copy_it = 1;
|
||||
}
|
||||
|
||||
@@ -1841,7 +1837,7 @@ DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i)
|
||||
goto fail;
|
||||
}
|
||||
} else
|
||||
abort(); /* cluster_count = 0; */
|
||||
assert(0); /* cluster_count = 0; */
|
||||
|
||||
ret += cluster_count;
|
||||
}
|
||||
@@ -2462,17 +2458,14 @@ static int handle_commits(BDRVVVFATState* s)
|
||||
commit_t* commit = array_get(&(s->commits), i);
|
||||
switch(commit->action) {
|
||||
case ACTION_RENAME: case ACTION_MKDIR:
|
||||
abort();
|
||||
assert(0);
|
||||
fail = -2;
|
||||
break;
|
||||
case ACTION_WRITEOUT: {
|
||||
#ifndef NDEBUG
|
||||
/* these variables are only used by assert() below */
|
||||
direntry_t* entry = array_get(&(s->directory),
|
||||
commit->param.writeout.dir_index);
|
||||
uint32_t begin = begin_of_direntry(entry);
|
||||
mapping_t* mapping = find_mapping_for_cluster(s, begin);
|
||||
#endif
|
||||
|
||||
assert(mapping);
|
||||
assert(mapping->begin == begin);
|
||||
@@ -2523,7 +2516,7 @@ static int handle_commits(BDRVVVFATState* s)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
abort();
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
if (i > 0 && array_remove_slice(&(s->commits), 0, i))
|
||||
@@ -2611,7 +2604,7 @@ static int do_commit(BDRVVVFATState* s)
|
||||
ret = handle_renames_and_mkdirs(s);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Error handling renames (%d)\n", ret);
|
||||
abort();
|
||||
assert(0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2622,21 +2615,21 @@ static int do_commit(BDRVVVFATState* s)
|
||||
ret = commit_direntries(s, 0, -1);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
|
||||
abort();
|
||||
assert(0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = handle_commits(s);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Error handling commits (%d)\n", ret);
|
||||
abort();
|
||||
assert(0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = handle_deletes(s);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Error deleting\n");
|
||||
abort();
|
||||
assert(0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2799,11 +2792,8 @@ static int enable_write_target(BDRVVVFATState *s)
|
||||
if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
|
||||
return -1;
|
||||
s->qcow = bdrv_new("");
|
||||
if (s->qcow == NULL ||
|
||||
bdrv_open(s->qcow, s->qcow_filename, BDRV_O_RDWR, bdrv_qcow) < 0)
|
||||
{
|
||||
if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
unlink(s->qcow_filename);
|
||||
@@ -2831,7 +2821,7 @@ static void vvfat_close(BlockDriverState *bs)
|
||||
static BlockDriver bdrv_vvfat = {
|
||||
.format_name = "vvfat",
|
||||
.instance_size = sizeof(BDRVVVFATState),
|
||||
.bdrv_file_open = vvfat_open,
|
||||
.bdrv_open = vvfat_open,
|
||||
.bdrv_read = vvfat_read,
|
||||
.bdrv_write = vvfat_write,
|
||||
.bdrv_close = vvfat_close,
|
||||
@@ -2869,7 +2859,7 @@ static void checkpoint(void) {
|
||||
return;
|
||||
/* avoid compiler warnings: */
|
||||
hexdump(NULL, 100);
|
||||
remove_mapping(vvv, 0);
|
||||
remove_mapping(vvv, NULL);
|
||||
print_mapping(NULL);
|
||||
print_direntry(NULL);
|
||||
}
|
||||
|
||||
69
block_int.h
69
block_int.h
@@ -26,7 +26,6 @@
|
||||
|
||||
#include "block.h"
|
||||
#include "qemu-option.h"
|
||||
#include "qemu-queue.h"
|
||||
|
||||
#define BLOCK_FLAG_ENCRYPT 1
|
||||
#define BLOCK_FLAG_COMPRESS 2
|
||||
@@ -51,8 +50,7 @@ struct BlockDriver {
|
||||
int instance_size;
|
||||
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
|
||||
int (*bdrv_probe_device)(const char *filename);
|
||||
int (*bdrv_open)(BlockDriverState *bs, int flags);
|
||||
int (*bdrv_file_open)(BlockDriverState *bs, const char *filename, int flags);
|
||||
int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
|
||||
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
|
||||
@@ -100,9 +98,6 @@ struct BlockDriver {
|
||||
int (*bdrv_load_vmstate)(BlockDriverState *bs, uint8_t *buf,
|
||||
int64_t pos, int size);
|
||||
|
||||
int (*bdrv_change_backing_file)(BlockDriverState *bs,
|
||||
const char *backing_file, const char *backing_fmt);
|
||||
|
||||
/* removable device specific */
|
||||
int (*bdrv_is_inserted)(BlockDriverState *bs);
|
||||
int (*bdrv_media_changed)(BlockDriverState *bs);
|
||||
@@ -119,36 +114,25 @@ struct BlockDriver {
|
||||
QEMUOptionParameter *create_options;
|
||||
|
||||
|
||||
/*
|
||||
* Returns 0 for completed check, -errno for internal errors.
|
||||
* The check results are stored in result.
|
||||
*/
|
||||
int (*bdrv_check)(BlockDriverState* bs, BdrvCheckResult *result);
|
||||
/* Returns number of errors in image, -errno for internal errors */
|
||||
int (*bdrv_check)(BlockDriverState* bs);
|
||||
|
||||
void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event);
|
||||
/* Set if newly created images are not guaranteed to contain only zeros */
|
||||
int no_zero_init;
|
||||
|
||||
/*
|
||||
* Returns 1 if newly created images are guaranteed to contain only
|
||||
* zeros, 0 otherwise.
|
||||
*/
|
||||
int (*bdrv_has_zero_init)(BlockDriverState *bs);
|
||||
|
||||
QLIST_ENTRY(BlockDriver) list;
|
||||
struct BlockDriver *next;
|
||||
};
|
||||
|
||||
struct BlockDriverState {
|
||||
int64_t total_sectors; /* if we are reading a disk image, give its
|
||||
size in sectors */
|
||||
int read_only; /* if true, the media is read only */
|
||||
int keep_read_only; /* if true, the media was requested to stay read only */
|
||||
int open_flags; /* flags used to open the file, re-used for re-open */
|
||||
int removable; /* if true, the media can be removed */
|
||||
int locked; /* if true, the media cannot temporarily be ejected */
|
||||
int tray_open; /* if true, the virtual tray is open */
|
||||
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* */
|
||||
int probed; /* if true, format was probed automatically */
|
||||
/* event callback when inserting/removing */
|
||||
void (*change_cb)(void *opaque);
|
||||
void *change_opaque;
|
||||
@@ -156,8 +140,6 @@ struct BlockDriverState {
|
||||
BlockDriver *drv; /* NULL means no media */
|
||||
void *opaque;
|
||||
|
||||
DeviceState *peer;
|
||||
|
||||
char filename[1024];
|
||||
char backing_file[1024]; /* if non zero, the image is a diff of
|
||||
this file image */
|
||||
@@ -166,8 +148,6 @@ struct BlockDriverState {
|
||||
int media_changed;
|
||||
|
||||
BlockDriverState *backing_hd;
|
||||
BlockDriverState *file;
|
||||
|
||||
/* async read/write emulation */
|
||||
|
||||
void *sync_aiocb;
|
||||
@@ -177,7 +157,6 @@ struct BlockDriverState {
|
||||
uint64_t wr_bytes;
|
||||
uint64_t rd_ops;
|
||||
uint64_t wr_ops;
|
||||
uint64_t wr_highest_sector;
|
||||
|
||||
/* Whether the disk can expand beyond total_sectors */
|
||||
int growable;
|
||||
@@ -192,11 +171,9 @@ struct BlockDriverState {
|
||||
drivers. They are not used by the block driver */
|
||||
int cyls, heads, secs, translation;
|
||||
int type;
|
||||
BlockErrorAction on_read_error, on_write_error;
|
||||
char device_name[32];
|
||||
unsigned long *dirty_bitmap;
|
||||
int64_t dirty_count;
|
||||
QTAILQ_ENTRY(BlockDriverState) list;
|
||||
BlockDriverState *next;
|
||||
void *private;
|
||||
};
|
||||
|
||||
@@ -216,38 +193,10 @@ void qemu_aio_release(void *p);
|
||||
|
||||
void *qemu_blockalign(BlockDriverState *bs, size_t size);
|
||||
|
||||
extern BlockDriverState *bdrv_first;
|
||||
|
||||
#ifdef _WIN32
|
||||
int is_windows_drive(const char *filename);
|
||||
#endif
|
||||
|
||||
typedef struct BlockConf {
|
||||
BlockDriverState *bs;
|
||||
uint16_t physical_block_size;
|
||||
uint16_t logical_block_size;
|
||||
uint16_t min_io_size;
|
||||
uint32_t opt_io_size;
|
||||
} BlockConf;
|
||||
|
||||
static inline unsigned int get_physical_block_exp(BlockConf *conf)
|
||||
{
|
||||
unsigned int exp = 0, size;
|
||||
|
||||
for (size = conf->physical_block_size;
|
||||
size > conf->logical_block_size;
|
||||
size >>= 1) {
|
||||
exp++;
|
||||
}
|
||||
|
||||
return exp;
|
||||
}
|
||||
|
||||
#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
|
||||
DEFINE_PROP_DRIVE("drive", _state, _conf.bs), \
|
||||
DEFINE_PROP_UINT16("logical_block_size", _state, \
|
||||
_conf.logical_block_size, 512), \
|
||||
DEFINE_PROP_UINT16("physical_block_size", _state, \
|
||||
_conf.physical_block_size, 512), \
|
||||
DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0), \
|
||||
DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0)
|
||||
|
||||
#endif /* BLOCK_INT_H */
|
||||
|
||||
599
blockdev.c
599
blockdev.c
@@ -1,599 +0,0 @@
|
||||
/*
|
||||
* QEMU host block devices
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "block.h"
|
||||
#include "blockdev.h"
|
||||
#include "monitor.h"
|
||||
#include "qerror.h"
|
||||
#include "qemu-option.h"
|
||||
#include "qemu-config.h"
|
||||
#include "sysemu.h"
|
||||
|
||||
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
|
||||
|
||||
/*
|
||||
* We automatically delete the drive when a device using it gets
|
||||
* unplugged. Questionable feature, but we can't just drop it.
|
||||
* Device models call blockdev_mark_auto_del() to schedule the
|
||||
* automatic deletion, and generic qdev code calls blockdev_auto_del()
|
||||
* when deletion is actually safe.
|
||||
*/
|
||||
void blockdev_mark_auto_del(BlockDriverState *bs)
|
||||
{
|
||||
DriveInfo *dinfo = drive_get_by_blockdev(bs);
|
||||
|
||||
dinfo->auto_del = 1;
|
||||
}
|
||||
|
||||
void blockdev_auto_del(BlockDriverState *bs)
|
||||
{
|
||||
DriveInfo *dinfo = drive_get_by_blockdev(bs);
|
||||
|
||||
if (dinfo->auto_del) {
|
||||
drive_uninit(dinfo);
|
||||
}
|
||||
}
|
||||
|
||||
QemuOpts *drive_add(const char *file, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char optstr[1024];
|
||||
QemuOpts *opts;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(optstr, sizeof(optstr), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
opts = qemu_opts_parse(&qemu_drive_opts, optstr, 0);
|
||||
if (!opts) {
|
||||
return NULL;
|
||||
}
|
||||
if (file)
|
||||
qemu_opt_set(opts, "file", file);
|
||||
return opts;
|
||||
}
|
||||
|
||||
DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
|
||||
{
|
||||
DriveInfo *dinfo;
|
||||
|
||||
/* seek interface, bus and unit */
|
||||
|
||||
QTAILQ_FOREACH(dinfo, &drives, next) {
|
||||
if (dinfo->type == type &&
|
||||
dinfo->bus == bus &&
|
||||
dinfo->unit == unit)
|
||||
return dinfo;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int drive_get_max_bus(BlockInterfaceType type)
|
||||
{
|
||||
int max_bus;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
max_bus = -1;
|
||||
QTAILQ_FOREACH(dinfo, &drives, next) {
|
||||
if(dinfo->type == type &&
|
||||
dinfo->bus > max_bus)
|
||||
max_bus = dinfo->bus;
|
||||
}
|
||||
return max_bus;
|
||||
}
|
||||
|
||||
DriveInfo *drive_get_by_blockdev(BlockDriverState *bs)
|
||||
{
|
||||
DriveInfo *dinfo;
|
||||
|
||||
QTAILQ_FOREACH(dinfo, &drives, next) {
|
||||
if (dinfo->bdrv == bs) {
|
||||
return dinfo;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void bdrv_format_print(void *opaque, const char *name)
|
||||
{
|
||||
fprintf(stderr, " %s", name);
|
||||
}
|
||||
|
||||
void drive_uninit(DriveInfo *dinfo)
|
||||
{
|
||||
qemu_opts_del(dinfo->opts);
|
||||
bdrv_delete(dinfo->bdrv);
|
||||
QTAILQ_REMOVE(&drives, dinfo, next);
|
||||
qemu_free(dinfo);
|
||||
}
|
||||
|
||||
static int parse_block_error_action(const char *buf, int is_read)
|
||||
{
|
||||
if (!strcmp(buf, "ignore")) {
|
||||
return BLOCK_ERR_IGNORE;
|
||||
} else if (!is_read && !strcmp(buf, "enospc")) {
|
||||
return BLOCK_ERR_STOP_ENOSPC;
|
||||
} else if (!strcmp(buf, "stop")) {
|
||||
return BLOCK_ERR_STOP_ANY;
|
||||
} else if (!strcmp(buf, "report")) {
|
||||
return BLOCK_ERR_REPORT;
|
||||
} else {
|
||||
fprintf(stderr, "qemu: '%s' invalid %s error action\n",
|
||||
buf, is_read ? "read" : "write");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
|
||||
{
|
||||
const char *buf;
|
||||
const char *file = NULL;
|
||||
char devname[128];
|
||||
const char *serial;
|
||||
const char *mediastr = "";
|
||||
BlockInterfaceType type;
|
||||
enum { MEDIA_DISK, MEDIA_CDROM } media;
|
||||
int bus_id, unit_id;
|
||||
int cyls, heads, secs, translation;
|
||||
BlockDriver *drv = NULL;
|
||||
int max_devs;
|
||||
int index;
|
||||
int ro = 0;
|
||||
int bdrv_flags = 0;
|
||||
int on_read_error, on_write_error;
|
||||
const char *devaddr;
|
||||
DriveInfo *dinfo;
|
||||
int snapshot = 0;
|
||||
int ret;
|
||||
|
||||
*fatal_error = 1;
|
||||
|
||||
translation = BIOS_ATA_TRANSLATION_AUTO;
|
||||
|
||||
if (default_to_scsi) {
|
||||
type = IF_SCSI;
|
||||
max_devs = MAX_SCSI_DEVS;
|
||||
pstrcpy(devname, sizeof(devname), "scsi");
|
||||
} else {
|
||||
type = IF_IDE;
|
||||
max_devs = MAX_IDE_DEVS;
|
||||
pstrcpy(devname, sizeof(devname), "ide");
|
||||
}
|
||||
media = MEDIA_DISK;
|
||||
|
||||
/* extract parameters */
|
||||
bus_id = qemu_opt_get_number(opts, "bus", 0);
|
||||
unit_id = qemu_opt_get_number(opts, "unit", -1);
|
||||
index = qemu_opt_get_number(opts, "index", -1);
|
||||
|
||||
cyls = qemu_opt_get_number(opts, "cyls", 0);
|
||||
heads = qemu_opt_get_number(opts, "heads", 0);
|
||||
secs = qemu_opt_get_number(opts, "secs", 0);
|
||||
|
||||
snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
|
||||
ro = qemu_opt_get_bool(opts, "readonly", 0);
|
||||
|
||||
file = qemu_opt_get(opts, "file");
|
||||
serial = qemu_opt_get(opts, "serial");
|
||||
|
||||
if ((buf = qemu_opt_get(opts, "if")) != NULL) {
|
||||
pstrcpy(devname, sizeof(devname), buf);
|
||||
if (!strcmp(buf, "ide")) {
|
||||
type = IF_IDE;
|
||||
max_devs = MAX_IDE_DEVS;
|
||||
} else if (!strcmp(buf, "scsi")) {
|
||||
type = IF_SCSI;
|
||||
max_devs = MAX_SCSI_DEVS;
|
||||
} else if (!strcmp(buf, "floppy")) {
|
||||
type = IF_FLOPPY;
|
||||
max_devs = 0;
|
||||
} else if (!strcmp(buf, "pflash")) {
|
||||
type = IF_PFLASH;
|
||||
max_devs = 0;
|
||||
} else if (!strcmp(buf, "mtd")) {
|
||||
type = IF_MTD;
|
||||
max_devs = 0;
|
||||
} else if (!strcmp(buf, "sd")) {
|
||||
type = IF_SD;
|
||||
max_devs = 0;
|
||||
} else if (!strcmp(buf, "virtio")) {
|
||||
type = IF_VIRTIO;
|
||||
max_devs = 0;
|
||||
} else if (!strcmp(buf, "xen")) {
|
||||
type = IF_XEN;
|
||||
max_devs = 0;
|
||||
} else if (!strcmp(buf, "none")) {
|
||||
type = IF_NONE;
|
||||
max_devs = 0;
|
||||
} else {
|
||||
fprintf(stderr, "qemu: unsupported bus type '%s'\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cyls || heads || secs) {
|
||||
if (cyls < 1 || (type == IF_IDE && cyls > 16383)) {
|
||||
fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
if (heads < 1 || (type == IF_IDE && heads > 16)) {
|
||||
fprintf(stderr, "qemu: '%s' invalid physical heads number\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
if (secs < 1 || (type == IF_IDE && secs > 63)) {
|
||||
fprintf(stderr, "qemu: '%s' invalid physical secs number\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((buf = qemu_opt_get(opts, "trans")) != NULL) {
|
||||
if (!cyls) {
|
||||
fprintf(stderr,
|
||||
"qemu: '%s' trans must be used with cyls,heads and secs\n",
|
||||
buf);
|
||||
return NULL;
|
||||
}
|
||||
if (!strcmp(buf, "none"))
|
||||
translation = BIOS_ATA_TRANSLATION_NONE;
|
||||
else if (!strcmp(buf, "lba"))
|
||||
translation = BIOS_ATA_TRANSLATION_LBA;
|
||||
else if (!strcmp(buf, "auto"))
|
||||
translation = BIOS_ATA_TRANSLATION_AUTO;
|
||||
else {
|
||||
fprintf(stderr, "qemu: '%s' invalid translation type\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((buf = qemu_opt_get(opts, "media")) != NULL) {
|
||||
if (!strcmp(buf, "disk")) {
|
||||
media = MEDIA_DISK;
|
||||
} else if (!strcmp(buf, "cdrom")) {
|
||||
if (cyls || secs || heads) {
|
||||
fprintf(stderr,
|
||||
"qemu: '%s' invalid physical CHS format\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
media = MEDIA_CDROM;
|
||||
} else {
|
||||
fprintf(stderr, "qemu: '%s' invalid media\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
|
||||
if (!strcmp(buf, "off") || !strcmp(buf, "none")) {
|
||||
bdrv_flags |= BDRV_O_NOCACHE;
|
||||
} else if (!strcmp(buf, "writeback")) {
|
||||
bdrv_flags |= BDRV_O_CACHE_WB;
|
||||
} else if (!strcmp(buf, "unsafe")) {
|
||||
bdrv_flags |= BDRV_O_CACHE_WB;
|
||||
bdrv_flags |= BDRV_O_NO_FLUSH;
|
||||
} else if (!strcmp(buf, "writethrough")) {
|
||||
/* this is the default */
|
||||
} else {
|
||||
fprintf(stderr, "qemu: invalid cache option\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
if ((buf = qemu_opt_get(opts, "aio")) != NULL) {
|
||||
if (!strcmp(buf, "native")) {
|
||||
bdrv_flags |= BDRV_O_NATIVE_AIO;
|
||||
} else if (!strcmp(buf, "threads")) {
|
||||
/* this is the default */
|
||||
} else {
|
||||
fprintf(stderr, "qemu: invalid aio option\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((buf = qemu_opt_get(opts, "format")) != NULL) {
|
||||
if (strcmp(buf, "?") == 0) {
|
||||
fprintf(stderr, "qemu: Supported formats:");
|
||||
bdrv_iterate_format(bdrv_format_print, NULL);
|
||||
fprintf(stderr, "\n");
|
||||
return NULL;
|
||||
}
|
||||
drv = bdrv_find_whitelisted_format(buf);
|
||||
if (!drv) {
|
||||
fprintf(stderr, "qemu: '%s' invalid format\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
on_write_error = BLOCK_ERR_STOP_ENOSPC;
|
||||
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
|
||||
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
|
||||
fprintf(stderr, "werror is no supported by this format\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
on_write_error = parse_block_error_action(buf, 0);
|
||||
if (on_write_error < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
on_read_error = BLOCK_ERR_REPORT;
|
||||
if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
|
||||
if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) {
|
||||
fprintf(stderr, "rerror is no supported by this format\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
on_read_error = parse_block_error_action(buf, 1);
|
||||
if (on_read_error < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) {
|
||||
if (type != IF_VIRTIO) {
|
||||
fprintf(stderr, "addr is not supported\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* compute bus and unit according index */
|
||||
|
||||
if (index != -1) {
|
||||
if (bus_id != 0 || unit_id != -1) {
|
||||
fprintf(stderr,
|
||||
"qemu: index cannot be used with bus and unit\n");
|
||||
return NULL;
|
||||
}
|
||||
if (max_devs == 0)
|
||||
{
|
||||
unit_id = index;
|
||||
bus_id = 0;
|
||||
} else {
|
||||
unit_id = index % max_devs;
|
||||
bus_id = index / max_devs;
|
||||
}
|
||||
}
|
||||
|
||||
/* if user doesn't specify a unit_id,
|
||||
* try to find the first free
|
||||
*/
|
||||
|
||||
if (unit_id == -1) {
|
||||
unit_id = 0;
|
||||
while (drive_get(type, bus_id, unit_id) != NULL) {
|
||||
unit_id++;
|
||||
if (max_devs && unit_id >= max_devs) {
|
||||
unit_id -= max_devs;
|
||||
bus_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check unit id */
|
||||
|
||||
if (max_devs && unit_id >= max_devs) {
|
||||
fprintf(stderr, "qemu: unit %d too big (max is %d)\n",
|
||||
unit_id, max_devs - 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ignore multiple definitions
|
||||
*/
|
||||
|
||||
if (drive_get(type, bus_id, unit_id) != NULL) {
|
||||
*fatal_error = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* init */
|
||||
|
||||
dinfo = qemu_mallocz(sizeof(*dinfo));
|
||||
if ((buf = qemu_opts_id(opts)) != NULL) {
|
||||
dinfo->id = qemu_strdup(buf);
|
||||
} else {
|
||||
/* no id supplied -> create one */
|
||||
dinfo->id = qemu_mallocz(32);
|
||||
if (type == IF_IDE || type == IF_SCSI)
|
||||
mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
|
||||
if (max_devs)
|
||||
snprintf(dinfo->id, 32, "%s%i%s%i",
|
||||
devname, bus_id, mediastr, unit_id);
|
||||
else
|
||||
snprintf(dinfo->id, 32, "%s%s%i",
|
||||
devname, mediastr, unit_id);
|
||||
}
|
||||
dinfo->bdrv = bdrv_new(dinfo->id);
|
||||
dinfo->devaddr = devaddr;
|
||||
dinfo->type = type;
|
||||
dinfo->bus = bus_id;
|
||||
dinfo->unit = unit_id;
|
||||
dinfo->opts = opts;
|
||||
if (serial)
|
||||
strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1);
|
||||
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
|
||||
|
||||
bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
|
||||
|
||||
switch(type) {
|
||||
case IF_IDE:
|
||||
case IF_SCSI:
|
||||
case IF_XEN:
|
||||
case IF_NONE:
|
||||
switch(media) {
|
||||
case MEDIA_DISK:
|
||||
if (cyls != 0) {
|
||||
bdrv_set_geometry_hint(dinfo->bdrv, cyls, heads, secs);
|
||||
bdrv_set_translation_hint(dinfo->bdrv, translation);
|
||||
}
|
||||
break;
|
||||
case MEDIA_CDROM:
|
||||
bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_CDROM);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IF_SD:
|
||||
/* FIXME: This isn't really a floppy, but it's a reasonable
|
||||
approximation. */
|
||||
case IF_FLOPPY:
|
||||
bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_FLOPPY);
|
||||
break;
|
||||
case IF_PFLASH:
|
||||
case IF_MTD:
|
||||
break;
|
||||
case IF_VIRTIO:
|
||||
/* add virtio block device */
|
||||
opts = qemu_opts_create(&qemu_device_opts, NULL, 0);
|
||||
qemu_opt_set(opts, "driver", "virtio-blk-pci");
|
||||
qemu_opt_set(opts, "drive", dinfo->id);
|
||||
if (devaddr)
|
||||
qemu_opt_set(opts, "addr", devaddr);
|
||||
break;
|
||||
case IF_COUNT:
|
||||
abort();
|
||||
}
|
||||
if (!file || !*file) {
|
||||
*fatal_error = 0;
|
||||
return NULL;
|
||||
}
|
||||
if (snapshot) {
|
||||
/* always use cache=unsafe with snapshot */
|
||||
bdrv_flags &= ~BDRV_O_CACHE_MASK;
|
||||
bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
|
||||
}
|
||||
|
||||
if (media == MEDIA_CDROM) {
|
||||
/* CDROM is fine for any interface, don't check. */
|
||||
ro = 1;
|
||||
} else if (ro == 1) {
|
||||
if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
|
||||
fprintf(stderr, "qemu: readonly flag not supported for drive with this interface\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
|
||||
|
||||
ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "qemu: could not open disk image %s: %s\n",
|
||||
file, strerror(-ret));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bdrv_key_required(dinfo->bdrv))
|
||||
autostart = 0;
|
||||
*fatal_error = 0;
|
||||
return dinfo;
|
||||
}
|
||||
|
||||
void do_commit(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
BlockDriverState *bs;
|
||||
|
||||
if (!strcmp(device, "all")) {
|
||||
bdrv_commit_all();
|
||||
} else {
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
qerror_report(QERR_DEVICE_NOT_FOUND, device);
|
||||
return;
|
||||
}
|
||||
bdrv_commit(bs);
|
||||
}
|
||||
}
|
||||
|
||||
static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
|
||||
{
|
||||
if (!force) {
|
||||
if (!bdrv_is_removable(bs)) {
|
||||
qerror_report(QERR_DEVICE_NOT_REMOVABLE,
|
||||
bdrv_get_device_name(bs));
|
||||
return -1;
|
||||
}
|
||||
if (bdrv_is_locked(bs)) {
|
||||
qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
bdrv_close(bs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
int force = qdict_get_try_bool(qdict, "force", 0);
|
||||
const char *filename = qdict_get_str(qdict, "device");
|
||||
|
||||
bs = bdrv_find(filename);
|
||||
if (!bs) {
|
||||
qerror_report(QERR_DEVICE_NOT_FOUND, filename);
|
||||
return -1;
|
||||
}
|
||||
return eject_device(mon, bs, force);
|
||||
}
|
||||
|
||||
int do_block_set_passwd(Monitor *mon, const QDict *qdict,
|
||||
QObject **ret_data)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
int err;
|
||||
|
||||
bs = bdrv_find(qdict_get_str(qdict, "device"));
|
||||
if (!bs) {
|
||||
qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = bdrv_set_key(bs, qdict_get_str(qdict, "password"));
|
||||
if (err == -EINVAL) {
|
||||
qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
|
||||
return -1;
|
||||
} else if (err < 0) {
|
||||
qerror_report(QERR_INVALID_PASSWORD);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_change_block(Monitor *mon, const char *device,
|
||||
const char *filename, const char *fmt)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriver *drv = NULL;
|
||||
int bdrv_flags;
|
||||
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
qerror_report(QERR_DEVICE_NOT_FOUND, device);
|
||||
return -1;
|
||||
}
|
||||
if (fmt) {
|
||||
drv = bdrv_find_whitelisted_format(fmt);
|
||||
if (!drv) {
|
||||
qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (eject_device(mon, bs, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
|
||||
bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
|
||||
if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
|
||||
qerror_report(QERR_OPEN_FILE_FAILED, filename);
|
||||
return -1;
|
||||
}
|
||||
return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
|
||||
}
|
||||
62
blockdev.h
62
blockdev.h
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* QEMU host block devices
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef BLOCKDEV_H
|
||||
#define BLOCKDEV_H
|
||||
|
||||
#include "block.h"
|
||||
#include "qemu-queue.h"
|
||||
|
||||
void blockdev_mark_auto_del(BlockDriverState *bs);
|
||||
void blockdev_auto_del(BlockDriverState *bs);
|
||||
|
||||
typedef enum {
|
||||
IF_NONE,
|
||||
IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN,
|
||||
IF_COUNT
|
||||
} BlockInterfaceType;
|
||||
|
||||
#define BLOCK_SERIAL_STRLEN 20
|
||||
|
||||
typedef struct DriveInfo {
|
||||
BlockDriverState *bdrv;
|
||||
char *id;
|
||||
const char *devaddr;
|
||||
BlockInterfaceType type;
|
||||
int bus;
|
||||
int unit;
|
||||
int auto_del; /* see blockdev_mark_auto_del() */
|
||||
QemuOpts *opts;
|
||||
char serial[BLOCK_SERIAL_STRLEN + 1];
|
||||
QTAILQ_ENTRY(DriveInfo) next;
|
||||
} DriveInfo;
|
||||
|
||||
#define MAX_IDE_DEVS 2
|
||||
#define MAX_SCSI_DEVS 7
|
||||
|
||||
extern DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
|
||||
extern int drive_get_max_bus(BlockInterfaceType type);
|
||||
extern void drive_uninit(DriveInfo *dinfo);
|
||||
extern DriveInfo *drive_get_by_blockdev(BlockDriverState *bs);
|
||||
|
||||
extern QemuOpts *drive_add(const char *file, const char *fmt, ...);
|
||||
extern DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi,
|
||||
int *fatal_error);
|
||||
|
||||
/* device-hotplug */
|
||||
|
||||
DriveInfo *add_init_drive(const char *opts);
|
||||
|
||||
void do_commit(Monitor *mon, const QDict *qdict);
|
||||
int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data);
|
||||
int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data);
|
||||
int do_change_block(Monitor *mon, const char *device,
|
||||
const char *filename, const char *fmt);
|
||||
|
||||
#endif
|
||||
@@ -30,8 +30,8 @@
|
||||
#include "qemu-common.h"
|
||||
/* For tb_lock */
|
||||
#include "exec-all.h"
|
||||
#include "tcg.h"
|
||||
#include "qemu-timer.h"
|
||||
|
||||
|
||||
#include "envlist.h"
|
||||
|
||||
#define DEBUG_LOGFILE "/tmp/qemu.log"
|
||||
@@ -43,7 +43,7 @@ unsigned long guest_base;
|
||||
int have_guest_base;
|
||||
#endif
|
||||
|
||||
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
|
||||
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
|
||||
extern char **environ;
|
||||
enum BSDType bsd_type;
|
||||
@@ -759,10 +759,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
cpu_model = NULL;
|
||||
#if defined(cpudef_setup)
|
||||
cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
|
||||
#endif
|
||||
|
||||
optind = 1;
|
||||
for(;;) {
|
||||
if (optind >= argc)
|
||||
@@ -970,13 +966,6 @@ int main(int argc, char **argv)
|
||||
syscall_init();
|
||||
signal_init();
|
||||
|
||||
#if defined(CONFIG_USE_GUEST_BASE)
|
||||
/* Now that we've loaded the binary, GUEST_BASE is fixed. Delay
|
||||
generating the prologue until now so that the prologue can take
|
||||
the real value of GUEST_BASE into account. */
|
||||
tcg_prologue_init(&tcg_ctx);
|
||||
#endif
|
||||
|
||||
/* build Task State */
|
||||
memset(ts, 0, sizeof(TaskState));
|
||||
init_task_state(ts);
|
||||
|
||||
@@ -77,15 +77,16 @@ void mmap_unlock(void)
|
||||
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);
|
||||
|
||||
if (h2g_valid(p)) {
|
||||
addr = (unsigned long)p;
|
||||
if (addr == (target_ulong) addr) {
|
||||
/* Allocated region overlaps guest address space.
|
||||
This may recurse. */
|
||||
abi_ulong addr = h2g(p);
|
||||
page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size),
|
||||
PAGE_RESERVED);
|
||||
}
|
||||
@@ -239,7 +240,7 @@ static int mmap_frag(abi_ulong real_start,
|
||||
possible while it is a shared mapping */
|
||||
if ((flags & TARGET_BSD_MAP_FLAGMASK) == MAP_SHARED &&
|
||||
(prot & PROT_WRITE))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
|
||||
/* adjust protection to be able to read */
|
||||
if (!(prot1 & PROT_WRITE))
|
||||
|
||||
8
bswap.h
8
bswap.h
@@ -205,10 +205,8 @@ static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
#define cpu_to_32wu cpu_to_be32wu
|
||||
#define leul_to_cpu(v) glue(glue(le,HOST_LONG_BITS),_to_cpu)(v)
|
||||
#else
|
||||
#define cpu_to_32wu cpu_to_le32wu
|
||||
#define leul_to_cpu(v) (v)
|
||||
#endif
|
||||
|
||||
#undef le_bswap
|
||||
@@ -216,10 +214,4 @@ static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
|
||||
#undef le_bswaps
|
||||
#undef be_bswaps
|
||||
|
||||
/* len must be one of 1, 2, 4 */
|
||||
static inline uint32_t qemu_bswap_len(uint32_t value, int len)
|
||||
{
|
||||
return bswap32(value) >> (32 - 8 * len);
|
||||
}
|
||||
|
||||
#endif /* BSWAP_H */
|
||||
|
||||
13
bt-host.c
13
bt-host.c
@@ -50,19 +50,19 @@ static void bt_host_send(struct HCIInfo *hci,
|
||||
struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci;
|
||||
uint8_t pkt = type;
|
||||
struct iovec iv[2];
|
||||
int ret;
|
||||
|
||||
iv[0].iov_base = (void *)&pkt;
|
||||
iv[0].iov_len = 1;
|
||||
iv[1].iov_base = (void *) data;
|
||||
iv[1].iov_len = len;
|
||||
|
||||
while (writev(s->fd, iv, 2) < 0) {
|
||||
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)
|
||||
@@ -80,6 +80,13 @@ 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;
|
||||
@@ -185,7 +192,7 @@ struct HCIInfo *bt_host_hci(const char *id)
|
||||
s->hci.acl_send = bt_host_acl;
|
||||
s->hci.bdaddr_set = bt_host_bdaddr_set;
|
||||
|
||||
qemu_set_fd_handler(s->fd, bt_host_read, NULL, s);
|
||||
qemu_set_fd_handler2(s->fd, bt_host_read_poll, bt_host_read, NULL, s);
|
||||
|
||||
return &s->hci;
|
||||
}
|
||||
|
||||
@@ -39,10 +39,10 @@ typedef struct QEMUFileBuffered
|
||||
} QEMUFileBuffered;
|
||||
|
||||
#ifdef DEBUG_BUFFERED_FILE
|
||||
#define DPRINTF(fmt, ...) \
|
||||
#define dprintf(fmt, ...) \
|
||||
do { printf("buffered-file: " fmt, ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) \
|
||||
#define dprintf(fmt, ...) \
|
||||
do { } while (0)
|
||||
#endif
|
||||
|
||||
@@ -52,7 +52,7 @@ static void buffered_append(QEMUFileBuffered *s,
|
||||
if (size > (s->buffer_capacity - s->buffer_size)) {
|
||||
void *tmp;
|
||||
|
||||
DPRINTF("increasing buffer capacity from %zu by %zu\n",
|
||||
dprintf("increasing buffer capacity from %zu by %zu\n",
|
||||
s->buffer_capacity, size + 1024);
|
||||
|
||||
s->buffer_capacity += size + 1024;
|
||||
@@ -75,11 +75,11 @@ static void buffered_flush(QEMUFileBuffered *s)
|
||||
size_t offset = 0;
|
||||
|
||||
if (s->has_error) {
|
||||
DPRINTF("flush when error, bailing\n");
|
||||
dprintf("flush when error, bailing\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size);
|
||||
dprintf("flushing %zu byte(s) of data\n", s->buffer_size);
|
||||
|
||||
while (offset < s->buffer_size) {
|
||||
ssize_t ret;
|
||||
@@ -87,22 +87,22 @@ static void buffered_flush(QEMUFileBuffered *s)
|
||||
ret = s->put_buffer(s->opaque, s->buffer + offset,
|
||||
s->buffer_size - offset);
|
||||
if (ret == -EAGAIN) {
|
||||
DPRINTF("backend not ready, freezing\n");
|
||||
dprintf("backend not ready, freezing\n");
|
||||
s->freeze_output = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret <= 0) {
|
||||
DPRINTF("error flushing data, %zd\n", ret);
|
||||
dprintf("error flushing data, %zd\n", ret);
|
||||
s->has_error = 1;
|
||||
break;
|
||||
} else {
|
||||
DPRINTF("flushed %zd byte(s)\n", ret);
|
||||
dprintf("flushed %zd byte(s)\n", ret);
|
||||
offset += ret;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF("flushed %zu of %zu byte(s)\n", offset, s->buffer_size);
|
||||
dprintf("flushed %zu of %zu byte(s)\n", offset, s->buffer_size);
|
||||
memmove(s->buffer, s->buffer + offset, s->buffer_size - offset);
|
||||
s->buffer_size -= offset;
|
||||
}
|
||||
@@ -113,45 +113,45 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, in
|
||||
int offset = 0;
|
||||
ssize_t ret;
|
||||
|
||||
DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos);
|
||||
dprintf("putting %d bytes at %" PRId64 "\n", size, pos);
|
||||
|
||||
if (s->has_error) {
|
||||
DPRINTF("flush when error, bailing\n");
|
||||
dprintf("flush when error, bailing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DPRINTF("unfreezing output\n");
|
||||
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");
|
||||
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");
|
||||
dprintf("backend not ready, freezing\n");
|
||||
s->freeze_output = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret <= 0) {
|
||||
DPRINTF("error putting\n");
|
||||
dprintf("error putting\n");
|
||||
s->has_error = 1;
|
||||
offset = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINTF("put %zd byte(s)\n", ret);
|
||||
dprintf("put %zd byte(s)\n", ret);
|
||||
offset += ret;
|
||||
s->bytes_xfer += ret;
|
||||
}
|
||||
|
||||
if (offset >= 0) {
|
||||
DPRINTF("buffering %d bytes\n", size - offset);
|
||||
dprintf("buffering %d bytes\n", size - offset);
|
||||
buffered_append(s, buf + offset, size - offset);
|
||||
offset = size;
|
||||
}
|
||||
@@ -164,7 +164,7 @@ static int buffered_close(void *opaque)
|
||||
QEMUFileBuffered *s = opaque;
|
||||
int ret;
|
||||
|
||||
DPRINTF("closing\n");
|
||||
dprintf("closing\n");
|
||||
|
||||
while (!s->has_error && s->buffer_size) {
|
||||
buffered_flush(s);
|
||||
|
||||
@@ -57,30 +57,6 @@ static void ppc_init_cacheline_sizes(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
static void ppc_init_cacheline_sizes(void)
|
||||
{
|
||||
size_t len = 4;
|
||||
unsigned cacheline;
|
||||
|
||||
if (sysctlbyname ("machdep.cacheline_size", &cacheline, &len, NULL, 0)) {
|
||||
fprintf(stderr, "sysctlbyname machdep.cacheline_size failed: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
qemu_cache_conf.dcache_bsize = cacheline;
|
||||
qemu_cache_conf.icache_bsize = cacheline;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
void qemu_cache_utils_init(char **envp)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,28 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this correct for PPC?
|
||||
*/
|
||||
static inline void dma_flush_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
|
||||
#elif defined(__ia64__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
while (start < stop) {
|
||||
asm volatile ("fc %0" :: "r"(start));
|
||||
start += 32;
|
||||
}
|
||||
asm volatile (";;sync.i;;srlz.i;;");
|
||||
}
|
||||
#define dma_flush_range(start, end) flush_icache_range(start, end)
|
||||
#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
|
||||
#else
|
||||
static inline void dma_flush_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
*
|
||||
* Authors:
|
||||
* Luiz Capitulino <lcapitulino@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*/
|
||||
#include <check.h>
|
||||
|
||||
@@ -50,7 +47,7 @@ START_TEST(qdict_put_obj_test)
|
||||
qdict_put_obj(qdict, "", QOBJECT(qint_from_int(num)));
|
||||
|
||||
fail_unless(qdict_size(qdict) == 1);
|
||||
ent = QLIST_FIRST(&qdict->table[12345 % QDICT_BUCKET_MAX]);
|
||||
ent = QLIST_FIRST(&qdict->table[12345 % QDICT_HASH_SIZE]);
|
||||
qi = qobject_to_qint(ent->value);
|
||||
fail_unless(qint_get_int(qi) == num);
|
||||
|
||||
@@ -194,36 +191,6 @@ START_TEST(qobject_to_qdict_test)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(qdict_iterapi_test)
|
||||
{
|
||||
int count;
|
||||
const QDictEntry *ent;
|
||||
|
||||
fail_unless(qdict_first(tests_dict) == NULL);
|
||||
|
||||
qdict_put(tests_dict, "key1", qint_from_int(1));
|
||||
qdict_put(tests_dict, "key2", qint_from_int(2));
|
||||
qdict_put(tests_dict, "key3", qint_from_int(3));
|
||||
|
||||
count = 0;
|
||||
for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
|
||||
fail_unless(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
|
||||
count++;
|
||||
}
|
||||
|
||||
fail_unless(count == qdict_size(tests_dict));
|
||||
|
||||
/* Do it again to test restarting */
|
||||
count = 0;
|
||||
for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
|
||||
fail_unless(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
|
||||
count++;
|
||||
}
|
||||
|
||||
fail_unless(count == qdict_size(tests_dict));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/*
|
||||
* Errors test-cases
|
||||
*/
|
||||
@@ -368,7 +335,6 @@ static Suite *qdict_suite(void)
|
||||
tcase_add_test(qdict_public2_tcase, qdict_haskey_test);
|
||||
tcase_add_test(qdict_public2_tcase, qdict_del_test);
|
||||
tcase_add_test(qdict_public2_tcase, qobject_to_qdict_test);
|
||||
tcase_add_test(qdict_public2_tcase, qdict_iterapi_test);
|
||||
|
||||
qdict_errors_tcase = tcase_create("Errors");
|
||||
suite_add_tcase(s, qdict_errors_tcase);
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
/*
|
||||
* QFloat unit-tests.
|
||||
*
|
||||
* Copyright (C) 2009 Red Hat Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Luiz Capitulino <lcapitulino@redhat.com>
|
||||
*
|
||||
* Copyright IBM, Corp. 2009
|
||||
*
|
||||
* Authors:
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
*
|
||||
* Authors:
|
||||
* Luiz Capitulino <lcapitulino@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*/
|
||||
#include <check.h>
|
||||
|
||||
|
||||
113
check-qjson.c
113
check-qjson.c
@@ -9,6 +9,7 @@
|
||||
*
|
||||
*/
|
||||
#include <check.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "qstring.h"
|
||||
#include "qint.h"
|
||||
@@ -28,13 +29,6 @@ START_TEST(escaped_string)
|
||||
const char *decoded;
|
||||
int skip;
|
||||
} test_cases[] = {
|
||||
{ "\"\\b\"", "\b" },
|
||||
{ "\"\\f\"", "\f" },
|
||||
{ "\"\\n\"", "\n" },
|
||||
{ "\"\\r\"", "\r" },
|
||||
{ "\"\\t\"", "\t" },
|
||||
{ "\"\\/\"", "\\/" },
|
||||
{ "\"\\\\\"", "\\" },
|
||||
{ "\"\\\"\"", "\"" },
|
||||
{ "\"hello world \\\"embedded string\\\"\"",
|
||||
"hello world \"embedded string\"" },
|
||||
@@ -55,14 +49,11 @@ START_TEST(escaped_string)
|
||||
fail_unless(qobject_type(obj) == QTYPE_QSTRING);
|
||||
|
||||
str = qobject_to_qstring(obj);
|
||||
fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0,
|
||||
"%s != %s\n", qstring_get_str(str), test_cases[i].decoded);
|
||||
fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
|
||||
|
||||
if (test_cases[i].skip == 0) {
|
||||
str = qobject_to_json(obj);
|
||||
fail_unless(strcmp(qstring_get_str(str),test_cases[i].encoded) == 0,
|
||||
"%s != %s\n", qstring_get_str(str),
|
||||
test_cases[i].encoded);
|
||||
fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
|
||||
|
||||
qobject_decref(obj);
|
||||
}
|
||||
@@ -637,90 +628,11 @@ START_TEST(simple_varargs)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(empty_input)
|
||||
{
|
||||
QObject *obj = qobject_from_json("");
|
||||
fail_unless(obj == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(unterminated_string)
|
||||
{
|
||||
QObject *obj = qobject_from_json("\"abc");
|
||||
fail_unless(obj == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(unterminated_sq_string)
|
||||
{
|
||||
QObject *obj = qobject_from_json("'abc");
|
||||
fail_unless(obj == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(unterminated_escape)
|
||||
{
|
||||
QObject *obj = qobject_from_json("\"abc\\\"");
|
||||
fail_unless(obj == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(unterminated_array)
|
||||
{
|
||||
QObject *obj = qobject_from_json("[32");
|
||||
fail_unless(obj == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(unterminated_array_comma)
|
||||
{
|
||||
QObject *obj = qobject_from_json("[32,");
|
||||
fail_unless(obj == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(invalid_array_comma)
|
||||
{
|
||||
QObject *obj = qobject_from_json("[32,}");
|
||||
fail_unless(obj == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(unterminated_dict)
|
||||
{
|
||||
QObject *obj = qobject_from_json("{'abc':32");
|
||||
fail_unless(obj == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(unterminated_dict_comma)
|
||||
{
|
||||
QObject *obj = qobject_from_json("{'abc':32,");
|
||||
fail_unless(obj == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
#if 0
|
||||
START_TEST(invalid_dict_comma)
|
||||
{
|
||||
QObject *obj = qobject_from_json("{'abc':32,}");
|
||||
fail_unless(obj == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(unterminated_literal)
|
||||
{
|
||||
QObject *obj = qobject_from_json("nul");
|
||||
fail_unless(obj == NULL);
|
||||
}
|
||||
END_TEST
|
||||
#endif
|
||||
|
||||
static Suite *qjson_suite(void)
|
||||
{
|
||||
Suite *suite;
|
||||
TCase *string_literals, *number_literals, *keyword_literals;
|
||||
TCase *dicts, *lists, *whitespace, *varargs, *errors;
|
||||
TCase *dicts, *lists, *whitespace, *varargs;
|
||||
|
||||
string_literals = tcase_create("String Literals");
|
||||
tcase_add_test(string_literals, simple_string);
|
||||
@@ -746,22 +658,6 @@ static Suite *qjson_suite(void)
|
||||
varargs = tcase_create("Varargs");
|
||||
tcase_add_test(varargs, simple_varargs);
|
||||
|
||||
errors = tcase_create("Invalid JSON");
|
||||
tcase_add_test(errors, empty_input);
|
||||
tcase_add_test(errors, unterminated_string);
|
||||
tcase_add_test(errors, unterminated_escape);
|
||||
tcase_add_test(errors, unterminated_sq_string);
|
||||
tcase_add_test(errors, unterminated_array);
|
||||
tcase_add_test(errors, unterminated_array_comma);
|
||||
tcase_add_test(errors, invalid_array_comma);
|
||||
tcase_add_test(errors, unterminated_dict);
|
||||
tcase_add_test(errors, unterminated_dict_comma);
|
||||
#if 0
|
||||
/* FIXME: this print parse error messages on stderr. */
|
||||
tcase_add_test(errors, invalid_dict_comma);
|
||||
tcase_add_test(errors, unterminated_literal);
|
||||
#endif
|
||||
|
||||
suite = suite_create("QJSON test-suite");
|
||||
suite_add_tcase(suite, string_literals);
|
||||
suite_add_tcase(suite, number_literals);
|
||||
@@ -770,7 +666,6 @@ static Suite *qjson_suite(void)
|
||||
suite_add_tcase(suite, lists);
|
||||
suite_add_tcase(suite, whitespace);
|
||||
suite_add_tcase(suite, varargs);
|
||||
suite_add_tcase(suite, errors);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
* Authors:
|
||||
* Luiz Capitulino <lcapitulino@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*/
|
||||
#include <check.h>
|
||||
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
*
|
||||
* Authors:
|
||||
* Luiz Capitulino <lcapitulino@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*/
|
||||
#include <check.h>
|
||||
|
||||
|
||||
36
cmd.c
36
cmd.c
@@ -24,7 +24,6 @@
|
||||
#include <getopt.h>
|
||||
|
||||
#include "cmd.h"
|
||||
#include "qemu-aio.h"
|
||||
|
||||
#define _(x) x /* not gettext support yet */
|
||||
|
||||
@@ -150,20 +149,10 @@ add_args_command(
|
||||
args_func = af;
|
||||
}
|
||||
|
||||
static void prep_fetchline(void *opaque)
|
||||
{
|
||||
int *fetchable = opaque;
|
||||
|
||||
qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
|
||||
*fetchable= 1;
|
||||
}
|
||||
|
||||
static char *get_prompt(void);
|
||||
|
||||
void
|
||||
command_loop(void)
|
||||
{
|
||||
int c, i, j = 0, done = 0, fetchable = 0, prompted = 0;
|
||||
int c, i, j = 0, done = 0;
|
||||
char *input;
|
||||
char **v;
|
||||
const cmdinfo_t *ct;
|
||||
@@ -197,21 +186,7 @@ command_loop(void)
|
||||
free(cmdline);
|
||||
return;
|
||||
}
|
||||
|
||||
while (!done) {
|
||||
if (!prompted) {
|
||||
printf("%s", get_prompt());
|
||||
fflush(stdout);
|
||||
qemu_aio_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, NULL,
|
||||
NULL, &fetchable);
|
||||
prompted = 1;
|
||||
}
|
||||
|
||||
qemu_aio_wait();
|
||||
|
||||
if (!fetchable) {
|
||||
continue;
|
||||
}
|
||||
if ((input = fetchline()) == NULL)
|
||||
break;
|
||||
v = breakline(input, &c);
|
||||
@@ -224,11 +199,7 @@ command_loop(void)
|
||||
v[0]);
|
||||
}
|
||||
doneline(input, v);
|
||||
|
||||
prompted = 0;
|
||||
fetchable = 0;
|
||||
}
|
||||
qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/* from libxcmd/input.c */
|
||||
@@ -299,6 +270,8 @@ fetchline(void)
|
||||
|
||||
if (!line)
|
||||
return NULL;
|
||||
printf("%s", get_prompt());
|
||||
fflush(stdout);
|
||||
if (!fgets(line, MAXREADLINESZ, stdin)) {
|
||||
free(line);
|
||||
return NULL;
|
||||
@@ -314,8 +287,7 @@ static char *qemu_strsep(char **input, const char *delim)
|
||||
{
|
||||
char *result = *input;
|
||||
if (result != NULL) {
|
||||
char *p;
|
||||
|
||||
char *p = result;
|
||||
for (p = result; *p != '\0'; p++) {
|
||||
if (strchr(delim, *p)) {
|
||||
break;
|
||||
|
||||
@@ -28,13 +28,6 @@
|
||||
#include "console.h"
|
||||
#include "sysemu.h"
|
||||
|
||||
#ifndef MAC_OS_X_VERSION_10_4
|
||||
#define MAC_OS_X_VERSION_10_4 1040
|
||||
#endif
|
||||
#ifndef MAC_OS_X_VERSION_10_5
|
||||
#define MAC_OS_X_VERSION_10_5 1050
|
||||
#endif
|
||||
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
@@ -236,7 +229,7 @@ int keymap[] =
|
||||
*/
|
||||
};
|
||||
|
||||
static int cocoa_keycode_to_qemu(int keycode)
|
||||
int cocoa_keycode_to_qemu(int keycode)
|
||||
{
|
||||
if((sizeof(keymap)/sizeof(int)) <= keycode)
|
||||
{
|
||||
@@ -305,11 +298,6 @@ static int cocoa_keycode_to_qemu(int keycode)
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) isOpaque
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void) drawRect:(NSRect) rect
|
||||
{
|
||||
COCOA_DEBUG("QemuCocoaView: drawRect\n");
|
||||
@@ -327,7 +315,7 @@ static int cocoa_keycode_to_qemu(int keycode)
|
||||
screen.bitsPerComponent, //bitsPerComponent
|
||||
screen.bitsPerPixel, //bitsPerPixel
|
||||
(screen.width * (screen.bitsPerComponent/2)), //bytesPerRow
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#if __LITTLE_ENDIAN__
|
||||
CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4
|
||||
kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
|
||||
#else
|
||||
@@ -339,7 +327,7 @@ static int cocoa_keycode_to_qemu(int keycode)
|
||||
0, //interpolate
|
||||
kCGRenderingIntentDefault //intent
|
||||
);
|
||||
// test if host supports "CGImageCreateWithImageInRect" at compile time
|
||||
// test if host support "CGImageCreateWithImageInRect" at compiletime
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
||||
if (CGImageCreateWithImageInRect == NULL) { // test if "CGImageCreateWithImageInRect" is supported on host at runtime
|
||||
#endif
|
||||
@@ -349,11 +337,7 @@ static int cocoa_keycode_to_qemu(int keycode)
|
||||
} else {
|
||||
// selective drawing code (draws only dirty rectangles) (OS X >= 10.4)
|
||||
const NSRect *rectList;
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
||||
NSInteger rectCount;
|
||||
#else
|
||||
int rectCount;
|
||||
#endif
|
||||
int i;
|
||||
CGImageRef clipImageRef;
|
||||
CGRect clipRect;
|
||||
@@ -419,7 +403,7 @@ static int cocoa_keycode_to_qemu(int keycode)
|
||||
} else {
|
||||
if (qemu_name)
|
||||
[normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
|
||||
[normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:NO];
|
||||
[normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:YES];
|
||||
}
|
||||
screen.width = w;
|
||||
screen.height = h;
|
||||
@@ -436,8 +420,8 @@ static int cocoa_keycode_to_qemu(int keycode)
|
||||
isFullscreen = FALSE;
|
||||
[self ungrabMouse];
|
||||
[self setContentDimensions];
|
||||
// test if host supports "exitFullScreenModeWithOptions" at compile time
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
||||
// test if host support "enterFullScreenMode:withOptions" at compiletime
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
||||
if ([NSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { // test if "exitFullScreenModeWithOptions" is supported on host at runtime
|
||||
[self exitFullScreenModeWithOptions:nil];
|
||||
} else {
|
||||
@@ -446,15 +430,15 @@ static int cocoa_keycode_to_qemu(int keycode)
|
||||
[normalWindow setContentView: self];
|
||||
[normalWindow makeKeyAndOrderFront: self];
|
||||
[NSMenu setMenuBarVisible:YES];
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
||||
}
|
||||
#endif
|
||||
} else { // switch from desktop to fullscreen
|
||||
isFullscreen = TRUE;
|
||||
[self grabMouse];
|
||||
[self setContentDimensions];
|
||||
// test if host supports "enterFullScreenMode:withOptions" at compile time
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
||||
// test if host support "enterFullScreenMode:withOptions" at compiletime
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
||||
if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime
|
||||
[self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
|
||||
@@ -470,7 +454,7 @@ static int cocoa_keycode_to_qemu(int keycode)
|
||||
[fullScreenWindow setHasShadow:NO];
|
||||
[fullScreenWindow setContentView:self];
|
||||
[fullScreenWindow makeKeyAndOrderFront:self];
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -740,7 +724,6 @@ static int cocoa_keycode_to_qemu(int keycode)
|
||||
[normalWindow setAcceptsMouseMovedEvents:YES];
|
||||
[normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]];
|
||||
[normalWindow setContentView:cocoaView];
|
||||
[normalWindow useOptimizedDrawing:YES];
|
||||
[normalWindow makeKeyAndOrderFront:self];
|
||||
[normalWindow center];
|
||||
|
||||
@@ -784,11 +767,6 @@ static int cocoa_keycode_to_qemu(int keycode)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
|
||||
{
|
||||
COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");
|
||||
@@ -805,7 +783,7 @@ static int cocoa_keycode_to_qemu(int keycode)
|
||||
if(returnCode == NSCancelButton) {
|
||||
exit(0);
|
||||
} else if(returnCode == NSOKButton) {
|
||||
const char *bin = "qemu";
|
||||
char *bin = "qemu";
|
||||
char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding];
|
||||
|
||||
char **argv = (char**)malloc( sizeof(char*)*3 );
|
||||
@@ -861,16 +839,6 @@ int main (int argc, const char * argv[]) {
|
||||
gArgc = argc;
|
||||
gArgv = (char **)argv;
|
||||
CPSProcessSerNum PSN;
|
||||
int i;
|
||||
|
||||
/* In case we don't need to display a window, let's not do that */
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-vnc") ||
|
||||
!strcmp(argv[i], "-nographic") ||
|
||||
!strcmp(argv[i], "-curses")) {
|
||||
return qemu_main(gArgc, gArgv);
|
||||
}
|
||||
}
|
||||
|
||||
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
||||
[NSApplication sharedApplication];
|
||||
@@ -954,7 +922,7 @@ static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
|
||||
w * [cocoaView cdx],
|
||||
h * [cocoaView cdy]);
|
||||
}
|
||||
[cocoaView setNeedsDisplayInRect:rect];
|
||||
[cocoaView displayRect:rect];
|
||||
}
|
||||
|
||||
static void cocoa_resize(DisplayState *ds)
|
||||
13
compat/sys/eventfd.h
Normal file
13
compat/sys/eventfd.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef _COMPAT_SYS_EVENTFD
|
||||
#define _COMPAT_SYS_EVENTFD
|
||||
|
||||
#include <unistd.h>
|
||||
#include <syscall.h>
|
||||
|
||||
|
||||
static inline int eventfd (int count, int flags)
|
||||
{
|
||||
return syscall(SYS_eventfd, count, flags);
|
||||
}
|
||||
|
||||
#endif
|
||||
143
compatfd.c
Normal file
143
compatfd.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* signalfd/eventfd compatibility
|
||||
*
|
||||
* 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 "compatfd.h"
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <pthread.h>
|
||||
|
||||
struct sigfd_compat_info
|
||||
{
|
||||
sigset_t mask;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static void *sigwait_compat(void *opaque)
|
||||
{
|
||||
struct sigfd_compat_info *info = opaque;
|
||||
int err;
|
||||
sigset_t all;
|
||||
|
||||
sigfillset(&all);
|
||||
sigprocmask(SIG_BLOCK, &all, NULL);
|
||||
|
||||
do {
|
||||
siginfo_t siginfo;
|
||||
|
||||
err = sigwaitinfo(&info->mask, &siginfo);
|
||||
if (err == -1 && errno == EINTR) {
|
||||
err = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (err > 0) {
|
||||
char buffer[128];
|
||||
size_t offset = 0;
|
||||
|
||||
memcpy(buffer, &err, sizeof(err));
|
||||
while (offset < sizeof(buffer)) {
|
||||
ssize_t len;
|
||||
|
||||
len = write(info->fd, buffer + offset,
|
||||
sizeof(buffer) - offset);
|
||||
if (len == -1 && errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (len <= 0) {
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
}
|
||||
}
|
||||
} while (err >= 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int qemu_signalfd_compat(const sigset_t *mask)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_t tid;
|
||||
struct sigfd_compat_info *info;
|
||||
int fds[2];
|
||||
|
||||
info = malloc(sizeof(*info));
|
||||
if (info == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pipe(fds) == -1) {
|
||||
free(info);
|
||||
return -1;
|
||||
}
|
||||
|
||||
qemu_set_cloexec(fds[0]);
|
||||
qemu_set_cloexec(fds[1]);
|
||||
|
||||
memcpy(&info->mask, mask, sizeof(*mask));
|
||||
info->fd = fds[1];
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
pthread_create(&tid, &attr, sigwait_compat, info);
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
return fds[0];
|
||||
}
|
||||
|
||||
int qemu_signalfd(const sigset_t *mask)
|
||||
{
|
||||
#if defined(CONFIG_SIGNALFD)
|
||||
int ret;
|
||||
|
||||
ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
|
||||
if (ret != -1) {
|
||||
qemu_set_cloexec(ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return qemu_signalfd_compat(mask);
|
||||
}
|
||||
|
||||
int qemu_eventfd(int *fds)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if defined(CONFIG_EVENTFD)
|
||||
ret = syscall(SYS_eventfd, 0);
|
||||
if (ret >= 0) {
|
||||
fds[0] = ret;
|
||||
qemu_set_cloexec(ret);
|
||||
if ((fds[1] = dup(ret)) == -1) {
|
||||
close(ret);
|
||||
return -1;
|
||||
}
|
||||
qemu_set_cloexec(fds[1]);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = pipe(fds);
|
||||
if (ret != -1) {
|
||||
qemu_set_cloexec(fds[0]);
|
||||
qemu_set_cloexec(fds[1]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
45
compatfd.h
Normal file
45
compatfd.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* signalfd/eventfd compatibility
|
||||
*
|
||||
* 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_COMPATFD_H
|
||||
#define QEMU_COMPATFD_H
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
struct qemu_signalfd_siginfo {
|
||||
uint32_t ssi_signo; /* Signal number */
|
||||
int32_t ssi_errno; /* Error number (unused) */
|
||||
int32_t ssi_code; /* Signal code */
|
||||
uint32_t ssi_pid; /* PID of sender */
|
||||
uint32_t ssi_uid; /* Real UID of sender */
|
||||
int32_t ssi_fd; /* File descriptor (SIGIO) */
|
||||
uint32_t ssi_tid; /* Kernel timer ID (POSIX timers) */
|
||||
uint32_t ssi_band; /* Band event (SIGIO) */
|
||||
uint32_t ssi_overrun; /* POSIX timer overrun count */
|
||||
uint32_t ssi_trapno; /* Trap number that caused signal */
|
||||
int32_t ssi_status; /* Exit status or signal (SIGCHLD) */
|
||||
int32_t ssi_int; /* Integer sent by sigqueue(2) */
|
||||
uint64_t ssi_ptr; /* Pointer sent by sigqueue(2) */
|
||||
uint64_t ssi_utime; /* User CPU time consumed (SIGCHLD) */
|
||||
uint64_t ssi_stime; /* System CPU time consumed (SIGCHLD) */
|
||||
uint64_t ssi_addr; /* Address that generated signal
|
||||
(for hardware-generated signals) */
|
||||
uint8_t pad[48]; /* Pad size to 128 bytes (allow for
|
||||
additional fields in the future) */
|
||||
};
|
||||
|
||||
int qemu_signalfd(const sigset_t *mask);
|
||||
|
||||
int qemu_eventfd(int *fds);
|
||||
|
||||
#endif
|
||||
195
console.c
195
console.c
@@ -154,7 +154,6 @@ struct TextConsole {
|
||||
QEMUTimer *kbd_timer;
|
||||
};
|
||||
|
||||
static DisplayState *display_state;
|
||||
static TextConsole *active_console;
|
||||
static TextConsole *consoles[MAX_CONSOLES];
|
||||
static int nb_consoles = 0;
|
||||
@@ -167,7 +166,7 @@ void vga_hw_update(void)
|
||||
|
||||
void vga_hw_invalidate(void)
|
||||
{
|
||||
if (active_console && active_console->hw_invalidate)
|
||||
if (active_console->hw_invalidate)
|
||||
active_console->hw_invalidate(active_console->hw);
|
||||
}
|
||||
|
||||
@@ -829,6 +828,7 @@ static void console_clear_xy(TextConsole *s, int x, int y)
|
||||
TextCell *c = &s->cells[y1 * s->width + x];
|
||||
c->ch = ' ';
|
||||
c->t_attrib = s->t_attrib_default;
|
||||
c++;
|
||||
update_xy(s, x, y);
|
||||
}
|
||||
|
||||
@@ -1265,117 +1265,6 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
|
||||
return s;
|
||||
}
|
||||
|
||||
static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
|
||||
{
|
||||
DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
|
||||
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->linesize = width * 4;
|
||||
surface->pf = qemu_default_pixelformat(32);
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
|
||||
#else
|
||||
surface->flags = QEMU_ALLOCATED_FLAG;
|
||||
#endif
|
||||
surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
|
||||
int width, int height)
|
||||
{
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->linesize = width * 4;
|
||||
surface->pf = qemu_default_pixelformat(32);
|
||||
if (surface->flags & QEMU_ALLOCATED_FLAG)
|
||||
surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
|
||||
else
|
||||
surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
|
||||
#else
|
||||
surface->flags = QEMU_ALLOCATED_FLAG;
|
||||
#endif
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
|
||||
int linesize, uint8_t *data)
|
||||
{
|
||||
DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
|
||||
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->linesize = linesize;
|
||||
surface->pf = qemu_default_pixelformat(bpp);
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
surface->flags = QEMU_BIG_ENDIAN_FLAG;
|
||||
#endif
|
||||
surface->data = data;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static void defaultallocator_free_displaysurface(DisplaySurface *surface)
|
||||
{
|
||||
if (surface == NULL)
|
||||
return;
|
||||
if (surface->flags & QEMU_ALLOCATED_FLAG)
|
||||
qemu_free(surface->data);
|
||||
qemu_free(surface);
|
||||
}
|
||||
|
||||
static struct DisplayAllocator default_allocator = {
|
||||
defaultallocator_create_displaysurface,
|
||||
defaultallocator_resize_displaysurface,
|
||||
defaultallocator_free_displaysurface
|
||||
};
|
||||
|
||||
static void dumb_display_init(void)
|
||||
{
|
||||
DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
|
||||
ds->allocator = &default_allocator;
|
||||
ds->surface = qemu_create_displaysurface(ds, 640, 480);
|
||||
register_displaystate(ds);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* register display */
|
||||
|
||||
void register_displaystate(DisplayState *ds)
|
||||
{
|
||||
DisplayState **s;
|
||||
s = &display_state;
|
||||
while (*s != NULL)
|
||||
s = &(*s)->next;
|
||||
ds->next = NULL;
|
||||
*s = ds;
|
||||
}
|
||||
|
||||
DisplayState *get_displaystate(void)
|
||||
{
|
||||
if (!display_state) {
|
||||
dumb_display_init ();
|
||||
}
|
||||
return display_state;
|
||||
}
|
||||
|
||||
DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
|
||||
{
|
||||
if(ds->allocator == &default_allocator) {
|
||||
DisplaySurface *surf;
|
||||
surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
|
||||
defaultallocator_free_displaysurface(ds->surface);
|
||||
ds->surface = surf;
|
||||
ds->allocator = da;
|
||||
}
|
||||
return ds->allocator;
|
||||
}
|
||||
|
||||
DisplayState *graphic_console_init(vga_hw_update_ptr update,
|
||||
vga_hw_invalidate_ptr invalidate,
|
||||
vga_hw_screen_dump_ptr screen_dump,
|
||||
@@ -1621,22 +1510,6 @@ PixelFormat qemu_default_pixelformat(int bpp)
|
||||
pf.depth = bpp == 32 ? 24 : bpp;
|
||||
|
||||
switch (bpp) {
|
||||
case 15:
|
||||
pf.bits_per_pixel = 16;
|
||||
pf.bytes_per_pixel = 2;
|
||||
pf.rmask = 0x00007c00;
|
||||
pf.gmask = 0x000003E0;
|
||||
pf.bmask = 0x0000001F;
|
||||
pf.rmax = 31;
|
||||
pf.gmax = 31;
|
||||
pf.bmax = 31;
|
||||
pf.rshift = 10;
|
||||
pf.gshift = 5;
|
||||
pf.bshift = 0;
|
||||
pf.rbits = 5;
|
||||
pf.gbits = 5;
|
||||
pf.bbits = 5;
|
||||
break;
|
||||
case 16:
|
||||
pf.rmask = 0x0000F800;
|
||||
pf.gmask = 0x000007E0;
|
||||
@@ -1686,3 +1559,67 @@ PixelFormat qemu_default_pixelformat(int bpp)
|
||||
}
|
||||
return pf;
|
||||
}
|
||||
|
||||
DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
|
||||
{
|
||||
DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
|
||||
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->linesize = width * 4;
|
||||
surface->pf = qemu_default_pixelformat(32);
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
|
||||
#else
|
||||
surface->flags = QEMU_ALLOCATED_FLAG;
|
||||
#endif
|
||||
surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
|
||||
int width, int height)
|
||||
{
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->linesize = width * 4;
|
||||
surface->pf = qemu_default_pixelformat(32);
|
||||
if (surface->flags & QEMU_ALLOCATED_FLAG)
|
||||
surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
|
||||
else
|
||||
surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
|
||||
#else
|
||||
surface->flags = QEMU_ALLOCATED_FLAG;
|
||||
#endif
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
|
||||
int linesize, uint8_t *data)
|
||||
{
|
||||
DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
|
||||
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->linesize = linesize;
|
||||
surface->pf = qemu_default_pixelformat(bpp);
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
surface->flags = QEMU_BIG_ENDIAN_FLAG;
|
||||
#endif
|
||||
surface->data = data;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
void defaultallocator_free_displaysurface(DisplaySurface *surface)
|
||||
{
|
||||
if (surface == NULL)
|
||||
return;
|
||||
if (surface->flags & QEMU_ALLOCATED_FLAG)
|
||||
qemu_free(surface->data);
|
||||
qemu_free(surface);
|
||||
}
|
||||
|
||||
60
console.h
60
console.h
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "qemu-char.h"
|
||||
#include "qdict.h"
|
||||
#include "notify.h"
|
||||
|
||||
/* keyboard/mouse support */
|
||||
|
||||
@@ -11,16 +10,10 @@
|
||||
#define MOUSE_EVENT_RBUTTON 0x02
|
||||
#define MOUSE_EVENT_MBUTTON 0x04
|
||||
|
||||
/* identical to the ps/2 keyboard bits */
|
||||
#define QEMU_SCROLL_LOCK_LED (1 << 0)
|
||||
#define QEMU_NUM_LOCK_LED (1 << 1)
|
||||
#define QEMU_CAPS_LOCK_LED (1 << 2)
|
||||
|
||||
/* in ms */
|
||||
#define GUI_REFRESH_INTERVAL 30
|
||||
|
||||
typedef void QEMUPutKBDEvent(void *opaque, int keycode);
|
||||
typedef void QEMUPutLEDEvent(void *opaque, int ledstate);
|
||||
typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state);
|
||||
|
||||
typedef struct QEMUPutMouseEntry {
|
||||
@@ -29,40 +22,19 @@ typedef struct QEMUPutMouseEntry {
|
||||
int qemu_put_mouse_event_absolute;
|
||||
char *qemu_put_mouse_event_name;
|
||||
|
||||
int index;
|
||||
|
||||
/* used internally by qemu for handling mice */
|
||||
QTAILQ_ENTRY(QEMUPutMouseEntry) node;
|
||||
struct QEMUPutMouseEntry *next;
|
||||
} QEMUPutMouseEntry;
|
||||
|
||||
typedef struct QEMUPutLEDEntry {
|
||||
QEMUPutLEDEvent *put_led;
|
||||
void *opaque;
|
||||
QTAILQ_ENTRY(QEMUPutLEDEntry) next;
|
||||
} QEMUPutLEDEntry;
|
||||
|
||||
void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
|
||||
void qemu_remove_kbd_event_handler(void);
|
||||
QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
|
||||
void *opaque, int absolute,
|
||||
const char *name);
|
||||
void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry);
|
||||
void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry);
|
||||
|
||||
QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, void *opaque);
|
||||
void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry);
|
||||
|
||||
void kbd_put_keycode(int keycode);
|
||||
void kbd_put_ledstate(int ledstate);
|
||||
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
|
||||
|
||||
/* Does the current mouse generate absolute events */
|
||||
int kbd_mouse_is_absolute(void);
|
||||
void qemu_add_mouse_mode_change_notifier(Notifier *notify);
|
||||
void qemu_remove_mouse_mode_change_notifier(Notifier *notify);
|
||||
|
||||
/* Of all the mice, is there one that generates absolute events */
|
||||
int kbd_mouse_has_absolute(void);
|
||||
|
||||
struct MouseTransformInfo {
|
||||
/* Touchscreen resolution */
|
||||
@@ -127,27 +99,6 @@ struct DisplaySurface {
|
||||
struct PixelFormat pf;
|
||||
};
|
||||
|
||||
/* cursor data format is 32bit RGBA */
|
||||
typedef struct QEMUCursor {
|
||||
int width, height;
|
||||
int hot_x, hot_y;
|
||||
int refcount;
|
||||
uint32_t data[];
|
||||
} QEMUCursor;
|
||||
|
||||
QEMUCursor *cursor_alloc(int width, int height);
|
||||
void cursor_get(QEMUCursor *c);
|
||||
void cursor_put(QEMUCursor *c);
|
||||
QEMUCursor *cursor_builtin_hidden(void);
|
||||
QEMUCursor *cursor_builtin_left_ptr(void);
|
||||
void cursor_print_ascii_art(QEMUCursor *c, const char *prefix);
|
||||
int cursor_get_mono_bpl(QEMUCursor *c);
|
||||
void cursor_set_mono(QEMUCursor *c,
|
||||
uint32_t foreground, uint32_t background, uint8_t *image,
|
||||
int transparent, uint8_t *mask);
|
||||
void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *mask);
|
||||
void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask);
|
||||
|
||||
struct DisplayChangeListener {
|
||||
int idle;
|
||||
uint64_t gui_timer_interval;
|
||||
@@ -180,7 +131,8 @@ struct DisplayState {
|
||||
struct DisplayChangeListener* listeners;
|
||||
|
||||
void (*mouse_set)(int x, int y, int on);
|
||||
void (*cursor_define)(QEMUCursor *cursor);
|
||||
void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y,
|
||||
uint8_t *image, uint8_t *mask);
|
||||
|
||||
struct DisplayState *next;
|
||||
};
|
||||
@@ -192,7 +144,11 @@ DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
|
||||
PixelFormat qemu_different_endianness_pixelformat(int bpp);
|
||||
PixelFormat qemu_default_pixelformat(int bpp);
|
||||
|
||||
extern struct DisplayAllocator default_allocator;
|
||||
DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da);
|
||||
DisplaySurface* defaultallocator_create_displaysurface(int width, int height);
|
||||
DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface, int width, int height);
|
||||
void defaultallocator_free_displaysurface(DisplaySurface *surface);
|
||||
|
||||
static inline DisplaySurface* qemu_create_displaysurface(DisplayState *ds, int width, int height)
|
||||
{
|
||||
@@ -327,8 +283,6 @@ static inline int ds_get_bytes_per_pixel(DisplayState *ds)
|
||||
typedef unsigned long console_ch_t;
|
||||
static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
|
||||
{
|
||||
if (!(ch & 0xff))
|
||||
ch |= ' ';
|
||||
cpu_to_le32wu((uint32_t *) dest, ch);
|
||||
}
|
||||
|
||||
|
||||
273
cpu-all.h
273
cpu-all.h
@@ -627,32 +627,23 @@ static inline void stfq_be_p(void *ptr, float64 v)
|
||||
#if defined(CONFIG_USE_GUEST_BASE)
|
||||
extern unsigned long guest_base;
|
||||
extern int have_guest_base;
|
||||
extern unsigned long reserved_va;
|
||||
#define GUEST_BASE guest_base
|
||||
#define RESERVED_VA reserved_va
|
||||
#else
|
||||
#define GUEST_BASE 0ul
|
||||
#define RESERVED_VA 0ul
|
||||
#endif
|
||||
|
||||
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
|
||||
#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
|
||||
|
||||
#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS
|
||||
#define h2g_valid(x) 1
|
||||
#else
|
||||
#define h2g_valid(x) ({ \
|
||||
unsigned long __guest = (unsigned long)(x) - GUEST_BASE; \
|
||||
__guest < (1ul << TARGET_VIRT_ADDR_SPACE_BITS); \
|
||||
})
|
||||
#endif
|
||||
|
||||
#define h2g(x) ({ \
|
||||
unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \
|
||||
/* Check if given address fits target address space */ \
|
||||
assert(h2g_valid(x)); \
|
||||
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 laddr(x) g2h(x)
|
||||
@@ -745,23 +736,16 @@ extern unsigned long qemu_host_page_mask;
|
||||
/* original state of the write flag (used when tracking self-modifying
|
||||
code */
|
||||
#define PAGE_WRITE_ORG 0x0010
|
||||
#if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
|
||||
/* FIXME: Code that sets/uses this is broken and needs to go away. */
|
||||
#define PAGE_RESERVED 0x0020
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
void page_dump(FILE *f);
|
||||
|
||||
typedef int (*walk_memory_regions_fn)(void *, abi_ulong,
|
||||
abi_ulong, unsigned long);
|
||||
int walk_memory_regions(void *, walk_memory_regions_fn);
|
||||
|
||||
int walk_memory_regions(void *,
|
||||
int (*fn)(void *, unsigned long, unsigned long, unsigned long));
|
||||
int page_get_flags(target_ulong address);
|
||||
void page_set_flags(target_ulong start, target_ulong end, int flags);
|
||||
int page_check_range(target_ulong start, target_ulong len, int flags);
|
||||
#endif
|
||||
|
||||
void cpu_exec_init_all(unsigned long tb_size);
|
||||
CPUState *cpu_copy(CPUState *env);
|
||||
CPUState *qemu_get_cpu(int cpu);
|
||||
|
||||
@@ -776,6 +760,8 @@ void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...)
|
||||
__attribute__ ((__format__ (__printf__, 2, 3)));
|
||||
extern CPUState *first_cpu;
|
||||
extern CPUState *cpu_single_env;
|
||||
extern int64_t qemu_icount;
|
||||
extern int use_icount;
|
||||
|
||||
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
|
||||
#define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */
|
||||
@@ -824,8 +810,11 @@ void cpu_watchpoint_remove_all(CPUState *env, int mask);
|
||||
|
||||
void cpu_single_step(CPUState *env, int enabled);
|
||||
void cpu_reset(CPUState *s);
|
||||
int cpu_is_stopped(CPUState *env);
|
||||
void run_on_cpu(CPUState *env, void (*func)(void *data), void *data);
|
||||
|
||||
/* Return the physical page corresponding to a virtual one. Use it
|
||||
only for debugging because no protection checks are done. Return -1
|
||||
if no page found. */
|
||||
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
|
||||
|
||||
#define CPU_LOG_TB_OUT_ASM (1 << 0)
|
||||
#define CPU_LOG_TB_IN_ASM (1 << 1)
|
||||
@@ -851,37 +840,16 @@ void cpu_set_log(int log_flags);
|
||||
void cpu_set_log_filename(const char *filename);
|
||||
int cpu_str_to_log_mask(const char *str);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
/* Return the physical page corresponding to a virtual one. Use it
|
||||
only for debugging because no protection checks are done. Return -1
|
||||
if no page found. */
|
||||
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
|
||||
/* IO ports API */
|
||||
#include "ioport.h"
|
||||
|
||||
/* memory API */
|
||||
|
||||
extern int phys_ram_fd;
|
||||
extern uint8_t *phys_ram_dirty;
|
||||
extern ram_addr_t ram_size;
|
||||
|
||||
typedef struct RAMBlock {
|
||||
uint8_t *host;
|
||||
ram_addr_t offset;
|
||||
ram_addr_t length;
|
||||
char idstr[256];
|
||||
QLIST_ENTRY(RAMBlock) next;
|
||||
#if defined(__linux__) && !defined(TARGET_S390X)
|
||||
int fd;
|
||||
#endif
|
||||
} RAMBlock;
|
||||
|
||||
typedef struct RAMList {
|
||||
uint8_t *phys_dirty;
|
||||
QLIST_HEAD(ram, RAMBlock) blocks;
|
||||
} RAMList;
|
||||
extern RAMList ram_list;
|
||||
|
||||
extern const char *mem_path;
|
||||
extern int mem_prealloc;
|
||||
extern ram_addr_t last_ram_offset;
|
||||
extern uint8_t *bios_mem;
|
||||
|
||||
/* physical memory access */
|
||||
|
||||
@@ -901,6 +869,9 @@ extern int mem_prealloc;
|
||||
/* Set if TLB entry is an IO callback. */
|
||||
#define TLB_MMIO (1 << 5)
|
||||
|
||||
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
|
||||
uint8_t *buf, int len, int is_write);
|
||||
|
||||
#define VGA_DIRTY_FLAG 0x01
|
||||
#define CODE_DIRTY_FLAG 0x02
|
||||
#define MIGRATION_DIRTY_FLAG 0x08
|
||||
@@ -908,44 +879,18 @@ extern int mem_prealloc;
|
||||
/* read dirty bit (return 0 or 1) */
|
||||
static inline int cpu_physical_memory_is_dirty(ram_addr_t addr)
|
||||
{
|
||||
return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] == 0xff;
|
||||
}
|
||||
|
||||
static inline int cpu_physical_memory_get_dirty_flags(ram_addr_t addr)
|
||||
{
|
||||
return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS];
|
||||
return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff;
|
||||
}
|
||||
|
||||
static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
|
||||
int dirty_flags)
|
||||
{
|
||||
return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
|
||||
return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
|
||||
}
|
||||
|
||||
static inline void cpu_physical_memory_set_dirty(ram_addr_t addr)
|
||||
{
|
||||
ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] = 0xff;
|
||||
}
|
||||
|
||||
static inline int cpu_physical_memory_set_dirty_flags(ram_addr_t addr,
|
||||
int dirty_flags)
|
||||
{
|
||||
return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] |= dirty_flags;
|
||||
}
|
||||
|
||||
static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start,
|
||||
int length,
|
||||
int dirty_flags)
|
||||
{
|
||||
int i, mask, len;
|
||||
uint8_t *p;
|
||||
|
||||
len = length >> TARGET_PAGE_BITS;
|
||||
mask = ~dirty_flags;
|
||||
p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
|
||||
for (i = 0; i < len; i++) {
|
||||
p[i] &= mask;
|
||||
}
|
||||
phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff;
|
||||
}
|
||||
|
||||
void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
|
||||
@@ -961,10 +906,170 @@ int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
|
||||
|
||||
void dump_exec_info(FILE *f,
|
||||
int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
|
||||
uint8_t *buf, int len, int is_write);
|
||||
/* 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) */
|
||||
|
||||
#if defined(_ARCH_PPC)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t retval;
|
||||
#ifdef _ARCH_PPC64
|
||||
/* This reads timebase in one 64bit go and includes Cell workaround from:
|
||||
http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027052.html
|
||||
*/
|
||||
__asm__ __volatile__ (
|
||||
"mftb %0\n\t"
|
||||
"cmpwi %0,0\n\t"
|
||||
"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__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm volatile ("rdtsc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
uint32_t low,high;
|
||||
int64_t val;
|
||||
asm volatile("rdtsc" : "=a" (low), "=d" (high));
|
||||
val = high;
|
||||
val <<= 32;
|
||||
val |= low;
|
||||
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)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__s390__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks (void)
|
||||
{
|
||||
#if defined(_LP64)
|
||||
uint64_t rval;
|
||||
asm volatile("rd %%tick,%0" : "=r"(rval));
|
||||
return rval;
|
||||
#else
|
||||
union {
|
||||
uint64_t i64;
|
||||
struct {
|
||||
uint32_t high;
|
||||
uint32_t low;
|
||||
} i32;
|
||||
} rval;
|
||||
asm volatile("rd %%tick,%1; srlx %1,32,%0"
|
||||
: "=r"(rval.i32.high), "=r"(rval.i32.low));
|
||||
return rval.i64;
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(__mips__) && \
|
||||
((defined(__mips_isa_rev) && __mips_isa_rev >= 2) || defined(__linux__))
|
||||
/*
|
||||
* binutils wants to use rdhwr only on mips32r2
|
||||
* but as linux kernel emulate it, it's fine
|
||||
* to use it.
|
||||
*
|
||||
*/
|
||||
#define MIPS_RDHWR(rd, value) { \
|
||||
__asm__ __volatile__ ( \
|
||||
".set push\n\t" \
|
||||
".set mips32r2\n\t" \
|
||||
"rdhwr %0, "rd"\n\t" \
|
||||
".set pop" \
|
||||
: "=r" (value)); \
|
||||
}
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
/* On kernels >= 2.6.25 rdhwr <reg>, $2 and $3 are emulated */
|
||||
uint32_t count;
|
||||
static uint32_t cyc_per_count = 0;
|
||||
|
||||
if (!cyc_per_count)
|
||||
MIPS_RDHWR("$3", cyc_per_count);
|
||||
|
||||
MIPS_RDHWR("$2", count);
|
||||
return (int64_t)(count * cyc_per_count);
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
/* profiling */
|
||||
#ifdef CONFIG_PROFILER
|
||||
static inline int64_t profile_getclock(void)
|
||||
{
|
||||
return cpu_get_real_ticks();
|
||||
}
|
||||
|
||||
extern int64_t qemu_time, qemu_time_start;
|
||||
extern int64_t tlb_flush_time;
|
||||
extern int64_t dev_time;
|
||||
#endif
|
||||
|
||||
void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
|
||||
uint64_t mcg_status, uint64_t addr, uint64_t misc);
|
||||
|
||||
48
cpu-common.h
48
cpu-common.h
@@ -3,22 +3,11 @@
|
||||
|
||||
/* CPU interfaces that are target indpendent. */
|
||||
|
||||
#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) || defined(__ia64__)
|
||||
#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__)
|
||||
#define WORDS_ALIGNED
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_PHYS_ADDR_BITS
|
||||
#include "targphys.h"
|
||||
#endif
|
||||
|
||||
#ifndef NEED_CPU_H
|
||||
#include "poison.h"
|
||||
#endif
|
||||
|
||||
#include "bswap.h"
|
||||
#include "qemu-queue.h"
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
/* address in the RAM (different from a physical address) */
|
||||
typedef unsigned long ram_addr_t;
|
||||
@@ -40,11 +29,12 @@ static inline void cpu_register_physical_memory(target_phys_addr_t start_addr,
|
||||
}
|
||||
|
||||
ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr);
|
||||
ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size);
|
||||
ram_addr_t qemu_ram_alloc(ram_addr_t);
|
||||
void qemu_ram_free(ram_addr_t addr);
|
||||
/* This should only be used for ram local to a device. */
|
||||
void *qemu_get_ram_ptr(ram_addr_t addr);
|
||||
/* This should not be used by devices. */
|
||||
int do_qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
|
||||
ram_addr_t qemu_ram_addr_from_host(void *ptr);
|
||||
|
||||
int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
|
||||
@@ -72,35 +62,6 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
|
||||
void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque));
|
||||
void cpu_unregister_map_client(void *cookie);
|
||||
|
||||
struct CPUPhysMemoryClient;
|
||||
typedef struct CPUPhysMemoryClient CPUPhysMemoryClient;
|
||||
struct CPUPhysMemoryClient {
|
||||
void (*set_memory)(struct CPUPhysMemoryClient *client,
|
||||
target_phys_addr_t start_addr,
|
||||
ram_addr_t size,
|
||||
ram_addr_t phys_offset);
|
||||
int (*sync_dirty_bitmap)(struct CPUPhysMemoryClient *client,
|
||||
target_phys_addr_t start_addr,
|
||||
target_phys_addr_t end_addr);
|
||||
int (*migration_log)(struct CPUPhysMemoryClient *client,
|
||||
int enable);
|
||||
QLIST_ENTRY(CPUPhysMemoryClient) list;
|
||||
};
|
||||
|
||||
void cpu_register_phys_memory_client(CPUPhysMemoryClient *);
|
||||
void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *);
|
||||
|
||||
/* 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);
|
||||
|
||||
void qemu_flush_coalesced_mmio_buffer(void);
|
||||
|
||||
uint32_t ldub_phys(target_phys_addr_t addr);
|
||||
uint32_t lduw_phys(target_phys_addr_t addr);
|
||||
uint32_t ldl_phys(target_phys_addr_t addr);
|
||||
@@ -125,7 +86,6 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr,
|
||||
/* Acts like a ROM when read and like a device when written. */
|
||||
#define IO_MEM_ROMD (1)
|
||||
#define IO_MEM_SUBPAGE (2)
|
||||
|
||||
#endif
|
||||
#define IO_MEM_SUBWIDTH (4)
|
||||
|
||||
#endif /* !CPU_COMMON_H */
|
||||
|
||||
56
cpu-defs.h
56
cpu-defs.h
@@ -27,6 +27,7 @@
|
||||
#include <setjmp.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include "osdep.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "targphys.h"
|
||||
@@ -72,11 +73,10 @@ typedef uint64_t target_ulong;
|
||||
#define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1)
|
||||
#define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE)
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#define CPU_TLB_BITS 8
|
||||
#define CPU_TLB_SIZE (1 << CPU_TLB_BITS)
|
||||
|
||||
#if HOST_LONG_BITS == 32 && TARGET_LONG_BITS == 32
|
||||
#if TARGET_PHYS_ADDR_BITS == 32 && TARGET_LONG_BITS == 32
|
||||
#define CPU_TLB_ENTRY_BITS 4
|
||||
#else
|
||||
#define CPU_TLB_ENTRY_BITS 5
|
||||
@@ -92,32 +92,21 @@ typedef struct CPUTLBEntry {
|
||||
target_ulong addr_read;
|
||||
target_ulong addr_write;
|
||||
target_ulong addr_code;
|
||||
/* Addend to virtual address to get host address. IO accesses
|
||||
/* Addend to virtual address to get physical address. IO accesses
|
||||
use the corresponding iotlb value. */
|
||||
unsigned long addend;
|
||||
#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;
|
||||
#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(unsigned long) - 1)) +
|
||||
sizeof(unsigned long))];
|
||||
((-sizeof(target_ulong) * 3) & (sizeof(target_phys_addr_t) - 1)) +
|
||||
sizeof(target_phys_addr_t))];
|
||||
} CPUTLBEntry;
|
||||
|
||||
extern int CPUTLBEntry_wrong_size[sizeof(CPUTLBEntry) == (1 << CPU_TLB_ENTRY_BITS) ? 1 : -1];
|
||||
|
||||
#define CPU_COMMON_TLB \
|
||||
/* 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]; \
|
||||
target_ulong tlb_flush_addr; \
|
||||
target_ulong tlb_flush_mask;
|
||||
|
||||
#else
|
||||
|
||||
#define CPU_COMMON_TLB
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
typedef struct icount_decr_u16 {
|
||||
uint16_t high;
|
||||
@@ -132,7 +121,6 @@ typedef struct icount_decr_u16 {
|
||||
|
||||
struct kvm_run;
|
||||
struct KVMState;
|
||||
struct qemu_work_item;
|
||||
|
||||
typedef struct CPUBreakpoint {
|
||||
target_ulong pc;
|
||||
@@ -147,6 +135,16 @@ typedef struct CPUWatchpoint {
|
||||
QTAILQ_ENTRY(CPUWatchpoint) entry;
|
||||
} CPUWatchpoint;
|
||||
|
||||
/* forward decleration */
|
||||
struct qemu_work_item;
|
||||
|
||||
struct KVMCPUState {
|
||||
pthread_t thread;
|
||||
int signalled;
|
||||
struct qemu_work_item *queued_work_first, *queued_work_last;
|
||||
int regs_modified;
|
||||
};
|
||||
|
||||
#define CPU_TEMP_BUF_NLONGS 128
|
||||
#define CPU_COMMON \
|
||||
struct TranslationBlock *current_tb; /* currently executing TB */ \
|
||||
@@ -161,7 +159,9 @@ typedef struct CPUWatchpoint {
|
||||
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
|
||||
uint32_t interrupt_request; \
|
||||
volatile sig_atomic_t exit_request; \
|
||||
CPU_COMMON_TLB \
|
||||
/* 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]; \
|
||||
/* buffer for temporaries in the code generator */ \
|
||||
long temp_buf[CPU_TEMP_BUF_NLONGS]; \
|
||||
@@ -197,19 +197,19 @@ typedef struct CPUWatchpoint {
|
||||
int nr_cores; /* number of cores within this CPU package */ \
|
||||
int nr_threads;/* number of threads within this CPU */ \
|
||||
int running; /* Nonzero if cpu is currently running(usermode). */ \
|
||||
int thread_id; \
|
||||
/* user data */ \
|
||||
void *opaque; \
|
||||
\
|
||||
uint32_t created; \
|
||||
uint32_t stop; /* Stop request */ \
|
||||
uint32_t stopped; /* Artificially stopped */ \
|
||||
struct QemuThread *thread; \
|
||||
struct QemuCond *halt_cond; \
|
||||
struct qemu_work_item *queued_work_first, *queued_work_last; \
|
||||
const char *cpu_model_str; \
|
||||
struct KVMState *kvm_state; \
|
||||
struct kvm_run *kvm_run; \
|
||||
int kvm_fd; \
|
||||
int kvm_vcpu_dirty;
|
||||
uint32_t stop; /* Stop request */ \
|
||||
uint32_t stopped; /* Artificially stopped */ \
|
||||
struct KVMCPUState kvm_cpu_state;
|
||||
|
||||
#endif
|
||||
|
||||
220
cpu-exec.c
220
cpu-exec.c
@@ -19,9 +19,10 @@
|
||||
#include "config.h"
|
||||
#include "exec.h"
|
||||
#include "disas.h"
|
||||
#if !defined(TARGET_IA64)
|
||||
#include "tcg.h"
|
||||
#endif
|
||||
#include "kvm.h"
|
||||
#include "qemu-barrier.h"
|
||||
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
#undef EAX
|
||||
@@ -39,6 +40,8 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "qemu-kvm.h"
|
||||
|
||||
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
|
||||
// Work around ugly bugs in glibc that mangle global register contents
|
||||
#undef env
|
||||
@@ -57,7 +60,9 @@ int qemu_cpu_has_work(CPUState *env)
|
||||
|
||||
void cpu_loop_exit(void)
|
||||
{
|
||||
env->current_tb = NULL;
|
||||
/* NOTE: the register at this point must be saved by hand because
|
||||
longjmp restore them */
|
||||
regs_to_env();
|
||||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
|
||||
@@ -82,11 +87,7 @@ void cpu_resume_from_signal(CPUState *env1, void *puc)
|
||||
if (puc) {
|
||||
/* XXX: use siglongjmp ? */
|
||||
#ifdef __linux__
|
||||
#ifdef __ia64
|
||||
sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL);
|
||||
#else
|
||||
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
|
||||
#endif
|
||||
#elif defined(__OpenBSD__)
|
||||
sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
|
||||
#endif
|
||||
@@ -113,7 +114,6 @@ static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
|
||||
env->current_tb = tb;
|
||||
/* execute the generated code */
|
||||
next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
|
||||
env->current_tb = NULL;
|
||||
|
||||
if ((next_tb & 3) == 2) {
|
||||
/* Restore PC. This may happen if async event occurs before
|
||||
@@ -130,13 +130,14 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
|
||||
{
|
||||
TranslationBlock *tb, **ptb1;
|
||||
unsigned int h;
|
||||
tb_page_addr_t phys_pc, phys_page1, phys_page2;
|
||||
target_ulong virt_page2;
|
||||
target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
|
||||
|
||||
tb_invalidated_flag = 0;
|
||||
|
||||
regs_to_env(); /* XXX: do it just before cpu_gen_code() */
|
||||
|
||||
/* find translated block using physical mappings */
|
||||
phys_pc = get_page_addr_code(env, pc);
|
||||
phys_pc = get_phys_addr_code(env, pc);
|
||||
phys_page1 = phys_pc & TARGET_PAGE_MASK;
|
||||
phys_page2 = -1;
|
||||
h = tb_phys_hash_func(phys_pc);
|
||||
@@ -153,7 +154,7 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
|
||||
if (tb->page_addr[1] != -1) {
|
||||
virt_page2 = (pc & TARGET_PAGE_MASK) +
|
||||
TARGET_PAGE_SIZE;
|
||||
phys_page2 = get_page_addr_code(env, virt_page2);
|
||||
phys_page2 = get_phys_addr_code(env, virt_page2);
|
||||
if (tb->page_addr[1] == phys_page2)
|
||||
goto found;
|
||||
} else {
|
||||
@@ -214,11 +215,10 @@ static void cpu_handle_debug_exception(CPUState *env)
|
||||
|
||||
/* main execution loop */
|
||||
|
||||
volatile sig_atomic_t exit_request;
|
||||
|
||||
int cpu_exec(CPUState *env1)
|
||||
{
|
||||
volatile host_reg_t saved_env_reg;
|
||||
#define DECLARE_HOST_REGS 1
|
||||
#include "hostregs_helper.h"
|
||||
int ret, interrupt_request;
|
||||
TranslationBlock *tb;
|
||||
uint8_t *tc_ptr;
|
||||
@@ -229,18 +229,12 @@ int cpu_exec(CPUState *env1)
|
||||
|
||||
cpu_single_env = env1;
|
||||
|
||||
/* the access to env below is actually saving the global register's
|
||||
value, so that files not including target-xyz/exec.h are free to
|
||||
use it. */
|
||||
QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
|
||||
saved_env_reg = (host_reg_t) env;
|
||||
barrier();
|
||||
/* first we save global registers */
|
||||
#define SAVE_HOST_REGS 1
|
||||
#include "hostregs_helper.h"
|
||||
env = env1;
|
||||
|
||||
if (unlikely(exit_request)) {
|
||||
env->exit_request = 1;
|
||||
}
|
||||
|
||||
env_to_regs();
|
||||
#if defined(TARGET_I386)
|
||||
if (!kvm_enabled()) {
|
||||
/* put eflags in CPU temporary format */
|
||||
@@ -262,6 +256,7 @@ int cpu_exec(CPUState *env1)
|
||||
#elif defined(TARGET_SH4)
|
||||
#elif defined(TARGET_CRIS)
|
||||
#elif defined(TARGET_S390X)
|
||||
#elif defined(TARGET_IA64)
|
||||
/* XXXXX */
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
@@ -276,6 +271,7 @@ int cpu_exec(CPUState *env1)
|
||||
env = cpu_single_env;
|
||||
#define env cpu_single_env
|
||||
#endif
|
||||
env->current_tb = NULL;
|
||||
/* if an exception is pending, we execute it here */
|
||||
if (env->exception_index >= 0) {
|
||||
if (env->exception_index >= EXCP_INTERRUPT) {
|
||||
@@ -328,10 +324,12 @@ int cpu_exec(CPUState *env1)
|
||||
do_interrupt(env);
|
||||
#elif defined(TARGET_M68K)
|
||||
do_interrupt(0);
|
||||
#elif defined(TARGET_IA64)
|
||||
do_interrupt(env);
|
||||
#endif
|
||||
env->exception_index = -1;
|
||||
#endif
|
||||
}
|
||||
env->exception_index = -1;
|
||||
}
|
||||
|
||||
if (kvm_enabled()) {
|
||||
@@ -460,20 +458,20 @@ int cpu_exec(CPUState *env1)
|
||||
next_tb = 0;
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
||||
if (cpu_interrupts_enabled(env) &&
|
||||
env->interrupt_index > 0) {
|
||||
int pil = env->interrupt_index & 0xf;
|
||||
int type = env->interrupt_index & 0xf0;
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
cpu_interrupts_enabled(env)) {
|
||||
int pil = env->interrupt_index & 15;
|
||||
int type = env->interrupt_index & 0xf0;
|
||||
|
||||
if (((type == TT_EXTINT) &&
|
||||
cpu_pil_allowed(env, pil)) ||
|
||||
type != TT_EXTINT) {
|
||||
env->exception_index = env->interrupt_index;
|
||||
do_interrupt(env);
|
||||
next_tb = 0;
|
||||
}
|
||||
}
|
||||
if (((type == TT_EXTINT) &&
|
||||
(pil == 15 || pil > env->psrpil)) ||
|
||||
type != TT_EXTINT) {
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||
env->exception_index = env->interrupt_index;
|
||||
do_interrupt(env);
|
||||
env->interrupt_index = 0;
|
||||
next_tb = 0;
|
||||
}
|
||||
} else if (interrupt_request & CPU_INTERRUPT_TIMER) {
|
||||
//do_interrupt(0, 0, 0, 0, 0);
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
|
||||
@@ -513,8 +511,7 @@ int cpu_exec(CPUState *env1)
|
||||
}
|
||||
#elif defined(TARGET_CRIS)
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD
|
||||
&& (env->pregs[PR_CCS] & I_FLAG)
|
||||
&& !env->locked_irq) {
|
||||
&& (env->pregs[PR_CCS] & I_FLAG)) {
|
||||
env->exception_index = EXCP_IRQ;
|
||||
do_interrupt(env);
|
||||
next_tb = 0;
|
||||
@@ -553,24 +550,41 @@ int cpu_exec(CPUState *env1)
|
||||
env->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
|
||||
#ifdef CONFIG_DEBUG_EXEC
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
|
||||
/* restore flags in standard format */
|
||||
regs_to_env();
|
||||
#if defined(TARGET_I386)
|
||||
env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
|
||||
log_cpu_state(env, X86_DUMP_CCOP);
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
#elif defined(TARGET_ARM)
|
||||
log_cpu_state(env, 0);
|
||||
#elif defined(TARGET_SPARC)
|
||||
log_cpu_state(env, 0);
|
||||
#elif defined(TARGET_PPC)
|
||||
log_cpu_state(env, 0);
|
||||
#elif defined(TARGET_M68K)
|
||||
cpu_m68k_flush_flags(env, env->cc_op);
|
||||
env->cc_op = CC_OP_FLAGS;
|
||||
env->sr = (env->sr & 0xffe0)
|
||||
| env->cc_dest | (env->cc_x << 4);
|
||||
log_cpu_state(env, 0);
|
||||
#else
|
||||
#elif defined(TARGET_MICROBLAZE)
|
||||
log_cpu_state(env, 0);
|
||||
#elif defined(TARGET_MIPS)
|
||||
log_cpu_state(env, 0);
|
||||
#elif defined(TARGET_SH4)
|
||||
log_cpu_state(env, 0);
|
||||
#elif defined(TARGET_ALPHA)
|
||||
log_cpu_state(env, 0);
|
||||
#elif defined(TARGET_CRIS)
|
||||
log_cpu_state(env, 0);
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
}
|
||||
#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
|
||||
#endif
|
||||
spin_lock(&tb_lock);
|
||||
tb = tb_find_fast();
|
||||
/* Note: we do it here to avoid a gcc bug on Mac OS X when
|
||||
@@ -590,18 +604,22 @@ int cpu_exec(CPUState *env1)
|
||||
/* see if we can patch the calling TB. When the TB
|
||||
spans two pages, we cannot safely do a direct
|
||||
jump. */
|
||||
if (next_tb != 0 && tb->page_addr[1] == -1) {
|
||||
{
|
||||
if (next_tb != 0 && tb->page_addr[1] == -1) {
|
||||
tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
|
||||
}
|
||||
}
|
||||
spin_unlock(&tb_lock);
|
||||
env->current_tb = tb;
|
||||
|
||||
/* cpu_interrupt might be called while translating the
|
||||
TB, but before it is linked into a potentially
|
||||
infinite loop and becomes env->current_tb. Avoid
|
||||
starting execution if there is a pending interrupt. */
|
||||
env->current_tb = tb;
|
||||
barrier();
|
||||
if (likely(!env->exit_request)) {
|
||||
if (unlikely (env->exit_request))
|
||||
env->current_tb = NULL;
|
||||
|
||||
while (env->current_tb) {
|
||||
tc_ptr = tb->tc_ptr;
|
||||
/* execute the generated code */
|
||||
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
|
||||
@@ -610,6 +628,7 @@ int cpu_exec(CPUState *env1)
|
||||
#define env cpu_single_env
|
||||
#endif
|
||||
next_tb = tcg_qemu_tb_exec(tc_ptr);
|
||||
env->current_tb = NULL;
|
||||
if ((next_tb & 3) == 2) {
|
||||
/* Instruction counter expired. */
|
||||
int insns_left;
|
||||
@@ -638,10 +657,11 @@ int cpu_exec(CPUState *env1)
|
||||
}
|
||||
}
|
||||
}
|
||||
env->current_tb = NULL;
|
||||
/* reset soft MMU for next block (it can currently
|
||||
only be set by a memory fault) */
|
||||
} /* for(;;) */
|
||||
} else {
|
||||
env_to_regs();
|
||||
}
|
||||
} /* for(;;) */
|
||||
|
||||
@@ -661,6 +681,7 @@ int cpu_exec(CPUState *env1)
|
||||
#elif defined(TARGET_MICROBLAZE)
|
||||
#elif defined(TARGET_MIPS)
|
||||
#elif defined(TARGET_SH4)
|
||||
#elif defined(TARGET_IA64)
|
||||
#elif defined(TARGET_ALPHA)
|
||||
#elif defined(TARGET_CRIS)
|
||||
#elif defined(TARGET_S390X)
|
||||
@@ -670,8 +691,7 @@ int cpu_exec(CPUState *env1)
|
||||
#endif
|
||||
|
||||
/* restore global registers */
|
||||
barrier();
|
||||
env = (void *) saved_env_reg;
|
||||
#include "hostregs_helper.h"
|
||||
|
||||
/* fail safe : never use cpu_single_env outside cpu_exec() */
|
||||
cpu_single_env = NULL;
|
||||
@@ -923,20 +943,6 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
# define TRAP_sig(context) REG_sig(trap, context)
|
||||
#endif /* linux */
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <ucontext.h>
|
||||
# define IAR_sig(context) ((context)->uc_mcontext.mc_srr0)
|
||||
# define MSR_sig(context) ((context)->uc_mcontext.mc_srr1)
|
||||
# define CTR_sig(context) ((context)->uc_mcontext.mc_ctr)
|
||||
# define XER_sig(context) ((context)->uc_mcontext.mc_xer)
|
||||
# define LR_sig(context) ((context)->uc_mcontext.mc_lr)
|
||||
# define CR_sig(context) ((context)->uc_mcontext.mc_cr)
|
||||
/* Exception Registers access */
|
||||
# define DAR_sig(context) ((context)->uc_mcontext.mc_dar)
|
||||
# define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr)
|
||||
# define TRAP_sig(context) ((context)->uc_mcontext.mc_exc)
|
||||
#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <sys/ucontext.h>
|
||||
typedef struct ucontext SIGCONTEXT;
|
||||
@@ -966,11 +972,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
ucontext_t *uc = puc;
|
||||
#else
|
||||
struct ucontext *uc = puc;
|
||||
#endif
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
|
||||
@@ -1146,7 +1148,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
|
||||
}
|
||||
return handle_cpu_signal(ip, (unsigned long)info->si_addr,
|
||||
is_write,
|
||||
(sigset_t *)&uc->uc_sigmask, puc);
|
||||
&uc->uc_sigmask, puc);
|
||||
}
|
||||
|
||||
#elif defined(__s390__)
|
||||
@@ -1157,47 +1159,11 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
siginfo_t *info = pinfo;
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
uint16_t *pinsn;
|
||||
int is_write = 0;
|
||||
int is_write;
|
||||
|
||||
pc = uc->uc_mcontext.psw.addr;
|
||||
|
||||
/* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
|
||||
of the normal 2 arguments. The 3rd argument contains the "int_code"
|
||||
from the hardware which does in fact contain the is_write value.
|
||||
The rt signal handler, as far as I can tell, does not give this value
|
||||
at all. Not that we could get to it from here even if it were. */
|
||||
/* ??? This is not even close to complete, since it ignores all
|
||||
of the read-modify-write instructions. */
|
||||
pinsn = (uint16_t *)pc;
|
||||
switch (pinsn[0] >> 8) {
|
||||
case 0x50: /* ST */
|
||||
case 0x42: /* STC */
|
||||
case 0x40: /* STH */
|
||||
is_write = 1;
|
||||
break;
|
||||
case 0xc4: /* RIL format insns */
|
||||
switch (pinsn[0] & 0xf) {
|
||||
case 0xf: /* STRL */
|
||||
case 0xb: /* STGRL */
|
||||
case 0x7: /* STHRL */
|
||||
is_write = 1;
|
||||
}
|
||||
break;
|
||||
case 0xe3: /* RXY format insns */
|
||||
switch (pinsn[2] & 0xff) {
|
||||
case 0x50: /* STY */
|
||||
case 0x24: /* STG */
|
||||
case 0x72: /* STCY */
|
||||
case 0x70: /* STHY */
|
||||
case 0x8e: /* STPQ */
|
||||
case 0x3f: /* STRVH */
|
||||
case 0x3e: /* STRV */
|
||||
case 0x2f: /* STRVG */
|
||||
is_write = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* XXX: compute is_write */
|
||||
is_write = 0;
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, &uc->uc_sigmask, puc);
|
||||
}
|
||||
@@ -1225,39 +1191,15 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
{
|
||||
struct siginfo *info = pinfo;
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
|
||||
uint32_t insn = *(uint32_t *)pc;
|
||||
int is_write = 0;
|
||||
|
||||
/* XXX: need kernel patch to get write flag faster. */
|
||||
switch (insn >> 26) {
|
||||
case 0x1a: /* STW */
|
||||
case 0x19: /* STH */
|
||||
case 0x18: /* STB */
|
||||
case 0x1b: /* STWM */
|
||||
is_write = 1;
|
||||
break;
|
||||
|
||||
case 0x09: /* CSTWX, FSTWX, FSTWS */
|
||||
case 0x0b: /* CSTDX, FSTDX, FSTDS */
|
||||
/* Distinguish from coprocessor load ... */
|
||||
is_write = (insn >> 9) & 1;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
switch ((insn >> 6) & 15) {
|
||||
case 0xa: /* STWS */
|
||||
case 0x9: /* STHS */
|
||||
case 0x8: /* STBS */
|
||||
case 0xe: /* STWAS */
|
||||
case 0xc: /* STBYS */
|
||||
is_write = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
|
||||
pc = uc->uc_mcontext.sc_iaoq[0];
|
||||
/* FIXME: compute is_write */
|
||||
is_write = 0;
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, &uc->uc_sigmask, puc);
|
||||
is_write,
|
||||
&uc->uc_sigmask, puc);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
861
cpus.c
861
cpus.c
@@ -1,861 +0,0 @@
|
||||
/*
|
||||
* QEMU System Emulator
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Needed early for CONFIG_BSD etc. */
|
||||
#include "config-host.h"
|
||||
|
||||
#include "monitor.h"
|
||||
#include "sysemu.h"
|
||||
#include "gdbstub.h"
|
||||
#include "dma.h"
|
||||
#include "kvm.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
#include "cpus.h"
|
||||
|
||||
#ifdef SIGRTMIN
|
||||
#define SIG_IPI (SIGRTMIN+4)
|
||||
#else
|
||||
#define SIG_IPI SIGUSR1
|
||||
#endif
|
||||
|
||||
static CPUState *next_cpu;
|
||||
|
||||
/***********************************************************/
|
||||
void hw_error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
CPUState *env;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "qemu: hardware error: ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
fprintf(stderr, "CPU #%d:\n", env->cpu_index);
|
||||
#ifdef TARGET_I386
|
||||
cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU);
|
||||
#else
|
||||
cpu_dump_state(env, stderr, fprintf, 0);
|
||||
#endif
|
||||
}
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
||||
|
||||
void cpu_synchronize_all_states(void)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
|
||||
cpu_synchronize_state(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_synchronize_all_post_reset(void)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
|
||||
cpu_synchronize_post_reset(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_synchronize_all_post_init(void)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
|
||||
cpu_synchronize_post_init(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
int cpu_is_stopped(CPUState *env)
|
||||
{
|
||||
return !vm_running || env->stopped;
|
||||
}
|
||||
|
||||
static void do_vm_stop(int reason)
|
||||
{
|
||||
if (vm_running) {
|
||||
cpu_disable_ticks();
|
||||
vm_running = 0;
|
||||
pause_all_vcpus();
|
||||
vm_state_notify(0, reason);
|
||||
monitor_protocol_event(QEVENT_STOP, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int cpu_can_run(CPUState *env)
|
||||
{
|
||||
if (env->stop)
|
||||
return 0;
|
||||
if (env->stopped || !vm_running)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cpu_has_work(CPUState *env)
|
||||
{
|
||||
if (env->stop)
|
||||
return 1;
|
||||
if (env->queued_work_first)
|
||||
return 1;
|
||||
if (env->stopped || !vm_running)
|
||||
return 0;
|
||||
if (!env->halted)
|
||||
return 1;
|
||||
if (qemu_cpu_has_work(env))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int any_cpu_has_work(void)
|
||||
{
|
||||
CPUState *env;
|
||||
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu)
|
||||
if (cpu_has_work(env))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cpu_debug_handler(CPUState *env)
|
||||
{
|
||||
gdb_set_stop_cpu(env);
|
||||
debug_requested = EXCP_DEBUG;
|
||||
vm_stop(EXCP_DEBUG);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
static int io_thread_fd = -1;
|
||||
|
||||
static void qemu_event_increment(void)
|
||||
{
|
||||
/* Write 8 bytes to be compatible with eventfd. */
|
||||
static const uint64_t val = 1;
|
||||
ssize_t ret;
|
||||
|
||||
if (io_thread_fd == -1)
|
||||
return;
|
||||
|
||||
do {
|
||||
ret = write(io_thread_fd, &val, sizeof(val));
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
/* EAGAIN is fine, a read must be pending. */
|
||||
if (ret < 0 && errno != EAGAIN) {
|
||||
fprintf(stderr, "qemu_event_increment: write() filed: %s\n",
|
||||
strerror(errno));
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_event_read(void *opaque)
|
||||
{
|
||||
int fd = (unsigned long)opaque;
|
||||
ssize_t len;
|
||||
char buffer[512];
|
||||
|
||||
/* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
|
||||
do {
|
||||
len = read(fd, buffer, sizeof(buffer));
|
||||
} while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
|
||||
}
|
||||
|
||||
static int qemu_event_init(void)
|
||||
{
|
||||
int err;
|
||||
int fds[2];
|
||||
|
||||
err = qemu_eventfd(fds);
|
||||
if (err == -1)
|
||||
return -errno;
|
||||
|
||||
err = fcntl_setfl(fds[0], O_NONBLOCK);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
|
||||
err = fcntl_setfl(fds[1], O_NONBLOCK);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
|
||||
qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
|
||||
(void *)(unsigned long)fds[0]);
|
||||
|
||||
io_thread_fd = fds[1];
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
HANDLE qemu_event_handle;
|
||||
|
||||
static void dummy_event_handler(void *opaque)
|
||||
{
|
||||
}
|
||||
|
||||
static int qemu_event_init(void)
|
||||
{
|
||||
qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (!qemu_event_handle) {
|
||||
fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qemu_event_increment(void)
|
||||
{
|
||||
if (!SetEvent(qemu_event_handle)) {
|
||||
fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n",
|
||||
GetLastError());
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_IOTHREAD
|
||||
int qemu_init_main_loop(void)
|
||||
{
|
||||
cpu_set_debug_excp_handler(cpu_debug_handler);
|
||||
|
||||
return qemu_event_init();
|
||||
}
|
||||
|
||||
void qemu_main_loop_start(void)
|
||||
{
|
||||
}
|
||||
|
||||
void qemu_init_vcpu(void *_env)
|
||||
{
|
||||
CPUState *env = _env;
|
||||
|
||||
env->nr_cores = smp_cores;
|
||||
env->nr_threads = smp_threads;
|
||||
if (kvm_enabled())
|
||||
kvm_init_vcpu(env);
|
||||
return;
|
||||
}
|
||||
|
||||
int qemu_cpu_self(void *env)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
|
||||
{
|
||||
func(data);
|
||||
}
|
||||
|
||||
void resume_all_vcpus(void)
|
||||
{
|
||||
}
|
||||
|
||||
void pause_all_vcpus(void)
|
||||
{
|
||||
}
|
||||
|
||||
void qemu_cpu_kick(void *env)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void qemu_notify_event(void)
|
||||
{
|
||||
CPUState *env = cpu_single_env;
|
||||
|
||||
qemu_event_increment ();
|
||||
if (env) {
|
||||
cpu_exit(env);
|
||||
}
|
||||
if (next_cpu && env != next_cpu) {
|
||||
cpu_exit(next_cpu);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_mutex_lock_iothread(void) {}
|
||||
void qemu_mutex_unlock_iothread(void) {}
|
||||
|
||||
void vm_stop(int reason)
|
||||
{
|
||||
do_vm_stop(reason);
|
||||
}
|
||||
|
||||
#else /* CONFIG_IOTHREAD */
|
||||
|
||||
#include "qemu-thread.h"
|
||||
|
||||
QemuMutex qemu_global_mutex;
|
||||
static QemuMutex qemu_fair_mutex;
|
||||
|
||||
static QemuThread io_thread;
|
||||
|
||||
static QemuThread *tcg_cpu_thread;
|
||||
static QemuCond *tcg_halt_cond;
|
||||
|
||||
static int qemu_system_ready;
|
||||
/* cpu creation */
|
||||
static QemuCond qemu_cpu_cond;
|
||||
/* system init */
|
||||
static QemuCond qemu_system_cond;
|
||||
static QemuCond qemu_pause_cond;
|
||||
static QemuCond qemu_work_cond;
|
||||
|
||||
static void tcg_init_ipi(void);
|
||||
static void kvm_init_ipi(CPUState *env);
|
||||
static void unblock_io_signals(void);
|
||||
|
||||
int qemu_init_main_loop(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
cpu_set_debug_excp_handler(cpu_debug_handler);
|
||||
|
||||
ret = qemu_event_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
qemu_cond_init(&qemu_pause_cond);
|
||||
qemu_cond_init(&qemu_system_cond);
|
||||
qemu_mutex_init(&qemu_fair_mutex);
|
||||
qemu_mutex_init(&qemu_global_mutex);
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
|
||||
unblock_io_signals();
|
||||
qemu_thread_self(&io_thread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qemu_main_loop_start(void)
|
||||
{
|
||||
qemu_system_ready = 1;
|
||||
qemu_cond_broadcast(&qemu_system_cond);
|
||||
}
|
||||
|
||||
void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
|
||||
{
|
||||
struct qemu_work_item wi;
|
||||
|
||||
if (qemu_cpu_self(env)) {
|
||||
func(data);
|
||||
return;
|
||||
}
|
||||
|
||||
wi.func = func;
|
||||
wi.data = data;
|
||||
if (!env->queued_work_first)
|
||||
env->queued_work_first = &wi;
|
||||
else
|
||||
env->queued_work_last->next = &wi;
|
||||
env->queued_work_last = &wi;
|
||||
wi.next = NULL;
|
||||
wi.done = false;
|
||||
|
||||
qemu_cpu_kick(env);
|
||||
while (!wi.done) {
|
||||
CPUState *self_env = cpu_single_env;
|
||||
|
||||
qemu_cond_wait(&qemu_work_cond, &qemu_global_mutex);
|
||||
cpu_single_env = self_env;
|
||||
}
|
||||
}
|
||||
|
||||
static void flush_queued_work(CPUState *env)
|
||||
{
|
||||
struct qemu_work_item *wi;
|
||||
|
||||
if (!env->queued_work_first)
|
||||
return;
|
||||
|
||||
while ((wi = env->queued_work_first)) {
|
||||
env->queued_work_first = wi->next;
|
||||
wi->func(wi->data);
|
||||
wi->done = true;
|
||||
}
|
||||
env->queued_work_last = NULL;
|
||||
qemu_cond_broadcast(&qemu_work_cond);
|
||||
}
|
||||
|
||||
static void qemu_wait_io_event_common(CPUState *env)
|
||||
{
|
||||
if (env->stop) {
|
||||
env->stop = 0;
|
||||
env->stopped = 1;
|
||||
qemu_cond_signal(&qemu_pause_cond);
|
||||
}
|
||||
flush_queued_work(env);
|
||||
}
|
||||
|
||||
static void qemu_tcg_wait_io_event(void)
|
||||
{
|
||||
CPUState *env;
|
||||
|
||||
while (!any_cpu_has_work())
|
||||
qemu_cond_timedwait(tcg_halt_cond, &qemu_global_mutex, 1000);
|
||||
|
||||
qemu_mutex_unlock(&qemu_global_mutex);
|
||||
|
||||
/*
|
||||
* Users of qemu_global_mutex can be starved, having no chance
|
||||
* to acquire it since this path will get to it first.
|
||||
* So use another lock to provide fairness.
|
||||
*/
|
||||
qemu_mutex_lock(&qemu_fair_mutex);
|
||||
qemu_mutex_unlock(&qemu_fair_mutex);
|
||||
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
qemu_wait_io_event_common(env);
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_kvm_eat_signal(CPUState *env, int timeout)
|
||||
{
|
||||
struct timespec ts;
|
||||
int r, e;
|
||||
siginfo_t siginfo;
|
||||
sigset_t waitset;
|
||||
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout % 1000) * 1000000;
|
||||
|
||||
sigemptyset(&waitset);
|
||||
sigaddset(&waitset, SIG_IPI);
|
||||
|
||||
qemu_mutex_unlock(&qemu_global_mutex);
|
||||
r = sigtimedwait(&waitset, &siginfo, &ts);
|
||||
e = errno;
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
|
||||
if (r == -1 && !(e == EAGAIN || e == EINTR)) {
|
||||
fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_kvm_wait_io_event(CPUState *env)
|
||||
{
|
||||
while (!cpu_has_work(env))
|
||||
qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000);
|
||||
|
||||
qemu_kvm_eat_signal(env, 0);
|
||||
qemu_wait_io_event_common(env);
|
||||
}
|
||||
|
||||
static int qemu_cpu_exec(CPUState *env);
|
||||
|
||||
static void *kvm_cpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUState *env = arg;
|
||||
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
qemu_thread_self(env->thread);
|
||||
if (kvm_enabled())
|
||||
kvm_init_vcpu(env);
|
||||
|
||||
kvm_init_ipi(env);
|
||||
|
||||
/* signal CPU creation */
|
||||
env->created = 1;
|
||||
qemu_cond_signal(&qemu_cpu_cond);
|
||||
|
||||
/* and wait for machine initialization */
|
||||
while (!qemu_system_ready)
|
||||
qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
|
||||
|
||||
while (1) {
|
||||
if (cpu_can_run(env))
|
||||
qemu_cpu_exec(env);
|
||||
qemu_kvm_wait_io_event(env);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *tcg_cpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUState *env = arg;
|
||||
|
||||
tcg_init_ipi();
|
||||
qemu_thread_self(env->thread);
|
||||
|
||||
/* signal CPU creation */
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu)
|
||||
env->created = 1;
|
||||
qemu_cond_signal(&qemu_cpu_cond);
|
||||
|
||||
/* and wait for machine initialization */
|
||||
while (!qemu_system_ready)
|
||||
qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
|
||||
|
||||
while (1) {
|
||||
cpu_exec_all();
|
||||
qemu_tcg_wait_io_event();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qemu_cpu_kick(void *_env)
|
||||
{
|
||||
CPUState *env = _env;
|
||||
qemu_cond_broadcast(env->halt_cond);
|
||||
qemu_thread_signal(env->thread, SIG_IPI);
|
||||
}
|
||||
|
||||
int qemu_cpu_self(void *_env)
|
||||
{
|
||||
CPUState *env = _env;
|
||||
QemuThread this;
|
||||
|
||||
qemu_thread_self(&this);
|
||||
|
||||
return qemu_thread_equal(&this, env->thread);
|
||||
}
|
||||
|
||||
static void cpu_signal(int sig)
|
||||
{
|
||||
if (cpu_single_env)
|
||||
cpu_exit(cpu_single_env);
|
||||
exit_request = 1;
|
||||
}
|
||||
|
||||
static void tcg_init_ipi(void)
|
||||
{
|
||||
sigset_t set;
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_handler = cpu_signal;
|
||||
sigaction(SIG_IPI, &sigact, NULL);
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIG_IPI);
|
||||
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
|
||||
}
|
||||
|
||||
static void dummy_signal(int sig)
|
||||
{
|
||||
}
|
||||
|
||||
static void kvm_init_ipi(CPUState *env)
|
||||
{
|
||||
int r;
|
||||
sigset_t set;
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_handler = dummy_signal;
|
||||
sigaction(SIG_IPI, &sigact, NULL);
|
||||
|
||||
pthread_sigmask(SIG_BLOCK, NULL, &set);
|
||||
sigdelset(&set, SIG_IPI);
|
||||
r = kvm_set_signal_mask(env, &set);
|
||||
if (r) {
|
||||
fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void unblock_io_signals(void)
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGUSR2);
|
||||
sigaddset(&set, SIGIO);
|
||||
sigaddset(&set, SIGALRM);
|
||||
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIG_IPI);
|
||||
pthread_sigmask(SIG_BLOCK, &set, NULL);
|
||||
}
|
||||
|
||||
void qemu_mutex_lock_iothread(void)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
qemu_mutex_lock(&qemu_fair_mutex);
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
qemu_mutex_unlock(&qemu_fair_mutex);
|
||||
} else {
|
||||
qemu_mutex_lock(&qemu_fair_mutex);
|
||||
if (qemu_mutex_trylock(&qemu_global_mutex)) {
|
||||
qemu_thread_signal(tcg_cpu_thread, SIG_IPI);
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
}
|
||||
qemu_mutex_unlock(&qemu_fair_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_mutex_unlock_iothread(void)
|
||||
{
|
||||
qemu_mutex_unlock(&qemu_global_mutex);
|
||||
}
|
||||
|
||||
static int all_vcpus_paused(void)
|
||||
{
|
||||
CPUState *penv = first_cpu;
|
||||
|
||||
while (penv) {
|
||||
if (!penv->stopped)
|
||||
return 0;
|
||||
penv = (CPUState *)penv->next_cpu;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void pause_all_vcpus(void)
|
||||
{
|
||||
CPUState *penv = first_cpu;
|
||||
|
||||
while (penv) {
|
||||
penv->stop = 1;
|
||||
qemu_cpu_kick(penv);
|
||||
penv = (CPUState *)penv->next_cpu;
|
||||
}
|
||||
|
||||
while (!all_vcpus_paused()) {
|
||||
qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);
|
||||
penv = first_cpu;
|
||||
while (penv) {
|
||||
qemu_cpu_kick(penv);
|
||||
penv = (CPUState *)penv->next_cpu;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resume_all_vcpus(void)
|
||||
{
|
||||
CPUState *penv = first_cpu;
|
||||
|
||||
while (penv) {
|
||||
penv->stop = 0;
|
||||
penv->stopped = 0;
|
||||
qemu_cpu_kick(penv);
|
||||
penv = (CPUState *)penv->next_cpu;
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_init_vcpu(void *_env)
|
||||
{
|
||||
CPUState *env = _env;
|
||||
/* share a single thread for all cpus with TCG */
|
||||
if (!tcg_cpu_thread) {
|
||||
env->thread = qemu_mallocz(sizeof(QemuThread));
|
||||
env->halt_cond = qemu_mallocz(sizeof(QemuCond));
|
||||
qemu_cond_init(env->halt_cond);
|
||||
qemu_thread_create(env->thread, tcg_cpu_thread_fn, env);
|
||||
while (env->created == 0)
|
||||
qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
|
||||
tcg_cpu_thread = env->thread;
|
||||
tcg_halt_cond = env->halt_cond;
|
||||
} else {
|
||||
env->thread = tcg_cpu_thread;
|
||||
env->halt_cond = tcg_halt_cond;
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_start_vcpu(CPUState *env)
|
||||
{
|
||||
env->thread = qemu_mallocz(sizeof(QemuThread));
|
||||
env->halt_cond = qemu_mallocz(sizeof(QemuCond));
|
||||
qemu_cond_init(env->halt_cond);
|
||||
qemu_thread_create(env->thread, kvm_cpu_thread_fn, env);
|
||||
while (env->created == 0)
|
||||
qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
|
||||
}
|
||||
|
||||
void qemu_init_vcpu(void *_env)
|
||||
{
|
||||
CPUState *env = _env;
|
||||
|
||||
env->nr_cores = smp_cores;
|
||||
env->nr_threads = smp_threads;
|
||||
if (kvm_enabled())
|
||||
kvm_start_vcpu(env);
|
||||
else
|
||||
tcg_init_vcpu(env);
|
||||
}
|
||||
|
||||
void qemu_notify_event(void)
|
||||
{
|
||||
qemu_event_increment();
|
||||
}
|
||||
|
||||
static void qemu_system_vmstop_request(int reason)
|
||||
{
|
||||
vmstop_requested = reason;
|
||||
qemu_notify_event();
|
||||
}
|
||||
|
||||
void vm_stop(int reason)
|
||||
{
|
||||
QemuThread me;
|
||||
qemu_thread_self(&me);
|
||||
|
||||
if (!qemu_thread_equal(&me, &io_thread)) {
|
||||
qemu_system_vmstop_request(reason);
|
||||
/*
|
||||
* FIXME: should not return to device code in case
|
||||
* vm_stop() has been requested.
|
||||
*/
|
||||
if (cpu_single_env) {
|
||||
cpu_exit(cpu_single_env);
|
||||
cpu_single_env->stop = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
do_vm_stop(reason);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int qemu_cpu_exec(CPUState *env)
|
||||
{
|
||||
int ret;
|
||||
#ifdef CONFIG_PROFILER
|
||||
int64_t ti;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
ti = profile_getclock();
|
||||
#endif
|
||||
if (use_icount) {
|
||||
int64_t count;
|
||||
int decr;
|
||||
qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
|
||||
env->icount_decr.u16.low = 0;
|
||||
env->icount_extra = 0;
|
||||
count = qemu_icount_round (qemu_next_deadline());
|
||||
qemu_icount += count;
|
||||
decr = (count > 0xffff) ? 0xffff : count;
|
||||
count -= decr;
|
||||
env->icount_decr.u16.low = decr;
|
||||
env->icount_extra = count;
|
||||
}
|
||||
ret = cpu_exec(env);
|
||||
#ifdef CONFIG_PROFILER
|
||||
qemu_time += profile_getclock() - ti;
|
||||
#endif
|
||||
if (use_icount) {
|
||||
/* Fold pending instructions back into the
|
||||
instruction counter, and clear the interrupt flag. */
|
||||
qemu_icount -= (env->icount_decr.u16.low
|
||||
+ env->icount_extra);
|
||||
env->icount_decr.u32 = 0;
|
||||
env->icount_extra = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool cpu_exec_all(void)
|
||||
{
|
||||
if (next_cpu == NULL)
|
||||
next_cpu = first_cpu;
|
||||
for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) {
|
||||
CPUState *env = next_cpu;
|
||||
|
||||
qemu_clock_enable(vm_clock,
|
||||
(env->singlestep_enabled & SSTEP_NOTIMER) == 0);
|
||||
|
||||
if (qemu_alarm_pending())
|
||||
break;
|
||||
if (cpu_can_run(env)) {
|
||||
if (qemu_cpu_exec(env) == EXCP_DEBUG) {
|
||||
break;
|
||||
}
|
||||
} else if (env->stop) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
exit_request = 0;
|
||||
return any_cpu_has_work();
|
||||
}
|
||||
|
||||
void set_numa_modes(void)
|
||||
{
|
||||
CPUState *env;
|
||||
int i;
|
||||
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
for (i = 0; i < nb_numa_nodes; i++) {
|
||||
if (node_cpumask[i] & (1 << env->cpu_index)) {
|
||||
env->numa_node = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_cpu_log(const char *optarg)
|
||||
{
|
||||
int mask;
|
||||
const CPULogItem *item;
|
||||
|
||||
mask = cpu_str_to_log_mask(optarg);
|
||||
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);
|
||||
}
|
||||
|
||||
/* Return the virtual CPU time, based on the instruction counter. */
|
||||
int64_t cpu_get_icount(void)
|
||||
{
|
||||
int64_t icount;
|
||||
CPUState *env = cpu_single_env;;
|
||||
|
||||
icount = qemu_icount;
|
||||
if (env) {
|
||||
if (!can_do_io(env)) {
|
||||
fprintf(stderr, "Bad clock read\n");
|
||||
}
|
||||
icount -= (env->icount_decr.u16.low + env->icount_extra);
|
||||
}
|
||||
return qemu_icount_bias + (icount << icount_time_shift);
|
||||
}
|
||||
|
||||
void list_cpus(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
|
||||
const char *optarg)
|
||||
{
|
||||
/* XXX: implement xxx_cpu_list for targets that still miss it */
|
||||
#if defined(cpu_list_id)
|
||||
cpu_list_id(f, cpu_fprintf, optarg);
|
||||
#elif defined(cpu_list)
|
||||
cpu_list(f, cpu_fprintf); /* deprecated */
|
||||
#endif
|
||||
}
|
||||
22
cpus.h
22
cpus.h
@@ -1,22 +0,0 @@
|
||||
#ifndef QEMU_CPUS_H
|
||||
#define QEMU_CPUS_H
|
||||
|
||||
/* cpus.c */
|
||||
int qemu_init_main_loop(void);
|
||||
void qemu_main_loop_start(void);
|
||||
void resume_all_vcpus(void);
|
||||
void pause_all_vcpus(void);
|
||||
|
||||
/* vl.c */
|
||||
extern int smp_cores;
|
||||
extern int smp_threads;
|
||||
extern int debug_requested;
|
||||
extern int vmstop_requested;
|
||||
void vm_state_notify(int running, int reason);
|
||||
bool cpu_exec_all(void);
|
||||
void set_numa_modes(void);
|
||||
void set_cpu_log(const char *optarg);
|
||||
void list_cpus(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
|
||||
const char *optarg);
|
||||
|
||||
#endif
|
||||
@@ -13,14 +13,10 @@ case $line in
|
||||
pkgversion=${line#*=}
|
||||
echo "#define QEMU_PKGVERSION \"$pkgversion\""
|
||||
;;
|
||||
prefix=* | [a-z]*dir=*) # directory configuration
|
||||
name=${line%=*}
|
||||
value=${line#*=}
|
||||
define_name=`echo $name | tr '[:lower:]' '[:upper:]'`
|
||||
eval "define_value=\"$value\""
|
||||
echo "#define CONFIG_QEMU_$define_name \"$define_value\""
|
||||
# save for the next definitions
|
||||
eval "$name=\$define_value"
|
||||
ARCH=*) # configuration
|
||||
arch=${line#*=}
|
||||
arch_name=`echo $arch | tr '[:lower:]' '[:upper:]'`
|
||||
echo "#define HOST_$arch_name 1"
|
||||
;;
|
||||
CONFIG_AUDIO_DRIVERS=*)
|
||||
drivers=${line#*=}
|
||||
|
||||
@@ -159,10 +159,11 @@ static void curses_cursor_position(DisplayState *ds, int x, int y)
|
||||
#include "curses_keys.h"
|
||||
|
||||
static kbd_layout_t *kbd_layout = NULL;
|
||||
static int keycode2keysym[CURSES_KEYS];
|
||||
|
||||
static void curses_refresh(DisplayState *ds)
|
||||
{
|
||||
int chr, nextchr, keysym, keycode, keycode_alt;
|
||||
int chr, nextchr, keysym, keycode;
|
||||
|
||||
if (invalidate) {
|
||||
clear();
|
||||
@@ -203,58 +204,43 @@ static void curses_refresh(DisplayState *ds)
|
||||
#endif
|
||||
|
||||
keycode = curses2keycode[chr];
|
||||
keycode_alt = 0;
|
||||
if (keycode == -1)
|
||||
continue;
|
||||
|
||||
/* alt key */
|
||||
if (keycode == 1) {
|
||||
nextchr = getch();
|
||||
|
||||
if (nextchr != ERR) {
|
||||
chr = nextchr;
|
||||
keycode_alt = ALT;
|
||||
keycode = curses2keycode[nextchr];
|
||||
nextchr = ERR;
|
||||
if (keycode == -1)
|
||||
continue;
|
||||
|
||||
if (keycode != -1) {
|
||||
keycode |= ALT;
|
||||
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);
|
||||
/* 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;
|
||||
}
|
||||
invalidate = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kbd_layout) {
|
||||
keysym = -1;
|
||||
if (chr < CURSES_KEYS)
|
||||
keysym = curses2keysym[chr];
|
||||
if (kbd_layout && !(keycode & GREY)) {
|
||||
keysym = keycode2keysym[keycode & KEY_MASK];
|
||||
if (keysym == -1)
|
||||
keysym = chr;
|
||||
|
||||
if (keysym == -1) {
|
||||
if (chr < ' ')
|
||||
keysym = (chr + '@' - 'A' + 'a') | KEYSYM_CNTRL;
|
||||
else
|
||||
keysym = chr;
|
||||
}
|
||||
|
||||
keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK);
|
||||
if (keycode == 0)
|
||||
continue;
|
||||
|
||||
keycode |= (keysym & ~KEYSYM_MASK) >> 16;
|
||||
keycode |= keycode_alt;
|
||||
keycode &= ~KEY_MASK;
|
||||
keycode |= keysym2scancode(kbd_layout, keysym);
|
||||
}
|
||||
|
||||
if (keycode == -1)
|
||||
continue;
|
||||
|
||||
if (is_graphic_console()) {
|
||||
/* since terminals don't know about key press and release
|
||||
* events, we need to emit both for each key received */
|
||||
@@ -264,20 +250,12 @@ static void curses_refresh(DisplayState *ds)
|
||||
kbd_put_keycode(CNTRL_CODE);
|
||||
if (keycode & ALT)
|
||||
kbd_put_keycode(ALT_CODE);
|
||||
if (keycode & ALTGR) {
|
||||
kbd_put_keycode(SCANCODE_EMUL0);
|
||||
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 & ALTGR) {
|
||||
kbd_put_keycode(SCANCODE_EMUL0);
|
||||
kbd_put_keycode(ALT_CODE | KEY_RELEASE);
|
||||
}
|
||||
if (keycode & ALT)
|
||||
kbd_put_keycode(ALT_CODE | KEY_RELEASE);
|
||||
if (keycode & CNTRL)
|
||||
@@ -285,7 +263,7 @@ static void curses_refresh(DisplayState *ds)
|
||||
if (keycode & SHIFT)
|
||||
kbd_put_keycode(SHIFT_CODE | KEY_RELEASE);
|
||||
} else {
|
||||
keysym = curses2qemu[chr];
|
||||
keysym = curses2keysym[chr];
|
||||
if (keysym == -1)
|
||||
keysym = chr;
|
||||
|
||||
@@ -294,11 +272,16 @@ static void curses_refresh(DisplayState *ds)
|
||||
}
|
||||
}
|
||||
|
||||
static void curses_atexit(void)
|
||||
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] = {
|
||||
@@ -318,6 +301,8 @@ static void curses_setup(void)
|
||||
|
||||
static void curses_keyboard_setup(void)
|
||||
{
|
||||
int i, keycode, keysym;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* always use generic keymaps */
|
||||
if (!keyboard_layout)
|
||||
@@ -328,6 +313,27 @@ static void curses_keyboard_setup(void)
|
||||
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)
|
||||
@@ -22,42 +22,25 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <curses.h>
|
||||
#include "keymaps.h"
|
||||
|
||||
|
||||
#define KEY_RELEASE 0x80
|
||||
#define KEY_MASK 0x7f
|
||||
#define GREY_CODE 0xe0
|
||||
#define GREY SCANCODE_GREY
|
||||
#define SHIFT_CODE 0x2a
|
||||
#define SHIFT SCANCODE_SHIFT
|
||||
#define SHIFT 0x0080
|
||||
#define GREY_CODE 0xe0
|
||||
#define GREY 0x0100
|
||||
#define CNTRL_CODE 0x1d
|
||||
#define CNTRL SCANCODE_CTRL
|
||||
#define CNTRL 0x0200
|
||||
#define ALT_CODE 0x38
|
||||
#define ALT SCANCODE_ALT
|
||||
#define ALTGR SCANCODE_ALTGR
|
||||
|
||||
#define KEYSYM_MASK 0x0ffffff
|
||||
#define KEYSYM_SHIFT (SCANCODE_SHIFT << 16)
|
||||
#define KEYSYM_CNTRL (SCANCODE_CTRL << 16)
|
||||
#define KEYSYM_ALT (SCANCODE_ALT << 16)
|
||||
#define KEYSYM_ALTGR (SCANCODE_ALTGR << 16)
|
||||
#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 curses2keysym[CURSES_KEYS] = {
|
||||
[0 ... (CURSES_KEYS - 1)] = -1,
|
||||
|
||||
[0x7f] = KEY_BACKSPACE,
|
||||
['\r'] = KEY_ENTER,
|
||||
['\n'] = KEY_ENTER,
|
||||
[KEY_BTAB] = '\t' | KEYSYM_SHIFT,
|
||||
};
|
||||
|
||||
static const int curses2keycode[CURSES_KEYS] = {
|
||||
[0 ... (CURSES_KEYS - 1)] = -1,
|
||||
|
||||
@@ -75,7 +58,7 @@ static const int curses2keycode[CURSES_KEYS] = {
|
||||
['-'] = 12,
|
||||
['='] = 13,
|
||||
[0x07f] = 14, /* Backspace */
|
||||
[KEY_BACKSPACE] = 14, /* Backspace */
|
||||
[0x107] = 14, /* Backspace */
|
||||
|
||||
['\t'] = 15, /* Tab */
|
||||
['q'] = 16,
|
||||
@@ -92,7 +75,7 @@ static const int curses2keycode[CURSES_KEYS] = {
|
||||
[']'] = 27,
|
||||
['\n'] = 28, /* Return */
|
||||
['\r'] = 28, /* Return */
|
||||
[KEY_ENTER] = 28, /* Return */
|
||||
[0x157] = 28, /* Return */
|
||||
|
||||
['a'] = 30,
|
||||
['s'] = 31,
|
||||
@@ -121,29 +104,29 @@ static const int curses2keycode[CURSES_KEYS] = {
|
||||
|
||||
[' '] = 57,
|
||||
|
||||
[KEY_F(1)] = 59, /* Function Key 1 */
|
||||
[KEY_F(2)] = 60, /* Function Key 2 */
|
||||
[KEY_F(3)] = 61, /* Function Key 3 */
|
||||
[KEY_F(4)] = 62, /* Function Key 4 */
|
||||
[KEY_F(5)] = 63, /* Function Key 5 */
|
||||
[KEY_F(6)] = 64, /* Function Key 6 */
|
||||
[KEY_F(7)] = 65, /* Function Key 7 */
|
||||
[KEY_F(8)] = 66, /* Function Key 8 */
|
||||
[KEY_F(9)] = 67, /* Function Key 9 */
|
||||
[KEY_F(10)] = 68, /* Function Key 10 */
|
||||
[KEY_F(11)] = 87, /* Function Key 11 */
|
||||
[KEY_F(12)] = 88, /* Function Key 12 */
|
||||
[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 */
|
||||
|
||||
[KEY_HOME] = 71 | GREY, /* Home */
|
||||
[KEY_UP] = 72 | GREY, /* Up Arrow */
|
||||
[KEY_PPAGE] = 73 | GREY, /* Page Up */
|
||||
[KEY_LEFT] = 75 | GREY, /* Left Arrow */
|
||||
[KEY_RIGHT] = 77 | GREY, /* Right Arrow */
|
||||
[KEY_END] = 79 | GREY, /* End */
|
||||
[KEY_DOWN] = 80 | GREY, /* Down Arrow */
|
||||
[KEY_NPAGE] = 81 | GREY, /* Page Down */
|
||||
[KEY_IC] = 82 | GREY, /* Insert */
|
||||
[KEY_DC] = 83 | GREY, /* Delete */
|
||||
[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,
|
||||
@@ -158,7 +141,7 @@ static const int curses2keycode[CURSES_KEYS] = {
|
||||
['_'] = 12 | SHIFT,
|
||||
['+'] = 13 | SHIFT,
|
||||
|
||||
[KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */
|
||||
[0x161] = 15 | SHIFT, /* Shift + Tab */
|
||||
['Q'] = 16 | SHIFT,
|
||||
['W'] = 17 | SHIFT,
|
||||
['E'] = 18 | SHIFT,
|
||||
@@ -197,51 +180,47 @@ static const int curses2keycode[CURSES_KEYS] = {
|
||||
['>'] = 52 | SHIFT,
|
||||
['?'] = 53 | SHIFT,
|
||||
|
||||
[KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */
|
||||
[KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */
|
||||
[KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */
|
||||
[KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */
|
||||
[KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */
|
||||
[KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */
|
||||
[KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */
|
||||
[KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */
|
||||
[KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */
|
||||
[KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */
|
||||
[KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */
|
||||
[KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */
|
||||
[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 */
|
||||
|
||||
['Q' - '@'] = 16 | CNTRL, /* Control + q */
|
||||
['W' - '@'] = 17 | CNTRL, /* Control + w */
|
||||
['E' - '@'] = 18 | CNTRL, /* Control + e */
|
||||
['R' - '@'] = 19 | CNTRL, /* Control + r */
|
||||
['T' - '@'] = 20 | CNTRL, /* Control + t */
|
||||
['Y' - '@'] = 21 | CNTRL, /* Control + y */
|
||||
['U' - '@'] = 22 | CNTRL, /* Control + u */
|
||||
[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 */
|
||||
['O' - '@'] = 24 | CNTRL, /* Control + o */
|
||||
['P' - '@'] = 25 | CNTRL, /* Control + p */
|
||||
[0x00f] = 24 | CNTRL, /* Control + o */
|
||||
[0x010] = 25 | CNTRL, /* Control + p */
|
||||
|
||||
['A' - '@'] = 30 | CNTRL, /* Control + a */
|
||||
['S' - '@'] = 31 | CNTRL, /* Control + s */
|
||||
['D' - '@'] = 32 | CNTRL, /* Control + d */
|
||||
['F' - '@'] = 33 | CNTRL, /* Control + f */
|
||||
['G' - '@'] = 34 | CNTRL, /* Control + g */
|
||||
['H' - '@'] = 35 | CNTRL, /* Control + h */
|
||||
[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 */
|
||||
/* Control + j collides with Return */
|
||||
['K' - '@'] = 37 | CNTRL, /* Control + k */
|
||||
['L' - '@'] = 38 | CNTRL, /* Control + l */
|
||||
[0x00b] = 37 | CNTRL, /* Control + k */
|
||||
[0x00c] = 38 | CNTRL, /* Control + l */
|
||||
|
||||
['Z' - '@'] = 44 | CNTRL, /* Control + z */
|
||||
['X' - '@'] = 45 | CNTRL, /* Control + x */
|
||||
['C' - '@'] = 46 | CNTRL, /* Control + c */
|
||||
['V' - '@'] = 47 | CNTRL, /* Control + v */
|
||||
['B' - '@'] = 48 | CNTRL, /* Control + b */
|
||||
['N' - '@'] = 49 | CNTRL, /* Control + n */
|
||||
[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 curses2qemu[CURSES_KEYS] = {
|
||||
static const int curses2keysym[CURSES_KEYS] = {
|
||||
[0 ... (CURSES_KEYS - 1)] = -1,
|
||||
|
||||
['\n'] = '\n',
|
||||
@@ -249,18 +228,18 @@ static const int curses2qemu[CURSES_KEYS] = {
|
||||
|
||||
[0x07f] = QEMU_KEY_BACKSPACE,
|
||||
|
||||
[KEY_DOWN] = QEMU_KEY_DOWN,
|
||||
[KEY_UP] = QEMU_KEY_UP,
|
||||
[KEY_LEFT] = QEMU_KEY_LEFT,
|
||||
[KEY_RIGHT] = QEMU_KEY_RIGHT,
|
||||
[KEY_HOME] = QEMU_KEY_HOME,
|
||||
[KEY_BACKSPACE] = 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,
|
||||
|
||||
[KEY_DC] = QEMU_KEY_DELETE,
|
||||
[KEY_NPAGE] = QEMU_KEY_PAGEDOWN,
|
||||
[KEY_PPAGE] = QEMU_KEY_PAGEUP,
|
||||
[KEY_ENTER] = '\n',
|
||||
[KEY_END] = QEMU_KEY_END,
|
||||
[0x14a] = QEMU_KEY_DELETE,
|
||||
[0x152] = QEMU_KEY_PAGEDOWN,
|
||||
[0x153] = QEMU_KEY_PAGEUP,
|
||||
[0x157] = '\n',
|
||||
[0x168] = QEMU_KEY_END,
|
||||
|
||||
};
|
||||
|
||||
@@ -465,43 +444,39 @@ static const name2keysym_t name2keysym[] = {
|
||||
{ "ydiaeresis", 0x0ff },
|
||||
|
||||
/* Special keys */
|
||||
{ "BackSpace", KEY_BACKSPACE },
|
||||
{ "BackSpace", 0x07f },
|
||||
{ "Tab", '\t' },
|
||||
{ "Return", KEY_ENTER },
|
||||
{ "Right", KEY_RIGHT },
|
||||
{ "Left", KEY_LEFT },
|
||||
{ "Up", KEY_UP },
|
||||
{ "Down", KEY_DOWN },
|
||||
{ "Page_Down", KEY_NPAGE },
|
||||
{ "Page_Up", KEY_PPAGE },
|
||||
{ "Insert", KEY_IC },
|
||||
{ "Delete", KEY_DC },
|
||||
{ "Home", KEY_HOME },
|
||||
{ "End", KEY_END },
|
||||
{ "F1", KEY_F(1) },
|
||||
{ "F2", KEY_F(2) },
|
||||
{ "F3", KEY_F(3) },
|
||||
{ "F4", KEY_F(4) },
|
||||
{ "F5", KEY_F(5) },
|
||||
{ "F6", KEY_F(6) },
|
||||
{ "F7", KEY_F(7) },
|
||||
{ "F8", KEY_F(8) },
|
||||
{ "F9", KEY_F(9) },
|
||||
{ "F10", KEY_F(10) },
|
||||
{ "F11", KEY_F(11) },
|
||||
{ "F12", KEY_F(12) },
|
||||
{ "F13", KEY_F(13) },
|
||||
{ "F14", KEY_F(14) },
|
||||
{ "F15", KEY_F(15) },
|
||||
{ "F16", KEY_F(16) },
|
||||
{ "F17", KEY_F(17) },
|
||||
{ "F18", KEY_F(18) },
|
||||
{ "F19", KEY_F(19) },
|
||||
{ "F20", KEY_F(20) },
|
||||
{ "F21", KEY_F(21) },
|
||||
{ "F22", KEY_F(22) },
|
||||
{ "F23", KEY_F(23) },
|
||||
{ "F24", KEY_F(24) },
|
||||
{ "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 },
|
||||
|
||||
{ NULL, 0 },
|
||||
210
cursor.c
210
cursor.c
@@ -1,210 +0,0 @@
|
||||
#include "qemu-common.h"
|
||||
#include "console.h"
|
||||
|
||||
#include "cursor_hidden.xpm"
|
||||
#include "cursor_left_ptr.xpm"
|
||||
|
||||
/* for creating built-in cursors */
|
||||
static QEMUCursor *cursor_parse_xpm(const char *xpm[])
|
||||
{
|
||||
QEMUCursor *c;
|
||||
uint32_t ctab[128];
|
||||
unsigned int width, height, colors, chars;
|
||||
unsigned int line = 0, i, r, g, b, x, y, pixel;
|
||||
char name[16];
|
||||
uint8_t idx;
|
||||
|
||||
/* parse header line: width, height, #colors, #chars */
|
||||
if (sscanf(xpm[line], "%d %d %d %d", &width, &height, &colors, &chars) != 4) {
|
||||
fprintf(stderr, "%s: header parse error: \"%s\"\n",
|
||||
__FUNCTION__, xpm[line]);
|
||||
return NULL;
|
||||
}
|
||||
if (chars != 1) {
|
||||
fprintf(stderr, "%s: chars != 1 not supported\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
line++;
|
||||
|
||||
/* parse color table */
|
||||
for (i = 0; i < colors; i++, line++) {
|
||||
if (sscanf(xpm[line], "%c c %15s", &idx, name) == 2) {
|
||||
if (sscanf(name, "#%02x%02x%02x", &r, &g, &b) == 3) {
|
||||
ctab[idx] = (0xff << 24) | (b << 16) | (g << 8) | r;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(name, "None") == 0) {
|
||||
ctab[idx] = 0x00000000;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s: color parse error: \"%s\"\n",
|
||||
__FUNCTION__, xpm[line]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* parse pixel data */
|
||||
c = cursor_alloc(width, height);
|
||||
for (pixel = 0, y = 0; y < height; y++, line++) {
|
||||
for (x = 0; x < height; x++, pixel++) {
|
||||
idx = xpm[line][x];
|
||||
c->data[pixel] = ctab[idx];
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/* nice for debugging */
|
||||
void cursor_print_ascii_art(QEMUCursor *c, const char *prefix)
|
||||
{
|
||||
uint32_t *data = c->data;
|
||||
int x,y;
|
||||
|
||||
for (y = 0; y < c->height; y++) {
|
||||
fprintf(stderr, "%s: %2d: |", prefix, y);
|
||||
for (x = 0; x < c->width; x++, data++) {
|
||||
if ((*data & 0xff000000) != 0xff000000) {
|
||||
fprintf(stderr, " "); /* transparent */
|
||||
} else if ((*data & 0x00ffffff) == 0x00ffffff) {
|
||||
fprintf(stderr, "."); /* white */
|
||||
} else if ((*data & 0x00ffffff) == 0x00000000) {
|
||||
fprintf(stderr, "X"); /* black */
|
||||
} else {
|
||||
fprintf(stderr, "o"); /* other */
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "|\n");
|
||||
}
|
||||
}
|
||||
|
||||
QEMUCursor *cursor_builtin_hidden(void)
|
||||
{
|
||||
QEMUCursor *c;
|
||||
|
||||
c = cursor_parse_xpm(cursor_hidden_xpm);
|
||||
return c;
|
||||
}
|
||||
|
||||
QEMUCursor *cursor_builtin_left_ptr(void)
|
||||
{
|
||||
QEMUCursor *c;
|
||||
|
||||
c = cursor_parse_xpm(cursor_left_ptr_xpm);
|
||||
return c;
|
||||
}
|
||||
|
||||
QEMUCursor *cursor_alloc(int width, int height)
|
||||
{
|
||||
QEMUCursor *c;
|
||||
int datasize = width * height * sizeof(uint32_t);
|
||||
|
||||
c = qemu_mallocz(sizeof(QEMUCursor) + datasize);
|
||||
c->width = width;
|
||||
c->height = height;
|
||||
c->refcount = 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
void cursor_get(QEMUCursor *c)
|
||||
{
|
||||
c->refcount++;
|
||||
}
|
||||
|
||||
void cursor_put(QEMUCursor *c)
|
||||
{
|
||||
if (c == NULL)
|
||||
return;
|
||||
c->refcount--;
|
||||
if (c->refcount)
|
||||
return;
|
||||
qemu_free(c);
|
||||
}
|
||||
|
||||
int cursor_get_mono_bpl(QEMUCursor *c)
|
||||
{
|
||||
return (c->width + 7) / 8;
|
||||
}
|
||||
|
||||
void cursor_set_mono(QEMUCursor *c,
|
||||
uint32_t foreground, uint32_t background, uint8_t *image,
|
||||
int transparent, uint8_t *mask)
|
||||
{
|
||||
uint32_t *data = c->data;
|
||||
uint8_t bit;
|
||||
int x,y,bpl;
|
||||
|
||||
bpl = cursor_get_mono_bpl(c);
|
||||
for (y = 0; y < c->height; y++) {
|
||||
bit = 0x80;
|
||||
for (x = 0; x < c->width; x++, data++) {
|
||||
if (transparent && mask[x/8] & bit) {
|
||||
*data = 0x00000000;
|
||||
} else if (!transparent && !(mask[x/8] & bit)) {
|
||||
*data = 0x00000000;
|
||||
} else if (image[x/8] & bit) {
|
||||
*data = 0xff000000 | foreground;
|
||||
} else {
|
||||
*data = 0xff000000 | background;
|
||||
}
|
||||
bit >>= 1;
|
||||
if (bit == 0) {
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
mask += bpl;
|
||||
image += bpl;
|
||||
}
|
||||
}
|
||||
|
||||
void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *image)
|
||||
{
|
||||
uint32_t *data = c->data;
|
||||
uint8_t bit;
|
||||
int x,y,bpl;
|
||||
|
||||
bpl = cursor_get_mono_bpl(c);
|
||||
memset(image, 0, bpl * c->height);
|
||||
for (y = 0; y < c->height; y++) {
|
||||
bit = 0x80;
|
||||
for (x = 0; x < c->width; x++, data++) {
|
||||
if (((*data & 0xff000000) == 0xff000000) &&
|
||||
((*data & 0x00ffffff) == foreground)) {
|
||||
image[x/8] |= bit;
|
||||
}
|
||||
bit >>= 1;
|
||||
if (bit == 0) {
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
image += bpl;
|
||||
}
|
||||
}
|
||||
|
||||
void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask)
|
||||
{
|
||||
uint32_t *data = c->data;
|
||||
uint8_t bit;
|
||||
int x,y,bpl;
|
||||
|
||||
bpl = cursor_get_mono_bpl(c);
|
||||
memset(mask, 0, bpl * c->height);
|
||||
for (y = 0; y < c->height; y++) {
|
||||
bit = 0x80;
|
||||
for (x = 0; x < c->width; x++, data++) {
|
||||
if ((*data & 0xff000000) != 0xff000000) {
|
||||
if (transparent != 0) {
|
||||
mask[x/8] |= bit;
|
||||
}
|
||||
} else {
|
||||
if (transparent == 0) {
|
||||
mask[x/8] |= bit;
|
||||
}
|
||||
}
|
||||
bit >>= 1;
|
||||
if (bit == 0) {
|
||||
bit = 0x80;
|
||||
}
|
||||
}
|
||||
mask += bpl;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/* XPM */
|
||||
static const char *cursor_hidden_xpm[] = {
|
||||
"32 32 1 1",
|
||||
" c None",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
/* XPM */
|
||||
static const char *cursor_left_ptr_xpm[] = {
|
||||
"32 32 3 1",
|
||||
"X c #000000",
|
||||
". c #ffffff",
|
||||
" c None",
|
||||
"X ",
|
||||
"XX ",
|
||||
"X.X ",
|
||||
"X..X ",
|
||||
"X...X ",
|
||||
"X....X ",
|
||||
"X.....X ",
|
||||
"X......X ",
|
||||
"X.......X ",
|
||||
"X........X ",
|
||||
"X.....XXXXX ",
|
||||
"X..X..X ",
|
||||
"X.X X..X ",
|
||||
"XX X..X ",
|
||||
"X X..X ",
|
||||
" X..X ",
|
||||
" X..X ",
|
||||
" X..X ",
|
||||
" XX ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
};
|
||||
23
cutils.c
23
cutils.c
@@ -218,6 +218,11 @@ void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* No dma flushing needed here, as the aio code will call dma_bdrv_cb()
|
||||
* on completion as well, which will result in a call to
|
||||
* dma_bdrv_unmap() which will do the flushing ....
|
||||
*/
|
||||
void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)buf;
|
||||
@@ -233,21 +238,3 @@ void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count)
|
||||
count -= copy;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Sets a specific flag */
|
||||
int fcntl_setfl(int fd, int flag)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
if (flags == -1)
|
||||
return -errno;
|
||||
|
||||
if (fcntl(fd, F_SETFL, flags | flag) == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ void do_compare_and_swap64(void *cpu_env, int num)
|
||||
uint64_t *value = (uint64_t*)((CPUX86State*)cpu_env)->regs[R_ESI];
|
||||
old = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_EDX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EAX];
|
||||
|
||||
DPRINTF("commpage: compare_and_swap64(%" PRIx64 ",new,%p)\n", old, value);
|
||||
DPRINTF("commpage: compare_and_swap64(%llx,new,%p)\n", old, value);
|
||||
swapped_val = tswap64(*value);
|
||||
|
||||
if(old == swapped_val)
|
||||
|
||||
@@ -82,9 +82,9 @@ static inline uint64_t cpu_ppc_get_tb (CPUState *env)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t cpu_ppc_load_tbl (CPUState *env)
|
||||
uint32_t cpu_ppc_load_tbl (CPUState *env)
|
||||
{
|
||||
return cpu_ppc_get_tb(env);
|
||||
return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
uint32_t cpu_ppc_load_tbu (CPUState *env)
|
||||
@@ -92,9 +92,9 @@ uint32_t cpu_ppc_load_tbu (CPUState *env)
|
||||
return cpu_ppc_get_tb(env) >> 32;
|
||||
}
|
||||
|
||||
uint64_t cpu_ppc_load_atbl (CPUState *env)
|
||||
uint32_t cpu_ppc_load_atbl (CPUState *env)
|
||||
{
|
||||
return cpu_ppc_get_tb(env);
|
||||
return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
uint32_t cpu_ppc_load_atbu (CPUState *env)
|
||||
@@ -113,12 +113,12 @@ uint32_t cpu_ppc601_load_rtcl (CPUState *env)
|
||||
}
|
||||
|
||||
/* XXX: to be fixed */
|
||||
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
|
||||
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
|
||||
int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -704,7 +704,7 @@ void cpu_loop(CPUX86State *env)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void usage(void)
|
||||
void usage(void)
|
||||
{
|
||||
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
|
||||
"usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n"
|
||||
|
||||
@@ -129,7 +129,7 @@ int mmap_frag(unsigned long host_start,
|
||||
if ((flags & MAP_SHARED) &&
|
||||
#endif
|
||||
(prot & PROT_WRITE))
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
|
||||
/* adjust protection to be able to read */
|
||||
if (!(prot1 & PROT_WRITE))
|
||||
|
||||
@@ -858,7 +858,7 @@ long no_syscall(void *cpu_env, int num);
|
||||
|
||||
long do_pread(uint32_t arg1, void * arg2, size_t arg3, off_t arg4)
|
||||
{
|
||||
DPRINTF("0x%x, %p, 0x%lx, 0x%" PRIx64 "\n", arg1, arg2, arg3, arg4);
|
||||
DPRINTF("0x%x, %p, 0x%lx, 0x%llx\n", arg1, arg2, arg3, arg4);
|
||||
long ret = pread(arg1, arg2, arg3, arg4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
38
def-helper.h
38
def-helper.h
@@ -81,29 +81,9 @@
|
||||
#define dh_is_64bit_ptr (TCG_TARGET_REG_BITS == 64)
|
||||
#define dh_is_64bit(t) glue(dh_is_64bit_, dh_alias(t))
|
||||
|
||||
#define dh_is_signed_void 0
|
||||
#define dh_is_signed_i32 0
|
||||
#define dh_is_signed_s32 1
|
||||
#define dh_is_signed_i64 0
|
||||
#define dh_is_signed_s64 1
|
||||
#define dh_is_signed_f32 0
|
||||
#define dh_is_signed_f64 0
|
||||
#define dh_is_signed_tl 0
|
||||
#define dh_is_signed_int 1
|
||||
/* ??? This is highly specific to the host cpu. There are even special
|
||||
extension instructions that may be required, e.g. ia64's addp4. But
|
||||
for now we don't support any 64-bit targets with 32-bit pointers. */
|
||||
#define dh_is_signed_ptr 0
|
||||
#define dh_is_signed_env dh_is_signed_ptr
|
||||
#define dh_is_signed(t) dh_is_signed_##t
|
||||
|
||||
#define dh_sizemask(t, n) \
|
||||
sizemask |= dh_is_64bit(t) << (n*2); \
|
||||
sizemask |= dh_is_signed(t) << (n*2+1)
|
||||
|
||||
#define dh_arg(t, n) \
|
||||
args[n - 1] = glue(GET_TCGV_, dh_alias(t))(glue(arg, n)); \
|
||||
dh_sizemask(t, n)
|
||||
sizemask |= dh_is_64bit(t) << n
|
||||
|
||||
#define dh_arg_decl(t, n) glue(TCGv_, dh_alias(t)) glue(arg, n)
|
||||
|
||||
@@ -158,8 +138,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret)) \
|
||||
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1)) \
|
||||
{ \
|
||||
TCGArg args[1]; \
|
||||
int sizemask = 0; \
|
||||
dh_sizemask(ret, 0); \
|
||||
int sizemask; \
|
||||
sizemask = dh_is_64bit(ret); \
|
||||
dh_arg(t1, 1); \
|
||||
tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 1, args); \
|
||||
}
|
||||
@@ -169,8 +149,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1
|
||||
dh_arg_decl(t2, 2)) \
|
||||
{ \
|
||||
TCGArg args[2]; \
|
||||
int sizemask = 0; \
|
||||
dh_sizemask(ret, 0); \
|
||||
int sizemask; \
|
||||
sizemask = dh_is_64bit(ret); \
|
||||
dh_arg(t1, 1); \
|
||||
dh_arg(t2, 2); \
|
||||
tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 2, args); \
|
||||
@@ -181,8 +161,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1
|
||||
dh_arg_decl(t2, 2), dh_arg_decl(t3, 3)) \
|
||||
{ \
|
||||
TCGArg args[3]; \
|
||||
int sizemask = 0; \
|
||||
dh_sizemask(ret, 0); \
|
||||
int sizemask; \
|
||||
sizemask = dh_is_64bit(ret); \
|
||||
dh_arg(t1, 1); \
|
||||
dh_arg(t2, 2); \
|
||||
dh_arg(t3, 3); \
|
||||
@@ -194,8 +174,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1
|
||||
dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), dh_arg_decl(t4, 4)) \
|
||||
{ \
|
||||
TCGArg args[4]; \
|
||||
int sizemask = 0; \
|
||||
dh_sizemask(ret, 0); \
|
||||
int sizemask; \
|
||||
sizemask = dh_is_64bit(ret); \
|
||||
dh_arg(t1, 1); \
|
||||
dh_arg(t2, 2); \
|
||||
dh_arg(t3, 3); \
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user