Compare commits
294 Commits
pull-input
...
v0.12.4
Author | SHA1 | Date | |
---|---|---|---|
|
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 |
210
Changelog
210
Changelog
@@ -1,3 +1,213 @@
|
|||||||
|
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
|
||||||
|
- e1000: fix device link status in Linux (Anthony Liguori)
|
||||||
|
- monitor: fix QMP for balloon command (Luiz Capitulino)
|
||||||
|
- QMP: Return an empty dict by default (Luiz Capitulino)
|
||||||
|
- QMP: Only handle converted commands (Luiz Capitulino)
|
||||||
|
- pci: support PCI based option rom loading (Gerd Hoffman/Anthony Liguori)
|
||||||
|
- Fix backcompat for hotplug of SCSI controllers (Daniel P. Berrange)
|
||||||
|
- fdc: fix migration from 0.11 (Juan Quintela)
|
||||||
|
- vmware-vga: fix segv on cursor resize. (Dave Airlie)
|
||||||
|
- vmware-vga: various fixes (Dave Airlie/Anthony Liguori)
|
||||||
|
- qdev: improve property error reporting. (Gerd Hoffmann)
|
||||||
|
- fix vga names in default_list (Gerd Hoffmann)
|
||||||
|
- usb-host: check mon before using it. (Gerd Hoffmann)
|
||||||
|
- usb-net: use qdev for -usbdevice (Gerd Hoffmann)
|
||||||
|
- monitor: Catch printing to non-existent monitor (Luiz Capitulino)
|
||||||
|
- Avoid permanently disabled QEMU monitor when UNIX migration fails (Daniel P. Berrange)
|
||||||
|
- Fix loading of ELF multiboot kernels (Kevin Wolf)
|
||||||
|
- qemu-io: Fix memory leak (Kevin Wolf)
|
||||||
|
- Fix thinko in linuxboot.S (Paolo Bonzini)
|
||||||
|
- target-i386: Fix evaluation of DR7 register (Jan Kiszka)
|
||||||
|
- vnc: hextile: do not generate ForegroundSpecified and SubrectsColoured tiles (Anthony Liguori)
|
||||||
|
- S390: Bail out without KVM (Alexander Graf)
|
||||||
|
- S390: Don't tell guest we're updating config space (Alexander Graf)
|
||||||
|
- target-s390: Fail on unknown instructions (Alexander Graf)
|
||||||
|
- osdep: Fix runtime failure on older Linux kernels (Andre Przywara)
|
||||||
|
- Fix a make -j race (Juergen Lock)
|
||||||
|
- target-alpha: Fix generic ctz64. (Richard Henderson)
|
||||||
|
- s390: Fix buggy assignment (Stefan Weil)
|
||||||
|
- target-mips: fix user-mode emulation startup (Nathan Froyd)
|
||||||
|
- target-i386: Update CPUID feature set for TCG (Andre Przywara)
|
||||||
|
- s390: fix build on 32 bit host (Michael S. Tsirkin)
|
||||||
|
|
||||||
|
version 0.12.0-rc2:
|
||||||
|
|
||||||
|
- v2: properly save kvm system time msr registers (Glauber Costa)
|
||||||
|
- convert more monitor commands to qmp (Luiz Capitulino)
|
||||||
|
- vnc: fix capslock tracking logic. (Gerd Hoffmann)
|
||||||
|
- QemuOpts: allow larger option values. (Gerd Hoffmann)
|
||||||
|
- scsi: fix drive hotplug. (Gerd Hoffmann)
|
||||||
|
- pci: don't hw_error() when no slot is available. (Gerd Hoffmann)
|
||||||
|
- pci: don't abort() when trying to hotplug with acpi off. (Gerd Hoffmann)
|
||||||
|
- allow default devices to be implemented in config file (Gerd Hoffman)
|
||||||
|
- vc: colorize chardev title line with blue background. (Gerd Hoffmann)
|
||||||
|
- chardev: make chardevs specified in config file work. (Gerd Hoffmann)
|
||||||
|
- qdev: also match bus name for global properties (Gerd Hoffmann)
|
||||||
|
- qdev: add command line option to set global defaults for properties. (Gerd Hoffmann)
|
||||||
|
- kvm: x86: Save/restore exception_index (Jan Kiszka)
|
||||||
|
- qdev: Replace device names containing whitespace (Markus Armbruster)
|
||||||
|
- fix rtc-td-hack on host without high-res timers (Gleb Natapov)
|
||||||
|
- virtio: verify features on load (Michael S. Tsirkin)
|
||||||
|
- vmware_vga: add rom file so that it boots. (Dave Airlie)
|
||||||
|
- Do not abort on qemu_malloc(0) in production builds (Anthony Liguori)
|
||||||
|
- Fix ARM userspace strex implementation. (Paul Brook)
|
||||||
|
- qemu: delete rule target on error (Michael S. Tsirkin)
|
||||||
|
- QMP: add human-readable description to error response (Markus Armbruster)
|
||||||
|
- convert more monitor commands to QError (Markus Armbruster)
|
||||||
|
- monitor: Fix double-prompt after "change vnc passwd BLA" (Markus Armbruster)
|
||||||
|
- monitor: do_cont(): Don't ask for passwords (Luiz Capitulino)
|
||||||
|
- monitor: Introduce 'block_passwd' command (Luiz Capitulino)
|
||||||
|
- pci: interrupt disable bit support (Michael S. Tsirkin)
|
||||||
|
- pci: interrupt status bit implementation (Michael S. Tsirkin)
|
||||||
|
- pci: prepare irq code for interrupt state (Michael S. Tsirkin)
|
||||||
|
- msix: function mask support (Michael S. Tsirkin)
|
||||||
|
- msix: macro rename for function mask support (Michael S. Tsirkin)
|
||||||
|
- cpuid: Fix multicore setup on Intel (Andre Przywara)
|
||||||
|
- kvm: x86: Fix initial kvm_has_msr_star (Jan Kiszka)
|
||||||
|
- Update OpenBIOS images to r640 (Aurelien Jarno)
|
||||||
|
|
||||||
version 0.10.2:
|
version 0.10.2:
|
||||||
|
|
||||||
- fix savevm/loadvm (Anthony Liguori)
|
- fix savevm/loadvm (Anthony Liguori)
|
||||||
|
19
Makefile
19
Makefile
@@ -70,7 +70,7 @@ $(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.a
|
|||||||
|
|
||||||
$(filter %-user,$(SUBDIR_RULES)): libuser.a
|
$(filter %-user,$(SUBDIR_RULES)): libuser.a
|
||||||
|
|
||||||
libuser.a:
|
libuser.a: $(GENERATED_HEADERS)
|
||||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libuser V="$(V)" TARGET_DIR="libuser/" all,)
|
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libuser V="$(V)" TARGET_DIR="libuser/" all,)
|
||||||
|
|
||||||
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
|
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
|
||||||
@@ -81,6 +81,12 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
|
|||||||
|
|
||||||
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
|
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 is code used by both qemu system emulation and qemu-img
|
||||||
|
|
||||||
@@ -120,6 +126,7 @@ net-obj-y += $(addprefix net/, $(net-nested-y))
|
|||||||
|
|
||||||
obj-y = $(block-obj-y)
|
obj-y = $(block-obj-y)
|
||||||
obj-y += $(net-obj-y)
|
obj-y += $(net-obj-y)
|
||||||
|
obj-y += $(qobject-obj-y)
|
||||||
obj-y += readline.o console.o
|
obj-y += readline.o console.o
|
||||||
|
|
||||||
obj-y += tcg-runtime.o host-utils.o
|
obj-y += tcg-runtime.o host-utils.o
|
||||||
@@ -152,8 +159,6 @@ obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
|
|||||||
obj-y += qemu-char.o aio.o savevm.o
|
obj-y += qemu-char.o aio.o savevm.o
|
||||||
obj-y += msmouse.o ps2.o
|
obj-y += msmouse.o ps2.o
|
||||||
obj-y += qdev.o qdev-properties.o
|
obj-y += qdev.o qdev-properties.o
|
||||||
obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o json-lexer.o
|
|
||||||
obj-y += json-streamer.o json-parser.o qjson.o qerror.o
|
|
||||||
obj-y += qemu-config.o block-migration.o
|
obj-y += qemu-config.o block-migration.o
|
||||||
|
|
||||||
obj-$(CONFIG_BRLAPI) += baum.o
|
obj-$(CONFIG_BRLAPI) += baum.o
|
||||||
@@ -230,18 +235,18 @@ libqemu_common.a: $(obj-y)
|
|||||||
|
|
||||||
qemu-img.o: qemu-img-cmds.h
|
qemu-img.o: qemu-img-cmds.h
|
||||||
|
|
||||||
qemu-img$(EXESUF): qemu-img.o qemu-tool.o $(block-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 $(block-obj-y)
|
qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o $(block-obj-y) $(qobject-obj-y)
|
||||||
|
|
||||||
qemu-io$(EXESUF): qemu-io.o qemu-tool.o cmd.o $(block-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
|
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
|
||||||
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $@")
|
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $@")
|
||||||
|
|
||||||
check-qint: check-qint.o qint.o qemu-malloc.o
|
check-qint: check-qint.o qint.o qemu-malloc.o
|
||||||
check-qstring: check-qstring.o qstring.o qemu-malloc.o
|
check-qstring: check-qstring.o qstring.o qemu-malloc.o
|
||||||
check-qdict: check-qdict.o qdict.o qint.o qstring.o qemu-malloc.o
|
check-qdict: check-qdict.o qdict.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o
|
||||||
check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o
|
check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o
|
||||||
check-qfloat: check-qfloat.o qfloat.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
|
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
|
||||||
|
@@ -2,10 +2,15 @@
|
|||||||
|
|
||||||
include ../config-host.mak
|
include ../config-host.mak
|
||||||
include $(SRC_PATH)/rules.mak
|
include $(SRC_PATH)/rules.mak
|
||||||
|
-include config.mak
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
|
|
||||||
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..
|
QEMU_CFLAGS+=-I..
|
||||||
|
|
||||||
|
34
QMP/README
34
QMP/README
@@ -4,45 +4,57 @@
|
|||||||
Introduction
|
Introduction
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The QEMU Monitor Protocol (QMP) is a JSON[1] based protocol for QEMU.
|
The QEMU Monitor Protocol (QMP) allows applications to communicate with
|
||||||
|
QEMU's Monitor.
|
||||||
|
|
||||||
By using it applications can control QEMU in reliable and "parseable" way,
|
QMP is JSON[1] based and has the following features:
|
||||||
QMP also provides asynchronous events support.
|
|
||||||
|
- Lightweight, text-based, easy to parse data format
|
||||||
|
- Asynchronous events support
|
||||||
|
- Stability
|
||||||
|
|
||||||
For more information, please, refer to the following files:
|
For more information, please, refer to the following files:
|
||||||
|
|
||||||
o qmp-spec.txt QEMU Monitor Protocol current draft specification
|
o qmp-spec.txt QEMU Monitor Protocol current specification
|
||||||
o qmp-events.txt List of available asynchronous events
|
o qmp-events.txt List of available asynchronous events
|
||||||
|
|
||||||
There are also two simple Python scripts available:
|
There are also two simple Python scripts available:
|
||||||
|
|
||||||
o qmp-shell A shell
|
o qmp-shell A shell
|
||||||
o vm-info Show some informations about the Virtal Machine
|
o vm-info Show some information about the Virtual Machine
|
||||||
|
|
||||||
[1] http://www.json.org
|
[1] http://www.json.org
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
|
|
||||||
To enable QMP, QEMU has to be started in "control mode". This is done
|
To enable QMP, QEMU has to be started in "control mode". There are
|
||||||
by passing the flag "control" to the "-monitor" command-line option.
|
two ways of doing this, the simplest one is using the the '-qmp'
|
||||||
|
command-line option.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
$ qemu [...] -monitor control,tcp:localhost:4444,server
|
$ qemu [...] -qmp tcp:localhost:4444,server
|
||||||
|
|
||||||
Will start QEMU in control mode, waiting for a client TCP connection
|
Will start QEMU in control mode, waiting for a client TCP connection
|
||||||
on localhost port 4444.
|
on localhost port 4444.
|
||||||
|
|
||||||
To manually test it you can connect with telnet and issue commands:
|
It is also possible to use the '-mon' command-line option to have
|
||||||
|
more complex combinations. Please, refer to the QEMU's manpage for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
Simple Testing
|
||||||
|
--------------
|
||||||
|
|
||||||
|
To manually test QMP one can connect with telnet and issue commands:
|
||||||
|
|
||||||
$ telnet localhost 4444
|
$ telnet localhost 4444
|
||||||
Trying ::1...
|
Trying 127.0.0.1...
|
||||||
Connected to localhost.
|
Connected to localhost.
|
||||||
Escape character is '^]'.
|
Escape character is '^]'.
|
||||||
{"QMP": {"capabilities": []}}
|
{"QMP": {"capabilities": []}}
|
||||||
{ "execute": "query-version" }
|
{ "execute": "query-version" }
|
||||||
{"return": "0.11.50"}
|
{"return": {"qemu": "0.11.50", "package": ""}}
|
||||||
|
|
||||||
Contact
|
Contact
|
||||||
-------
|
-------
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
QEMU Monitor Protocol Draft Specification - Version 0.1
|
QEMU Monitor Protocol Specification - Version 0.1
|
||||||
|
|
||||||
1. Introduction
|
1. Introduction
|
||||||
===============
|
===============
|
||||||
@@ -27,9 +27,9 @@ the JSON standard:
|
|||||||
|
|
||||||
http://www.ietf.org/rfc/rfc4627.txt
|
http://www.ietf.org/rfc/rfc4627.txt
|
||||||
|
|
||||||
For convenience, json-objects mentioned in this document will have its members
|
For convenience, json-object members and json-array elements mentioned in
|
||||||
in a certain order. However, in real protocol usage json-objects members can
|
this document will be in a certain order. However, in real protocol usage
|
||||||
be in ANY order, thus no particular order should be assumed.
|
they can be in ANY order, thus no particular order should be assumed.
|
||||||
|
|
||||||
2.1 General Definitions
|
2.1 General Definitions
|
||||||
-----------------------
|
-----------------------
|
||||||
@@ -85,12 +85,13 @@ without errors.
|
|||||||
|
|
||||||
The format is:
|
The format is:
|
||||||
|
|
||||||
{ "return": json-value, "id": json-value }
|
{ "return": json-object, "id": json-value }
|
||||||
|
|
||||||
Where,
|
Where,
|
||||||
|
|
||||||
- The "return" member contains the command returned data, which is defined
|
- The "return" member contains the command returned data, which is defined
|
||||||
in a per-command basis or "OK" if the command does not return data
|
in a per-command basis or an empty json-object if the command does not
|
||||||
|
return data
|
||||||
- The "id" member contains the transaction identification associated
|
- The "id" member contains the transaction identification associated
|
||||||
with the command execution (if issued by the Client)
|
with the command execution (if issued by the Client)
|
||||||
|
|
||||||
@@ -102,13 +103,16 @@ completed because of an error condition.
|
|||||||
|
|
||||||
The format is:
|
The format is:
|
||||||
|
|
||||||
{ "error": { "class": json-string, "data": json-value }, "id": json-value }
|
{ "error": { "class": json-string, "data": json-object, "desc": json-string },
|
||||||
|
"id": json-value }
|
||||||
|
|
||||||
Where,
|
Where,
|
||||||
|
|
||||||
- The "class" member contains the error class name (eg. "ServiceUnavailable")
|
- The "class" member contains the error class name (eg. "ServiceUnavailable")
|
||||||
- The "data" member contains specific error data and is defined in a
|
- The "data" member contains specific error data and is defined in a
|
||||||
per-command basis, it will be an empty json-object if the error has no data
|
per-command basis, it will be an empty json-object if the error has no data
|
||||||
|
- The "desc" member is a human-readable error message. Clients should
|
||||||
|
not attempt to parse this message.
|
||||||
- The "id" member contains the transaction identification associated with
|
- The "id" member contains the transaction identification associated with
|
||||||
the command execution (if issued by the Client)
|
the command execution (if issued by the Client)
|
||||||
|
|
||||||
@@ -124,7 +128,7 @@ to the Client at any time. They are called 'asynchronous events'.
|
|||||||
|
|
||||||
The format is:
|
The format is:
|
||||||
|
|
||||||
{ "event": json-string, "data": json-value,
|
{ "event": json-string, "data": json-object,
|
||||||
"timestamp": { "seconds": json-number, "microseconds": json-number } }
|
"timestamp": { "seconds": json-number, "microseconds": json-number } }
|
||||||
|
|
||||||
Where,
|
Where,
|
||||||
@@ -132,7 +136,7 @@ The format is:
|
|||||||
- The "event" member contains the event's name
|
- The "event" member contains the event's name
|
||||||
- The "data" member contains event specific data, which is defined in a
|
- The "data" member contains event specific data, which is defined in a
|
||||||
per-event basis, it is optional
|
per-event basis, it is optional
|
||||||
- The "timestamp" member contains the exact time of when the event ocurred
|
- The "timestamp" member contains the exact time of when the event occurred
|
||||||
in the Server. It is a fixed json-object with time in seconds and
|
in the Server. It is a fixed json-object with time in seconds and
|
||||||
microseconds
|
microseconds
|
||||||
|
|
||||||
@@ -154,19 +158,20 @@ S: {"QMP": {"capabilities": []}}
|
|||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
C: { "execute": "stop" }
|
C: { "execute": "stop" }
|
||||||
S: {"return": "OK"}
|
S: {"return": {}}
|
||||||
|
|
||||||
3.3 KVM information
|
3.3 KVM information
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
C: {"execute": "query-kvm", "id": "example"}
|
C: { "execute": "query-kvm", "id": "example" }
|
||||||
S: {"return": "enabled", "id": "example"}
|
S: {"return": {"enabled": true, "present": true}, "id": "example"}
|
||||||
|
|
||||||
3.4 Parsing error
|
3.4 Parsing error
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
C: { "execute": }
|
C: { "execute": }
|
||||||
S: {"error": {"class": "JSONParsing", "data": {}}}
|
S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
|
||||||
|
{}}}
|
||||||
|
|
||||||
3.5 Powerdown event
|
3.5 Powerdown event
|
||||||
-------------------
|
-------------------
|
||||||
@@ -174,19 +179,25 @@ S: {"error": {"class": "JSONParsing", "data": {}}}
|
|||||||
S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
|
S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
|
||||||
"POWERDOWN"}
|
"POWERDOWN"}
|
||||||
|
|
||||||
4. Notes to Client implementors
|
4. Compatibility Considerations
|
||||||
-------------------------------
|
--------------------------------
|
||||||
|
|
||||||
4.1 It is recommended to always start the Server in pause mode, thus the
|
In order to achieve maximum compatibility between versions, Clients must not
|
||||||
Client is able to perform any setup procedure without the risk of
|
assume any particular:
|
||||||
race conditions and related problems
|
|
||||||
|
|
||||||
4.2 It is recommended to always check the capabilities json-array, issued
|
- Size of json-objects or length of json-arrays
|
||||||
with the greeting message, at connection time
|
- 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
|
||||||
|
|
||||||
4.3 Json-objects or json-arrays mentioned in this document are not fixed
|
Additionally, Clients should always:
|
||||||
and no particular size or number of members/elements should be assumed.
|
|
||||||
New members/elements can be added at any time.
|
|
||||||
|
|
||||||
4.4 No particular order of json-objects members should be assumed, they
|
- Check the capabilities json-array at connection time
|
||||||
can change at any time
|
- Check the availability of commands with 'query-commands' before issuing them
|
||||||
|
|
||||||
|
5. Recommendations to Client implementors
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
5.1 The Server should be always started in pause mode, thus the Client is
|
||||||
|
able to perform any setup procedure without the risk of race conditions
|
||||||
|
and related problems
|
||||||
|
@@ -38,6 +38,10 @@
|
|||||||
#define AUDIO_CAP "oss"
|
#define AUDIO_CAP "oss"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
|
|
||||||
|
#if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
|
||||||
|
#define USE_DSP_POLICY
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct OSSVoiceOut {
|
typedef struct OSSVoiceOut {
|
||||||
HWVoiceOut hw;
|
HWVoiceOut hw;
|
||||||
void *pcm_buf;
|
void *pcm_buf;
|
||||||
@@ -236,14 +240,39 @@ static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_DSP_POLICY
|
||||||
|
static int oss_get_version (int fd, int *version, const char *typ)
|
||||||
|
{
|
||||||
|
if (ioctl (fd, OSS_GETVERSION, &version)) {
|
||||||
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
|
/*
|
||||||
|
* Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
|
||||||
|
* since 7.x, but currently only on the mixer device (or in
|
||||||
|
* the Linuxolator), and in the native version that part of
|
||||||
|
* the code is in fact never reached so the ioctl fails anyway.
|
||||||
|
* Until this is fixed, just check the errno and if its what
|
||||||
|
* FreeBSD's sound drivers return atm assume they are new enough.
|
||||||
|
*/
|
||||||
|
if (errno == EINVAL) {
|
||||||
|
*version = 0x040000;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
oss_logerr2 (errno, typ, "Failed to get OSS version\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int oss_open (int in, struct oss_params *req,
|
static int oss_open (int in, struct oss_params *req,
|
||||||
struct oss_params *obt, int *pfd)
|
struct oss_params *obt, int *pfd)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
int version;
|
|
||||||
int oflags = conf.exclusive ? O_EXCL : 0;
|
int oflags = conf.exclusive ? O_EXCL : 0;
|
||||||
audio_buf_info abinfo;
|
audio_buf_info abinfo;
|
||||||
int fmt, freq, nchannels;
|
int fmt, freq, nchannels;
|
||||||
|
int setfragment = 1;
|
||||||
const char *dspname = in ? conf.devpath_in : conf.devpath_out;
|
const char *dspname = in ? conf.devpath_in : conf.devpath_out;
|
||||||
const char *typ = in ? "ADC" : "DAC";
|
const char *typ = in ? "ADC" : "DAC";
|
||||||
|
|
||||||
@@ -281,27 +310,30 @@ static int oss_open (int in, struct oss_params *req,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl (fd, OSS_GETVERSION, &version)) {
|
#ifdef USE_DSP_POLICY
|
||||||
oss_logerr2 (errno, typ, "Failed to get OSS version\n");
|
if (conf.policy >= 0) {
|
||||||
version = 0;
|
int version;
|
||||||
}
|
|
||||||
|
|
||||||
if (conf.debug) {
|
if (!oss_get_version (fd, &version, typ)) {
|
||||||
dolog ("OSS version = %#x\n", version);
|
if (conf.debug) {
|
||||||
}
|
dolog ("OSS version = %#x\n", version);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SNDCTL_DSP_POLICY
|
if (version >= 0x040000) {
|
||||||
if (conf.policy >= 0 && version >= 0x040000) {
|
int policy = conf.policy;
|
||||||
int policy = conf.policy;
|
if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
|
||||||
if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
|
oss_logerr2 (errno, typ,
|
||||||
oss_logerr2 (errno, typ, "Failed to set timing policy to %d\n",
|
"Failed to set timing policy to %d\n",
|
||||||
conf.policy);
|
conf.policy);
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
setfragment = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
|
if (setfragment) {
|
||||||
int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
|
int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
|
||||||
if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
|
if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
|
||||||
oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
|
oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
|
||||||
@@ -857,7 +889,7 @@ static struct audio_option oss_options[] = {
|
|||||||
.valp = &conf.exclusive,
|
.valp = &conf.exclusive,
|
||||||
.descr = "Open device in exclusive mode (vmix wont work)"
|
.descr = "Open device in exclusive mode (vmix wont work)"
|
||||||
},
|
},
|
||||||
#ifdef SNDCTL_DSP_POLICY
|
#ifdef USE_DSP_POLICY
|
||||||
{
|
{
|
||||||
.name = "POLICY",
|
.name = "POLICY",
|
||||||
.tag = AUD_OPT_INT,
|
.tag = AUD_OPT_INT,
|
||||||
|
283
block.c
283
block.c
@@ -26,6 +26,7 @@
|
|||||||
#include "monitor.h"
|
#include "monitor.h"
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
#include "qemu-objects.h"
|
||||||
|
|
||||||
#ifdef CONFIG_BSD
|
#ifdef CONFIG_BSD
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@@ -690,6 +691,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
|||||||
uint8_t tmp_buf[BDRV_SECTOR_SIZE];
|
uint8_t tmp_buf[BDRV_SECTOR_SIZE];
|
||||||
int len, nb_sectors, count;
|
int len, nb_sectors, count;
|
||||||
int64_t sector_num;
|
int64_t sector_num;
|
||||||
|
int ret;
|
||||||
|
|
||||||
count = count1;
|
count = count1;
|
||||||
/* first read to align to sector start */
|
/* first read to align to sector start */
|
||||||
@@ -698,8 +700,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
|||||||
len = count;
|
len = count;
|
||||||
sector_num = offset >> BDRV_SECTOR_BITS;
|
sector_num = offset >> BDRV_SECTOR_BITS;
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
|
if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
|
||||||
return -EIO;
|
return ret;
|
||||||
memcpy(buf, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), len);
|
memcpy(buf, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), len);
|
||||||
count -= len;
|
count -= len;
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
@@ -711,8 +713,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
|||||||
/* read the sectors "in place" */
|
/* read the sectors "in place" */
|
||||||
nb_sectors = count >> BDRV_SECTOR_BITS;
|
nb_sectors = count >> BDRV_SECTOR_BITS;
|
||||||
if (nb_sectors > 0) {
|
if (nb_sectors > 0) {
|
||||||
if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0)
|
if ((ret = bdrv_read(bs, sector_num, buf, nb_sectors)) < 0)
|
||||||
return -EIO;
|
return ret;
|
||||||
sector_num += nb_sectors;
|
sector_num += nb_sectors;
|
||||||
len = nb_sectors << BDRV_SECTOR_BITS;
|
len = nb_sectors << BDRV_SECTOR_BITS;
|
||||||
buf += len;
|
buf += len;
|
||||||
@@ -721,8 +723,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
|||||||
|
|
||||||
/* add data from the last sector */
|
/* add data from the last sector */
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
|
if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
|
||||||
return -EIO;
|
return ret;
|
||||||
memcpy(buf, tmp_buf, count);
|
memcpy(buf, tmp_buf, count);
|
||||||
}
|
}
|
||||||
return count1;
|
return count1;
|
||||||
@@ -734,6 +736,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
|||||||
uint8_t tmp_buf[BDRV_SECTOR_SIZE];
|
uint8_t tmp_buf[BDRV_SECTOR_SIZE];
|
||||||
int len, nb_sectors, count;
|
int len, nb_sectors, count;
|
||||||
int64_t sector_num;
|
int64_t sector_num;
|
||||||
|
int ret;
|
||||||
|
|
||||||
count = count1;
|
count = count1;
|
||||||
/* first write to align to sector start */
|
/* first write to align to sector start */
|
||||||
@@ -742,11 +745,11 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
|||||||
len = count;
|
len = count;
|
||||||
sector_num = offset >> BDRV_SECTOR_BITS;
|
sector_num = offset >> BDRV_SECTOR_BITS;
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
|
if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
|
||||||
return -EIO;
|
return ret;
|
||||||
memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len);
|
memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len);
|
||||||
if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
|
if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
|
||||||
return -EIO;
|
return ret;
|
||||||
count -= len;
|
count -= len;
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return count1;
|
return count1;
|
||||||
@@ -757,8 +760,8 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
|||||||
/* write the sectors "in place" */
|
/* write the sectors "in place" */
|
||||||
nb_sectors = count >> BDRV_SECTOR_BITS;
|
nb_sectors = count >> BDRV_SECTOR_BITS;
|
||||||
if (nb_sectors > 0) {
|
if (nb_sectors > 0) {
|
||||||
if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0)
|
if ((ret = bdrv_write(bs, sector_num, buf, nb_sectors)) < 0)
|
||||||
return -EIO;
|
return ret;
|
||||||
sector_num += nb_sectors;
|
sector_num += nb_sectors;
|
||||||
len = nb_sectors << BDRV_SECTOR_BITS;
|
len = nb_sectors << BDRV_SECTOR_BITS;
|
||||||
buf += len;
|
buf += len;
|
||||||
@@ -767,11 +770,11 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
|||||||
|
|
||||||
/* add data from the last sector */
|
/* add data from the last sector */
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
|
if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
|
||||||
return -EIO;
|
return ret;
|
||||||
memcpy(tmp_buf, buf, count);
|
memcpy(tmp_buf, buf, count);
|
||||||
if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
|
if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
|
||||||
return -EIO;
|
return ret;
|
||||||
}
|
}
|
||||||
return count1;
|
return count1;
|
||||||
}
|
}
|
||||||
@@ -1139,61 +1142,203 @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
|||||||
return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum);
|
return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_info(Monitor *mon)
|
static void bdrv_print_dict(QObject *obj, void *opaque)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs;
|
QDict *bs_dict;
|
||||||
|
Monitor *mon = opaque;
|
||||||
|
|
||||||
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
|
bs_dict = qobject_to_qdict(obj);
|
||||||
monitor_printf(mon, "%s:", bs->device_name);
|
|
||||||
monitor_printf(mon, " type=");
|
monitor_printf(mon, "%s: type=%s removable=%d",
|
||||||
switch(bs->type) {
|
qdict_get_str(bs_dict, "device"),
|
||||||
case BDRV_TYPE_HD:
|
qdict_get_str(bs_dict, "type"),
|
||||||
monitor_printf(mon, "hd");
|
qdict_get_bool(bs_dict, "removable"));
|
||||||
break;
|
|
||||||
case BDRV_TYPE_CDROM:
|
if (qdict_get_bool(bs_dict, "removable")) {
|
||||||
monitor_printf(mon, "cdrom");
|
monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
|
||||||
break;
|
|
||||||
case BDRV_TYPE_FLOPPY:
|
|
||||||
monitor_printf(mon, "floppy");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
monitor_printf(mon, " removable=%d", bs->removable);
|
|
||||||
if (bs->removable) {
|
|
||||||
monitor_printf(mon, " locked=%d", bs->locked);
|
|
||||||
}
|
|
||||||
if (bs->drv) {
|
|
||||||
monitor_printf(mon, " file=");
|
|
||||||
monitor_print_filename(mon, bs->filename);
|
|
||||||
if (bs->backing_file[0] != '\0') {
|
|
||||||
monitor_printf(mon, " backing_file=");
|
|
||||||
monitor_print_filename(mon, bs->backing_file);
|
|
||||||
}
|
|
||||||
monitor_printf(mon, " ro=%d", bs->read_only);
|
|
||||||
monitor_printf(mon, " drv=%s", bs->drv->format_name);
|
|
||||||
monitor_printf(mon, " encrypted=%d", bdrv_is_encrypted(bs));
|
|
||||||
} else {
|
|
||||||
monitor_printf(mon, " [not inserted]");
|
|
||||||
}
|
|
||||||
monitor_printf(mon, "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (qdict_haskey(bs_dict, "inserted")) {
|
||||||
|
QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
|
||||||
|
|
||||||
|
monitor_printf(mon, " file=");
|
||||||
|
monitor_print_filename(mon, qdict_get_str(qdict, "file"));
|
||||||
|
if (qdict_haskey(qdict, "backing_file")) {
|
||||||
|
monitor_printf(mon, " backing_file=");
|
||||||
|
monitor_print_filename(mon, qdict_get_str(qdict, "backing_file"));
|
||||||
|
}
|
||||||
|
monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
|
||||||
|
qdict_get_bool(qdict, "ro"),
|
||||||
|
qdict_get_str(qdict, "drv"),
|
||||||
|
qdict_get_bool(qdict, "encrypted"));
|
||||||
|
} else {
|
||||||
|
monitor_printf(mon, " [not inserted]");
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor_printf(mon, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The "info blockstats" command. */
|
void bdrv_info_print(Monitor *mon, const QObject *data)
|
||||||
void bdrv_info_stats(Monitor *mon)
|
|
||||||
{
|
{
|
||||||
|
qlist_iter(qobject_to_qlist(data), bdrv_print_dict, mon);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdrv_info(): Block devices information
|
||||||
|
*
|
||||||
|
* Each block device information is stored in a QDict and the
|
||||||
|
* returned QObject is a QList of all devices.
|
||||||
|
*
|
||||||
|
* The QDict contains the following:
|
||||||
|
*
|
||||||
|
* - "device": device name
|
||||||
|
* - "type": device type
|
||||||
|
* - "removable": true if the device is removable, false otherwise
|
||||||
|
* - "locked": true if the device is locked, false otherwise
|
||||||
|
* - "inserted": only present if the device is inserted, it is a QDict
|
||||||
|
* containing the following:
|
||||||
|
* - "file": device file name
|
||||||
|
* - "ro": true if read-only, false otherwise
|
||||||
|
* - "drv": driver format name
|
||||||
|
* - "backing_file": backing file name if one is used
|
||||||
|
* - "encrypted": true if encrypted, false otherwise
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* [ { "device": "ide0-hd0", "type": "hd", "removable": false, "locked": false,
|
||||||
|
* "inserted": { "file": "/tmp/foobar", "ro": false, "drv": "qcow2" } },
|
||||||
|
* { "device": "floppy0", "type": "floppy", "removable": true,
|
||||||
|
* "locked": false } ]
|
||||||
|
*/
|
||||||
|
void bdrv_info(Monitor *mon, QObject **ret_data)
|
||||||
|
{
|
||||||
|
QList *bs_list;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
|
||||||
|
bs_list = qlist_new();
|
||||||
|
|
||||||
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
|
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
|
||||||
monitor_printf(mon, "%s:"
|
QObject *bs_obj;
|
||||||
" rd_bytes=%" PRIu64
|
const char *type = "unknown";
|
||||||
" wr_bytes=%" PRIu64
|
|
||||||
" rd_operations=%" PRIu64
|
switch(bs->type) {
|
||||||
" wr_operations=%" PRIu64
|
case BDRV_TYPE_HD:
|
||||||
"\n",
|
type = "hd";
|
||||||
bs->device_name,
|
break;
|
||||||
bs->rd_bytes, bs->wr_bytes,
|
case BDRV_TYPE_CDROM:
|
||||||
bs->rd_ops, bs->wr_ops);
|
type = "cdrom";
|
||||||
|
break;
|
||||||
|
case BDRV_TYPE_FLOPPY:
|
||||||
|
type = "floppy";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': %s, "
|
||||||
|
"'removable': %i, 'locked': %i }",
|
||||||
|
bs->device_name, type, bs->removable,
|
||||||
|
bs->locked);
|
||||||
|
assert(bs_obj != NULL);
|
||||||
|
|
||||||
|
if (bs->drv) {
|
||||||
|
QObject *obj;
|
||||||
|
QDict *bs_dict = qobject_to_qdict(bs_obj);
|
||||||
|
|
||||||
|
obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, "
|
||||||
|
"'encrypted': %i }",
|
||||||
|
bs->filename, bs->read_only,
|
||||||
|
bs->drv->format_name,
|
||||||
|
bdrv_is_encrypted(bs));
|
||||||
|
assert(obj != NULL);
|
||||||
|
if (bs->backing_file[0] != '\0') {
|
||||||
|
QDict *qdict = qobject_to_qdict(obj);
|
||||||
|
qdict_put(qdict, "backing_file",
|
||||||
|
qstring_from_str(bs->backing_file));
|
||||||
|
}
|
||||||
|
|
||||||
|
qdict_put_obj(bs_dict, "inserted", obj);
|
||||||
|
}
|
||||||
|
qlist_append_obj(bs_list, bs_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*ret_data = QOBJECT(bs_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bdrv_stats_iter(QObject *data, void *opaque)
|
||||||
|
{
|
||||||
|
QDict *qdict;
|
||||||
|
Monitor *mon = opaque;
|
||||||
|
|
||||||
|
qdict = qobject_to_qdict(data);
|
||||||
|
monitor_printf(mon, "%s:", qdict_get_str(qdict, "device"));
|
||||||
|
|
||||||
|
qdict = qobject_to_qdict(qdict_get(qdict, "stats"));
|
||||||
|
monitor_printf(mon, " rd_bytes=%" PRId64
|
||||||
|
" wr_bytes=%" PRId64
|
||||||
|
" rd_operations=%" PRId64
|
||||||
|
" wr_operations=%" PRId64
|
||||||
|
"\n",
|
||||||
|
qdict_get_int(qdict, "rd_bytes"),
|
||||||
|
qdict_get_int(qdict, "wr_bytes"),
|
||||||
|
qdict_get_int(qdict, "rd_operations"),
|
||||||
|
qdict_get_int(qdict, "wr_operations"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdrv_stats_print(Monitor *mon, const QObject *data)
|
||||||
|
{
|
||||||
|
qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdrv_info_stats(): show block device statistics
|
||||||
|
*
|
||||||
|
* Each device statistic information is stored in a QDict and
|
||||||
|
* the returned QObject is a QList of all devices.
|
||||||
|
*
|
||||||
|
* The QDict contains the following:
|
||||||
|
*
|
||||||
|
* - "device": device name
|
||||||
|
* - "stats": A QDict with the statistics information, it contains:
|
||||||
|
* - "rd_bytes": bytes read
|
||||||
|
* - "wr_bytes": bytes written
|
||||||
|
* - "rd_operations": read operations
|
||||||
|
* - "wr_operations": write operations
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* [ { "device": "ide0-hd0",
|
||||||
|
* "stats": { "rd_bytes": 512,
|
||||||
|
* "wr_bytes": 0,
|
||||||
|
* "rd_operations": 1,
|
||||||
|
* "wr_operations": 0 } },
|
||||||
|
* { "device": "ide1-cd0",
|
||||||
|
* "stats": { "rd_bytes": 0,
|
||||||
|
* "wr_bytes": 0,
|
||||||
|
* "rd_operations": 0,
|
||||||
|
* "wr_operations": 0 } } ]
|
||||||
|
*/
|
||||||
|
void bdrv_info_stats(Monitor *mon, QObject **ret_data)
|
||||||
|
{
|
||||||
|
QObject *obj;
|
||||||
|
QList *devices;
|
||||||
|
BlockDriverState *bs;
|
||||||
|
|
||||||
|
devices = qlist_new();
|
||||||
|
|
||||||
|
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
|
||||||
|
obj = qobject_from_jsonf("{ 'device': %s, 'stats': {"
|
||||||
|
"'rd_bytes': %" PRId64 ","
|
||||||
|
"'wr_bytes': %" PRId64 ","
|
||||||
|
"'rd_operations': %" PRId64 ","
|
||||||
|
"'wr_operations': %" PRId64
|
||||||
|
"} }",
|
||||||
|
bs->device_name,
|
||||||
|
bs->rd_bytes, bs->wr_bytes,
|
||||||
|
bs->rd_ops, bs->wr_ops);
|
||||||
|
assert(obj != NULL);
|
||||||
|
qlist_append_obj(devices, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret_data = QOBJECT(devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
|
const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
|
||||||
@@ -1463,8 +1608,11 @@ static void multiwrite_user_cb(MultiwriteCB *mcb)
|
|||||||
|
|
||||||
for (i = 0; i < mcb->num_callbacks; i++) {
|
for (i = 0; i < mcb->num_callbacks; i++) {
|
||||||
mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
|
mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
|
||||||
|
if (mcb->callbacks[i].free_qiov) {
|
||||||
|
qemu_iovec_destroy(mcb->callbacks[i].free_qiov);
|
||||||
|
}
|
||||||
qemu_free(mcb->callbacks[i].free_qiov);
|
qemu_free(mcb->callbacks[i].free_qiov);
|
||||||
qemu_free(mcb->callbacks[i].free_buf);
|
qemu_vfree(mcb->callbacks[i].free_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1472,7 +1620,7 @@ static void multiwrite_cb(void *opaque, int ret)
|
|||||||
{
|
{
|
||||||
MultiwriteCB *mcb = opaque;
|
MultiwriteCB *mcb = opaque;
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0 && !mcb->error) {
|
||||||
mcb->error = ret;
|
mcb->error = ret;
|
||||||
multiwrite_user_cb(mcb);
|
multiwrite_user_cb(mcb);
|
||||||
}
|
}
|
||||||
@@ -1524,6 +1672,10 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
|
|||||||
merge = bs->drv->bdrv_merge_requests(bs, &reqs[outidx], &reqs[i]);
|
merge = bs->drv->bdrv_merge_requests(bs, &reqs[outidx], &reqs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1 > IOV_MAX) {
|
||||||
|
merge = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (merge) {
|
if (merge) {
|
||||||
size_t size;
|
size_t size;
|
||||||
QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov));
|
QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov));
|
||||||
@@ -1609,10 +1761,11 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
|
|||||||
// submitted yet. Otherwise we'll wait for the submitted AIOs to
|
// submitted yet. Otherwise we'll wait for the submitted AIOs to
|
||||||
// complete and report the error in the callback.
|
// complete and report the error in the callback.
|
||||||
if (mcb->num_requests == 0) {
|
if (mcb->num_requests == 0) {
|
||||||
reqs[i].error = EIO;
|
reqs[i].error = -EIO;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else {
|
} else {
|
||||||
mcb->error = EIO;
|
mcb->num_requests++;
|
||||||
|
multiwrite_cb(mcb, -EIO);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
7
block.h
7
block.h
@@ -4,6 +4,7 @@
|
|||||||
#include "qemu-aio.h"
|
#include "qemu-aio.h"
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qemu-option.h"
|
#include "qemu-option.h"
|
||||||
|
#include "qobject.h"
|
||||||
|
|
||||||
/* block.c */
|
/* block.c */
|
||||||
typedef struct BlockDriver BlockDriver;
|
typedef struct BlockDriver BlockDriver;
|
||||||
@@ -45,8 +46,10 @@ typedef struct QEMUSnapshotInfo {
|
|||||||
#define BDRV_SECTOR_SIZE (1 << BDRV_SECTOR_BITS)
|
#define BDRV_SECTOR_SIZE (1 << BDRV_SECTOR_BITS)
|
||||||
#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1);
|
#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1);
|
||||||
|
|
||||||
void bdrv_info(Monitor *mon);
|
void bdrv_info_print(Monitor *mon, const QObject *data);
|
||||||
void bdrv_info_stats(Monitor *mon);
|
void bdrv_info(Monitor *mon, QObject **ret_data);
|
||||||
|
void bdrv_stats_print(Monitor *mon, const QObject *data);
|
||||||
|
void bdrv_info_stats(Monitor *mon, QObject **ret_data);
|
||||||
|
|
||||||
void bdrv_init(void);
|
void bdrv_init(void);
|
||||||
void bdrv_init_with_whitelist(void);
|
void bdrv_init_with_whitelist(void);
|
||||||
|
@@ -309,7 +309,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
|
|
||||||
static int inited = 0;
|
static int inited = 0;
|
||||||
|
|
||||||
file = strdup(filename);
|
file = qemu_strdup(filename);
|
||||||
s->readahead_size = READ_AHEAD_SIZE;
|
s->readahead_size = READ_AHEAD_SIZE;
|
||||||
|
|
||||||
/* Parse a trailing ":readahead=#:" param, if present. */
|
/* Parse a trailing ":readahead=#:" param, if present. */
|
||||||
|
28
block/dmg.c
28
block/dmg.c
@@ -90,24 +90,21 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
|
|
||||||
/* read offset of info blocks */
|
/* read offset of info blocks */
|
||||||
if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
|
if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
|
||||||
dmg_close:
|
goto fail;
|
||||||
close(s->fd);
|
|
||||||
/* open raw instead */
|
|
||||||
bs->drv=bdrv_find_format("raw");
|
|
||||||
return bs->drv->bdrv_open(bs, filename, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info_begin=read_off(s->fd);
|
info_begin=read_off(s->fd);
|
||||||
if(info_begin==0)
|
if(info_begin==0)
|
||||||
goto dmg_close;
|
goto fail;
|
||||||
if(lseek(s->fd,info_begin,SEEK_SET)<0)
|
if(lseek(s->fd,info_begin,SEEK_SET)<0)
|
||||||
goto dmg_close;
|
goto fail;
|
||||||
if(read_uint32(s->fd)!=0x100)
|
if(read_uint32(s->fd)!=0x100)
|
||||||
goto dmg_close;
|
goto fail;
|
||||||
if((count = read_uint32(s->fd))==0)
|
if((count = read_uint32(s->fd))==0)
|
||||||
goto dmg_close;
|
goto fail;
|
||||||
info_end = info_begin+count;
|
info_end = info_begin+count;
|
||||||
if(lseek(s->fd,0xf8,SEEK_CUR)<0)
|
if(lseek(s->fd,0xf8,SEEK_CUR)<0)
|
||||||
goto dmg_close;
|
goto fail;
|
||||||
|
|
||||||
/* read offsets */
|
/* read offsets */
|
||||||
last_in_offset = last_out_offset = 0;
|
last_in_offset = last_out_offset = 0;
|
||||||
@@ -116,14 +113,14 @@ dmg_close:
|
|||||||
|
|
||||||
count = read_uint32(s->fd);
|
count = read_uint32(s->fd);
|
||||||
if(count==0)
|
if(count==0)
|
||||||
goto dmg_close;
|
goto fail;
|
||||||
type = read_uint32(s->fd);
|
type = read_uint32(s->fd);
|
||||||
if(type!=0x6d697368 || count<244)
|
if(type!=0x6d697368 || count<244)
|
||||||
lseek(s->fd,count-4,SEEK_CUR);
|
lseek(s->fd,count-4,SEEK_CUR);
|
||||||
else {
|
else {
|
||||||
int new_size, chunk_count;
|
int new_size, chunk_count;
|
||||||
if(lseek(s->fd,200,SEEK_CUR)<0)
|
if(lseek(s->fd,200,SEEK_CUR)<0)
|
||||||
goto dmg_close;
|
goto fail;
|
||||||
chunk_count = (count-204)/40;
|
chunk_count = (count-204)/40;
|
||||||
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
|
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
|
||||||
s->types = qemu_realloc(s->types, new_size/2);
|
s->types = qemu_realloc(s->types, new_size/2);
|
||||||
@@ -142,7 +139,7 @@ dmg_close:
|
|||||||
chunk_count--;
|
chunk_count--;
|
||||||
i--;
|
i--;
|
||||||
if(lseek(s->fd,36,SEEK_CUR)<0)
|
if(lseek(s->fd,36,SEEK_CUR)<0)
|
||||||
goto dmg_close;
|
goto fail;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
read_uint32(s->fd);
|
read_uint32(s->fd);
|
||||||
@@ -163,11 +160,14 @@ dmg_close:
|
|||||||
s->compressed_chunk = qemu_malloc(max_compressed_size+1);
|
s->compressed_chunk = qemu_malloc(max_compressed_size+1);
|
||||||
s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk);
|
s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk);
|
||||||
if(inflateInit(&s->zstream) != Z_OK)
|
if(inflateInit(&s->zstream) != Z_OK)
|
||||||
goto dmg_close;
|
goto fail;
|
||||||
|
|
||||||
s->current_chunk = s->n_chunks;
|
s->current_chunk = s->n_chunks;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
fail:
|
||||||
|
close(s->fd);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int is_sector_in_chunk(BDRVDMGState* s,
|
static inline int is_sector_in_chunk(BDRVDMGState* s,
|
||||||
|
@@ -33,7 +33,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
|
|||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int new_l1_size, new_l1_size2, ret, i;
|
int new_l1_size, new_l1_size2, ret, i;
|
||||||
uint64_t *new_l1_table;
|
uint64_t *new_l1_table;
|
||||||
uint64_t new_l1_table_offset;
|
int64_t new_l1_table_offset;
|
||||||
uint8_t data[12];
|
uint8_t data[12];
|
||||||
|
|
||||||
new_l1_size = s->l1_size;
|
new_l1_size = s->l1_size;
|
||||||
@@ -55,6 +55,10 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
|
|||||||
|
|
||||||
/* write new table (align to cluster) */
|
/* write new table (align to cluster) */
|
||||||
new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
for(i = 0; i < s->l1_size; i++)
|
for(i = 0; i < s->l1_size; i++)
|
||||||
new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
|
new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
|
||||||
@@ -67,9 +71,10 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
|
|||||||
/* set new table */
|
/* set new table */
|
||||||
cpu_to_be32w((uint32_t*)data, new_l1_size);
|
cpu_to_be32w((uint32_t*)data, new_l1_size);
|
||||||
cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
|
cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
|
||||||
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,
|
ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,sizeof(data));
|
||||||
sizeof(data)) != sizeof(data))
|
if (ret != sizeof(data)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
qemu_free(s->l1_table);
|
qemu_free(s->l1_table);
|
||||||
qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
|
qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
|
||||||
s->l1_table_offset = new_l1_table_offset;
|
s->l1_table_offset = new_l1_table_offset;
|
||||||
@@ -77,8 +82,9 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
|
|||||||
s->l1_size = new_l1_size;
|
s->l1_size = new_l1_size;
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
qemu_free(s->l1_table);
|
qemu_free(new_l1_table);
|
||||||
return -EIO;
|
qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2);
|
||||||
|
return ret < 0 ? ret : -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qcow2_l2_cache_reset(BlockDriverState *bs)
|
void qcow2_l2_cache_reset(BlockDriverState *bs)
|
||||||
@@ -213,13 +219,17 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
|
|||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int min_index;
|
int min_index;
|
||||||
uint64_t old_l2_offset;
|
uint64_t old_l2_offset;
|
||||||
uint64_t *l2_table, l2_offset;
|
uint64_t *l2_table;
|
||||||
|
int64_t l2_offset;
|
||||||
|
|
||||||
old_l2_offset = s->l1_table[l1_index];
|
old_l2_offset = s->l1_table[l1_index];
|
||||||
|
|
||||||
/* allocate a new l2 entry */
|
/* allocate a new l2 entry */
|
||||||
|
|
||||||
l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
|
l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
|
||||||
|
if (l2_offset < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* update the L1 entry */
|
/* update the L1 entry */
|
||||||
|
|
||||||
@@ -479,8 +489,8 @@ out:
|
|||||||
* the l2 table offset in the qcow2 file and the cluster index
|
* the l2 table offset in the qcow2 file and the cluster index
|
||||||
* in the l2 table are given to the caller.
|
* in the l2 table are given to the caller.
|
||||||
*
|
*
|
||||||
|
* Returns 0 on success, -errno in failure case
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
||||||
uint64_t **new_l2_table,
|
uint64_t **new_l2_table,
|
||||||
uint64_t *new_l2_offset,
|
uint64_t *new_l2_offset,
|
||||||
@@ -496,8 +506,9 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
|||||||
l1_index = offset >> (s->l2_bits + s->cluster_bits);
|
l1_index = offset >> (s->l2_bits + s->cluster_bits);
|
||||||
if (l1_index >= s->l1_size) {
|
if (l1_index >= s->l1_size) {
|
||||||
ret = qcow2_grow_l1_table(bs, l1_index + 1);
|
ret = qcow2_grow_l1_table(bs, l1_index + 1);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
return 0;
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
l2_offset = s->l1_table[l1_index];
|
l2_offset = s->l1_table[l1_index];
|
||||||
|
|
||||||
@@ -507,14 +518,16 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
|||||||
/* load the l2 table in memory */
|
/* load the l2 table in memory */
|
||||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
l2_offset &= ~QCOW_OFLAG_COPIED;
|
||||||
l2_table = l2_load(bs, l2_offset);
|
l2_table = l2_load(bs, l2_offset);
|
||||||
if (l2_table == NULL)
|
if (l2_table == NULL) {
|
||||||
return 0;
|
return -EIO;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (l2_offset)
|
if (l2_offset)
|
||||||
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
|
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
|
||||||
l2_table = l2_allocate(bs, l1_index);
|
l2_table = l2_allocate(bs, l1_index);
|
||||||
if (l2_table == NULL)
|
if (l2_table == NULL) {
|
||||||
return 0;
|
return -EIO;
|
||||||
|
}
|
||||||
l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
|
l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,7 +539,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
|||||||
*new_l2_offset = l2_offset;
|
*new_l2_offset = l2_offset;
|
||||||
*new_l2_index = l2_index;
|
*new_l2_index = l2_index;
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -548,12 +561,14 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
|||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int l2_index, ret;
|
int l2_index, ret;
|
||||||
uint64_t l2_offset, *l2_table, cluster_offset;
|
uint64_t l2_offset, *l2_table;
|
||||||
|
int64_t cluster_offset;
|
||||||
int nb_csectors;
|
int nb_csectors;
|
||||||
|
|
||||||
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
|
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
|
||||||
if (ret == 0)
|
if (ret < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
||||||
if (cluster_offset & QCOW_OFLAG_COPIED)
|
if (cluster_offset & QCOW_OFLAG_COPIED)
|
||||||
@@ -563,6 +578,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
|||||||
qcow2_free_any_clusters(bs, cluster_offset, 1);
|
qcow2_free_any_clusters(bs, cluster_offset, 1);
|
||||||
|
|
||||||
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
|
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
|
||||||
|
if (cluster_offset < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
|
nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
|
||||||
(cluster_offset >> 9);
|
(cluster_offset >> 9);
|
||||||
|
|
||||||
@@ -605,12 +624,12 @@ static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
|
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
||||||
QCowL2Meta *m)
|
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int i, j = 0, l2_index, ret;
|
int i, j = 0, l2_index, ret;
|
||||||
uint64_t *old_cluster, start_sect, l2_offset, *l2_table;
|
uint64_t *old_cluster, start_sect, l2_offset, *l2_table;
|
||||||
|
uint64_t cluster_offset = m->cluster_offset;
|
||||||
|
|
||||||
if (m->nb_clusters == 0)
|
if (m->nb_clusters == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -633,10 +652,11 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = -EIO;
|
|
||||||
/* update L2 table */
|
/* update L2 table */
|
||||||
if (!get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index))
|
ret = get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index);
|
||||||
|
if (ret < 0) {
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < m->nb_clusters; i++) {
|
for (i = 0; i < m->nb_clusters; i++) {
|
||||||
/* if two concurrent writes happen to the same unallocated cluster
|
/* if two concurrent writes happen to the same unallocated cluster
|
||||||
@@ -670,30 +690,36 @@ err:
|
|||||||
/*
|
/*
|
||||||
* alloc_cluster_offset
|
* alloc_cluster_offset
|
||||||
*
|
*
|
||||||
* For a given offset of the disk image, return cluster offset in
|
* For a given offset of the disk image, return cluster offset in qcow2 file.
|
||||||
* qcow2 file.
|
|
||||||
*
|
|
||||||
* If the offset is not found, allocate a new cluster.
|
* If the offset is not found, allocate a new cluster.
|
||||||
*
|
*
|
||||||
* Return the cluster offset if successful,
|
* If the cluster was already allocated, m->nb_clusters is set to 0,
|
||||||
* Return 0, otherwise.
|
* m->depends_on is set to NULL and the other fields in m are meaningless.
|
||||||
*
|
*
|
||||||
|
* If the cluster is newly allocated, m->nb_clusters is set to the number of
|
||||||
|
* contiguous clusters that have been allocated. This may be 0 if the request
|
||||||
|
* conflict with another write request in flight; in this case, m->depends_on
|
||||||
|
* is set and the remaining fields of m are meaningless.
|
||||||
|
*
|
||||||
|
* If m->nb_clusters is non-zero, the other fields of m are valid and contain
|
||||||
|
* information about the first allocated cluster.
|
||||||
|
*
|
||||||
|
* Return 0 on success and -errno in error cases
|
||||||
*/
|
*/
|
||||||
|
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
int n_start, int n_end, int *num, QCowL2Meta *m)
|
||||||
uint64_t offset,
|
|
||||||
int n_start, int n_end,
|
|
||||||
int *num, QCowL2Meta *m)
|
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int l2_index, ret;
|
int l2_index, ret;
|
||||||
uint64_t l2_offset, *l2_table, cluster_offset;
|
uint64_t l2_offset, *l2_table;
|
||||||
|
int64_t cluster_offset;
|
||||||
unsigned int nb_clusters, i = 0;
|
unsigned int nb_clusters, i = 0;
|
||||||
QCowL2Meta *old_alloc;
|
QCowL2Meta *old_alloc;
|
||||||
|
|
||||||
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
|
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
|
||||||
if (ret == 0)
|
if (ret < 0) {
|
||||||
return 0;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
nb_clusters = size_to_clusters(s, n_end << 9);
|
nb_clusters = size_to_clusters(s, n_end << 9);
|
||||||
|
|
||||||
@@ -709,6 +735,7 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
|||||||
|
|
||||||
cluster_offset &= ~QCOW_OFLAG_COPIED;
|
cluster_offset &= ~QCOW_OFLAG_COPIED;
|
||||||
m->nb_clusters = 0;
|
m->nb_clusters = 0;
|
||||||
|
m->depends_on = NULL;
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -723,12 +750,15 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
|||||||
while (i < nb_clusters) {
|
while (i < nb_clusters) {
|
||||||
i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
|
i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
|
||||||
&l2_table[l2_index], i, 0);
|
&l2_table[l2_index], i, 0);
|
||||||
|
if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
|
||||||
if(be64_to_cpu(l2_table[l2_index + i]))
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
i += count_contiguous_free_clusters(nb_clusters - i,
|
i += count_contiguous_free_clusters(nb_clusters - i,
|
||||||
&l2_table[l2_index + i]);
|
&l2_table[l2_index + i]);
|
||||||
|
if (i >= nb_clusters) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
|
cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
|
||||||
|
|
||||||
@@ -736,6 +766,7 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
|||||||
(cluster_offset & QCOW_OFLAG_COMPRESSED))
|
(cluster_offset & QCOW_OFLAG_COMPRESSED))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
assert(i <= nb_clusters);
|
||||||
nb_clusters = i;
|
nb_clusters = i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -779,6 +810,10 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
|||||||
/* allocate a new cluster */
|
/* allocate a new cluster */
|
||||||
|
|
||||||
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
|
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
|
||||||
|
if (cluster_offset < 0) {
|
||||||
|
QLIST_REMOVE(m, next_in_flight);
|
||||||
|
return cluster_offset;
|
||||||
|
}
|
||||||
|
|
||||||
/* save info needed for meta data update */
|
/* save info needed for meta data update */
|
||||||
m->offset = offset;
|
m->offset = offset;
|
||||||
@@ -787,10 +822,11 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
|
m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
|
||||||
|
m->cluster_offset = cluster_offset;
|
||||||
|
|
||||||
*num = m->nb_available - n_start;
|
*num = m->nb_available - n_start;
|
||||||
|
|
||||||
return cluster_offset;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
|
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
#include "block/qcow2.h"
|
#include "block/qcow2.h"
|
||||||
|
|
||||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
|
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
|
||||||
static int update_refcount(BlockDriverState *bs,
|
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||||
int64_t offset, int64_t length,
|
int64_t offset, int64_t length,
|
||||||
int addend);
|
int addend);
|
||||||
|
|
||||||
@@ -123,121 +123,266 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
|||||||
return be16_to_cpu(s->refcount_block_cache[block_index]);
|
return be16_to_cpu(s->refcount_block_cache[block_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int grow_refcount_table(BlockDriverState *bs, int min_size)
|
/*
|
||||||
|
* Rounds the refcount table size up to avoid growing the table for each single
|
||||||
|
* refcount block that is allocated.
|
||||||
|
*/
|
||||||
|
static unsigned int next_refcount_table_size(BDRVQcowState *s,
|
||||||
|
unsigned int min_size)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
unsigned int min_clusters = (min_size >> (s->cluster_bits - 3)) + 1;
|
||||||
int new_table_size, new_table_size2, refcount_table_clusters, i, ret;
|
unsigned int refcount_table_clusters =
|
||||||
uint64_t *new_table;
|
MAX(1, s->refcount_table_size >> (s->cluster_bits - 3));
|
||||||
int64_t table_offset;
|
|
||||||
uint8_t data[12];
|
|
||||||
int old_table_size;
|
|
||||||
int64_t old_table_offset;
|
|
||||||
|
|
||||||
if (min_size <= s->refcount_table_size)
|
while (min_clusters > refcount_table_clusters) {
|
||||||
return 0;
|
refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
|
||||||
/* compute new table size */
|
|
||||||
refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
|
|
||||||
for(;;) {
|
|
||||||
if (refcount_table_clusters == 0) {
|
|
||||||
refcount_table_clusters = 1;
|
|
||||||
} else {
|
|
||||||
refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
|
|
||||||
}
|
|
||||||
new_table_size = refcount_table_clusters << (s->cluster_bits - 3);
|
|
||||||
if (min_size <= new_table_size)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_ALLOC2
|
|
||||||
printf("grow_refcount_table from %d to %d\n",
|
|
||||||
s->refcount_table_size,
|
|
||||||
new_table_size);
|
|
||||||
#endif
|
|
||||||
new_table_size2 = new_table_size * sizeof(uint64_t);
|
|
||||||
new_table = qemu_mallocz(new_table_size2);
|
|
||||||
memcpy(new_table, s->refcount_table,
|
|
||||||
s->refcount_table_size * sizeof(uint64_t));
|
|
||||||
for(i = 0; i < s->refcount_table_size; i++)
|
|
||||||
cpu_to_be64s(&new_table[i]);
|
|
||||||
/* Note: we cannot update the refcount now to avoid recursion */
|
|
||||||
table_offset = alloc_clusters_noref(bs, new_table_size2);
|
|
||||||
ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2);
|
|
||||||
if (ret != new_table_size2)
|
|
||||||
goto fail;
|
|
||||||
for(i = 0; i < s->refcount_table_size; i++)
|
|
||||||
be64_to_cpus(&new_table[i]);
|
|
||||||
|
|
||||||
cpu_to_be64w((uint64_t*)data, table_offset);
|
return refcount_table_clusters << (s->cluster_bits - 3);
|
||||||
cpu_to_be32w((uint32_t*)(data + 8), refcount_table_clusters);
|
|
||||||
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
|
|
||||||
data, sizeof(data)) != sizeof(data))
|
|
||||||
goto fail;
|
|
||||||
qemu_free(s->refcount_table);
|
|
||||||
old_table_offset = s->refcount_table_offset;
|
|
||||||
old_table_size = s->refcount_table_size;
|
|
||||||
s->refcount_table = new_table;
|
|
||||||
s->refcount_table_size = new_table_size;
|
|
||||||
s->refcount_table_offset = table_offset;
|
|
||||||
|
|
||||||
update_refcount(bs, table_offset, new_table_size2, 1);
|
|
||||||
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
|
|
||||||
return 0;
|
|
||||||
fail:
|
|
||||||
qemu_free(new_table);
|
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Checks if two offsets are described by the same refcount block */
|
||||||
|
static int in_same_refcount_block(BDRVQcowState *s, uint64_t offset_a,
|
||||||
|
uint64_t offset_b)
|
||||||
|
{
|
||||||
|
uint64_t block_a = offset_a >> (2 * s->cluster_bits - REFCOUNT_SHIFT);
|
||||||
|
uint64_t block_b = offset_b >> (2 * s->cluster_bits - REFCOUNT_SHIFT);
|
||||||
|
|
||||||
|
return (block_a == block_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads a refcount block. If it doesn't exist yet, it is allocated first
|
||||||
|
* (including growing the refcount table if needed).
|
||||||
|
*
|
||||||
|
* Returns the offset of the refcount block on success or -errno in error case
|
||||||
|
*/
|
||||||
static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
|
static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int64_t offset, refcount_block_offset;
|
|
||||||
unsigned int refcount_table_index;
|
unsigned int refcount_table_index;
|
||||||
int ret;
|
int ret;
|
||||||
uint64_t data64;
|
|
||||||
int cache = cache_refcount_updates;
|
|
||||||
|
|
||||||
/* Find L1 index and grow refcount table if needed */
|
/* Find the refcount block for the given cluster */
|
||||||
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
|
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
|
||||||
if (refcount_table_index >= s->refcount_table_size) {
|
|
||||||
ret = grow_refcount_table(bs, refcount_table_index + 1);
|
if (refcount_table_index < s->refcount_table_size) {
|
||||||
if (ret < 0)
|
|
||||||
|
uint64_t refcount_block_offset =
|
||||||
|
s->refcount_table[refcount_table_index];
|
||||||
|
|
||||||
|
/* If it's already there, we're done */
|
||||||
|
if (refcount_block_offset) {
|
||||||
|
if (refcount_block_offset != s->refcount_block_cache_offset) {
|
||||||
|
ret = load_refcount_block(bs, refcount_block_offset);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return refcount_block_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we came here, we need to allocate something. Something is at least
|
||||||
|
* a cluster for the new refcount block. It may also include a new refcount
|
||||||
|
* table if the old refcount table is too small.
|
||||||
|
*
|
||||||
|
* Note that allocating clusters here needs some special care:
|
||||||
|
*
|
||||||
|
* - We can't use the normal qcow2_alloc_clusters(), it would try to
|
||||||
|
* increase the refcount and very likely we would end up with an endless
|
||||||
|
* recursion. Instead we must place the refcount blocks in a way that
|
||||||
|
* they can describe them themselves.
|
||||||
|
*
|
||||||
|
* - We need to consider that at this point we are inside update_refcounts
|
||||||
|
* and doing the initial refcount increase. This means that some clusters
|
||||||
|
* have already been allocated by the caller, but their refcount isn't
|
||||||
|
* accurate yet. free_cluster_index tells us where this allocation ends
|
||||||
|
* as long as we don't overwrite it by freeing clusters.
|
||||||
|
*
|
||||||
|
* - alloc_clusters_noref and qcow2_free_clusters may load a different
|
||||||
|
* refcount block into the cache
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (cache_refcount_updates) {
|
||||||
|
ret = write_refcount_block(s);
|
||||||
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load or allocate the refcount block */
|
/* Allocate the refcount block itself and mark it as used */
|
||||||
refcount_block_offset = s->refcount_table[refcount_table_index];
|
uint64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
|
||||||
if (!refcount_block_offset) {
|
memset(s->refcount_block_cache, 0, s->cluster_size);
|
||||||
if (cache_refcount_updates) {
|
s->refcount_block_cache_offset = new_block;
|
||||||
write_refcount_block(s);
|
|
||||||
cache_refcount_updates = 0;
|
|
||||||
}
|
|
||||||
/* create a new refcount block */
|
|
||||||
/* Note: we cannot update the refcount now to avoid recursion */
|
|
||||||
offset = alloc_clusters_noref(bs, s->cluster_size);
|
|
||||||
memset(s->refcount_block_cache, 0, s->cluster_size);
|
|
||||||
ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size);
|
|
||||||
if (ret != s->cluster_size)
|
|
||||||
return -EINVAL;
|
|
||||||
s->refcount_table[refcount_table_index] = offset;
|
|
||||||
data64 = cpu_to_be64(offset);
|
|
||||||
ret = bdrv_pwrite(s->hd, s->refcount_table_offset +
|
|
||||||
refcount_table_index * sizeof(uint64_t),
|
|
||||||
&data64, sizeof(data64));
|
|
||||||
if (ret != sizeof(data64))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
refcount_block_offset = offset;
|
#ifdef DEBUG_ALLOC2
|
||||||
s->refcount_block_cache_offset = offset;
|
fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64
|
||||||
update_refcount(bs, offset, s->cluster_size, 1);
|
" at %" PRIx64 "\n",
|
||||||
cache_refcount_updates = cache;
|
refcount_table_index, cluster_index << s->cluster_bits, new_block);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (in_same_refcount_block(s, new_block, cluster_index << s->cluster_bits)) {
|
||||||
|
/* The block describes itself, need to update the cache */
|
||||||
|
int block_index = (new_block >> s->cluster_bits) &
|
||||||
|
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
|
||||||
|
s->refcount_block_cache[block_index] = cpu_to_be16(1);
|
||||||
} else {
|
} else {
|
||||||
if (refcount_block_offset != s->refcount_block_cache_offset) {
|
/* Described somewhere else. This can recurse at most twice before we
|
||||||
if (load_refcount_block(bs, refcount_block_offset) < 0)
|
* arrive at a block that describes itself. */
|
||||||
return -EIO;
|
ret = update_refcount(bs, new_block, s->cluster_size, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail_block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return refcount_block_offset;
|
/* Now the new refcount block needs to be written to disk */
|
||||||
|
ret = bdrv_pwrite(s->hd, new_block, s->refcount_block_cache,
|
||||||
|
s->cluster_size);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
ret = bdrv_pwrite(s->hd,
|
||||||
|
s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
|
||||||
|
&data64, sizeof(data64));
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->refcount_table[refcount_table_index] = new_block;
|
||||||
|
return new_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we come here, we need to grow the refcount table. Again, a new
|
||||||
|
* refcount table needs some space and we can't simply allocate to avoid
|
||||||
|
* endless recursion.
|
||||||
|
*
|
||||||
|
* Therefore let's grab new refcount blocks at the end of the image, which
|
||||||
|
* will describe themselves and the new refcount table. This way we can
|
||||||
|
* reference them only in the new table and do the switch to the new
|
||||||
|
* refcount table at once without producing an inconsistent state in
|
||||||
|
* between.
|
||||||
|
*/
|
||||||
|
/* 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 +
|
||||||
|
refcount_block_clusters - 1) / refcount_block_clusters;
|
||||||
|
|
||||||
|
/* And now we need at least one block more for the new metadata */
|
||||||
|
uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
|
||||||
|
uint64_t last_table_size;
|
||||||
|
uint64_t blocks_clusters;
|
||||||
|
do {
|
||||||
|
uint64_t table_clusters = size_to_clusters(s, table_size);
|
||||||
|
blocks_clusters = 1 +
|
||||||
|
((table_clusters + refcount_block_clusters - 1)
|
||||||
|
/ refcount_block_clusters);
|
||||||
|
uint64_t meta_clusters = table_clusters + blocks_clusters;
|
||||||
|
|
||||||
|
last_table_size = table_size;
|
||||||
|
table_size = next_refcount_table_size(s, blocks_used +
|
||||||
|
((meta_clusters + refcount_block_clusters - 1)
|
||||||
|
/ refcount_block_clusters));
|
||||||
|
|
||||||
|
} while (last_table_size != table_size);
|
||||||
|
|
||||||
|
#ifdef DEBUG_ALLOC2
|
||||||
|
fprintf(stderr, "qcow2: Grow refcount table %" PRId32 " => %" PRId64 "\n",
|
||||||
|
s->refcount_table_size, table_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Create the new refcount table and blocks */
|
||||||
|
uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
|
||||||
|
s->cluster_size;
|
||||||
|
uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
|
||||||
|
uint16_t *new_blocks = qemu_mallocz(blocks_clusters * s->cluster_size);
|
||||||
|
uint64_t *new_table = qemu_mallocz(table_size * sizeof(uint64_t));
|
||||||
|
|
||||||
|
assert(meta_offset >= (s->free_cluster_index * s->cluster_size));
|
||||||
|
|
||||||
|
/* Fill the new refcount table */
|
||||||
|
memcpy(new_table, s->refcount_table,
|
||||||
|
s->refcount_table_size * sizeof(uint64_t));
|
||||||
|
new_table[refcount_table_index] = new_block;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < blocks_clusters; i++) {
|
||||||
|
new_table[blocks_used + i] = meta_offset + (i * s->cluster_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill the refcount blocks */
|
||||||
|
uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t));
|
||||||
|
int block = 0;
|
||||||
|
for (i = 0; i < table_clusters + blocks_clusters; i++) {
|
||||||
|
new_blocks[block++] = cpu_to_be16(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write refcount blocks to disk */
|
||||||
|
ret = bdrv_pwrite(s->hd, meta_offset, new_blocks,
|
||||||
|
blocks_clusters * s->cluster_size);
|
||||||
|
qemu_free(new_blocks);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write refcount table to disk */
|
||||||
|
for(i = 0; i < table_size; i++) {
|
||||||
|
cpu_to_be64s(&new_table[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bdrv_pwrite(s->hd, table_offset, new_table,
|
||||||
|
table_size * sizeof(uint64_t));
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < table_size; i++) {
|
||||||
|
cpu_to_be64s(&new_table[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hook up the new refcount table in the qcow2 header */
|
||||||
|
uint8_t data[12];
|
||||||
|
cpu_to_be64w((uint64_t*)data, table_offset);
|
||||||
|
cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
|
||||||
|
ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
|
||||||
|
data, sizeof(data));
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And switch it in memory */
|
||||||
|
uint64_t old_table_offset = s->refcount_table_offset;
|
||||||
|
uint64_t old_table_size = s->refcount_table_size;
|
||||||
|
|
||||||
|
qemu_free(s->refcount_table);
|
||||||
|
s->refcount_table = new_table;
|
||||||
|
s->refcount_table_size = table_size;
|
||||||
|
s->refcount_table_offset = table_offset;
|
||||||
|
|
||||||
|
/* Free old table. Remember, we must not change free_cluster_index */
|
||||||
|
uint64_t old_free_cluster_index = s->free_cluster_index;
|
||||||
|
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
|
||||||
|
s->free_cluster_index = old_free_cluster_index;
|
||||||
|
|
||||||
|
ret = load_refcount_block(bs, new_block);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_block;
|
||||||
|
|
||||||
|
fail_table:
|
||||||
|
qemu_free(new_table);
|
||||||
|
fail_block:
|
||||||
|
s->refcount_block_cache_offset = 0;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define REFCOUNTS_PER_SECTOR (512 >> REFCOUNT_SHIFT)
|
#define REFCOUNTS_PER_SECTOR (512 >> REFCOUNT_SHIFT)
|
||||||
@@ -266,22 +411,26 @@ static int write_refcount_block_entries(BDRVQcowState *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: cache several refcount block clusters ? */
|
/* XXX: cache several refcount block clusters ? */
|
||||||
static int update_refcount(BlockDriverState *bs,
|
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||||
int64_t offset, int64_t length,
|
int64_t offset, int64_t length, int addend)
|
||||||
int addend)
|
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int64_t start, last, cluster_offset;
|
int64_t start, last, cluster_offset;
|
||||||
int64_t refcount_block_offset = 0;
|
int64_t refcount_block_offset = 0;
|
||||||
int64_t table_index = -1, old_table_index;
|
int64_t table_index = -1, old_table_index;
|
||||||
int first_index = -1, last_index = -1;
|
int first_index = -1, last_index = -1;
|
||||||
|
int ret;
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC2
|
#ifdef DEBUG_ALLOC2
|
||||||
printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",
|
printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",
|
||||||
offset, length, addend);
|
offset, length, addend);
|
||||||
#endif
|
#endif
|
||||||
if (length <= 0)
|
if (length < 0) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
} else if (length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
start = offset & ~(s->cluster_size - 1);
|
start = offset & ~(s->cluster_size - 1);
|
||||||
last = (offset + length - 1) & ~(s->cluster_size - 1);
|
last = (offset + length - 1) & ~(s->cluster_size - 1);
|
||||||
for(cluster_offset = start; cluster_offset <= last;
|
for(cluster_offset = start; cluster_offset <= last;
|
||||||
@@ -289,6 +438,7 @@ static int update_refcount(BlockDriverState *bs,
|
|||||||
{
|
{
|
||||||
int block_index, refcount;
|
int block_index, refcount;
|
||||||
int64_t cluster_index = cluster_offset >> s->cluster_bits;
|
int64_t cluster_index = cluster_offset >> s->cluster_bits;
|
||||||
|
int64_t new_block;
|
||||||
|
|
||||||
/* Only write refcount block to disk when we are done with it */
|
/* Only write refcount block to disk when we are done with it */
|
||||||
old_table_index = table_index;
|
old_table_index = table_index;
|
||||||
@@ -306,10 +456,12 @@ static int update_refcount(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load the refcount block and allocate it if needed */
|
/* Load the refcount block and allocate it if needed */
|
||||||
refcount_block_offset = alloc_refcount_block(bs, cluster_index);
|
new_block = alloc_refcount_block(bs, cluster_index);
|
||||||
if (refcount_block_offset < 0) {
|
if (new_block < 0) {
|
||||||
return refcount_block_offset;
|
ret = new_block;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
refcount_block_offset = new_block;
|
||||||
|
|
||||||
/* we can update the count and save it */
|
/* we can update the count and save it */
|
||||||
block_index = cluster_index &
|
block_index = cluster_index &
|
||||||
@@ -323,24 +475,38 @@ static int update_refcount(BlockDriverState *bs,
|
|||||||
|
|
||||||
refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
|
refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
|
||||||
refcount += addend;
|
refcount += addend;
|
||||||
if (refcount < 0 || refcount > 0xffff)
|
if (refcount < 0 || refcount > 0xffff) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
if (refcount == 0 && cluster_index < s->free_cluster_index) {
|
if (refcount == 0 && cluster_index < s->free_cluster_index) {
|
||||||
s->free_cluster_index = cluster_index;
|
s->free_cluster_index = cluster_index;
|
||||||
}
|
}
|
||||||
s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
|
s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
fail:
|
||||||
|
|
||||||
/* Write last changed block to disk */
|
/* Write last changed block to disk */
|
||||||
if (refcount_block_offset != 0) {
|
if (refcount_block_offset != 0) {
|
||||||
if (write_refcount_block_entries(s, refcount_block_offset,
|
if (write_refcount_block_entries(s, refcount_block_offset,
|
||||||
first_index, last_index) < 0)
|
first_index, last_index) < 0)
|
||||||
{
|
{
|
||||||
return -EIO;
|
return ret < 0 ? ret : -EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
/*
|
||||||
|
* Try do undo any updates if an error is returned (This may succeed in
|
||||||
|
* some cases like ENOSPC for allocating a new refcount block)
|
||||||
|
*/
|
||||||
|
if (ret < 0) {
|
||||||
|
int dummy;
|
||||||
|
dummy = update_refcount(bs, offset, cluster_offset - offset, -addend);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* addend must be 1 or -1 */
|
/* addend must be 1 or -1 */
|
||||||
@@ -390,9 +556,13 @@ retry:
|
|||||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
|
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
|
||||||
{
|
{
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
|
int ret;
|
||||||
|
|
||||||
offset = alloc_clusters_noref(bs, size);
|
offset = alloc_clusters_noref(bs, size);
|
||||||
update_refcount(bs, offset, size, 1);
|
ret = update_refcount(bs, offset, size, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,6 +577,9 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
|||||||
assert(size > 0 && size <= s->cluster_size);
|
assert(size > 0 && size <= s->cluster_size);
|
||||||
if (s->free_byte_offset == 0) {
|
if (s->free_byte_offset == 0) {
|
||||||
s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size);
|
s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size);
|
||||||
|
if (s->free_byte_offset < 0) {
|
||||||
|
return s->free_byte_offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
redo:
|
redo:
|
||||||
free_in_cluster = s->cluster_size -
|
free_in_cluster = s->cluster_size -
|
||||||
@@ -422,6 +595,9 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
|||||||
update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
|
update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
|
||||||
} else {
|
} else {
|
||||||
offset = qcow2_alloc_clusters(bs, s->cluster_size);
|
offset = qcow2_alloc_clusters(bs, s->cluster_size);
|
||||||
|
if (offset < 0) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
|
cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
|
||||||
if ((cluster_offset + s->cluster_size) == offset) {
|
if ((cluster_offset + s->cluster_size) == offset) {
|
||||||
/* we are lucky: contiguous data */
|
/* we are lucky: contiguous data */
|
||||||
@@ -439,7 +615,13 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
|||||||
void qcow2_free_clusters(BlockDriverState *bs,
|
void qcow2_free_clusters(BlockDriverState *bs,
|
||||||
int64_t offset, int64_t size)
|
int64_t offset, int64_t size)
|
||||||
{
|
{
|
||||||
update_refcount(bs, offset, size, -1);
|
int ret;
|
||||||
|
|
||||||
|
ret = update_refcount(bs, offset, size, -1);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -549,9 +731,15 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||||||
if (offset & QCOW_OFLAG_COMPRESSED) {
|
if (offset & QCOW_OFLAG_COMPRESSED) {
|
||||||
nb_csectors = ((offset >> s->csize_shift) &
|
nb_csectors = ((offset >> s->csize_shift) &
|
||||||
s->csize_mask) + 1;
|
s->csize_mask) + 1;
|
||||||
if (addend != 0)
|
if (addend != 0) {
|
||||||
update_refcount(bs, (offset & s->cluster_offset_mask) & ~511,
|
int ret;
|
||||||
nb_csectors * 512, addend);
|
ret = update_refcount(bs,
|
||||||
|
(offset & s->cluster_offset_mask) & ~511,
|
||||||
|
nb_csectors * 512, addend);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* compressed clusters are never modified */
|
/* compressed clusters are never modified */
|
||||||
refcount = 2;
|
refcount = 2;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -139,6 +139,9 @@ static int qcow_write_snapshots(BlockDriverState *bs)
|
|||||||
|
|
||||||
snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
|
snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
|
||||||
offset = snapshots_offset;
|
offset = snapshots_offset;
|
||||||
|
if (offset < 0) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
for(i = 0; i < s->nb_snapshots; i++) {
|
for(i = 0; i < s->nb_snapshots; i++) {
|
||||||
sn = s->snapshots + i;
|
sn = s->snapshots + i;
|
||||||
@@ -235,6 +238,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
|||||||
QCowSnapshot *snapshots1, sn1, *sn = &sn1;
|
QCowSnapshot *snapshots1, sn1, *sn = &sn1;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
uint64_t *l1_table = NULL;
|
uint64_t *l1_table = NULL;
|
||||||
|
int64_t l1_table_offset;
|
||||||
|
|
||||||
memset(sn, 0, sizeof(*sn));
|
memset(sn, 0, sizeof(*sn));
|
||||||
|
|
||||||
@@ -263,7 +267,12 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
|||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* create the L1 table of the snapshot */
|
/* create the L1 table of the snapshot */
|
||||||
sn->l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
|
l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
|
||||||
|
if (l1_table_offset < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
sn->l1_table_offset = l1_table_offset;
|
||||||
sn->l1_size = s->l1_size;
|
sn->l1_size = s->l1_size;
|
||||||
|
|
||||||
if (s->l1_size != 0) {
|
if (s->l1_size != 0) {
|
||||||
|
@@ -467,8 +467,10 @@ static void qcow_aio_read_cb(void *opaque, int ret)
|
|||||||
acb->hd_aiocb = bdrv_aio_readv(s->hd,
|
acb->hd_aiocb = bdrv_aio_readv(s->hd,
|
||||||
(acb->cluster_offset >> 9) + index_in_cluster,
|
(acb->cluster_offset >> 9) + index_in_cluster,
|
||||||
&acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
|
&acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
|
||||||
if (acb->hd_aiocb == NULL)
|
if (acb->hd_aiocb == NULL) {
|
||||||
|
ret = -EIO;
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -561,7 +563,7 @@ static void qcow_aio_write_cb(void *opaque, int ret)
|
|||||||
acb->hd_aiocb = NULL;
|
acb->hd_aiocb = NULL;
|
||||||
|
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
ret = qcow2_alloc_cluster_link_l2(bs, acb->cluster_offset, &acb->l2meta);
|
ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
run_dependent_requests(&acb->l2meta);
|
run_dependent_requests(&acb->l2meta);
|
||||||
@@ -585,21 +587,23 @@ static void qcow_aio_write_cb(void *opaque, int ret)
|
|||||||
n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors)
|
n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors)
|
||||||
n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
|
n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
|
||||||
|
|
||||||
acb->cluster_offset = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
|
ret = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
|
||||||
index_in_cluster,
|
index_in_cluster, n_end, &acb->n, &acb->l2meta);
|
||||||
n_end, &acb->n, &acb->l2meta);
|
if (ret < 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
acb->cluster_offset = acb->l2meta.cluster_offset;
|
||||||
|
|
||||||
/* Need to wait for another request? If so, we are done for now. */
|
/* Need to wait for another request? If so, we are done for now. */
|
||||||
if (!acb->cluster_offset && acb->l2meta.depends_on != NULL) {
|
if (acb->l2meta.nb_clusters == 0 && acb->l2meta.depends_on != NULL) {
|
||||||
QLIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests,
|
QLIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests,
|
||||||
acb, next_depend);
|
acb, next_depend);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!acb->cluster_offset || (acb->cluster_offset & 511) != 0) {
|
assert((acb->cluster_offset & 511) == 0);
|
||||||
ret = -EIO;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (s->crypt_method) {
|
if (s->crypt_method) {
|
||||||
if (!acb->cluster_data) {
|
if (!acb->cluster_data) {
|
||||||
acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS *
|
acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS *
|
||||||
@@ -618,11 +622,17 @@ static void qcow_aio_write_cb(void *opaque, int ret)
|
|||||||
(acb->cluster_offset >> 9) + index_in_cluster,
|
(acb->cluster_offset >> 9) + index_in_cluster,
|
||||||
&acb->hd_qiov, acb->n,
|
&acb->hd_qiov, acb->n,
|
||||||
qcow_aio_write_cb, acb);
|
qcow_aio_write_cb, acb);
|
||||||
if (acb->hd_aiocb == NULL)
|
if (acb->hd_aiocb == NULL) {
|
||||||
goto done;
|
ret = -EIO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (acb->l2meta.nb_clusters != 0) {
|
||||||
|
QLIST_REMOVE(&acb->l2meta, next_in_flight);
|
||||||
|
}
|
||||||
done:
|
done:
|
||||||
if (acb->qiov->niov > 1)
|
if (acb->qiov->niov > 1)
|
||||||
qemu_vfree(acb->orig_buf);
|
qemu_vfree(acb->orig_buf);
|
||||||
@@ -683,27 +693,27 @@ static int get_bits_from_size(size_t size)
|
|||||||
static int preallocate(BlockDriverState *bs)
|
static int preallocate(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint64_t cluster_offset = 0;
|
|
||||||
uint64_t nb_sectors;
|
uint64_t nb_sectors;
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
int num;
|
int num;
|
||||||
|
int ret;
|
||||||
QCowL2Meta meta;
|
QCowL2Meta meta;
|
||||||
|
|
||||||
nb_sectors = bdrv_getlength(bs) >> 9;
|
nb_sectors = bdrv_getlength(bs) >> 9;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
QLIST_INIT(&meta.dependent_requests);
|
QLIST_INIT(&meta.dependent_requests);
|
||||||
|
meta.cluster_offset = 0;
|
||||||
|
|
||||||
while (nb_sectors) {
|
while (nb_sectors) {
|
||||||
num = MIN(nb_sectors, INT_MAX >> 9);
|
num = MIN(nb_sectors, INT_MAX >> 9);
|
||||||
cluster_offset = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
|
ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num, &meta);
|
||||||
&meta);
|
|
||||||
|
|
||||||
if (cluster_offset == 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcow2_alloc_cluster_link_l2(bs, cluster_offset, &meta) < 0) {
|
if (qcow2_alloc_cluster_link_l2(bs, &meta) < 0) {
|
||||||
qcow2_free_any_clusters(bs, cluster_offset, meta.nb_clusters);
|
qcow2_free_any_clusters(bs, meta.cluster_offset, meta.nb_clusters);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,10 +732,10 @@ static int preallocate(BlockDriverState *bs)
|
|||||||
* all of the allocated clusters (otherwise we get failing reads after
|
* all of the allocated clusters (otherwise we get failing reads after
|
||||||
* EOF). Extend the image to the last allocated sector.
|
* EOF). Extend the image to the last allocated sector.
|
||||||
*/
|
*/
|
||||||
if (cluster_offset != 0) {
|
if (meta.cluster_offset != 0) {
|
||||||
uint8_t buf[512];
|
uint8_t buf[512];
|
||||||
memset(buf, 0, 512);
|
memset(buf, 0, 512);
|
||||||
bdrv_write(s->hd, (cluster_offset >> 9) + num - 1, buf, 1);
|
bdrv_write(s->hd, (meta.cluster_offset >> 9) + num - 1, buf, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1056,12 +1066,13 @@ static int qcow_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
|
|||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int growable = bs->growable;
|
int growable = bs->growable;
|
||||||
|
int ret;
|
||||||
|
|
||||||
bs->growable = 1;
|
bs->growable = 1;
|
||||||
bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size);
|
ret = bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size);
|
||||||
bs->growable = growable;
|
bs->growable = growable;
|
||||||
|
|
||||||
return size;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcow_load_vmstate(BlockDriverState *bs, uint8_t *buf,
|
static int qcow_load_vmstate(BlockDriverState *bs, uint8_t *buf,
|
||||||
|
@@ -135,6 +135,7 @@ struct QCowAIOCB;
|
|||||||
typedef struct QCowL2Meta
|
typedef struct QCowL2Meta
|
||||||
{
|
{
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
|
uint64_t cluster_offset;
|
||||||
int n_start;
|
int n_start;
|
||||||
int nb_available;
|
int nb_available;
|
||||||
int nb_clusters;
|
int nb_clusters;
|
||||||
@@ -191,16 +192,13 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
|||||||
|
|
||||||
uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
int *num);
|
int *num);
|
||||||
uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
uint64_t offset,
|
int n_start, int n_end, int *num, QCowL2Meta *m);
|
||||||
int n_start, int n_end,
|
|
||||||
int *num, QCowL2Meta *m);
|
|
||||||
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||||
uint64_t offset,
|
uint64_t offset,
|
||||||
int compressed_size);
|
int compressed_size);
|
||||||
|
|
||||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
|
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
|
||||||
QCowL2Meta *m);
|
|
||||||
|
|
||||||
/* qcow2-snapshot.c functions */
|
/* qcow2-snapshot.c functions */
|
||||||
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
|
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
|
||||||
|
@@ -595,7 +595,7 @@ static void raw_close(BlockDriverState *bs)
|
|||||||
close(s->fd);
|
close(s->fd);
|
||||||
s->fd = -1;
|
s->fd = -1;
|
||||||
if (s->aligned_buf != NULL)
|
if (s->aligned_buf != NULL)
|
||||||
qemu_free(s->aligned_buf);
|
qemu_vfree(s->aligned_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -882,7 +882,7 @@ static int init_directories(BDRVVVFATState* s,
|
|||||||
mapping->dir_index = 0;
|
mapping->dir_index = 0;
|
||||||
mapping->info.dir.parent_mapping_index = -1;
|
mapping->info.dir.parent_mapping_index = -1;
|
||||||
mapping->first_mapping_index = -1;
|
mapping->first_mapping_index = -1;
|
||||||
mapping->path = strdup(dirname);
|
mapping->path = qemu_strdup(dirname);
|
||||||
i = strlen(mapping->path);
|
i = strlen(mapping->path);
|
||||||
if (i > 0 && mapping->path[i - 1] == '/')
|
if (i > 0 && mapping->path[i - 1] == '/')
|
||||||
mapping->path[i - 1] = '\0';
|
mapping->path[i - 1] = '\0';
|
||||||
@@ -1632,10 +1632,10 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
|
|||||||
|
|
||||||
/* rename */
|
/* rename */
|
||||||
if (strcmp(basename, basename2))
|
if (strcmp(basename, basename2))
|
||||||
schedule_rename(s, cluster_num, strdup(path));
|
schedule_rename(s, cluster_num, qemu_strdup(path));
|
||||||
} else if (is_file(direntry))
|
} else if (is_file(direntry))
|
||||||
/* new file */
|
/* new file */
|
||||||
schedule_new_file(s, strdup(path), cluster_num);
|
schedule_new_file(s, qemu_strdup(path), cluster_num);
|
||||||
else {
|
else {
|
||||||
assert(0);
|
assert(0);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1752,10 +1752,10 @@ static int check_directory_consistency(BDRVVVFATState *s,
|
|||||||
mapping->mode &= ~MODE_DELETED;
|
mapping->mode &= ~MODE_DELETED;
|
||||||
|
|
||||||
if (strcmp(basename, basename2))
|
if (strcmp(basename, basename2))
|
||||||
schedule_rename(s, cluster_num, strdup(path));
|
schedule_rename(s, cluster_num, qemu_strdup(path));
|
||||||
} else
|
} else
|
||||||
/* new directory */
|
/* new directory */
|
||||||
schedule_mkdir(s, cluster_num, strdup(path));
|
schedule_mkdir(s, cluster_num, qemu_strdup(path));
|
||||||
|
|
||||||
lfn_init(&lfn);
|
lfn_init(&lfn);
|
||||||
do {
|
do {
|
||||||
|
@@ -205,6 +205,8 @@ START_TEST(qdict_put_exists_test)
|
|||||||
|
|
||||||
value = qdict_get_int(tests_dict, key);
|
value = qdict_get_int(tests_dict, key);
|
||||||
fail_unless(value == 2);
|
fail_unless(value == 2);
|
||||||
|
|
||||||
|
fail_unless(qdict_size(tests_dict) == 1);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
21
configure
vendored
21
configure
vendored
@@ -256,6 +256,7 @@ blobs="yes"
|
|||||||
pkgversion=""
|
pkgversion=""
|
||||||
check_utests="no"
|
check_utests="no"
|
||||||
user_pie="no"
|
user_pie="no"
|
||||||
|
zero_malloc=""
|
||||||
|
|
||||||
# OS specific
|
# OS specific
|
||||||
if check_define __linux__ ; then
|
if check_define __linux__ ; then
|
||||||
@@ -1792,8 +1793,9 @@ fi
|
|||||||
|
|
||||||
# Consult white-list to determine whether to enable werror
|
# Consult white-list to determine whether to enable werror
|
||||||
# by default. Only enable by default for git builds
|
# by default. Only enable by default for git builds
|
||||||
|
z_version=`cut -f3 -d. $source_path/VERSION`
|
||||||
|
|
||||||
if test -z "$werror" ; then
|
if test -z "$werror" ; then
|
||||||
z_version=`cut -f3 -d. $source_path/VERSION`
|
|
||||||
if test "$z_version" = "50" -a \
|
if test "$z_version" = "50" -a \
|
||||||
"$linux" = "yes" ; then
|
"$linux" = "yes" ; then
|
||||||
werror="yes"
|
werror="yes"
|
||||||
@@ -1802,6 +1804,16 @@ if test -z "$werror" ; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Disable zero malloc errors for official releases unless explicitly told to
|
||||||
|
# enable/disable
|
||||||
|
if test -z "$zero_malloc" ; then
|
||||||
|
if test "$z_version" = "50" ; then
|
||||||
|
zero_malloc="no"
|
||||||
|
else
|
||||||
|
zero_malloc="yes"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$werror" = "yes" ; then
|
if test "$werror" = "yes" ; then
|
||||||
QEMU_CFLAGS="-Werror $QEMU_CFLAGS"
|
QEMU_CFLAGS="-Werror $QEMU_CFLAGS"
|
||||||
fi
|
fi
|
||||||
@@ -2109,6 +2121,10 @@ fi
|
|||||||
|
|
||||||
echo "CONFIG_UNAME_RELEASE=\"$uname_release\"" >> $config_host_mak
|
echo "CONFIG_UNAME_RELEASE=\"$uname_release\"" >> $config_host_mak
|
||||||
|
|
||||||
|
if test "$zero_malloc" = "yes" ; then
|
||||||
|
echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
# USB host support
|
# USB host support
|
||||||
case "$usb" in
|
case "$usb" in
|
||||||
linux)
|
linux)
|
||||||
@@ -2636,3 +2652,6 @@ d=libuser
|
|||||||
mkdir -p $d
|
mkdir -p $d
|
||||||
rm -f $d/Makefile
|
rm -f $d/Makefile
|
||||||
ln -s $source_path/Makefile.user $d/Makefile
|
ln -s $source_path/Makefile.user $d/Makefile
|
||||||
|
if test "$static" = "no" -a "$user_pie" = "yes" ; then
|
||||||
|
echo "QEMU_CFLAGS+=-fpie" > $d/config.mak
|
||||||
|
fi
|
||||||
|
10
console.c
10
console.c
@@ -1384,6 +1384,16 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpt
|
|||||||
s->t_attrib = s->t_attrib_default;
|
s->t_attrib = s->t_attrib_default;
|
||||||
text_console_resize(s);
|
text_console_resize(s);
|
||||||
|
|
||||||
|
if (chr->label) {
|
||||||
|
char msg[128];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
s->t_attrib.bgcol = COLOR_BLUE;
|
||||||
|
len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
|
||||||
|
console_puts(chr, (uint8_t*)msg, len);
|
||||||
|
s->t_attrib = s->t_attrib_default;
|
||||||
|
}
|
||||||
|
|
||||||
qemu_chr_generic_open(chr);
|
qemu_chr_generic_open(chr);
|
||||||
if (chr->init)
|
if (chr->init)
|
||||||
chr->init(chr);
|
chr->init(chr);
|
||||||
|
@@ -44,7 +44,8 @@ struct MouseTransformInfo {
|
|||||||
int a[7];
|
int a[7];
|
||||||
};
|
};
|
||||||
|
|
||||||
void do_info_mice(Monitor *mon);
|
void do_info_mice_print(Monitor *mon, const QObject *data);
|
||||||
|
void do_info_mice(Monitor *mon, QObject **ret_data);
|
||||||
void do_mouse_set(Monitor *mon, const QDict *qdict);
|
void do_mouse_set(Monitor *mon, const QDict *qdict);
|
||||||
|
|
||||||
/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
|
/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
|
||||||
@@ -322,7 +323,8 @@ void vnc_display_init(DisplayState *ds);
|
|||||||
void vnc_display_close(DisplayState *ds);
|
void vnc_display_close(DisplayState *ds);
|
||||||
int vnc_display_open(DisplayState *ds, const char *display);
|
int vnc_display_open(DisplayState *ds, const char *display);
|
||||||
int vnc_display_password(DisplayState *ds, const char *password);
|
int vnc_display_password(DisplayState *ds, const char *password);
|
||||||
void do_info_vnc(Monitor *mon);
|
void do_info_vnc_print(Monitor *mon, const QObject *data);
|
||||||
|
void do_info_vnc(Monitor *mon, QObject **ret_data);
|
||||||
char *vnc_display_local_addr(DisplayState *ds);
|
char *vnc_display_local_addr(DisplayState *ds);
|
||||||
|
|
||||||
/* curses.c */
|
/* curses.c */
|
||||||
|
@@ -1017,7 +1017,8 @@ static inline int64_t cpu_get_real_ticks (void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif (defined(__mips_isa_rev) && __mips_isa_rev >= 2) || defined(__linux__)
|
#elif defined(__mips__) && \
|
||||||
|
((defined(__mips_isa_rev) && __mips_isa_rev >= 2) || defined(__linux__))
|
||||||
/*
|
/*
|
||||||
* binutils wants to use rdhwr only on mips32r2
|
* binutils wants to use rdhwr only on mips32r2
|
||||||
* but as linux kernel emulate it, it's fine
|
* but as linux kernel emulate it, it's fine
|
||||||
|
12
cpu-exec.c
12
cpu-exec.c
@@ -232,11 +232,13 @@ int cpu_exec(CPUState *env1)
|
|||||||
|
|
||||||
env_to_regs();
|
env_to_regs();
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
/* put eflags in CPU temporary format */
|
if (!kvm_enabled()) {
|
||||||
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
/* put eflags in CPU temporary format */
|
||||||
DF = 1 - (2 * ((env->eflags >> 10) & 1));
|
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||||
CC_OP = CC_OP_EFLAGS;
|
DF = 1 - (2 * ((env->eflags >> 10) & 1));
|
||||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
CC_OP = CC_OP_EFLAGS;
|
||||||
|
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||||
|
}
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
#elif defined(TARGET_M68K)
|
#elif defined(TARGET_M68K)
|
||||||
env->cc_op = CC_OP_FLAGS;
|
env->cc_op = CC_OP_FLAGS;
|
||||||
|
@@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
CONFIG_USB_OHCI=y
|
CONFIG_USB_OHCI=y
|
||||||
CONFIG_PTIMER=y
|
CONFIG_PTIMER=y
|
||||||
|
CONFIG_ISA_MMIO=y
|
||||||
|
@@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
CONFIG_USB_OHCI=y
|
CONFIG_USB_OHCI=y
|
||||||
CONFIG_PTIMER=y
|
CONFIG_PTIMER=y
|
||||||
|
CONFIG_ISA_MMIO=y
|
||||||
|
@@ -69,9 +69,9 @@ extern int printf(const char *, ...);
|
|||||||
#define AREG1 "r14"
|
#define AREG1 "r14"
|
||||||
#define AREG2 "r15"
|
#define AREG2 "r15"
|
||||||
#elif defined(__mips__)
|
#elif defined(__mips__)
|
||||||
#define AREG0 "fp"
|
#define AREG0 "s0"
|
||||||
#define AREG1 "s0"
|
#define AREG1 "s1"
|
||||||
#define AREG2 "s1"
|
#define AREG2 "fp"
|
||||||
#elif defined(__sparc__)
|
#elif defined(__sparc__)
|
||||||
#ifdef CONFIG_SOLARIS
|
#ifdef CONFIG_SOLARIS
|
||||||
#define AREG0 "g2"
|
#define AREG0 "g2"
|
||||||
|
2
exec.c
2
exec.c
@@ -3307,7 +3307,7 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
|
|||||||
if (is_write) {
|
if (is_write) {
|
||||||
cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
|
cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
|
||||||
}
|
}
|
||||||
qemu_free(bounce.buffer);
|
qemu_vfree(bounce.buffer);
|
||||||
bounce.buffer = NULL;
|
bounce.buffer = NULL;
|
||||||
cpu_notify_map_clients();
|
cpu_notify_map_clients();
|
||||||
}
|
}
|
||||||
|
@@ -164,7 +164,7 @@ static inline int ctz64(uint64_t val)
|
|||||||
{
|
{
|
||||||
#if QEMU_GNUC_PREREQ(3, 4)
|
#if QEMU_GNUC_PREREQ(3, 4)
|
||||||
if (val)
|
if (val)
|
||||||
return __builtin_ctz(val);
|
return __builtin_ctzll(val);
|
||||||
else
|
else
|
||||||
return 64;
|
return 64;
|
||||||
#else
|
#else
|
||||||
|
@@ -19,8 +19,15 @@ typedef struct QEMUMachine {
|
|||||||
QEMUMachineInitFunc *init;
|
QEMUMachineInitFunc *init;
|
||||||
int use_scsi;
|
int use_scsi;
|
||||||
int max_cpus;
|
int max_cpus;
|
||||||
|
int no_serial:1,
|
||||||
|
no_parallel:1,
|
||||||
|
use_virtcon:1,
|
||||||
|
no_vga:1,
|
||||||
|
no_floppy:1,
|
||||||
|
no_cdrom:1,
|
||||||
|
no_sdcard:1;
|
||||||
int is_default;
|
int is_default;
|
||||||
CompatProperty *compat_props;
|
GlobalProperty *compat_props;
|
||||||
struct QEMUMachine *next;
|
struct QEMUMachine *next;
|
||||||
} QEMUMachine;
|
} QEMUMachine;
|
||||||
|
|
||||||
|
@@ -552,7 +552,7 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
|
|||||||
BT_HID_MTU, bt_hid_new_interrupt_ch);
|
BT_HID_MTU, bt_hid_new_interrupt_ch);
|
||||||
|
|
||||||
s->usbdev = dev;
|
s->usbdev = dev;
|
||||||
s->btdev.device.lmp_name = s->usbdev->devname;
|
s->btdev.device.lmp_name = s->usbdev->product_desc;
|
||||||
usb_hid_datain_cb(s->usbdev, s, bt_hid_datain);
|
usb_hid_datain_cb(s->usbdev, s, bt_hid_datain);
|
||||||
|
|
||||||
s->btdev.device.handle_destroy = bt_hid_destroy;
|
s->btdev.device.handle_destroy = bt_hid_destroy;
|
||||||
@@ -566,6 +566,6 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
|
|||||||
|
|
||||||
struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
|
struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
|
||||||
{
|
{
|
||||||
USBDevice *dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Keyboard");
|
USBDevice *dev = usb_create_simple(NULL /* FIXME */, "usb-kbd");
|
||||||
return bt_hid_init(net, dev, class_keyboard);
|
return bt_hid_init(net, dev, class_keyboard);
|
||||||
}
|
}
|
||||||
|
@@ -2585,9 +2585,11 @@ static void map_linear_vram(CirrusVGAState *s)
|
|||||||
|
|
||||||
static void unmap_linear_vram(CirrusVGAState *s)
|
static void unmap_linear_vram(CirrusVGAState *s)
|
||||||
{
|
{
|
||||||
if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end)
|
if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
|
||||||
s->vga.map_addr = s->vga.map_end = 0;
|
s->vga.map_addr = s->vga.map_end = 0;
|
||||||
|
cpu_register_physical_memory(s->vga.lfb_addr, s->vga.vram_size,
|
||||||
|
s->cirrus_linear_io_addr);
|
||||||
|
}
|
||||||
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
|
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
|
||||||
s->vga.vga_io_memory);
|
s->vga.vga_io_memory);
|
||||||
}
|
}
|
||||||
@@ -3209,22 +3211,21 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
|
|||||||
pci_register_bar((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE,
|
pci_register_bar((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE,
|
||||||
PCI_BASE_ADDRESS_SPACE_MEMORY, cirrus_pci_mmio_map);
|
PCI_BASE_ADDRESS_SPACE_MEMORY, cirrus_pci_mmio_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ROM BIOS */
|
|
||||||
rom_add_vga(VGABIOS_CIRRUS_FILENAME);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pci_cirrus_vga_init(PCIBus *bus)
|
void pci_cirrus_vga_init(PCIBus *bus)
|
||||||
{
|
{
|
||||||
pci_create_simple(bus, -1, "Cirrus VGA");
|
pci_create_simple(bus, -1, "cirrus-vga");
|
||||||
}
|
}
|
||||||
|
|
||||||
static PCIDeviceInfo cirrus_vga_info = {
|
static PCIDeviceInfo cirrus_vga_info = {
|
||||||
.qdev.name = "Cirrus VGA",
|
.qdev.name = "cirrus-vga",
|
||||||
|
.qdev.desc = "Cirrus CLGD 54xx VGA",
|
||||||
.qdev.size = sizeof(PCICirrusVGAState),
|
.qdev.size = sizeof(PCICirrusVGAState),
|
||||||
.qdev.vmsd = &vmstate_pci_cirrus_vga,
|
.qdev.vmsd = &vmstate_pci_cirrus_vga,
|
||||||
.init = pci_cirrus_vga_initfn,
|
.init = pci_cirrus_vga_initfn,
|
||||||
|
.romfile = VGABIOS_CIRRUS_FILENAME,
|
||||||
.config_write = pci_cirrus_write_config,
|
.config_write = pci_cirrus_write_config,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
10
hw/e1000.c
10
hw/e1000.c
@@ -1089,7 +1089,6 @@ static int pci_e1000_init(PCIDevice *pci_dev)
|
|||||||
|
|
||||||
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
|
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
|
||||||
pci_config_set_device_id(pci_conf, E1000_DEVID);
|
pci_config_set_device_id(pci_conf, E1000_DEVID);
|
||||||
*(uint16_t *)(pci_conf+0x04) = cpu_to_le16(0x0407);
|
|
||||||
*(uint16_t *)(pci_conf+0x06) = cpu_to_le16(0x0010);
|
*(uint16_t *)(pci_conf+0x06) = cpu_to_le16(0x0010);
|
||||||
pci_conf[0x08] = 0x03;
|
pci_conf[0x08] = 0x03;
|
||||||
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
|
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
|
||||||
@@ -1121,14 +1120,6 @@ static int pci_e1000_init(PCIDevice *pci_dev)
|
|||||||
d->dev.qdev.info->name, d->dev.qdev.id, d);
|
d->dev.qdev.info->name, d->dev.qdev.id, d);
|
||||||
|
|
||||||
qemu_format_nic_info_str(&d->nic->nc, macaddr);
|
qemu_format_nic_info_str(&d->nic->nc, macaddr);
|
||||||
|
|
||||||
if (!pci_dev->qdev.hotplugged) {
|
|
||||||
static int loaded = 0;
|
|
||||||
if (!loaded) {
|
|
||||||
rom_add_option("pxe-e1000.bin");
|
|
||||||
loaded = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1146,6 +1137,7 @@ static PCIDeviceInfo e1000_info = {
|
|||||||
.qdev.vmsd = &vmstate_e1000,
|
.qdev.vmsd = &vmstate_e1000,
|
||||||
.init = pci_e1000_init,
|
.init = pci_e1000_init,
|
||||||
.exit = pci_e1000_uninit,
|
.exit = pci_e1000_uninit,
|
||||||
|
.romfile = "pxe-e1000.bin",
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
DEFINE_NIC_PROPERTIES(E1000State, conf),
|
DEFINE_NIC_PROPERTIES(E1000State, conf),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
65
hw/fdc.c
65
hw/fdc.c
@@ -661,7 +661,7 @@ static int fdc_post_load(void *opaque, int version_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_fdc = {
|
static const VMStateDescription vmstate_fdc = {
|
||||||
.name = "fdctrl",
|
.name = "fdc",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
.minimum_version_id = 2,
|
.minimum_version_id = 2,
|
||||||
.minimum_version_id_old = 2,
|
.minimum_version_id_old = 2,
|
||||||
@@ -699,31 +699,6 @@ static const VMStateDescription vmstate_fdc = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const VMStateDescription vmstate_fdc_isa = {
|
|
||||||
.name = "fdc",
|
|
||||||
.version_id = 2,
|
|
||||||
.minimum_version_id = 2,
|
|
||||||
.minimum_version_id_old = 2,
|
|
||||||
.fields = (VMStateField []) {
|
|
||||||
/* Controller State */
|
|
||||||
VMSTATE_STRUCT(state, fdctrl_isabus_t, 0, vmstate_fdc, fdctrl_t),
|
|
||||||
VMSTATE_END_OF_LIST()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const VMStateDescription vmstate_fdc_sysbus = {
|
|
||||||
.name = "fdc",
|
|
||||||
.version_id = 2,
|
|
||||||
.minimum_version_id = 2,
|
|
||||||
.minimum_version_id_old = 2,
|
|
||||||
.fields = (VMStateField []) {
|
|
||||||
/* Controller State */
|
|
||||||
VMSTATE_STRUCT(state, fdctrl_sysbus_t, 0, vmstate_fdc, fdctrl_t),
|
|
||||||
VMSTATE_END_OF_LIST()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void fdctrl_external_reset_sysbus(DeviceState *d)
|
static void fdctrl_external_reset_sysbus(DeviceState *d)
|
||||||
{
|
{
|
||||||
fdctrl_sysbus_t *sys = container_of(d, fdctrl_sysbus_t, busdev.qdev);
|
fdctrl_sysbus_t *sys = container_of(d, fdctrl_sysbus_t, busdev.qdev);
|
||||||
@@ -960,6 +935,12 @@ static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl)
|
|||||||
fdctrl->dsr &= ~FD_DSR_PWRDOWN;
|
fdctrl->dsr &= ~FD_DSR_PWRDOWN;
|
||||||
fdctrl->dor |= FD_DOR_nRESET;
|
fdctrl->dor |= FD_DOR_nRESET;
|
||||||
|
|
||||||
|
/* Sparc mutation */
|
||||||
|
if (fdctrl->sun4m) {
|
||||||
|
retval |= FD_MSR_DIO;
|
||||||
|
fdctrl_reset_irq(fdctrl);
|
||||||
|
};
|
||||||
|
|
||||||
FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
|
FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@@ -1879,8 +1860,12 @@ fdctrl_t *fdctrl_init_isa(DriveInfo **fds)
|
|||||||
ISADevice *dev;
|
ISADevice *dev;
|
||||||
|
|
||||||
dev = isa_create("isa-fdc");
|
dev = isa_create("isa-fdc");
|
||||||
qdev_prop_set_drive(&dev->qdev, "driveA", fds[0]);
|
if (fds[0]) {
|
||||||
qdev_prop_set_drive(&dev->qdev, "driveB", fds[1]);
|
qdev_prop_set_drive(&dev->qdev, "driveA", fds[0]);
|
||||||
|
}
|
||||||
|
if (fds[1]) {
|
||||||
|
qdev_prop_set_drive(&dev->qdev, "driveB", fds[1]);
|
||||||
|
}
|
||||||
if (qdev_init(&dev->qdev) < 0)
|
if (qdev_init(&dev->qdev) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
return &(DO_UPCAST(fdctrl_isabus_t, busdev, dev)->state);
|
return &(DO_UPCAST(fdctrl_isabus_t, busdev, dev)->state);
|
||||||
@@ -1898,8 +1883,12 @@ fdctrl_t *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
|
|||||||
sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
|
sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
|
||||||
fdctrl = &sys->state;
|
fdctrl = &sys->state;
|
||||||
fdctrl->dma_chann = dma_chann; /* FIXME */
|
fdctrl->dma_chann = dma_chann; /* FIXME */
|
||||||
qdev_prop_set_drive(dev, "driveA", fds[0]);
|
if (fds[0]) {
|
||||||
qdev_prop_set_drive(dev, "driveB", fds[1]);
|
qdev_prop_set_drive(dev, "driveA", fds[0]);
|
||||||
|
}
|
||||||
|
if (fds[1]) {
|
||||||
|
qdev_prop_set_drive(dev, "driveB", fds[1]);
|
||||||
|
}
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
sysbus_connect_irq(&sys->busdev, 0, irq);
|
sysbus_connect_irq(&sys->busdev, 0, irq);
|
||||||
sysbus_mmio_map(&sys->busdev, 0, mmio_base);
|
sysbus_mmio_map(&sys->busdev, 0, mmio_base);
|
||||||
@@ -1915,7 +1904,9 @@ fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
|
|||||||
fdctrl_t *fdctrl;
|
fdctrl_t *fdctrl;
|
||||||
|
|
||||||
dev = qdev_create(NULL, "SUNW,fdtwo");
|
dev = qdev_create(NULL, "SUNW,fdtwo");
|
||||||
qdev_prop_set_drive(dev, "drive", fds[0]);
|
if (fds[0]) {
|
||||||
|
qdev_prop_set_drive(dev, "drive", fds[0]);
|
||||||
|
}
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
|
sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
|
||||||
fdctrl = &sys->state;
|
fdctrl = &sys->state;
|
||||||
@@ -1926,7 +1917,7 @@ fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
|
|||||||
return fdctrl;
|
return fdctrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fdctrl_init_common(fdctrl_t *fdctrl)
|
static int fdctrl_init_common(fdctrl_t *fdctrl, target_phys_addr_t io_base)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
static int command_tables_inited = 0;
|
static int command_tables_inited = 0;
|
||||||
@@ -1957,6 +1948,7 @@ static int fdctrl_init_common(fdctrl_t *fdctrl)
|
|||||||
DMA_register_channel(fdctrl->dma_chann, &fdctrl_transfer_handler, fdctrl);
|
DMA_register_channel(fdctrl->dma_chann, &fdctrl_transfer_handler, fdctrl);
|
||||||
fdctrl_connect_drives(fdctrl);
|
fdctrl_connect_drives(fdctrl);
|
||||||
|
|
||||||
|
vmstate_register(io_base, &vmstate_fdc, fdctrl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1980,7 +1972,7 @@ static int isabus_fdc_init1(ISADevice *dev)
|
|||||||
isa_init_irq(&isa->busdev, &fdctrl->irq, isairq);
|
isa_init_irq(&isa->busdev, &fdctrl->irq, isairq);
|
||||||
fdctrl->dma_chann = dma_chann;
|
fdctrl->dma_chann = dma_chann;
|
||||||
|
|
||||||
ret = fdctrl_init_common(fdctrl);
|
ret = fdctrl_init_common(fdctrl, iobase);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1998,7 +1990,7 @@ static int sysbus_fdc_init1(SysBusDevice *dev)
|
|||||||
qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
|
qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
|
||||||
fdctrl->dma_chann = -1;
|
fdctrl->dma_chann = -1;
|
||||||
|
|
||||||
ret = fdctrl_init_common(fdctrl);
|
ret = fdctrl_init_common(fdctrl, io);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -2015,7 +2007,7 @@ static int sun4m_fdc_init1(SysBusDevice *dev)
|
|||||||
qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
|
qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
|
||||||
|
|
||||||
fdctrl->sun4m = 1;
|
fdctrl->sun4m = 1;
|
||||||
return fdctrl_init_common(fdctrl);
|
return fdctrl_init_common(fdctrl, io);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ISADeviceInfo isa_fdc_info = {
|
static ISADeviceInfo isa_fdc_info = {
|
||||||
@@ -2023,7 +2015,6 @@ static ISADeviceInfo isa_fdc_info = {
|
|||||||
.qdev.name = "isa-fdc",
|
.qdev.name = "isa-fdc",
|
||||||
.qdev.size = sizeof(fdctrl_isabus_t),
|
.qdev.size = sizeof(fdctrl_isabus_t),
|
||||||
.qdev.no_user = 1,
|
.qdev.no_user = 1,
|
||||||
.qdev.vmsd = &vmstate_fdc_isa,
|
|
||||||
.qdev.reset = fdctrl_external_reset_isa,
|
.qdev.reset = fdctrl_external_reset_isa,
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
DEFINE_PROP_DRIVE("driveA", fdctrl_isabus_t, state.drives[0].dinfo),
|
DEFINE_PROP_DRIVE("driveA", fdctrl_isabus_t, state.drives[0].dinfo),
|
||||||
@@ -2036,7 +2027,6 @@ static SysBusDeviceInfo sysbus_fdc_info = {
|
|||||||
.init = sysbus_fdc_init1,
|
.init = sysbus_fdc_init1,
|
||||||
.qdev.name = "sysbus-fdc",
|
.qdev.name = "sysbus-fdc",
|
||||||
.qdev.size = sizeof(fdctrl_sysbus_t),
|
.qdev.size = sizeof(fdctrl_sysbus_t),
|
||||||
.qdev.vmsd = &vmstate_fdc_sysbus,
|
|
||||||
.qdev.reset = fdctrl_external_reset_sysbus,
|
.qdev.reset = fdctrl_external_reset_sysbus,
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
DEFINE_PROP_DRIVE("driveA", fdctrl_sysbus_t, state.drives[0].dinfo),
|
DEFINE_PROP_DRIVE("driveA", fdctrl_sysbus_t, state.drives[0].dinfo),
|
||||||
@@ -2049,7 +2039,6 @@ static SysBusDeviceInfo sun4m_fdc_info = {
|
|||||||
.init = sun4m_fdc_init1,
|
.init = sun4m_fdc_init1,
|
||||||
.qdev.name = "SUNW,fdtwo",
|
.qdev.name = "SUNW,fdtwo",
|
||||||
.qdev.size = sizeof(fdctrl_sysbus_t),
|
.qdev.size = sizeof(fdctrl_sysbus_t),
|
||||||
.qdev.vmsd = &vmstate_fdc_sysbus,
|
|
||||||
.qdev.reset = fdctrl_external_reset_sysbus,
|
.qdev.reset = fdctrl_external_reset_sysbus,
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
DEFINE_PROP_DRIVE("drive", fdctrl_sysbus_t, state.drives[0].dinfo),
|
DEFINE_PROP_DRIVE("drive", fdctrl_sysbus_t, state.drives[0].dinfo),
|
||||||
|
75
hw/fw_cfg.c
75
hw/fw_cfg.c
@@ -45,11 +45,12 @@ typedef struct _FWCfgEntry {
|
|||||||
FWCfgCallback callback;
|
FWCfgCallback callback;
|
||||||
} FWCfgEntry;
|
} FWCfgEntry;
|
||||||
|
|
||||||
typedef struct _FWCfgState {
|
struct _FWCfgState {
|
||||||
FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
|
FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
|
||||||
|
FWCfgFiles *files;
|
||||||
uint16_t cur_entry;
|
uint16_t cur_entry;
|
||||||
uint32_t cur_offset;
|
uint32_t cur_offset;
|
||||||
} FWCfgState;
|
};
|
||||||
|
|
||||||
static void fw_cfg_write(FWCfgState *s, uint8_t value)
|
static void fw_cfg_write(FWCfgState *s, uint8_t value)
|
||||||
{
|
{
|
||||||
@@ -178,7 +179,7 @@ static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size)
|
|||||||
|
|
||||||
static void put_unused(QEMUFile *f, void *pv, size_t size)
|
static void put_unused(QEMUFile *f, void *pv, size_t size)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "uint32_as_uint16 is only used for backward compatibilty.\n");
|
fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n");
|
||||||
fprintf(stderr, "This functions shouldn't be called.\n");
|
fprintf(stderr, "This functions shouldn't be called.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,9 +211,8 @@ static const VMStateDescription vmstate_fw_cfg = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int fw_cfg_add_bytes(void *opaque, uint16_t key, uint8_t *data, uint32_t len)
|
int fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len)
|
||||||
{
|
{
|
||||||
FWCfgState *s = opaque;
|
|
||||||
int arch = !!(key & FW_CFG_ARCH_LOCAL);
|
int arch = !!(key & FW_CFG_ARCH_LOCAL);
|
||||||
|
|
||||||
key &= FW_CFG_ENTRY_MASK;
|
key &= FW_CFG_ENTRY_MASK;
|
||||||
@@ -226,37 +226,36 @@ int fw_cfg_add_bytes(void *opaque, uint16_t key, uint8_t *data, uint32_t len)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fw_cfg_add_i16(void *opaque, uint16_t key, uint16_t value)
|
int fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value)
|
||||||
{
|
{
|
||||||
uint16_t *copy;
|
uint16_t *copy;
|
||||||
|
|
||||||
copy = qemu_malloc(sizeof(value));
|
copy = qemu_malloc(sizeof(value));
|
||||||
*copy = cpu_to_le16(value);
|
*copy = cpu_to_le16(value);
|
||||||
return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
|
return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
int fw_cfg_add_i32(void *opaque, uint16_t key, uint32_t value)
|
int fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value)
|
||||||
{
|
{
|
||||||
uint32_t *copy;
|
uint32_t *copy;
|
||||||
|
|
||||||
copy = qemu_malloc(sizeof(value));
|
copy = qemu_malloc(sizeof(value));
|
||||||
*copy = cpu_to_le32(value);
|
*copy = cpu_to_le32(value);
|
||||||
return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
|
return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
int fw_cfg_add_i64(void *opaque, uint16_t key, uint64_t value)
|
int fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value)
|
||||||
{
|
{
|
||||||
uint64_t *copy;
|
uint64_t *copy;
|
||||||
|
|
||||||
copy = qemu_malloc(sizeof(value));
|
copy = qemu_malloc(sizeof(value));
|
||||||
*copy = cpu_to_le64(value);
|
*copy = cpu_to_le64(value);
|
||||||
return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
|
return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback,
|
int fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
|
||||||
void *callback_opaque, uint8_t *data, size_t len)
|
void *callback_opaque, uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
FWCfgState *s = opaque;
|
|
||||||
int arch = !!(key & FW_CFG_ARCH_LOCAL);
|
int arch = !!(key & FW_CFG_ARCH_LOCAL);
|
||||||
|
|
||||||
if (!(key & FW_CFG_WRITE_CHANNEL))
|
if (!(key & FW_CFG_WRITE_CHANNEL))
|
||||||
@@ -275,8 +274,54 @@ int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
int fw_cfg_add_file(FWCfgState *s, const char *dir, const char *filename,
|
||||||
target_phys_addr_t ctl_addr, target_phys_addr_t data_addr)
|
uint8_t *data, uint32_t len)
|
||||||
|
{
|
||||||
|
const char *basename;
|
||||||
|
int i, index;
|
||||||
|
|
||||||
|
if (!s->files) {
|
||||||
|
int dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
|
||||||
|
s->files = qemu_mallocz(dsize);
|
||||||
|
fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, (uint8_t*)s->files, dsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
index = be32_to_cpu(s->files->count);
|
||||||
|
if (index == FW_CFG_FILE_SLOTS) {
|
||||||
|
fprintf(stderr, "fw_cfg: out of file slots\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_cfg_add_bytes(s, FW_CFG_FILE_FIRST + index, data, len);
|
||||||
|
|
||||||
|
basename = strrchr(filename, '/');
|
||||||
|
if (basename) {
|
||||||
|
basename++;
|
||||||
|
} else {
|
||||||
|
basename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(s->files->f[index].name, sizeof(s->files->f[index].name),
|
||||||
|
"%s/%s", dir, basename);
|
||||||
|
for (i = 0; i < index; i++) {
|
||||||
|
if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) {
|
||||||
|
FW_CFG_DPRINTF("%s: skip duplicate: %s\n", __FUNCTION__,
|
||||||
|
s->files->f[index].name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s->files->f[index].size = cpu_to_be32(len);
|
||||||
|
s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
|
||||||
|
FW_CFG_DPRINTF("%s: #%d: %s (%d bytes)\n", __FUNCTION__,
|
||||||
|
index, s->files->f[index].name, len);
|
||||||
|
|
||||||
|
s->files->count = cpu_to_be32(index+1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
||||||
|
target_phys_addr_t ctl_addr, target_phys_addr_t data_addr)
|
||||||
{
|
{
|
||||||
FWCfgState *s;
|
FWCfgState *s;
|
||||||
int io_ctl_memory, io_data_memory;
|
int io_ctl_memory, io_data_memory;
|
||||||
|
35
hw/fw_cfg.h
35
hw/fw_cfg.h
@@ -26,7 +26,11 @@
|
|||||||
#define FW_CFG_SETUP_ADDR 0x16
|
#define FW_CFG_SETUP_ADDR 0x16
|
||||||
#define FW_CFG_SETUP_SIZE 0x17
|
#define FW_CFG_SETUP_SIZE 0x17
|
||||||
#define FW_CFG_SETUP_DATA 0x18
|
#define FW_CFG_SETUP_DATA 0x18
|
||||||
#define FW_CFG_MAX_ENTRY 0x19
|
#define FW_CFG_FILE_DIR 0x19
|
||||||
|
|
||||||
|
#define FW_CFG_FILE_FIRST 0x20
|
||||||
|
#define FW_CFG_FILE_SLOTS 0x10
|
||||||
|
#define FW_CFG_MAX_ENTRY (FW_CFG_FILE_FIRST+FW_CFG_FILE_SLOTS)
|
||||||
|
|
||||||
#define FW_CFG_WRITE_CHANNEL 0x4000
|
#define FW_CFG_WRITE_CHANNEL 0x4000
|
||||||
#define FW_CFG_ARCH_LOCAL 0x8000
|
#define FW_CFG_ARCH_LOCAL 0x8000
|
||||||
@@ -35,16 +39,31 @@
|
|||||||
#define FW_CFG_INVALID 0xffff
|
#define FW_CFG_INVALID 0xffff
|
||||||
|
|
||||||
#ifndef NO_QEMU_PROTOS
|
#ifndef NO_QEMU_PROTOS
|
||||||
|
typedef struct FWCfgFile {
|
||||||
|
uint32_t size; /* file size */
|
||||||
|
uint16_t select; /* write this to 0x510 to read it */
|
||||||
|
uint16_t reserved;
|
||||||
|
char name[56];
|
||||||
|
} FWCfgFile;
|
||||||
|
|
||||||
|
typedef struct FWCfgFiles {
|
||||||
|
uint32_t count;
|
||||||
|
FWCfgFile f[];
|
||||||
|
} FWCfgFiles;
|
||||||
|
|
||||||
typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
|
typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
|
||||||
|
|
||||||
int fw_cfg_add_bytes(void *opaque, uint16_t key, uint8_t *data, uint32_t len);
|
typedef struct _FWCfgState FWCfgState;
|
||||||
int fw_cfg_add_i16(void *opaque, uint16_t key, uint16_t value);
|
int fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len);
|
||||||
int fw_cfg_add_i32(void *opaque, uint16_t key, uint32_t value);
|
int fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value);
|
||||||
int fw_cfg_add_i64(void *opaque, uint16_t key, uint64_t value);
|
int fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value);
|
||||||
int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback,
|
int fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value);
|
||||||
|
int fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
|
||||||
void *callback_opaque, uint8_t *data, size_t len);
|
void *callback_opaque, uint8_t *data, size_t len);
|
||||||
void *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
int fw_cfg_add_file(FWCfgState *s, const char *dir, const char *filename,
|
||||||
target_phys_addr_t crl_addr, target_phys_addr_t data_addr);
|
uint8_t *data, uint32_t len);
|
||||||
|
FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
||||||
|
target_phys_addr_t crl_addr, target_phys_addr_t data_addr);
|
||||||
|
|
||||||
#endif /* NO_QEMU_PROTOS */
|
#endif /* NO_QEMU_PROTOS */
|
||||||
|
|
||||||
|
@@ -178,7 +178,7 @@ static PCIDeviceInfo grackle_pci_host_info = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static PCIDeviceInfo dec_21154_pci_host_info = {
|
static PCIDeviceInfo dec_21154_pci_host_info = {
|
||||||
.qdev.name = "DEC 21154",
|
.qdev.name = "dec-21154",
|
||||||
.qdev.size = sizeof(PCIDevice),
|
.qdev.size = sizeof(PCIDevice),
|
||||||
.init = dec_21154_pci_host_init,
|
.init = dec_21154_pci_host_init,
|
||||||
};
|
};
|
||||||
@@ -188,7 +188,7 @@ static void grackle_register_devices(void)
|
|||||||
sysbus_register_dev("grackle", sizeof(GrackleState),
|
sysbus_register_dev("grackle", sizeof(GrackleState),
|
||||||
pci_grackle_init_device);
|
pci_grackle_init_device);
|
||||||
pci_qdev_register(&grackle_pci_host_info);
|
pci_qdev_register(&grackle_pci_host_info);
|
||||||
sysbus_register_dev("DEC 21154", sizeof(GrackleState),
|
sysbus_register_dev("dec-21154", sizeof(GrackleState),
|
||||||
pci_dec_21154_init_device);
|
pci_dec_21154_init_device);
|
||||||
pci_qdev_register(&dec_21154_pci_host_info);
|
pci_qdev_register(&dec_21154_pci_host_info);
|
||||||
}
|
}
|
||||||
|
@@ -70,11 +70,7 @@ static void ide_map(PCIDevice *pci_dev, int region_num,
|
|||||||
|
|
||||||
static PCIIDEState *pci_from_bm(BMDMAState *bm)
|
static PCIIDEState *pci_from_bm(BMDMAState *bm)
|
||||||
{
|
{
|
||||||
if (bm->unit == 0) {
|
return bm->pci_dev;
|
||||||
return container_of(bm, PCIIDEState, bmdma[0]);
|
|
||||||
} else {
|
|
||||||
return container_of(bm, PCIIDEState, bmdma[1]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t bmdma_readb(void *opaque, uint32_t addr)
|
static uint32_t bmdma_readb(void *opaque, uint32_t addr)
|
||||||
@@ -145,6 +141,7 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
|
|||||||
BMDMAState *bm = &d->bmdma[i];
|
BMDMAState *bm = &d->bmdma[i];
|
||||||
d->bus[i].bmdma = bm;
|
d->bus[i].bmdma = bm;
|
||||||
bm->bus = d->bus+i;
|
bm->bus = d->bus+i;
|
||||||
|
bm->pci_dev = d;
|
||||||
qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
|
qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
|
||||||
|
|
||||||
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
|
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
|
||||||
@@ -245,7 +242,7 @@ void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
|
|||||||
{
|
{
|
||||||
PCIDevice *dev;
|
PCIDevice *dev;
|
||||||
|
|
||||||
dev = pci_create(bus, -1, "CMD646 IDE");
|
dev = pci_create(bus, -1, "cmd646-ide");
|
||||||
qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
|
qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
|
||||||
qdev_init_nofail(&dev->qdev);
|
qdev_init_nofail(&dev->qdev);
|
||||||
|
|
||||||
@@ -254,7 +251,7 @@ void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
|
|||||||
|
|
||||||
static PCIDeviceInfo cmd646_ide_info[] = {
|
static PCIDeviceInfo cmd646_ide_info[] = {
|
||||||
{
|
{
|
||||||
.qdev.name = "CMD646 IDE",
|
.qdev.name = "cmd646-ide",
|
||||||
.qdev.size = sizeof(PCIIDEState),
|
.qdev.size = sizeof(PCIIDEState),
|
||||||
.init = pci_cmd646_ide_initfn,
|
.init = pci_cmd646_ide_initfn,
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
|
@@ -115,7 +115,7 @@ static void ide_identify(IDEState *s)
|
|||||||
put_le16(p + 20, 3); /* XXX: retired, remove ? */
|
put_le16(p + 20, 3); /* XXX: retired, remove ? */
|
||||||
put_le16(p + 21, 512); /* cache size in sectors */
|
put_le16(p + 21, 512); /* cache size in sectors */
|
||||||
put_le16(p + 22, 4); /* ecc bytes */
|
put_le16(p + 22, 4); /* ecc bytes */
|
||||||
padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */
|
padstr((char *)(p + 23), s->version, 8); /* firmware version */
|
||||||
padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */
|
padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */
|
||||||
#if MAX_MULT_SECTORS > 1
|
#if MAX_MULT_SECTORS > 1
|
||||||
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
|
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
|
||||||
@@ -186,7 +186,7 @@ static void ide_atapi_identify(IDEState *s)
|
|||||||
put_le16(p + 20, 3); /* buffer type */
|
put_le16(p + 20, 3); /* buffer type */
|
||||||
put_le16(p + 21, 512); /* cache size in sectors */
|
put_le16(p + 21, 512); /* cache size in sectors */
|
||||||
put_le16(p + 22, 4); /* ecc bytes */
|
put_le16(p + 22, 4); /* ecc bytes */
|
||||||
padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */
|
padstr((char *)(p + 23), s->version, 8); /* firmware version */
|
||||||
padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */
|
padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */
|
||||||
put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
|
put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
|
||||||
#ifdef USE_DMA_CDROM
|
#ifdef USE_DMA_CDROM
|
||||||
@@ -238,7 +238,7 @@ static void ide_cfata_identify(IDEState *s)
|
|||||||
put_le16(p + 8, s->nb_sectors); /* Sectors per card */
|
put_le16(p + 8, s->nb_sectors); /* Sectors per card */
|
||||||
padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
|
padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
|
||||||
put_le16(p + 22, 0x0004); /* ECC bytes */
|
put_le16(p + 22, 0x0004); /* ECC bytes */
|
||||||
padstr((char *) (p + 23), QEMU_VERSION, 8); /* Firmware Revision */
|
padstr((char *) (p + 23), s->version, 8); /* Firmware Revision */
|
||||||
padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */
|
padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */
|
||||||
#if MAX_MULT_SECTORS > 1
|
#if MAX_MULT_SECTORS > 1
|
||||||
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
|
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
|
||||||
@@ -1591,7 +1591,7 @@ static void ide_atapi_cmd(IDEState *s)
|
|||||||
buf[7] = 0; /* reserved */
|
buf[7] = 0; /* reserved */
|
||||||
padstr8(buf + 8, 8, "QEMU");
|
padstr8(buf + 8, 8, "QEMU");
|
||||||
padstr8(buf + 16, 16, "QEMU DVD-ROM");
|
padstr8(buf + 16, 16, "QEMU DVD-ROM");
|
||||||
padstr8(buf + 32, 4, QEMU_VERSION);
|
padstr8(buf + 32, 4, s->version);
|
||||||
ide_atapi_cmd_reply(s, 36, max_len);
|
ide_atapi_cmd_reply(s, 36, max_len);
|
||||||
break;
|
break;
|
||||||
case GPCMD_GET_CONFIGURATION:
|
case GPCMD_GET_CONFIGURATION:
|
||||||
@@ -2590,7 +2590,7 @@ void ide_bus_reset(IDEBus *bus)
|
|||||||
ide_clear_hob(bus);
|
ide_clear_hob(bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ide_init_drive(IDEState *s, DriveInfo *dinfo)
|
void ide_init_drive(IDEState *s, DriveInfo *dinfo, const char *version)
|
||||||
{
|
{
|
||||||
int cylinders, heads, secs;
|
int cylinders, heads, secs;
|
||||||
uint64_t nb_sectors;
|
uint64_t nb_sectors;
|
||||||
@@ -2619,6 +2619,11 @@ void ide_init_drive(IDEState *s, DriveInfo *dinfo)
|
|||||||
if (strlen(s->drive_serial_str) == 0)
|
if (strlen(s->drive_serial_str) == 0)
|
||||||
snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
|
snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
|
||||||
"QM%05d", s->drive_serial);
|
"QM%05d", s->drive_serial);
|
||||||
|
if (version) {
|
||||||
|
pstrcpy(s->version, sizeof(s->version), version);
|
||||||
|
} else {
|
||||||
|
pstrcpy(s->version, sizeof(s->version), QEMU_VERSION);
|
||||||
|
}
|
||||||
ide_reset(s);
|
ide_reset(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2635,13 +2640,14 @@ void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
|
|||||||
s->unit = i;
|
s->unit = i;
|
||||||
s->drive_serial = drive_serial++;
|
s->drive_serial = drive_serial++;
|
||||||
s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
|
s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
|
||||||
|
s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
|
||||||
s->smart_selftest_data = qemu_blockalign(s->bs, 512);
|
s->smart_selftest_data = qemu_blockalign(s->bs, 512);
|
||||||
s->sector_write_timer = qemu_new_timer(vm_clock,
|
s->sector_write_timer = qemu_new_timer(vm_clock,
|
||||||
ide_sector_write_timer_cb, s);
|
ide_sector_write_timer_cb, s);
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
ide_init_drive(s, hd0);
|
ide_init_drive(s, hd0, NULL);
|
||||||
if (i == 1)
|
if (i == 1)
|
||||||
ide_init_drive(s, hd1);
|
ide_init_drive(s, hd1, NULL);
|
||||||
}
|
}
|
||||||
bus->irq = irq;
|
bus->irq = irq;
|
||||||
}
|
}
|
||||||
@@ -2669,6 +2675,25 @@ static bool is_identify_set(void *opaque, int version_id)
|
|||||||
return s->identify_set != 0;
|
return s->identify_set != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EndTransferFunc* transfer_end_table[] = {
|
||||||
|
ide_sector_read,
|
||||||
|
ide_sector_write,
|
||||||
|
ide_transfer_stop,
|
||||||
|
ide_atapi_cmd_reply_end,
|
||||||
|
ide_atapi_cmd,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int transfer_end_table_idx(EndTransferFunc *fn)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++)
|
||||||
|
if (transfer_end_table[i] == fn)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int ide_drive_post_load(void *opaque, int version_id)
|
static int ide_drive_post_load(void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
IDEState *s = opaque;
|
IDEState *s = opaque;
|
||||||
@@ -2679,14 +2704,42 @@ static int ide_drive_post_load(void *opaque, int version_id)
|
|||||||
s->cdrom_changed = 1;
|
s->cdrom_changed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s->cur_io_buffer_len) {
|
||||||
|
s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
|
||||||
|
s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
|
||||||
|
s->data_end = s->data_ptr + s->cur_io_buffer_len;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ide_drive_pre_save(void *opaque)
|
||||||
|
{
|
||||||
|
IDEState *s = opaque;
|
||||||
|
|
||||||
|
s->cur_io_buffer_len = 0;
|
||||||
|
|
||||||
|
if (!(s->status & DRQ_STAT))
|
||||||
|
return;
|
||||||
|
|
||||||
|
s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
|
||||||
|
s->cur_io_buffer_len = s->data_end - s->data_ptr;
|
||||||
|
|
||||||
|
s->end_transfer_fn_idx = transfer_end_table_idx(s->end_transfer_func);
|
||||||
|
if (s->end_transfer_fn_idx == -1) {
|
||||||
|
fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
|
||||||
|
__func__);
|
||||||
|
s->end_transfer_fn_idx = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const VMStateDescription vmstate_ide_drive = {
|
const VMStateDescription vmstate_ide_drive = {
|
||||||
.name = "ide_drive",
|
.name = "ide_drive",
|
||||||
.version_id = 3,
|
.version_id = 4,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
.minimum_version_id_old = 0,
|
||||||
|
.pre_save = ide_drive_pre_save,
|
||||||
.post_load = ide_drive_post_load,
|
.post_load = ide_drive_post_load,
|
||||||
.fields = (VMStateField []) {
|
.fields = (VMStateField []) {
|
||||||
VMSTATE_INT32(mult_sectors, IDEState),
|
VMSTATE_INT32(mult_sectors, IDEState),
|
||||||
@@ -2709,7 +2762,14 @@ const VMStateDescription vmstate_ide_drive = {
|
|||||||
VMSTATE_UINT8(sense_key, IDEState),
|
VMSTATE_UINT8(sense_key, IDEState),
|
||||||
VMSTATE_UINT8(asc, IDEState),
|
VMSTATE_UINT8(asc, IDEState),
|
||||||
VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
|
VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
|
||||||
/* XXX: if a transfer is pending, we do not save it yet */
|
VMSTATE_INT32_V(req_nb_sectors, IDEState, 4),
|
||||||
|
VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 4,
|
||||||
|
vmstate_info_uint8, uint8_t),
|
||||||
|
VMSTATE_INT32_V(cur_io_buffer_offset, IDEState, 4),
|
||||||
|
VMSTATE_INT32_V(cur_io_buffer_len, IDEState, 4),
|
||||||
|
VMSTATE_UINT8_V(end_transfer_fn_idx, IDEState, 4),
|
||||||
|
VMSTATE_INT32_V(elementary_transfer_size, IDEState, 4),
|
||||||
|
VMSTATE_INT32_V(packet_transfer_size, IDEState, 4),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -397,6 +397,7 @@ struct IDEState {
|
|||||||
/* set for lba48 access */
|
/* set for lba48 access */
|
||||||
uint8_t lba48;
|
uint8_t lba48;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
char version[9];
|
||||||
/* ATAPI specific */
|
/* ATAPI specific */
|
||||||
uint8_t sense_key;
|
uint8_t sense_key;
|
||||||
uint8_t asc;
|
uint8_t asc;
|
||||||
@@ -416,6 +417,11 @@ struct IDEState {
|
|||||||
uint8_t *data_ptr;
|
uint8_t *data_ptr;
|
||||||
uint8_t *data_end;
|
uint8_t *data_end;
|
||||||
uint8_t *io_buffer;
|
uint8_t *io_buffer;
|
||||||
|
/* PIO save/restore */
|
||||||
|
int32_t io_buffer_total_len;
|
||||||
|
int cur_io_buffer_offset;
|
||||||
|
int cur_io_buffer_len;
|
||||||
|
uint8_t end_transfer_fn_idx;
|
||||||
QEMUTimer *sector_write_timer; /* only used for win2k install hack */
|
QEMUTimer *sector_write_timer; /* only used for win2k install hack */
|
||||||
uint32_t irq_count; /* counts IRQs when using win2k install hack */
|
uint32_t irq_count; /* counts IRQs when using win2k install hack */
|
||||||
/* CF-ATA extended error */
|
/* CF-ATA extended error */
|
||||||
@@ -449,6 +455,7 @@ struct IDEDevice {
|
|||||||
DeviceState qdev;
|
DeviceState qdev;
|
||||||
uint32_t unit;
|
uint32_t unit;
|
||||||
DriveInfo *dinfo;
|
DriveInfo *dinfo;
|
||||||
|
char *version;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*ide_qdev_initfn)(IDEDevice *dev);
|
typedef int (*ide_qdev_initfn)(IDEDevice *dev);
|
||||||
@@ -474,6 +481,7 @@ struct BMDMAState {
|
|||||||
uint8_t status;
|
uint8_t status;
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
|
|
||||||
|
struct PCIIDEState *pci_dev;
|
||||||
IDEBus *bus;
|
IDEBus *bus;
|
||||||
/* current transfer state */
|
/* current transfer state */
|
||||||
uint32_t cur_addr;
|
uint32_t cur_addr;
|
||||||
@@ -548,7 +556,7 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr);
|
|||||||
void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
|
void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
|
||||||
uint32_t ide_data_readl(void *opaque, uint32_t addr);
|
uint32_t ide_data_readl(void *opaque, uint32_t addr);
|
||||||
|
|
||||||
void ide_init_drive(IDEState *s, DriveInfo *dinfo);
|
void ide_init_drive(IDEState *s, DriveInfo *dinfo, const char *version);
|
||||||
void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
|
void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
|
||||||
qemu_irq irq);
|
qemu_irq irq);
|
||||||
void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
|
void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
|
||||||
|
@@ -78,6 +78,7 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
|
|||||||
BMDMAState *bm = &d->bmdma[i];
|
BMDMAState *bm = &d->bmdma[i];
|
||||||
d->bus[i].bmdma = bm;
|
d->bus[i].bmdma = bm;
|
||||||
bm->bus = d->bus+i;
|
bm->bus = d->bus+i;
|
||||||
|
bm->pci_dev = d;
|
||||||
qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
|
qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
|
||||||
|
|
||||||
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
|
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
|
||||||
@@ -161,7 +162,7 @@ void pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
|
|||||||
{
|
{
|
||||||
PCIDevice *dev;
|
PCIDevice *dev;
|
||||||
|
|
||||||
dev = pci_create_simple(bus, devfn, "PIIX3 IDE");
|
dev = pci_create_simple(bus, devfn, "piix3-ide");
|
||||||
pci_ide_create_devs(dev, hd_table);
|
pci_ide_create_devs(dev, hd_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,18 +172,18 @@ void pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
|
|||||||
{
|
{
|
||||||
PCIDevice *dev;
|
PCIDevice *dev;
|
||||||
|
|
||||||
dev = pci_create_simple(bus, devfn, "PIIX4 IDE");
|
dev = pci_create_simple(bus, devfn, "piix4-ide");
|
||||||
pci_ide_create_devs(dev, hd_table);
|
pci_ide_create_devs(dev, hd_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PCIDeviceInfo piix_ide_info[] = {
|
static PCIDeviceInfo piix_ide_info[] = {
|
||||||
{
|
{
|
||||||
.qdev.name = "PIIX3 IDE",
|
.qdev.name = "piix3-ide",
|
||||||
.qdev.size = sizeof(PCIIDEState),
|
.qdev.size = sizeof(PCIIDEState),
|
||||||
.qdev.no_user = 1,
|
.qdev.no_user = 1,
|
||||||
.init = pci_piix3_ide_initfn,
|
.init = pci_piix3_ide_initfn,
|
||||||
},{
|
},{
|
||||||
.qdev.name = "PIIX4 IDE",
|
.qdev.name = "piix4-ide",
|
||||||
.qdev.size = sizeof(PCIIDEState),
|
.qdev.size = sizeof(PCIIDEState),
|
||||||
.qdev.no_user = 1,
|
.qdev.no_user = 1,
|
||||||
.init = pci_piix4_ide_initfn,
|
.init = pci_piix4_ide_initfn,
|
||||||
|
@@ -99,7 +99,7 @@ typedef struct IDEDrive {
|
|||||||
static int ide_drive_initfn(IDEDevice *dev)
|
static int ide_drive_initfn(IDEDevice *dev)
|
||||||
{
|
{
|
||||||
IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
|
IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
|
||||||
ide_init_drive(bus->ifs + dev->unit, dev->dinfo);
|
ide_init_drive(bus->ifs + dev->unit, dev->dinfo, dev->version);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +110,7 @@ static IDEDeviceInfo ide_drive_info = {
|
|||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1),
|
DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1),
|
||||||
DEFINE_PROP_DRIVE("drive", IDEDrive, dev.dinfo),
|
DEFINE_PROP_DRIVE("drive", IDEDrive, dev.dinfo),
|
||||||
|
DEFINE_PROP_STRING("ver", IDEDrive, dev.version),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
136
hw/loader.c
136
hw/loader.c
@@ -48,6 +48,7 @@
|
|||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
#include "uboot_image.h"
|
#include "uboot_image.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
|
#include "fw_cfg.h"
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
@@ -526,15 +527,15 @@ struct Rom {
|
|||||||
char *path;
|
char *path;
|
||||||
size_t romsize;
|
size_t romsize;
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
int align;
|
|
||||||
int isrom;
|
int isrom;
|
||||||
|
char *fw_dir;
|
||||||
|
char *fw_file;
|
||||||
|
|
||||||
target_phys_addr_t min;
|
|
||||||
target_phys_addr_t max;
|
|
||||||
target_phys_addr_t addr;
|
target_phys_addr_t addr;
|
||||||
QTAILQ_ENTRY(Rom) next;
|
QTAILQ_ENTRY(Rom) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static FWCfgState *fw_cfg;
|
||||||
static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms);
|
static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms);
|
||||||
int rom_enable_driver_roms;
|
int rom_enable_driver_roms;
|
||||||
|
|
||||||
@@ -548,7 +549,7 @@ static void rom_insert(Rom *rom)
|
|||||||
|
|
||||||
/* list is ordered by load address */
|
/* list is ordered by load address */
|
||||||
QTAILQ_FOREACH(item, &roms, next) {
|
QTAILQ_FOREACH(item, &roms, next) {
|
||||||
if (rom->min >= item->min)
|
if (rom->addr >= item->addr)
|
||||||
continue;
|
continue;
|
||||||
QTAILQ_INSERT_BEFORE(item, rom, next);
|
QTAILQ_INSERT_BEFORE(item, rom, next);
|
||||||
return;
|
return;
|
||||||
@@ -556,8 +557,8 @@ static void rom_insert(Rom *rom)
|
|||||||
QTAILQ_INSERT_TAIL(&roms, rom, next);
|
QTAILQ_INSERT_TAIL(&roms, rom, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rom_add_file(const char *file,
|
int rom_add_file(const char *file, const char *fw_dir,
|
||||||
target_phys_addr_t min, target_phys_addr_t max, int align)
|
target_phys_addr_t addr)
|
||||||
{
|
{
|
||||||
Rom *rom;
|
Rom *rom;
|
||||||
int rc, fd = -1;
|
int rc, fd = -1;
|
||||||
@@ -576,9 +577,11 @@ int rom_add_file(const char *file,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
rom->align = align;
|
if (fw_dir) {
|
||||||
rom->min = min;
|
rom->fw_dir = qemu_strdup(fw_dir);
|
||||||
rom->max = max;
|
rom->fw_file = qemu_strdup(file);
|
||||||
|
}
|
||||||
|
rom->addr = addr;
|
||||||
rom->romsize = lseek(fd, 0, SEEK_END);
|
rom->romsize = lseek(fd, 0, SEEK_END);
|
||||||
rom->data = qemu_mallocz(rom->romsize);
|
rom->data = qemu_mallocz(rom->romsize);
|
||||||
lseek(fd, 0, SEEK_SET);
|
lseek(fd, 0, SEEK_SET);
|
||||||
@@ -590,6 +593,8 @@ int rom_add_file(const char *file,
|
|||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
rom_insert(rom);
|
rom_insert(rom);
|
||||||
|
if (rom->fw_file && fw_cfg)
|
||||||
|
fw_cfg_add_file(fw_cfg, rom->fw_dir, rom->fw_file, rom->data, rom->romsize);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@@ -603,15 +608,13 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int rom_add_blob(const char *name, const void *blob, size_t len,
|
int rom_add_blob(const char *name, const void *blob, size_t len,
|
||||||
target_phys_addr_t min, target_phys_addr_t max, int align)
|
target_phys_addr_t addr)
|
||||||
{
|
{
|
||||||
Rom *rom;
|
Rom *rom;
|
||||||
|
|
||||||
rom = qemu_mallocz(sizeof(*rom));
|
rom = qemu_mallocz(sizeof(*rom));
|
||||||
rom->name = qemu_strdup(name);
|
rom->name = qemu_strdup(name);
|
||||||
rom->align = align;
|
rom->addr = addr;
|
||||||
rom->min = min;
|
|
||||||
rom->max = max;
|
|
||||||
rom->romsize = len;
|
rom->romsize = len;
|
||||||
rom->data = qemu_mallocz(rom->romsize);
|
rom->data = qemu_mallocz(rom->romsize);
|
||||||
memcpy(rom->data, blob, len);
|
memcpy(rom->data, blob, len);
|
||||||
@@ -623,14 +626,14 @@ int rom_add_vga(const char *file)
|
|||||||
{
|
{
|
||||||
if (!rom_enable_driver_roms)
|
if (!rom_enable_driver_roms)
|
||||||
return 0;
|
return 0;
|
||||||
return rom_add_file(file, PC_ROM_MIN_VGA, PC_ROM_MAX, PC_ROM_ALIGN);
|
return rom_add_file(file, "vgaroms", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rom_add_option(const char *file)
|
int rom_add_option(const char *file)
|
||||||
{
|
{
|
||||||
if (!rom_enable_driver_roms)
|
if (!rom_enable_driver_roms)
|
||||||
return 0;
|
return 0;
|
||||||
return rom_add_file(file, PC_ROM_MIN_OPTION, PC_ROM_MAX, PC_ROM_ALIGN);
|
return rom_add_file(file, "genroms", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rom_reset(void *unused)
|
static void rom_reset(void *unused)
|
||||||
@@ -638,8 +641,12 @@ static void rom_reset(void *unused)
|
|||||||
Rom *rom;
|
Rom *rom;
|
||||||
|
|
||||||
QTAILQ_FOREACH(rom, &roms, next) {
|
QTAILQ_FOREACH(rom, &roms, next) {
|
||||||
if (rom->data == NULL)
|
if (rom->fw_file) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
if (rom->data == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize);
|
cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize);
|
||||||
if (rom->isrom) {
|
if (rom->isrom) {
|
||||||
/* rom needs to be written only once */
|
/* rom needs to be written only once */
|
||||||
@@ -656,32 +663,17 @@ int rom_load_all(void)
|
|||||||
Rom *rom;
|
Rom *rom;
|
||||||
|
|
||||||
QTAILQ_FOREACH(rom, &roms, next) {
|
QTAILQ_FOREACH(rom, &roms, next) {
|
||||||
if (addr < rom->min)
|
if (rom->fw_file) {
|
||||||
addr = rom->min;
|
continue;
|
||||||
if (rom->max) {
|
|
||||||
/* load address range */
|
|
||||||
if (rom->align) {
|
|
||||||
addr += (rom->align-1);
|
|
||||||
addr &= ~(rom->align-1);
|
|
||||||
}
|
|
||||||
if (addr + rom->romsize > rom->max) {
|
|
||||||
fprintf(stderr, "rom: out of memory (rom %s, "
|
|
||||||
"addr 0x" TARGET_FMT_plx
|
|
||||||
", size 0x%zx, max 0x" TARGET_FMT_plx ")\n",
|
|
||||||
rom->name, addr, rom->romsize, rom->max);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* fixed address requested */
|
|
||||||
if (addr != rom->min) {
|
|
||||||
fprintf(stderr, "rom: requested regions overlap "
|
|
||||||
"(rom %s. free=0x" TARGET_FMT_plx
|
|
||||||
", addr=0x" TARGET_FMT_plx ")\n",
|
|
||||||
rom->name, addr, rom->min);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rom->addr = addr;
|
if (addr > rom->addr) {
|
||||||
|
fprintf(stderr, "rom: requested regions overlap "
|
||||||
|
"(rom %s. free=0x" TARGET_FMT_plx
|
||||||
|
", addr=0x" TARGET_FMT_plx ")\n",
|
||||||
|
rom->name, addr, rom->addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
addr = rom->addr;
|
||||||
addr += rom->romsize;
|
addr += rom->romsize;
|
||||||
memtype = cpu_get_physical_page_desc(rom->addr) & (3 << IO_MEM_SHIFT);
|
memtype = cpu_get_physical_page_desc(rom->addr) & (3 << IO_MEM_SHIFT);
|
||||||
if (memtype == IO_MEM_ROM)
|
if (memtype == IO_MEM_ROM)
|
||||||
@@ -692,22 +684,35 @@ int rom_load_all(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rom_set_fw(void *f)
|
||||||
|
{
|
||||||
|
fw_cfg = f;
|
||||||
|
}
|
||||||
|
|
||||||
static Rom *find_rom(target_phys_addr_t addr)
|
static Rom *find_rom(target_phys_addr_t addr)
|
||||||
{
|
{
|
||||||
Rom *rom;
|
Rom *rom;
|
||||||
|
|
||||||
QTAILQ_FOREACH(rom, &roms, next) {
|
QTAILQ_FOREACH(rom, &roms, next) {
|
||||||
if (rom->max)
|
if (rom->fw_file) {
|
||||||
continue;
|
continue;
|
||||||
if (rom->min > addr)
|
}
|
||||||
|
if (rom->addr > addr) {
|
||||||
continue;
|
continue;
|
||||||
if (rom->min + rom->romsize < addr)
|
}
|
||||||
|
if (rom->addr + rom->romsize < addr) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
return rom;
|
return rom;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copies memory from registered ROMs to dest. Any memory that is contained in
|
||||||
|
* a ROM between addr and addr + size is copied. Note that this can involve
|
||||||
|
* multiple ROMs, which need not start at addr and need not end at addr + size.
|
||||||
|
*/
|
||||||
int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size)
|
int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size)
|
||||||
{
|
{
|
||||||
target_phys_addr_t end = addr + size;
|
target_phys_addr_t end = addr + size;
|
||||||
@@ -716,25 +721,27 @@ int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size)
|
|||||||
Rom *rom;
|
Rom *rom;
|
||||||
|
|
||||||
QTAILQ_FOREACH(rom, &roms, next) {
|
QTAILQ_FOREACH(rom, &roms, next) {
|
||||||
if (rom->max)
|
if (rom->fw_file) {
|
||||||
continue;
|
continue;
|
||||||
if (rom->min > addr)
|
}
|
||||||
|
if (rom->addr + rom->romsize < addr) {
|
||||||
continue;
|
continue;
|
||||||
if (rom->min + rom->romsize < addr)
|
}
|
||||||
continue;
|
if (rom->addr > end) {
|
||||||
if (rom->min > end)
|
|
||||||
break;
|
break;
|
||||||
if (!rom->data)
|
}
|
||||||
|
if (!rom->data) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
d = dest + (rom->min - addr);
|
d = dest + (rom->addr - addr);
|
||||||
s = rom->data;
|
s = rom->data;
|
||||||
l = rom->romsize;
|
l = rom->romsize;
|
||||||
|
|
||||||
if (rom->min < addr) {
|
if (rom->addr < addr) {
|
||||||
d = dest;
|
d = dest;
|
||||||
s += (addr - rom->min);
|
s += (addr - rom->addr);
|
||||||
l -= (addr - rom->min);
|
l -= (addr - rom->addr);
|
||||||
}
|
}
|
||||||
if ((d + l) > (dest + size)) {
|
if ((d + l) > (dest + size)) {
|
||||||
l = dest - d;
|
l = dest - d;
|
||||||
@@ -753,7 +760,7 @@ void *rom_ptr(target_phys_addr_t addr)
|
|||||||
rom = find_rom(addr);
|
rom = find_rom(addr);
|
||||||
if (!rom || !rom->data)
|
if (!rom || !rom->data)
|
||||||
return NULL;
|
return NULL;
|
||||||
return rom->data + (addr - rom->min);
|
return rom->data + (addr - rom->addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_info_roms(Monitor *mon)
|
void do_info_roms(Monitor *mon)
|
||||||
@@ -761,10 +768,19 @@ void do_info_roms(Monitor *mon)
|
|||||||
Rom *rom;
|
Rom *rom;
|
||||||
|
|
||||||
QTAILQ_FOREACH(rom, &roms, next) {
|
QTAILQ_FOREACH(rom, &roms, next) {
|
||||||
monitor_printf(mon, "addr=" TARGET_FMT_plx
|
if (!rom->fw_file) {
|
||||||
" size=0x%06zx mem=%s name=\"%s\" \n",
|
monitor_printf(mon, "addr=" TARGET_FMT_plx
|
||||||
rom->addr, rom->romsize,
|
" size=0x%06zx mem=%s name=\"%s\" \n",
|
||||||
rom->isrom ? "rom" : "ram",
|
rom->addr, rom->romsize,
|
||||||
rom->name);
|
rom->isrom ? "rom" : "ram",
|
||||||
|
rom->name);
|
||||||
|
} else {
|
||||||
|
monitor_printf(mon, "fw=%s/%s"
|
||||||
|
" size=0x%06zx name=\"%s\" \n",
|
||||||
|
rom->fw_dir,
|
||||||
|
rom->fw_file,
|
||||||
|
rom->romsize,
|
||||||
|
rom->name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
hw/loader.h
12
hw/loader.h
@@ -19,19 +19,21 @@ void pstrcpy_targphys(const char *name,
|
|||||||
target_phys_addr_t dest, int buf_size,
|
target_phys_addr_t dest, int buf_size,
|
||||||
const char *source);
|
const char *source);
|
||||||
|
|
||||||
int rom_add_file(const char *file,
|
|
||||||
target_phys_addr_t min, target_phys_addr_t max, int align);
|
int rom_add_file(const char *file, const char *fw_dir,
|
||||||
|
target_phys_addr_t addr);
|
||||||
int rom_add_blob(const char *name, const void *blob, size_t len,
|
int rom_add_blob(const char *name, const void *blob, size_t len,
|
||||||
target_phys_addr_t min, target_phys_addr_t max, int align);
|
target_phys_addr_t addr);
|
||||||
int rom_load_all(void);
|
int rom_load_all(void);
|
||||||
|
void rom_set_fw(void *f);
|
||||||
int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size);
|
int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size);
|
||||||
void *rom_ptr(target_phys_addr_t addr);
|
void *rom_ptr(target_phys_addr_t addr);
|
||||||
void do_info_roms(Monitor *mon);
|
void do_info_roms(Monitor *mon);
|
||||||
|
|
||||||
#define rom_add_file_fixed(_f, _a) \
|
#define rom_add_file_fixed(_f, _a) \
|
||||||
rom_add_file(_f, _a, 0, 0)
|
rom_add_file(_f, NULL, _a)
|
||||||
#define rom_add_blob_fixed(_f, _b, _l, _a) \
|
#define rom_add_blob_fixed(_f, _b, _l, _a) \
|
||||||
rom_add_blob(_f, _b, _l, _a, 0, 0)
|
rom_add_blob(_f, _b, _l, _a)
|
||||||
|
|
||||||
#define PC_ROM_MIN_VGA 0xc0000
|
#define PC_ROM_MIN_VGA 0xc0000
|
||||||
#define PC_ROM_MIN_OPTION 0xc8000
|
#define PC_ROM_MIN_OPTION 0xc8000
|
||||||
|
176
hw/lsi53c895a.c
176
hw/lsi53c895a.c
@@ -173,11 +173,15 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
|
|||||||
/* Flag set if this is a tagged command. */
|
/* Flag set if this is a tagged command. */
|
||||||
#define LSI_TAG_VALID (1 << 16)
|
#define LSI_TAG_VALID (1 << 16)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct lsi_request {
|
||||||
uint32_t tag;
|
uint32_t tag;
|
||||||
|
SCSIDevice *dev;
|
||||||
|
uint32_t dma_len;
|
||||||
|
uint8_t *dma_buf;
|
||||||
uint32_t pending;
|
uint32_t pending;
|
||||||
int out;
|
int out;
|
||||||
} lsi_queue;
|
QTAILQ_ENTRY(lsi_request) next;
|
||||||
|
} lsi_request;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PCIDevice dev;
|
PCIDevice dev;
|
||||||
@@ -198,16 +202,13 @@ typedef struct {
|
|||||||
* 3 if a DMA operation is in progress. */
|
* 3 if a DMA operation is in progress. */
|
||||||
int waiting;
|
int waiting;
|
||||||
SCSIBus bus;
|
SCSIBus bus;
|
||||||
SCSIDevice *current_dev;
|
SCSIDevice *select_dev;
|
||||||
int current_lun;
|
int current_lun;
|
||||||
/* The tag is a combination of the device ID and the SCSI tag. */
|
/* The tag is a combination of the device ID and the SCSI tag. */
|
||||||
uint32_t current_tag;
|
uint32_t select_tag;
|
||||||
uint32_t current_dma_len;
|
|
||||||
int command_complete;
|
int command_complete;
|
||||||
uint8_t *dma_buf;
|
QTAILQ_HEAD(, lsi_request) queue;
|
||||||
lsi_queue *queue;
|
lsi_request *current;
|
||||||
int queue_len;
|
|
||||||
int active_commands;
|
|
||||||
|
|
||||||
uint32_t dsa;
|
uint32_t dsa;
|
||||||
uint32_t temp;
|
uint32_t temp;
|
||||||
@@ -370,7 +371,7 @@ static int lsi_dma_64bit(LSIState *s)
|
|||||||
static uint8_t lsi_reg_readb(LSIState *s, int offset);
|
static uint8_t lsi_reg_readb(LSIState *s, int offset);
|
||||||
static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
|
static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
|
||||||
static void lsi_execute_script(LSIState *s);
|
static void lsi_execute_script(LSIState *s);
|
||||||
static void lsi_reselect(LSIState *s, uint32_t tag);
|
static void lsi_reselect(LSIState *s, lsi_request *p);
|
||||||
|
|
||||||
static inline uint32_t read_dword(LSIState *s, uint32_t addr)
|
static inline uint32_t read_dword(LSIState *s, uint32_t addr)
|
||||||
{
|
{
|
||||||
@@ -391,9 +392,9 @@ static void lsi_stop_script(LSIState *s)
|
|||||||
|
|
||||||
static void lsi_update_irq(LSIState *s)
|
static void lsi_update_irq(LSIState *s)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int level;
|
int level;
|
||||||
static int last_level;
|
static int last_level;
|
||||||
|
lsi_request *p;
|
||||||
|
|
||||||
/* It's unclear whether the DIP/SIP bits should be cleared when the
|
/* It's unclear whether the DIP/SIP bits should be cleared when the
|
||||||
Interrupt Status Registers are cleared or when istat0 is read.
|
Interrupt Status Registers are cleared or when istat0 is read.
|
||||||
@@ -427,9 +428,9 @@ static void lsi_update_irq(LSIState *s)
|
|||||||
if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
|
if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
|
||||||
DPRINTF("Handled IRQs & disconnected, looking for pending "
|
DPRINTF("Handled IRQs & disconnected, looking for pending "
|
||||||
"processes\n");
|
"processes\n");
|
||||||
for (i = 0; i < s->active_commands; i++) {
|
QTAILQ_FOREACH(p, &s->queue, next) {
|
||||||
if (s->queue[i].pending) {
|
if (p->pending) {
|
||||||
lsi_reselect(s, s->queue[i].tag);
|
lsi_reselect(s, p);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -508,15 +509,16 @@ static void lsi_do_dma(LSIState *s, int out)
|
|||||||
uint32_t count;
|
uint32_t count;
|
||||||
target_phys_addr_t addr;
|
target_phys_addr_t addr;
|
||||||
|
|
||||||
if (!s->current_dma_len) {
|
assert(s->current);
|
||||||
|
if (!s->current->dma_len) {
|
||||||
/* Wait until data is available. */
|
/* Wait until data is available. */
|
||||||
DPRINTF("DMA no data available\n");
|
DPRINTF("DMA no data available\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = s->dbc;
|
count = s->dbc;
|
||||||
if (count > s->current_dma_len)
|
if (count > s->current->dma_len)
|
||||||
count = s->current_dma_len;
|
count = s->current->dma_len;
|
||||||
|
|
||||||
addr = s->dnad;
|
addr = s->dnad;
|
||||||
/* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
|
/* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
|
||||||
@@ -532,29 +534,29 @@ static void lsi_do_dma(LSIState *s, int out)
|
|||||||
s->dnad += count;
|
s->dnad += count;
|
||||||
s->dbc -= count;
|
s->dbc -= count;
|
||||||
|
|
||||||
if (s->dma_buf == NULL) {
|
if (s->current->dma_buf == NULL) {
|
||||||
s->dma_buf = s->current_dev->info->get_buf(s->current_dev,
|
s->current->dma_buf = s->current->dev->info->get_buf(s->current->dev,
|
||||||
s->current_tag);
|
s->current->tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ??? Set SFBR to first data byte. */
|
/* ??? Set SFBR to first data byte. */
|
||||||
if (out) {
|
if (out) {
|
||||||
cpu_physical_memory_read(addr, s->dma_buf, count);
|
cpu_physical_memory_read(addr, s->current->dma_buf, count);
|
||||||
} else {
|
} else {
|
||||||
cpu_physical_memory_write(addr, s->dma_buf, count);
|
cpu_physical_memory_write(addr, s->current->dma_buf, count);
|
||||||
}
|
}
|
||||||
s->current_dma_len -= count;
|
s->current->dma_len -= count;
|
||||||
if (s->current_dma_len == 0) {
|
if (s->current->dma_len == 0) {
|
||||||
s->dma_buf = NULL;
|
s->current->dma_buf = NULL;
|
||||||
if (out) {
|
if (out) {
|
||||||
/* Write the data. */
|
/* Write the data. */
|
||||||
s->current_dev->info->write_data(s->current_dev, s->current_tag);
|
s->current->dev->info->write_data(s->current->dev, s->current->tag);
|
||||||
} else {
|
} else {
|
||||||
/* Request any remaining data. */
|
/* Request any remaining data. */
|
||||||
s->current_dev->info->read_data(s->current_dev, s->current_tag);
|
s->current->dev->info->read_data(s->current->dev, s->current->tag);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s->dma_buf += count;
|
s->current->dma_buf += count;
|
||||||
lsi_resume_script(s);
|
lsi_resume_script(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,15 +565,14 @@ static void lsi_do_dma(LSIState *s, int out)
|
|||||||
/* Add a command to the queue. */
|
/* Add a command to the queue. */
|
||||||
static void lsi_queue_command(LSIState *s)
|
static void lsi_queue_command(LSIState *s)
|
||||||
{
|
{
|
||||||
lsi_queue *p;
|
lsi_request *p = s->current;
|
||||||
|
|
||||||
DPRINTF("Queueing tag=0x%x\n", s->current_tag);
|
DPRINTF("Queueing tag=0x%x\n", s->current_tag);
|
||||||
if (s->queue_len == s->active_commands) {
|
assert(s->current != NULL);
|
||||||
s->queue_len++;
|
assert(s->current->dma_len == 0);
|
||||||
s->queue = qemu_realloc(s->queue, s->queue_len * sizeof(lsi_queue));
|
QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
|
||||||
}
|
s->current = NULL;
|
||||||
p = &s->queue[s->active_commands++];
|
|
||||||
p->tag = s->current_tag;
|
|
||||||
p->pending = 0;
|
p->pending = 0;
|
||||||
p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
|
p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
|
||||||
}
|
}
|
||||||
@@ -588,45 +589,29 @@ static void lsi_add_msg_byte(LSIState *s, uint8_t data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Perform reselection to continue a command. */
|
/* Perform reselection to continue a command. */
|
||||||
static void lsi_reselect(LSIState *s, uint32_t tag)
|
static void lsi_reselect(LSIState *s, lsi_request *p)
|
||||||
{
|
{
|
||||||
lsi_queue *p;
|
|
||||||
int n;
|
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
p = NULL;
|
assert(s->current == NULL);
|
||||||
for (n = 0; n < s->active_commands; n++) {
|
QTAILQ_REMOVE(&s->queue, p, next);
|
||||||
p = &s->queue[n];
|
s->current = p;
|
||||||
if (p->tag == tag)
|
|
||||||
break;
|
id = (p->tag >> 8) & 0xf;
|
||||||
}
|
|
||||||
if (n == s->active_commands) {
|
|
||||||
BADF("Reselected non-existant command tag=0x%x\n", tag);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
id = (tag >> 8) & 0xf;
|
|
||||||
s->ssid = id | 0x80;
|
s->ssid = id | 0x80;
|
||||||
/* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
|
/* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
|
||||||
if (!s->dcntl & LSI_DCNTL_COM) {
|
if (!s->dcntl & LSI_DCNTL_COM) {
|
||||||
s->sfbr = 1 << (id & 0x7);
|
s->sfbr = 1 << (id & 0x7);
|
||||||
}
|
}
|
||||||
DPRINTF("Reselected target %d\n", id);
|
DPRINTF("Reselected target %d\n", id);
|
||||||
s->current_dev = s->bus.devs[id];
|
|
||||||
s->current_tag = tag;
|
|
||||||
s->scntl1 |= LSI_SCNTL1_CON;
|
s->scntl1 |= LSI_SCNTL1_CON;
|
||||||
lsi_set_phase(s, PHASE_MI);
|
lsi_set_phase(s, PHASE_MI);
|
||||||
s->msg_action = p->out ? 2 : 3;
|
s->msg_action = p->out ? 2 : 3;
|
||||||
s->current_dma_len = p->pending;
|
s->current->dma_len = p->pending;
|
||||||
s->dma_buf = NULL;
|
|
||||||
lsi_add_msg_byte(s, 0x80);
|
lsi_add_msg_byte(s, 0x80);
|
||||||
if (s->current_tag & LSI_TAG_VALID) {
|
if (s->current->tag & LSI_TAG_VALID) {
|
||||||
lsi_add_msg_byte(s, 0x20);
|
lsi_add_msg_byte(s, 0x20);
|
||||||
lsi_add_msg_byte(s, tag & 0xff);
|
lsi_add_msg_byte(s, p->tag & 0xff);
|
||||||
}
|
|
||||||
|
|
||||||
s->active_commands--;
|
|
||||||
if (n != s->active_commands) {
|
|
||||||
s->queue[n] = s->queue[s->active_commands];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lsi_irq_on_rsl(s)) {
|
if (lsi_irq_on_rsl(s)) {
|
||||||
@@ -638,10 +623,9 @@ static void lsi_reselect(LSIState *s, uint32_t tag)
|
|||||||
the device was reselected, nonzero if the IO is deferred. */
|
the device was reselected, nonzero if the IO is deferred. */
|
||||||
static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
|
static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
|
||||||
{
|
{
|
||||||
lsi_queue *p;
|
lsi_request *p;
|
||||||
int i;
|
|
||||||
for (i = 0; i < s->active_commands; i++) {
|
QTAILQ_FOREACH(p, &s->queue, next) {
|
||||||
p = &s->queue[i];
|
|
||||||
if (p->tag == tag) {
|
if (p->tag == tag) {
|
||||||
if (p->pending) {
|
if (p->pending) {
|
||||||
BADF("Multiple IO pending for tag %d\n", tag);
|
BADF("Multiple IO pending for tag %d\n", tag);
|
||||||
@@ -656,10 +640,10 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
|
|||||||
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
|
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
|
||||||
!(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
|
!(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
|
||||||
/* Reselect device. */
|
/* Reselect device. */
|
||||||
lsi_reselect(s, tag);
|
lsi_reselect(s, p);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
DPRINTF("Queueing IO tag=0x%x\n", tag);
|
DPRINTF("Queueing IO tag=0x%x\n", tag);
|
||||||
p->pending = arg;
|
p->pending = arg;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -687,11 +671,15 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
|
|||||||
} else {
|
} else {
|
||||||
lsi_set_phase(s, PHASE_ST);
|
lsi_set_phase(s, PHASE_ST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_free(s->current);
|
||||||
|
s->current = NULL;
|
||||||
|
|
||||||
lsi_resume_script(s);
|
lsi_resume_script(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->waiting == 1 || tag != s->current_tag ||
|
if (s->waiting == 1 || !s->current || tag != s->current->tag ||
|
||||||
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
|
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
|
||||||
if (lsi_queue_tag(s, tag, arg))
|
if (lsi_queue_tag(s, tag, arg))
|
||||||
return;
|
return;
|
||||||
@@ -699,7 +687,7 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
|
|||||||
|
|
||||||
/* host adapter (re)connected */
|
/* host adapter (re)connected */
|
||||||
DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg);
|
DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg);
|
||||||
s->current_dma_len = arg;
|
s->current->dma_len = arg;
|
||||||
s->command_complete = 1;
|
s->command_complete = 1;
|
||||||
if (!s->waiting)
|
if (!s->waiting)
|
||||||
return;
|
return;
|
||||||
@@ -721,14 +709,20 @@ static void lsi_do_command(LSIState *s)
|
|||||||
cpu_physical_memory_read(s->dnad, buf, s->dbc);
|
cpu_physical_memory_read(s->dnad, buf, s->dbc);
|
||||||
s->sfbr = buf[0];
|
s->sfbr = buf[0];
|
||||||
s->command_complete = 0;
|
s->command_complete = 0;
|
||||||
n = s->current_dev->info->send_command(s->current_dev, s->current_tag, buf,
|
|
||||||
s->current_lun);
|
assert(s->current == NULL);
|
||||||
|
s->current = qemu_mallocz(sizeof(lsi_request));
|
||||||
|
s->current->tag = s->select_tag;
|
||||||
|
s->current->dev = s->select_dev;
|
||||||
|
|
||||||
|
n = s->current->dev->info->send_command(s->current->dev, s->current->tag, buf,
|
||||||
|
s->current_lun);
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
lsi_set_phase(s, PHASE_DI);
|
lsi_set_phase(s, PHASE_DI);
|
||||||
s->current_dev->info->read_data(s->current_dev, s->current_tag);
|
s->current->dev->info->read_data(s->current->dev, s->current->tag);
|
||||||
} else if (n < 0) {
|
} else if (n < 0) {
|
||||||
lsi_set_phase(s, PHASE_DO);
|
lsi_set_phase(s, PHASE_DO);
|
||||||
s->current_dev->info->write_data(s->current_dev, s->current_tag);
|
s->current->dev->info->write_data(s->current->dev, s->current->tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s->command_complete) {
|
if (!s->command_complete) {
|
||||||
@@ -851,16 +845,16 @@ static void lsi_do_msgout(LSIState *s)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x20: /* SIMPLE queue */
|
case 0x20: /* SIMPLE queue */
|
||||||
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||||
DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff);
|
DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff);
|
||||||
break;
|
break;
|
||||||
case 0x21: /* HEAD of queue */
|
case 0x21: /* HEAD of queue */
|
||||||
BADF("HEAD queue not implemented\n");
|
BADF("HEAD queue not implemented\n");
|
||||||
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||||
break;
|
break;
|
||||||
case 0x22: /* ORDERED queue */
|
case 0x22: /* ORDERED queue */
|
||||||
BADF("ORDERED queue not implemented\n");
|
BADF("ORDERED queue not implemented\n");
|
||||||
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if ((msg & 0x80) == 0) {
|
if ((msg & 0x80) == 0) {
|
||||||
@@ -905,17 +899,17 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
|
|||||||
|
|
||||||
static void lsi_wait_reselect(LSIState *s)
|
static void lsi_wait_reselect(LSIState *s)
|
||||||
{
|
{
|
||||||
int i;
|
lsi_request *p;
|
||||||
|
|
||||||
DPRINTF("Wait Reselect\n");
|
DPRINTF("Wait Reselect\n");
|
||||||
if (s->current_dma_len)
|
|
||||||
BADF("Reselect with pending DMA\n");
|
QTAILQ_FOREACH(p, &s->queue, next) {
|
||||||
for (i = 0; i < s->active_commands; i++) {
|
if (p->pending) {
|
||||||
if (s->queue[i].pending) {
|
lsi_reselect(s, p);
|
||||||
lsi_reselect(s, s->queue[i].tag);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (s->current_dma_len == 0) {
|
if (s->current == NULL) {
|
||||||
s->waiting = 1;
|
s->waiting = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1093,8 +1087,8 @@ again:
|
|||||||
/* ??? Linux drivers compain when this is set. Maybe
|
/* ??? Linux drivers compain when this is set. Maybe
|
||||||
it only applies in low-level mode (unimplemented).
|
it only applies in low-level mode (unimplemented).
|
||||||
lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
|
lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
|
||||||
s->current_dev = s->bus.devs[id];
|
s->select_dev = s->bus.devs[id];
|
||||||
s->current_tag = id << 8;
|
s->select_tag = id << 8;
|
||||||
s->scntl1 |= LSI_SCNTL1_CON;
|
s->scntl1 |= LSI_SCNTL1_CON;
|
||||||
if (insn & (1 << 3)) {
|
if (insn & (1 << 3)) {
|
||||||
s->socl |= LSI_SOCL_ATN;
|
s->socl |= LSI_SOCL_ATN;
|
||||||
@@ -2006,9 +2000,11 @@ static void lsi_pre_save(void *opaque)
|
|||||||
{
|
{
|
||||||
LSIState *s = opaque;
|
LSIState *s = opaque;
|
||||||
|
|
||||||
assert(s->dma_buf == NULL);
|
if (s->current) {
|
||||||
assert(s->current_dma_len == 0);
|
assert(s->current->dma_buf == NULL);
|
||||||
assert(s->active_commands == 0);
|
assert(s->current->dma_len == 0);
|
||||||
|
}
|
||||||
|
assert(QTAILQ_EMPTY(&s->queue));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_lsi_scsi = {
|
static const VMStateDescription vmstate_lsi_scsi = {
|
||||||
@@ -2101,8 +2097,6 @@ static int lsi_scsi_uninit(PCIDevice *d)
|
|||||||
cpu_unregister_io_memory(s->mmio_io_addr);
|
cpu_unregister_io_memory(s->mmio_io_addr);
|
||||||
cpu_unregister_io_memory(s->ram_io_addr);
|
cpu_unregister_io_memory(s->ram_io_addr);
|
||||||
|
|
||||||
qemu_free(s->queue);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2138,9 +2132,7 @@ static int lsi_scsi_init(PCIDevice *dev)
|
|||||||
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc);
|
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc);
|
||||||
pci_register_bar((struct PCIDevice *)s, 2, 0x2000,
|
pci_register_bar((struct PCIDevice *)s, 2, 0x2000,
|
||||||
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
|
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
|
||||||
s->queue = qemu_malloc(sizeof(lsi_queue));
|
QTAILQ_INIT(&s->queue);
|
||||||
s->queue_len = 1;
|
|
||||||
s->active_commands = 0;
|
|
||||||
|
|
||||||
lsi_soft_reset(s);
|
lsi_soft_reset(s);
|
||||||
|
|
||||||
|
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
//#define DEBUG_CMOS
|
//#define DEBUG_CMOS
|
||||||
|
|
||||||
|
#define RTC_REINJECT_ON_ACK_COUNT 20
|
||||||
|
|
||||||
#define RTC_SECONDS 0
|
#define RTC_SECONDS 0
|
||||||
#define RTC_SECONDS_ALARM 1
|
#define RTC_SECONDS_ALARM 1
|
||||||
#define RTC_MINUTES 2
|
#define RTC_MINUTES 2
|
||||||
@@ -76,6 +78,7 @@ struct RTCState {
|
|||||||
int64_t next_periodic_time;
|
int64_t next_periodic_time;
|
||||||
/* second update */
|
/* second update */
|
||||||
int64_t next_second_time;
|
int64_t next_second_time;
|
||||||
|
uint16_t irq_reinject_on_ack_count;
|
||||||
uint32_t irq_coalesced;
|
uint32_t irq_coalesced;
|
||||||
uint32_t period;
|
uint32_t period;
|
||||||
QEMUTimer *coalesced_timer;
|
QEMUTimer *coalesced_timer;
|
||||||
@@ -180,6 +183,8 @@ static void rtc_periodic_timer(void *opaque)
|
|||||||
s->cmos_data[RTC_REG_C] |= 0xc0;
|
s->cmos_data[RTC_REG_C] |= 0xc0;
|
||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
if(rtc_td_hack) {
|
if(rtc_td_hack) {
|
||||||
|
if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
|
||||||
|
s->irq_reinject_on_ack_count = 0;
|
||||||
apic_reset_irq_delivered();
|
apic_reset_irq_delivered();
|
||||||
rtc_irq_raise(s->irq);
|
rtc_irq_raise(s->irq);
|
||||||
if (!apic_get_irq_delivered()) {
|
if (!apic_get_irq_delivered()) {
|
||||||
@@ -458,6 +463,18 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
|
|||||||
case RTC_REG_C:
|
case RTC_REG_C:
|
||||||
ret = s->cmos_data[s->cmos_index];
|
ret = s->cmos_data[s->cmos_index];
|
||||||
qemu_irq_lower(s->irq);
|
qemu_irq_lower(s->irq);
|
||||||
|
#ifdef TARGET_I386
|
||||||
|
if(s->irq_coalesced &&
|
||||||
|
s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) {
|
||||||
|
s->irq_reinject_on_ack_count++;
|
||||||
|
apic_reset_irq_delivered();
|
||||||
|
qemu_irq_raise(s->irq);
|
||||||
|
if (apic_get_irq_delivered())
|
||||||
|
s->irq_coalesced--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
s->cmos_data[RTC_REG_C] = 0x00;
|
s->cmos_data[RTC_REG_C] = 0x00;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
74
hw/msix.c
74
hw/msix.c
@@ -20,6 +20,7 @@
|
|||||||
#define PCI_MSIX_FLAGS 2 /* Table at lower 11 bits */
|
#define PCI_MSIX_FLAGS 2 /* Table at lower 11 bits */
|
||||||
#define PCI_MSIX_FLAGS_QSIZE 0x7FF
|
#define PCI_MSIX_FLAGS_QSIZE 0x7FF
|
||||||
#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
|
#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
|
||||||
|
#define PCI_MSIX_FLAGS_MASKALL (1 << 14)
|
||||||
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
|
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
|
||||||
|
|
||||||
/* MSI-X capability structure */
|
/* MSI-X capability structure */
|
||||||
@@ -27,9 +28,10 @@
|
|||||||
#define MSIX_PBA_OFFSET 8
|
#define MSIX_PBA_OFFSET 8
|
||||||
#define MSIX_CAP_LENGTH 12
|
#define MSIX_CAP_LENGTH 12
|
||||||
|
|
||||||
/* MSI enable bit is in byte 1 in FLAGS register */
|
/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */
|
||||||
#define MSIX_ENABLE_OFFSET (PCI_MSIX_FLAGS + 1)
|
#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1)
|
||||||
#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
|
#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
|
||||||
|
#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8)
|
||||||
|
|
||||||
/* MSI-X table format */
|
/* MSI-X table format */
|
||||||
#define MSIX_MSG_ADDR 0
|
#define MSIX_MSG_ADDR 0
|
||||||
@@ -101,22 +103,11 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
|
|||||||
bar_nr);
|
bar_nr);
|
||||||
pdev->msix_cap = config_offset;
|
pdev->msix_cap = config_offset;
|
||||||
/* Make flags bit writeable. */
|
/* Make flags bit writeable. */
|
||||||
pdev->wmask[config_offset + MSIX_ENABLE_OFFSET] |= MSIX_ENABLE_MASK;
|
pdev->wmask[config_offset + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK |
|
||||||
|
MSIX_MASKALL_MASK;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle MSI-X capability config write. */
|
|
||||||
void msix_write_config(PCIDevice *dev, uint32_t addr,
|
|
||||||
uint32_t val, int len)
|
|
||||||
{
|
|
||||||
unsigned enable_pos = dev->msix_cap + MSIX_ENABLE_OFFSET;
|
|
||||||
if (addr + len <= enable_pos || addr > enable_pos)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (msix_enabled(dev))
|
|
||||||
qemu_set_irq(dev->irq[0], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr)
|
static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr)
|
||||||
{
|
{
|
||||||
PCIDevice *dev = opaque;
|
PCIDevice *dev = opaque;
|
||||||
@@ -157,10 +148,50 @@ static void msix_clr_pending(PCIDevice *dev, int vector)
|
|||||||
*msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector);
|
*msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int msix_function_masked(PCIDevice *dev)
|
||||||
|
{
|
||||||
|
return dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
static int msix_is_masked(PCIDevice *dev, int vector)
|
static int msix_is_masked(PCIDevice *dev, int vector)
|
||||||
{
|
{
|
||||||
unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL;
|
unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL;
|
||||||
return dev->msix_table_page[offset] & MSIX_VECTOR_MASK;
|
return msix_function_masked(dev) ||
|
||||||
|
dev->msix_table_page[offset] & MSIX_VECTOR_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void msix_handle_mask_update(PCIDevice *dev, int vector)
|
||||||
|
{
|
||||||
|
if (!msix_is_masked(dev, vector) && msix_is_pending(dev, vector)) {
|
||||||
|
msix_clr_pending(dev, vector);
|
||||||
|
msix_notify(dev, vector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle MSI-X capability config write. */
|
||||||
|
void msix_write_config(PCIDevice *dev, uint32_t addr,
|
||||||
|
uint32_t val, int len)
|
||||||
|
{
|
||||||
|
unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
|
||||||
|
int vector;
|
||||||
|
|
||||||
|
if (addr + len <= enable_pos || addr > enable_pos) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!msix_enabled(dev)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_set_irq(dev->irq[0], 0);
|
||||||
|
|
||||||
|
if (msix_function_masked(dev)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
|
||||||
|
msix_handle_mask_update(dev, vector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
|
static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
|
||||||
@@ -170,10 +201,7 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
|
|||||||
unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
|
unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
|
||||||
int vector = offset / MSIX_ENTRY_SIZE;
|
int vector = offset / MSIX_ENTRY_SIZE;
|
||||||
pci_set_long(dev->msix_table_page + offset, val);
|
pci_set_long(dev->msix_table_page + offset, val);
|
||||||
if (!msix_is_masked(dev, vector) && msix_is_pending(dev, vector)) {
|
msix_handle_mask_update(dev, vector);
|
||||||
msix_clr_pending(dev, vector);
|
|
||||||
msix_notify(dev, vector);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void msix_mmio_write_unallowed(void *opaque, target_phys_addr_t addr,
|
static void msix_mmio_write_unallowed(void *opaque, target_phys_addr_t addr,
|
||||||
@@ -327,7 +355,7 @@ int msix_present(PCIDevice *dev)
|
|||||||
int msix_enabled(PCIDevice *dev)
|
int msix_enabled(PCIDevice *dev)
|
||||||
{
|
{
|
||||||
return (dev->cap_present & QEMU_PCI_CAP_MSIX) &&
|
return (dev->cap_present & QEMU_PCI_CAP_MSIX) &&
|
||||||
(dev->config[dev->msix_cap + MSIX_ENABLE_OFFSET] &
|
(dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
|
||||||
MSIX_ENABLE_MASK);
|
MSIX_ENABLE_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,8 +391,8 @@ void msix_reset(PCIDevice *dev)
|
|||||||
if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
|
if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
|
||||||
return;
|
return;
|
||||||
msix_free_irq_entries(dev);
|
msix_free_irq_entries(dev);
|
||||||
dev->config[dev->msix_cap + MSIX_ENABLE_OFFSET] &=
|
dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
|
||||||
~dev->wmask[dev->msix_cap + MSIX_ENABLE_OFFSET];
|
~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
|
||||||
memset(dev->msix_table_page, 0, MSIX_PAGE_SIZE);
|
memset(dev->msix_table_page, 0, MSIX_PAGE_SIZE);
|
||||||
msix_mask_all(dev, dev->msix_entries_nr);
|
msix_mask_all(dev, dev->msix_entries_nr);
|
||||||
}
|
}
|
||||||
|
@@ -67,7 +67,7 @@
|
|||||||
#define MP_AUDIO_IRQ 30
|
#define MP_AUDIO_IRQ 30
|
||||||
|
|
||||||
/* Wolfson 8750 I2C address */
|
/* Wolfson 8750 I2C address */
|
||||||
#define MP_WM_ADDR 0x34
|
#define MP_WM_ADDR 0x1A
|
||||||
|
|
||||||
/* Ethernet register offsets */
|
/* Ethernet register offsets */
|
||||||
#define MP_ETH_SMIR 0x010
|
#define MP_ETH_SMIR 0x010
|
||||||
@@ -238,14 +238,13 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index)
|
|||||||
{
|
{
|
||||||
uint32_t desc_addr = s->tx_queue[queue_index];
|
uint32_t desc_addr = s->tx_queue[queue_index];
|
||||||
mv88w8618_tx_desc desc;
|
mv88w8618_tx_desc desc;
|
||||||
|
uint32_t next_desc;
|
||||||
uint8_t buf[2048];
|
uint8_t buf[2048];
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (!desc_addr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
do {
|
do {
|
||||||
eth_tx_desc_get(desc_addr, &desc);
|
eth_tx_desc_get(desc_addr, &desc);
|
||||||
|
next_desc = desc.next;
|
||||||
if (desc.cmdstat & MP_ETH_TX_OWN) {
|
if (desc.cmdstat & MP_ETH_TX_OWN) {
|
||||||
len = desc.bytes;
|
len = desc.bytes;
|
||||||
if (len < 2048) {
|
if (len < 2048) {
|
||||||
@@ -256,7 +255,7 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index)
|
|||||||
s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
|
s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
|
||||||
eth_tx_desc_put(desc_addr, &desc);
|
eth_tx_desc_put(desc_addr, &desc);
|
||||||
}
|
}
|
||||||
desc_addr = desc.next;
|
desc_addr = next_desc;
|
||||||
} while (desc_addr != s->tx_queue[queue_index]);
|
} while (desc_addr != s->tx_queue[queue_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
55
hw/pc.c
55
hw/pc.c
@@ -560,19 +560,21 @@ static int load_multiboot(void *fw_cfg,
|
|||||||
}
|
}
|
||||||
if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
|
if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
|
||||||
uint64_t elf_entry;
|
uint64_t elf_entry;
|
||||||
|
uint64_t elf_low, elf_high;
|
||||||
int kernel_size;
|
int kernel_size;
|
||||||
fclose(f);
|
fclose(f);
|
||||||
kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
|
kernel_size = load_elf(kernel_filename, 0, &elf_entry, &elf_low, &elf_high,
|
||||||
0, ELF_MACHINE, 0);
|
0, ELF_MACHINE, 0);
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
fprintf(stderr, "Error while loading elf kernel\n");
|
fprintf(stderr, "Error while loading elf kernel\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
mh_load_addr = mh_entry_addr = elf_entry;
|
mh_load_addr = elf_low;
|
||||||
mb_kernel_size = kernel_size;
|
mb_kernel_size = elf_high - elf_low;
|
||||||
|
mh_entry_addr = elf_entry;
|
||||||
|
|
||||||
mb_kernel_data = qemu_malloc(mb_kernel_size);
|
mb_kernel_data = qemu_malloc(mb_kernel_size);
|
||||||
if (rom_copy(mb_kernel_data, elf_entry, kernel_size) != kernel_size) {
|
if (rom_copy(mb_kernel_data, mh_load_addr, mb_kernel_size) != mb_kernel_size) {
|
||||||
fprintf(stderr, "Error while fetching elf kernel from rom\n");
|
fprintf(stderr, "Error while fetching elf kernel from rom\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -1088,6 +1090,7 @@ static void pc_init1(ram_addr_t ram_size,
|
|||||||
bios_size, bios_offset | IO_MEM_ROM);
|
bios_size, bios_offset | IO_MEM_ROM);
|
||||||
|
|
||||||
fw_cfg = bochs_bios_init();
|
fw_cfg = bochs_bios_init();
|
||||||
|
rom_set_fw(fw_cfg);
|
||||||
|
|
||||||
if (linux_boot) {
|
if (linux_boot) {
|
||||||
load_linux(fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size);
|
load_linux(fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size);
|
||||||
@@ -1285,7 +1288,7 @@ void cmos_set_s3_resume(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static QEMUMachine pc_machine = {
|
static QEMUMachine pc_machine = {
|
||||||
.name = "pc-0.11",
|
.name = "pc-0.12",
|
||||||
.alias = "pc",
|
.alias = "pc",
|
||||||
.desc = "Standard PC",
|
.desc = "Standard PC",
|
||||||
.init = pc_init_pci,
|
.init = pc_init_pci,
|
||||||
@@ -1293,12 +1296,39 @@ static QEMUMachine pc_machine = {
|
|||||||
.is_default = 1,
|
.is_default = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static QEMUMachine pc_machine_v0_11 = {
|
||||||
|
.name = "pc-0.11",
|
||||||
|
.desc = "Standard PC, qemu 0.11",
|
||||||
|
.init = pc_init_pci,
|
||||||
|
.max_cpus = 255,
|
||||||
|
.compat_props = (GlobalProperty[]) {
|
||||||
|
{
|
||||||
|
.driver = "virtio-blk-pci",
|
||||||
|
.property = "vectors",
|
||||||
|
.value = stringify(0),
|
||||||
|
},{
|
||||||
|
.driver = "ide-drive",
|
||||||
|
.property = "ver",
|
||||||
|
.value = "0.11",
|
||||||
|
},{
|
||||||
|
.driver = "scsi-disk",
|
||||||
|
.property = "ver",
|
||||||
|
.value = "0.11",
|
||||||
|
},{
|
||||||
|
.driver = "PCI",
|
||||||
|
.property = "rombar",
|
||||||
|
.value = stringify(0),
|
||||||
|
},
|
||||||
|
{ /* end of list */ }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static QEMUMachine pc_machine_v0_10 = {
|
static QEMUMachine pc_machine_v0_10 = {
|
||||||
.name = "pc-0.10",
|
.name = "pc-0.10",
|
||||||
.desc = "Standard PC, qemu 0.10",
|
.desc = "Standard PC, qemu 0.10",
|
||||||
.init = pc_init_pci,
|
.init = pc_init_pci,
|
||||||
.max_cpus = 255,
|
.max_cpus = 255,
|
||||||
.compat_props = (CompatProperty[]) {
|
.compat_props = (GlobalProperty[]) {
|
||||||
{
|
{
|
||||||
.driver = "virtio-blk-pci",
|
.driver = "virtio-blk-pci",
|
||||||
.property = "class",
|
.property = "class",
|
||||||
@@ -1315,6 +1345,18 @@ static QEMUMachine pc_machine_v0_10 = {
|
|||||||
.driver = "virtio-blk-pci",
|
.driver = "virtio-blk-pci",
|
||||||
.property = "vectors",
|
.property = "vectors",
|
||||||
.value = stringify(0),
|
.value = stringify(0),
|
||||||
|
},{
|
||||||
|
.driver = "ide-drive",
|
||||||
|
.property = "ver",
|
||||||
|
.value = "0.10",
|
||||||
|
},{
|
||||||
|
.driver = "scsi-disk",
|
||||||
|
.property = "ver",
|
||||||
|
.value = "0.10",
|
||||||
|
},{
|
||||||
|
.driver = "PCI",
|
||||||
|
.property = "rombar",
|
||||||
|
.value = stringify(0),
|
||||||
},
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
},
|
},
|
||||||
@@ -1330,6 +1372,7 @@ static QEMUMachine isapc_machine = {
|
|||||||
static void pc_machine_init(void)
|
static void pc_machine_init(void)
|
||||||
{
|
{
|
||||||
qemu_register_machine(&pc_machine);
|
qemu_register_machine(&pc_machine);
|
||||||
|
qemu_register_machine(&pc_machine_v0_11);
|
||||||
qemu_register_machine(&pc_machine_v0_10);
|
qemu_register_machine(&pc_machine_v0_10);
|
||||||
qemu_register_machine(&isapc_machine);
|
qemu_register_machine(&isapc_machine);
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
#include "scsi.h"
|
#include "scsi.h"
|
||||||
#include "virtio-blk.h"
|
#include "virtio-blk.h"
|
||||||
#include "qemu-config.h"
|
#include "qemu-config.h"
|
||||||
|
#include "qemu-objects.h"
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
|
static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
|
||||||
@@ -40,7 +41,18 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
|
|||||||
const char *opts_str)
|
const char *opts_str)
|
||||||
{
|
{
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
int ret;
|
PCIBus *bus;
|
||||||
|
int ret, devfn;
|
||||||
|
|
||||||
|
bus = pci_get_bus_devfn(&devfn, devaddr);
|
||||||
|
if (!bus) {
|
||||||
|
monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!((BusState*)bus)->allow_hotplug) {
|
||||||
|
monitor_printf(mon, "PCI bus doesn't support hotplug\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", NULL);
|
opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", NULL);
|
||||||
if (!opts) {
|
if (!opts) {
|
||||||
@@ -82,6 +94,7 @@ static int scsi_hot_add(DeviceState *adapter, DriveInfo *dinfo, int printinfo)
|
|||||||
*/
|
*/
|
||||||
dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
|
dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
|
||||||
scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo, dinfo->unit);
|
scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo, dinfo->unit);
|
||||||
|
dinfo->unit = scsidev->id;
|
||||||
|
|
||||||
if (printinfo)
|
if (printinfo)
|
||||||
qemu_error("OK bus %d, unit %d\n", scsibus->busnr, scsidev->id);
|
qemu_error("OK bus %d, unit %d\n", scsibus->busnr, scsidev->id);
|
||||||
@@ -179,17 +192,17 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
|
|||||||
monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
|
monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (!((BusState*)bus)->allow_hotplug) {
|
||||||
|
monitor_printf(mon, "PCI bus doesn't support hotplug\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case IF_SCSI:
|
case IF_SCSI:
|
||||||
if (!dinfo) {
|
|
||||||
monitor_printf(mon, "scsi requires a backing file/device.\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
dev = pci_create(bus, devfn, "lsi53c895a");
|
dev = pci_create(bus, devfn, "lsi53c895a");
|
||||||
if (qdev_init(&dev->qdev) < 0)
|
if (qdev_init(&dev->qdev) < 0)
|
||||||
dev = NULL;
|
dev = NULL;
|
||||||
if (dev) {
|
if (dev && dinfo) {
|
||||||
if (scsi_hot_add(&dev->qdev, dinfo, 0) != 0) {
|
if (scsi_hot_add(&dev->qdev, dinfo, 0) != 0) {
|
||||||
qdev_unplug(&dev->qdev);
|
qdev_unplug(&dev->qdev);
|
||||||
dev = NULL;
|
dev = NULL;
|
||||||
@@ -212,7 +225,36 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
|
|||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pci_device_hot_add(Monitor *mon, const QDict *qdict)
|
void pci_device_hot_add_print(Monitor *mon, const QObject *data)
|
||||||
|
{
|
||||||
|
QDict *qdict;
|
||||||
|
|
||||||
|
assert(qobject_type(data) == QTYPE_QDICT);
|
||||||
|
qdict = qobject_to_qdict(data);
|
||||||
|
|
||||||
|
monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n",
|
||||||
|
(int) qdict_get_int(qdict, "domain"),
|
||||||
|
(int) qdict_get_int(qdict, "bus"),
|
||||||
|
(int) qdict_get_int(qdict, "slot"),
|
||||||
|
(int) qdict_get_int(qdict, "function"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_device_hot_add(): Hot add a PCI device
|
||||||
|
*
|
||||||
|
* Return a QDict with the following device information:
|
||||||
|
*
|
||||||
|
* - "domain": domain number
|
||||||
|
* - "bus": bus number
|
||||||
|
* - "slot": slot number
|
||||||
|
* - "function": function number
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* { "domain": 0, "bus": 0, "slot": 5, "function": 0 }
|
||||||
|
*/
|
||||||
|
void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||||
{
|
{
|
||||||
PCIDevice *dev = NULL;
|
PCIDevice *dev = NULL;
|
||||||
const char *pci_addr = qdict_get_str(qdict, "pci_addr");
|
const char *pci_addr = qdict_get_str(qdict, "pci_addr");
|
||||||
@@ -239,9 +281,11 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict)
|
|||||||
monitor_printf(mon, "invalid type: %s\n", type);
|
monitor_printf(mon, "invalid type: %s\n", type);
|
||||||
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n",
|
*ret_data =
|
||||||
0, pci_bus_num(dev->bus), PCI_SLOT(dev->devfn),
|
qobject_from_jsonf("{ 'domain': 0, 'bus': %d, 'slot': %d, "
|
||||||
PCI_FUNC(dev->devfn));
|
"'function': %d }", pci_bus_num(dev->bus),
|
||||||
|
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
|
||||||
|
assert(*ret_data != NULL);
|
||||||
} else
|
} else
|
||||||
monitor_printf(mon, "failed to add %s\n", opts);
|
monitor_printf(mon, "failed to add %s\n", opts);
|
||||||
}
|
}
|
||||||
|
194
hw/pci.c
194
hw/pci.c
@@ -26,6 +26,7 @@
|
|||||||
#include "monitor.h"
|
#include "monitor.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
|
#include "loader.h"
|
||||||
|
|
||||||
//#define DEBUG_PCI
|
//#define DEBUG_PCI
|
||||||
#ifdef DEBUG_PCI
|
#ifdef DEBUG_PCI
|
||||||
@@ -62,12 +63,15 @@ static struct BusInfo pci_bus_info = {
|
|||||||
.print_dev = pcibus_dev_print,
|
.print_dev = pcibus_dev_print,
|
||||||
.props = (Property[]) {
|
.props = (Property[]) {
|
||||||
DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
|
DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
|
||||||
|
DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
|
||||||
|
DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1),
|
||||||
DEFINE_PROP_END_OF_LIST()
|
DEFINE_PROP_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pci_update_mappings(PCIDevice *d);
|
static void pci_update_mappings(PCIDevice *d);
|
||||||
static void pci_set_irq(void *opaque, int irq_num, int level);
|
static void pci_set_irq(void *opaque, int irq_num, int level);
|
||||||
|
static int pci_add_option_rom(PCIDevice *pdev);
|
||||||
|
|
||||||
target_phys_addr_t pci_mem_base;
|
target_phys_addr_t pci_mem_base;
|
||||||
static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
|
static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
|
||||||
@@ -103,11 +107,48 @@ static int pci_bar(PCIDevice *d, int reg)
|
|||||||
return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS;
|
return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int pci_irq_state(PCIDevice *d, int irq_num)
|
||||||
|
{
|
||||||
|
return (d->irq_state >> irq_num) & 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level)
|
||||||
|
{
|
||||||
|
d->irq_state &= ~(0x1 << irq_num);
|
||||||
|
d->irq_state |= level << irq_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change)
|
||||||
|
{
|
||||||
|
PCIBus *bus;
|
||||||
|
for (;;) {
|
||||||
|
bus = pci_dev->bus;
|
||||||
|
irq_num = bus->map_irq(pci_dev, irq_num);
|
||||||
|
if (bus->set_irq)
|
||||||
|
break;
|
||||||
|
pci_dev = bus->parent_dev;
|
||||||
|
}
|
||||||
|
bus->irq_count[irq_num] += change;
|
||||||
|
bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update interrupt status bit in config space on interrupt
|
||||||
|
* state change. */
|
||||||
|
static void pci_update_irq_status(PCIDevice *dev)
|
||||||
|
{
|
||||||
|
if (dev->irq_state) {
|
||||||
|
dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT;
|
||||||
|
} else {
|
||||||
|
dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void pci_device_reset(PCIDevice *dev)
|
static void pci_device_reset(PCIDevice *dev)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
memset(dev->irq_state, 0, sizeof dev->irq_state);
|
dev->irq_state = 0;
|
||||||
|
pci_update_irq_status(dev);
|
||||||
dev->config[PCI_COMMAND] &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
|
dev->config[PCI_COMMAND] &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
|
||||||
PCI_COMMAND_MASTER);
|
PCI_COMMAND_MASTER);
|
||||||
dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
|
dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
|
||||||
@@ -274,6 +315,43 @@ static VMStateInfo vmstate_info_pci_config = {
|
|||||||
.put = put_pci_config_device,
|
.put = put_pci_config_device,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size)
|
||||||
|
{
|
||||||
|
PCIDevice *s = container_of(pv, PCIDevice, config);
|
||||||
|
uint32_t irq_state[PCI_NUM_PINS];
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < PCI_NUM_PINS; ++i) {
|
||||||
|
irq_state[i] = qemu_get_be32(f);
|
||||||
|
if (irq_state[i] != 0x1 && irq_state[i] != 0) {
|
||||||
|
fprintf(stderr, "irq state %d: must be 0 or 1.\n",
|
||||||
|
irq_state[i]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < PCI_NUM_PINS; ++i) {
|
||||||
|
pci_set_irq_state(s, i, irq_state[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PCIDevice *s = container_of(pv, PCIDevice, config);
|
||||||
|
|
||||||
|
for (i = 0; i < PCI_NUM_PINS; ++i) {
|
||||||
|
qemu_put_be32(f, pci_irq_state(s, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VMStateInfo vmstate_info_pci_irq_state = {
|
||||||
|
.name = "pci irq state",
|
||||||
|
.get = get_pci_irq_state,
|
||||||
|
.put = put_pci_irq_state,
|
||||||
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_pci_device = {
|
const VMStateDescription vmstate_pci_device = {
|
||||||
.name = "PCIDevice",
|
.name = "PCIDevice",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
@@ -284,7 +362,9 @@ const VMStateDescription vmstate_pci_device = {
|
|||||||
VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
|
VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
|
||||||
vmstate_info_pci_config,
|
vmstate_info_pci_config,
|
||||||
PCI_CONFIG_SPACE_SIZE),
|
PCI_CONFIG_SPACE_SIZE),
|
||||||
VMSTATE_INT32_ARRAY_V(irq_state, PCIDevice, PCI_NUM_PINS, 2),
|
VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
|
||||||
|
vmstate_info_pci_irq_state,
|
||||||
|
PCI_NUM_PINS * sizeof(int32_t)),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -299,7 +379,9 @@ const VMStateDescription vmstate_pcie_device = {
|
|||||||
VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
|
VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
|
||||||
vmstate_info_pci_config,
|
vmstate_info_pci_config,
|
||||||
PCIE_CONFIG_SPACE_SIZE),
|
PCIE_CONFIG_SPACE_SIZE),
|
||||||
VMSTATE_INT32_ARRAY_V(irq_state, PCIDevice, PCI_NUM_PINS, 2),
|
VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
|
||||||
|
vmstate_info_pci_irq_state,
|
||||||
|
PCI_NUM_PINS * sizeof(int32_t)),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -311,12 +393,23 @@ static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s)
|
|||||||
|
|
||||||
void pci_device_save(PCIDevice *s, QEMUFile *f)
|
void pci_device_save(PCIDevice *s, QEMUFile *f)
|
||||||
{
|
{
|
||||||
|
/* Clear interrupt status bit: it is implicit
|
||||||
|
* in irq_state which we are saving.
|
||||||
|
* This makes us compatible with old devices
|
||||||
|
* which never set or clear this bit. */
|
||||||
|
s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
|
||||||
vmstate_save_state(f, pci_get_vmstate(s), s);
|
vmstate_save_state(f, pci_get_vmstate(s), s);
|
||||||
|
/* Restore the interrupt status bit. */
|
||||||
|
pci_update_irq_status(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pci_device_load(PCIDevice *s, QEMUFile *f)
|
int pci_device_load(PCIDevice *s, QEMUFile *f)
|
||||||
{
|
{
|
||||||
return vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id);
|
int ret;
|
||||||
|
ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id);
|
||||||
|
/* Restore the interrupt status bit. */
|
||||||
|
pci_update_irq_status(s);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pci_set_default_subsystem_id(PCIDevice *pci_dev)
|
static int pci_set_default_subsystem_id(PCIDevice *pci_dev)
|
||||||
@@ -490,16 +583,18 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
|
|||||||
if (!bus->devices[devfn])
|
if (!bus->devices[devfn])
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
hw_error("PCI: no devfn available for %s, all in use\n", name);
|
qemu_error("PCI: no devfn available for %s, all in use\n", name);
|
||||||
|
return NULL;
|
||||||
found: ;
|
found: ;
|
||||||
} else if (bus->devices[devfn]) {
|
} else if (bus->devices[devfn]) {
|
||||||
hw_error("PCI: devfn %d not available for %s, in use by %s\n", devfn,
|
qemu_error("PCI: devfn %d not available for %s, in use by %s\n", devfn,
|
||||||
name, bus->devices[devfn]->name);
|
name, bus->devices[devfn]->name);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
pci_dev->bus = bus;
|
pci_dev->bus = bus;
|
||||||
pci_dev->devfn = devfn;
|
pci_dev->devfn = devfn;
|
||||||
pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
|
pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
|
||||||
memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state));
|
pci_dev->irq_state = 0;
|
||||||
pci_config_alloc(pci_dev);
|
pci_config_alloc(pci_dev);
|
||||||
|
|
||||||
header_type &= ~PCI_HEADER_TYPE_MULTI_FUNCTION;
|
header_type &= ~PCI_HEADER_TYPE_MULTI_FUNCTION;
|
||||||
@@ -535,6 +630,9 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
|
|||||||
pci_dev = do_pci_register_device(pci_dev, bus, name, devfn,
|
pci_dev = do_pci_register_device(pci_dev, bus, name, devfn,
|
||||||
config_read, config_write,
|
config_read, config_write,
|
||||||
PCI_HEADER_TYPE_NORMAL);
|
PCI_HEADER_TYPE_NORMAL);
|
||||||
|
if (pci_dev == NULL) {
|
||||||
|
hw_error("PCI: can't register device\n");
|
||||||
|
}
|
||||||
return pci_dev;
|
return pci_dev;
|
||||||
}
|
}
|
||||||
static target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr)
|
static target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr)
|
||||||
@@ -882,23 +980,15 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
|
|||||||
static void pci_set_irq(void *opaque, int irq_num, int level)
|
static void pci_set_irq(void *opaque, int irq_num, int level)
|
||||||
{
|
{
|
||||||
PCIDevice *pci_dev = opaque;
|
PCIDevice *pci_dev = opaque;
|
||||||
PCIBus *bus;
|
|
||||||
int change;
|
int change;
|
||||||
|
|
||||||
change = level - pci_dev->irq_state[irq_num];
|
change = level - pci_irq_state(pci_dev, irq_num);
|
||||||
if (!change)
|
if (!change)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pci_dev->irq_state[irq_num] = level;
|
pci_set_irq_state(pci_dev, irq_num, level);
|
||||||
for (;;) {
|
pci_update_irq_status(pci_dev);
|
||||||
bus = pci_dev->bus;
|
pci_change_irq_level(pci_dev, irq_num, change);
|
||||||
irq_num = bus->map_irq(pci_dev, irq_num);
|
|
||||||
if (bus->set_irq)
|
|
||||||
break;
|
|
||||||
pci_dev = bus->parent_dev;
|
|
||||||
}
|
|
||||||
bus->irq_count[irq_num] += change;
|
|
||||||
bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
@@ -1270,9 +1360,17 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
|||||||
pci_dev = do_pci_register_device(pci_dev, bus, base->name, devfn,
|
pci_dev = do_pci_register_device(pci_dev, bus, base->name, devfn,
|
||||||
info->config_read, info->config_write,
|
info->config_read, info->config_write,
|
||||||
info->header_type);
|
info->header_type);
|
||||||
|
if (pci_dev == NULL)
|
||||||
|
return -1;
|
||||||
rc = info->init(pci_dev);
|
rc = info->init(pci_dev);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
/* rom loading */
|
||||||
|
if (pci_dev->romfile == NULL && info->romfile != NULL)
|
||||||
|
pci_dev->romfile = qemu_strdup(info->romfile);
|
||||||
|
pci_add_option_rom(pci_dev);
|
||||||
|
|
||||||
if (qdev->hotplugged)
|
if (qdev->hotplugged)
|
||||||
bus->hotplug(pci_dev, 1);
|
bus->hotplug(pci_dev, 1);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1350,6 +1448,64 @@ static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
|
|||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, pcibus_t size, int type)
|
||||||
|
{
|
||||||
|
cpu_register_physical_memory(addr, size, pdev->rom_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an option rom for the device */
|
||||||
|
static int pci_add_option_rom(PCIDevice *pdev)
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
char *path;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
if (!pdev->romfile)
|
||||||
|
return 0;
|
||||||
|
if (strlen(pdev->romfile) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!pdev->rom_bar) {
|
||||||
|
/*
|
||||||
|
* Load rom via fw_cfg instead of creating a rom bar,
|
||||||
|
* for 0.11 compatibility.
|
||||||
|
*/
|
||||||
|
int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
|
||||||
|
if (class == 0x0300) {
|
||||||
|
rom_add_vga(pdev->romfile);
|
||||||
|
} else {
|
||||||
|
rom_add_option(pdev->romfile);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile);
|
||||||
|
if (path == NULL) {
|
||||||
|
path = qemu_strdup(pdev->romfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
size = get_image_size(path);
|
||||||
|
if (size < 0) {
|
||||||
|
qemu_error("%s: failed to find romfile \"%s\"\n", __FUNCTION__,
|
||||||
|
pdev->romfile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (size & (size - 1)) {
|
||||||
|
size = 1 << qemu_fls(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdev->rom_offset = qemu_ram_alloc(size);
|
||||||
|
|
||||||
|
ptr = qemu_get_ram_ptr(pdev->rom_offset);
|
||||||
|
load_image(path, ptr);
|
||||||
|
qemu_free(path);
|
||||||
|
|
||||||
|
pci_register_bar(pdev, PCI_ROM_SLOT, size,
|
||||||
|
0, pci_map_option_rom);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Reserve space and add capability to the linked list in pci config space */
|
/* Reserve space and add capability to the linked list in pci config space */
|
||||||
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
|
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
|
||||||
{
|
{
|
||||||
|
11
hw/pci.h
11
hw/pci.h
@@ -102,6 +102,7 @@ typedef struct PCIIORegion {
|
|||||||
#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
|
#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
|
||||||
#define PCI_COMMAND_MASTER 0x4 /* Enable bus master */
|
#define PCI_COMMAND_MASTER 0x4 /* Enable bus master */
|
||||||
#define PCI_STATUS 0x06 /* 16 bits */
|
#define PCI_STATUS 0x06 /* 16 bits */
|
||||||
|
#define PCI_STATUS_INTERRUPT 0x08
|
||||||
#define PCI_REVISION_ID 0x08 /* 8 bits */
|
#define PCI_REVISION_ID 0x08 /* 8 bits */
|
||||||
#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
|
#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
|
||||||
#define PCI_CLASS_DEVICE 0x0a /* Device class */
|
#define PCI_CLASS_DEVICE 0x0a /* Device class */
|
||||||
@@ -220,7 +221,7 @@ struct PCIDevice {
|
|||||||
qemu_irq *irq;
|
qemu_irq *irq;
|
||||||
|
|
||||||
/* Current IRQ levels. Used internally by the generic PCI code. */
|
/* Current IRQ levels. Used internally by the generic PCI code. */
|
||||||
int irq_state[PCI_NUM_PINS];
|
uint8_t irq_state;
|
||||||
|
|
||||||
/* Capability bits */
|
/* Capability bits */
|
||||||
uint32_t cap_present;
|
uint32_t cap_present;
|
||||||
@@ -241,6 +242,11 @@ struct PCIDevice {
|
|||||||
uint32_t msix_bar_size;
|
uint32_t msix_bar_size;
|
||||||
/* Version id needed for VMState */
|
/* Version id needed for VMState */
|
||||||
int32_t version_id;
|
int32_t version_id;
|
||||||
|
|
||||||
|
/* Location of option rom */
|
||||||
|
char *romfile;
|
||||||
|
ram_addr_t rom_offset;
|
||||||
|
uint32_t rom_bar;
|
||||||
};
|
};
|
||||||
|
|
||||||
PCIDevice *pci_register_device(PCIBus *bus, const char *name,
|
PCIDevice *pci_register_device(PCIBus *bus, const char *name,
|
||||||
@@ -379,6 +385,9 @@ typedef struct {
|
|||||||
|
|
||||||
/* pcie stuff */
|
/* pcie stuff */
|
||||||
int is_express; /* is this device pci express? */
|
int is_express; /* is this device pci express? */
|
||||||
|
|
||||||
|
/* rom bar */
|
||||||
|
const char *romfile;
|
||||||
} PCIDeviceInfo;
|
} PCIDeviceInfo;
|
||||||
|
|
||||||
void pci_qdev_register(PCIDeviceInfo *info);
|
void pci_qdev_register(PCIDeviceInfo *info);
|
||||||
|
@@ -500,7 +500,12 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
|
|||||||
dev->info->name, name);
|
dev->info->name, name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return prop->info->parse(dev, prop, value);
|
if (prop->info->parse(dev, prop, value) != 0) {
|
||||||
|
fprintf(stderr, "property \"%s.%s\": failed to parse \"%s\"\n",
|
||||||
|
dev->info->name, name, value);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type)
|
void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type)
|
||||||
@@ -593,26 +598,33 @@ void qdev_prop_set_defaults(DeviceState *dev, Property *props)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static CompatProperty *compat_props;
|
static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props);
|
||||||
|
|
||||||
void qdev_prop_register_compat(CompatProperty *props)
|
void qdev_prop_register_global(GlobalProperty *prop)
|
||||||
{
|
{
|
||||||
compat_props = props;
|
QTAILQ_INSERT_TAIL(&global_props, prop, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qdev_prop_set_compat(DeviceState *dev)
|
void qdev_prop_register_global_list(GlobalProperty *props)
|
||||||
{
|
{
|
||||||
CompatProperty *prop;
|
int i;
|
||||||
|
|
||||||
if (!compat_props) {
|
for (i = 0; props[i].driver != NULL; i++) {
|
||||||
return;
|
qdev_prop_register_global(props+i);
|
||||||
}
|
}
|
||||||
for (prop = compat_props; prop->driver != NULL; prop++) {
|
}
|
||||||
if (strcmp(dev->info->name, prop->driver) != 0) {
|
|
||||||
|
void qdev_prop_set_globals(DeviceState *dev)
|
||||||
|
{
|
||||||
|
GlobalProperty *prop;
|
||||||
|
|
||||||
|
QTAILQ_FOREACH(prop, &global_props, next) {
|
||||||
|
if (strcmp(dev->info->name, prop->driver) != 0 &&
|
||||||
|
strcmp(dev->info->bus_info->name, prop->driver) != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
|
if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
|
||||||
abort();
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -103,7 +103,7 @@ DeviceState *qdev_create(BusState *bus, const char *name)
|
|||||||
dev->parent_bus = bus;
|
dev->parent_bus = bus;
|
||||||
qdev_prop_set_defaults(dev, dev->info->props);
|
qdev_prop_set_defaults(dev, dev->info->props);
|
||||||
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
|
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
|
||||||
qdev_prop_set_compat(dev);
|
qdev_prop_set_globals(dev);
|
||||||
QLIST_INSERT_HEAD(&bus->children, dev, sibling);
|
QLIST_INSERT_HEAD(&bus->children, dev, sibling);
|
||||||
if (qdev_hotplug) {
|
if (qdev_hotplug) {
|
||||||
assert(bus->allow_hotplug);
|
assert(bus->allow_hotplug);
|
||||||
|
10
hw/qdev.h
10
hw/qdev.h
@@ -92,11 +92,12 @@ struct PropertyInfo {
|
|||||||
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
|
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CompatProperty {
|
typedef struct GlobalProperty {
|
||||||
const char *driver;
|
const char *driver;
|
||||||
const char *property;
|
const char *property;
|
||||||
const char *value;
|
const char *value;
|
||||||
};
|
QTAILQ_ENTRY(GlobalProperty) next;
|
||||||
|
} GlobalProperty;
|
||||||
|
|
||||||
/*** Board API. This should go away once we have a machine config file. ***/
|
/*** Board API. This should go away once we have a machine config file. ***/
|
||||||
|
|
||||||
@@ -256,8 +257,9 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
|
|||||||
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
|
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
|
||||||
void qdev_prop_set_defaults(DeviceState *dev, Property *props);
|
void qdev_prop_set_defaults(DeviceState *dev, Property *props);
|
||||||
|
|
||||||
void qdev_prop_register_compat(CompatProperty *props);
|
void qdev_prop_register_global(GlobalProperty *prop);
|
||||||
void qdev_prop_set_compat(DeviceState *dev);
|
void qdev_prop_register_global_list(GlobalProperty *props);
|
||||||
|
void qdev_prop_set_globals(DeviceState *dev);
|
||||||
|
|
||||||
/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
|
/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
|
||||||
extern struct BusInfo system_bus_info;
|
extern struct BusInfo system_bus_info;
|
||||||
|
@@ -3353,14 +3353,6 @@ static int pci_rtl8139_init(PCIDevice *dev)
|
|||||||
qemu_mod_timer(s->timer,
|
qemu_mod_timer(s->timer,
|
||||||
rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock)));
|
rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock)));
|
||||||
#endif /* RTL8139_ONBOARD_TIMER */
|
#endif /* RTL8139_ONBOARD_TIMER */
|
||||||
|
|
||||||
if (!dev->qdev.hotplugged) {
|
|
||||||
static int loaded = 0;
|
|
||||||
if (!loaded) {
|
|
||||||
rom_add_option("pxe-rtl8139.bin");
|
|
||||||
loaded = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3371,6 +3363,7 @@ static PCIDeviceInfo rtl8139_info = {
|
|||||||
.qdev.vmsd = &vmstate_rtl8139,
|
.qdev.vmsd = &vmstate_rtl8139,
|
||||||
.init = pci_rtl8139_init,
|
.init = pci_rtl8139_init,
|
||||||
.exit = pci_rtl8139_uninit,
|
.exit = pci_rtl8139_uninit,
|
||||||
|
.romfile = "pxe-rtl8139.bin",
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
DEFINE_NIC_PROPERTIES(RTL8139State, conf),
|
DEFINE_NIC_PROPERTIES(RTL8139State, conf),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
@@ -307,7 +307,7 @@ static void virtio_s390_notify(void *opaque, uint16_t vector)
|
|||||||
uint64_t token = s390_virtio_device_vq_token(dev, vector);
|
uint64_t token = s390_virtio_device_vq_token(dev, vector);
|
||||||
|
|
||||||
/* XXX kvm dependency! */
|
/* XXX kvm dependency! */
|
||||||
kvm_s390_virtio_irq(s390_cpu_addr2state(0), 1, token);
|
kvm_s390_virtio_irq(s390_cpu_addr2state(0), 0, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************** S390 Virtio Bus Device Descriptions *******************/
|
/**************** S390 Virtio Bus Device Descriptions *******************/
|
||||||
|
@@ -142,6 +142,13 @@ static void s390_init(ram_addr_t ram_size,
|
|||||||
ram_addr_t initrd_size = 0;
|
ram_addr_t initrd_size = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/* XXX we only work on KVM for now */
|
||||||
|
|
||||||
|
if (!kvm_enabled()) {
|
||||||
|
fprintf(stderr, "The S390 target only works with KVM enabled\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/* get a BUS */
|
/* get a BUS */
|
||||||
s390_bus = s390_virtio_bus_init(&ram_size);
|
s390_bus = s390_virtio_bus_init(&ram_size);
|
||||||
|
|
||||||
@@ -181,7 +188,7 @@ static void s390_init(ram_addr_t ram_size,
|
|||||||
|
|
||||||
cpu_synchronize_state(env);
|
cpu_synchronize_state(env);
|
||||||
env->psw.addr = KERN_IMAGE_START;
|
env->psw.addr = KERN_IMAGE_START;
|
||||||
env->psw.mask = 0x0000000180000000UL;
|
env->psw.mask = 0x0000000180000000ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initrd_filename) {
|
if (initrd_filename) {
|
||||||
@@ -201,7 +208,11 @@ static void s390_init(ram_addr_t ram_size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Create VirtIO console */
|
/* Create VirtIO console */
|
||||||
qdev_init_nofail(qdev_create((BusState *)s390_bus, "virtio-console-s390"));
|
for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
|
||||||
|
if (virtcon_hds[i]) {
|
||||||
|
qdev_init_nofail(qdev_create((BusState *)s390_bus, "virtio-console-s390"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Create VirtIO network adapters */
|
/* Create VirtIO network adapters */
|
||||||
for(i = 0; i < nb_nics; i++) {
|
for(i = 0; i < nb_nics; i++) {
|
||||||
@@ -209,7 +220,7 @@ static void s390_init(ram_addr_t ram_size,
|
|||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
|
|
||||||
if (!nd->model) {
|
if (!nd->model) {
|
||||||
nd->model = (char*)"virtio";
|
nd->model = qemu_strdup("virtio");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(nd->model, "virtio")) {
|
if (strcmp(nd->model, "virtio")) {
|
||||||
@@ -243,6 +254,10 @@ static QEMUMachine s390_machine = {
|
|||||||
.alias = "s390",
|
.alias = "s390",
|
||||||
.desc = "VirtIO based S390 machine",
|
.desc = "VirtIO based S390 machine",
|
||||||
.init = s390_init,
|
.init = s390_init,
|
||||||
|
.no_serial = 1,
|
||||||
|
.no_parallel = 1,
|
||||||
|
.use_virtcon = 1,
|
||||||
|
.no_vga = 1,
|
||||||
.max_cpus = 255,
|
.max_cpus = 255,
|
||||||
.is_default = 1,
|
.is_default = 1,
|
||||||
};
|
};
|
||||||
|
@@ -5,6 +5,12 @@
|
|||||||
* Based on code by Fabrice Bellard
|
* Based on code by Fabrice Bellard
|
||||||
*
|
*
|
||||||
* Written by Paul Brook
|
* Written by Paul Brook
|
||||||
|
* Modifications:
|
||||||
|
* 2009-Dec-12 Artyom Tarasenko : implemented stamdard inquiry for the case
|
||||||
|
* when the allocation length of CDB is smaller
|
||||||
|
* than 36.
|
||||||
|
* 2009-Oct-13 Artyom Tarasenko : implemented the block descriptor in the
|
||||||
|
* MODE SENSE response.
|
||||||
*
|
*
|
||||||
* This code is licenced under the LGPL.
|
* This code is licenced under the LGPL.
|
||||||
*
|
*
|
||||||
@@ -59,6 +65,7 @@ struct SCSIDiskState
|
|||||||
int cluster_size;
|
int cluster_size;
|
||||||
uint64_t max_lba;
|
uint64_t max_lba;
|
||||||
QEMUBH *bh;
|
QEMUBH *bh;
|
||||||
|
char *version;
|
||||||
};
|
};
|
||||||
|
|
||||||
static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
|
static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
|
||||||
@@ -74,7 +81,7 @@ static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
|
|||||||
|
|
||||||
static void scsi_remove_request(SCSIDiskReq *r)
|
static void scsi_remove_request(SCSIDiskReq *r)
|
||||||
{
|
{
|
||||||
qemu_free(r->iov.iov_base);
|
qemu_vfree(r->iov.iov_base);
|
||||||
scsi_req_free(&r->req);
|
scsi_req_free(&r->req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,6 +316,7 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
|
|||||||
static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
||||||
{
|
{
|
||||||
BlockDriverState *bdrv = req->dev->dinfo->bdrv;
|
BlockDriverState *bdrv = req->dev->dinfo->bdrv;
|
||||||
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||||
int buflen = 0;
|
int buflen = 0;
|
||||||
|
|
||||||
if (req->cmd.buf[1] & 0x2) {
|
if (req->cmd.buf[1] & 0x2) {
|
||||||
@@ -406,11 +414,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req->cmd.xfer < 36) {
|
|
||||||
BADF("Error: Inquiry (STANDARD) buffer size %zd "
|
|
||||||
"is less than 36 (TODO: only 5 required)\n", req->cmd.xfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
buflen = req->cmd.xfer;
|
buflen = req->cmd.xfer;
|
||||||
if (buflen > SCSI_MAX_INQUIRY_LEN)
|
if (buflen > SCSI_MAX_INQUIRY_LEN)
|
||||||
buflen = SCSI_MAX_INQUIRY_LEN;
|
buflen = SCSI_MAX_INQUIRY_LEN;
|
||||||
@@ -431,12 +434,22 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
memcpy(&outbuf[16], "QEMU HARDDISK ", 16);
|
memcpy(&outbuf[16], "QEMU HARDDISK ", 16);
|
||||||
}
|
}
|
||||||
memcpy(&outbuf[8], "QEMU ", 8);
|
memcpy(&outbuf[8], "QEMU ", 8);
|
||||||
memcpy(&outbuf[32], QEMU_VERSION, 4);
|
memset(&outbuf[32], 0, 4);
|
||||||
|
memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION,
|
||||||
|
MIN(4, strlen(s->version ? s->version : QEMU_VERSION)));
|
||||||
/* Identify device as SCSI-3 rev 1.
|
/* Identify device as SCSI-3 rev 1.
|
||||||
Some later commands are also implemented. */
|
Some later commands are also implemented. */
|
||||||
outbuf[2] = 3;
|
outbuf[2] = 3;
|
||||||
outbuf[3] = 2; /* Format 2 */
|
outbuf[3] = 2; /* Format 2 */
|
||||||
outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
|
|
||||||
|
if (buflen > 36) {
|
||||||
|
outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
|
||||||
|
} else {
|
||||||
|
/* If the allocation length of CDB is too small,
|
||||||
|
the additional length is not adjusted */
|
||||||
|
outbuf[4] = 36 - 5;
|
||||||
|
}
|
||||||
|
|
||||||
/* Sync data transfer and TCQ. */
|
/* Sync data transfer and TCQ. */
|
||||||
outbuf[7] = 0x10 | (req->bus->tcq ? 0x02 : 0);
|
outbuf[7] = 0x10 | (req->bus->tcq ? 0x02 : 0);
|
||||||
return buflen;
|
return buflen;
|
||||||
@@ -1020,6 +1033,7 @@ static SCSIDeviceInfo scsi_disk_info = {
|
|||||||
.get_buf = scsi_get_buf,
|
.get_buf = scsi_get_buf,
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.dinfo),
|
DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.dinfo),
|
||||||
|
DEFINE_PROP_STRING("ver", SCSIDiskState, version),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -396,8 +396,11 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr,
|
|||||||
portb_changed(s, temp);
|
portb_changed(s, temp);
|
||||||
return;
|
return;
|
||||||
case SH7750_MMUCR_A7:
|
case SH7750_MMUCR_A7:
|
||||||
s->cpu->mmucr = mem_value;
|
if (mem_value & MMUCR_TI) {
|
||||||
return;
|
cpu_sh4_invalidate_tlb(s->cpu);
|
||||||
|
}
|
||||||
|
s->cpu->mmucr = mem_value & ~MMUCR_TI;
|
||||||
|
return;
|
||||||
case SH7750_PTEH_A7:
|
case SH7750_PTEH_A7:
|
||||||
/* If asid changes, clear all registered tlb entries. */
|
/* If asid changes, clear all registered tlb entries. */
|
||||||
if ((s->cpu->pteh & 0xff) != (mem_value & 0xff))
|
if ((s->cpu->pteh & 0xff) != (mem_value & 0xff))
|
||||||
|
111
hw/sh_pci.c
111
hw/sh_pci.c
@@ -47,10 +47,15 @@ static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val)
|
|||||||
pcic->par = val;
|
pcic->par = val;
|
||||||
break;
|
break;
|
||||||
case 0x1c4:
|
case 0x1c4:
|
||||||
pcic->mbr = val;
|
pcic->mbr = val & 0xff000001;
|
||||||
break;
|
break;
|
||||||
case 0x1c8:
|
case 0x1c8:
|
||||||
pcic->iobr = val;
|
if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) {
|
||||||
|
cpu_register_physical_memory(pcic->iobr & 0xfffc0000, 0x40000,
|
||||||
|
IO_MEM_UNASSIGNED);
|
||||||
|
pcic->iobr = val & 0xfffc0001;
|
||||||
|
isa_mmio_init(pcic->iobr & 0xfffc0000, 0x40000);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x220:
|
case 0x220:
|
||||||
pci_data_write(pcic->bus, pcic->par, val, 4);
|
pci_data_write(pcic->bus, pcic->par, val, 4);
|
||||||
@@ -66,89 +71,16 @@ static uint32_t sh_pci_reg_read (void *p, target_phys_addr_t addr)
|
|||||||
return le32_to_cpup((uint32_t*)(pcic->dev->config + addr));
|
return le32_to_cpup((uint32_t*)(pcic->dev->config + addr));
|
||||||
case 0x1c0:
|
case 0x1c0:
|
||||||
return pcic->par;
|
return pcic->par;
|
||||||
|
case 0x1c4:
|
||||||
|
return pcic->mbr;
|
||||||
|
case 0x1c8:
|
||||||
|
return pcic->iobr;
|
||||||
case 0x220:
|
case 0x220:
|
||||||
return pci_data_read(pcic->bus, pcic->par, 4);
|
return pci_data_read(pcic->bus, pcic->par, 4);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sh_pci_data_write (SHPCIC *pcic, target_phys_addr_t addr,
|
|
||||||
uint32_t val, int size)
|
|
||||||
{
|
|
||||||
pci_data_write(pcic->bus, addr + pcic->mbr, val, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t sh_pci_mem_read (SHPCIC *pcic, target_phys_addr_t addr,
|
|
||||||
int size)
|
|
||||||
{
|
|
||||||
return pci_data_read(pcic->bus, addr + pcic->mbr, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sh_pci_writeb (void *p, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
|
||||||
sh_pci_data_write(p, addr, val, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sh_pci_writew (void *p, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
|
||||||
sh_pci_data_write(p, addr, val, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sh_pci_writel (void *p, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
|
||||||
sh_pci_data_write(p, addr, val, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t sh_pci_readb (void *p, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
return sh_pci_mem_read(p, addr, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t sh_pci_readw (void *p, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
return sh_pci_mem_read(p, addr, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t sh_pci_readl (void *p, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
return sh_pci_mem_read(p, addr, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sh_pci_addr2port(SHPCIC *pcic, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
return addr + pcic->iobr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sh_pci_outb (void *p, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
|
||||||
cpu_outb(sh_pci_addr2port(p, addr), val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sh_pci_outw (void *p, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
|
||||||
cpu_outw(sh_pci_addr2port(p, addr), val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sh_pci_outl (void *p, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
|
||||||
cpu_outl(sh_pci_addr2port(p, addr), val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t sh_pci_inb (void *p, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
return cpu_inb(sh_pci_addr2port(p, addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t sh_pci_inw (void *p, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
return cpu_inw(sh_pci_addr2port(p, addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t sh_pci_inl (void *p, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
return cpu_inl(sh_pci_addr2port(p, addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
CPUReadMemoryFunc * const r[3];
|
CPUReadMemoryFunc * const r[3];
|
||||||
CPUWriteMemoryFunc * const w[3];
|
CPUWriteMemoryFunc * const w[3];
|
||||||
@@ -159,21 +91,11 @@ static MemOp sh_pci_reg = {
|
|||||||
{ NULL, NULL, sh_pci_reg_write },
|
{ NULL, NULL, sh_pci_reg_write },
|
||||||
};
|
};
|
||||||
|
|
||||||
static MemOp sh_pci_mem = {
|
|
||||||
{ sh_pci_readb, sh_pci_readw, sh_pci_readl },
|
|
||||||
{ sh_pci_writeb, sh_pci_writew, sh_pci_writel },
|
|
||||||
};
|
|
||||||
|
|
||||||
static MemOp sh_pci_iop = {
|
|
||||||
{ sh_pci_inb, sh_pci_inw, sh_pci_inl },
|
|
||||||
{ sh_pci_outb, sh_pci_outw, sh_pci_outl },
|
|
||||||
};
|
|
||||||
|
|
||||||
PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
|
PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
|
||||||
void *opaque, int devfn_min, int nirq)
|
void *opaque, int devfn_min, int nirq)
|
||||||
{
|
{
|
||||||
SHPCIC *p;
|
SHPCIC *p;
|
||||||
int mem, reg, iop;
|
int reg;
|
||||||
|
|
||||||
p = qemu_mallocz(sizeof(SHPCIC));
|
p = qemu_mallocz(sizeof(SHPCIC));
|
||||||
p->bus = pci_register_bus(NULL, "pci",
|
p->bus = pci_register_bus(NULL, "pci",
|
||||||
@@ -182,14 +104,11 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
|
|||||||
p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice),
|
p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice),
|
||||||
-1, NULL, NULL);
|
-1, NULL, NULL);
|
||||||
reg = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w, p);
|
reg = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w, p);
|
||||||
iop = cpu_register_io_memory(sh_pci_iop.r, sh_pci_iop.w, p);
|
|
||||||
mem = cpu_register_io_memory(sh_pci_mem.r, sh_pci_mem.w, p);
|
|
||||||
cpu_register_physical_memory(0x1e200000, 0x224, reg);
|
cpu_register_physical_memory(0x1e200000, 0x224, reg);
|
||||||
cpu_register_physical_memory(0x1e240000, 0x40000, iop);
|
|
||||||
cpu_register_physical_memory(0x1d000000, 0x1000000, mem);
|
|
||||||
cpu_register_physical_memory(0xfe200000, 0x224, reg);
|
cpu_register_physical_memory(0xfe200000, 0x224, reg);
|
||||||
cpu_register_physical_memory(0xfe240000, 0x40000, iop);
|
|
||||||
cpu_register_physical_memory(0xfd000000, 0x1000000, mem);
|
p->iobr = 0xfe240000;
|
||||||
|
isa_mmio_init(p->iobr, 0x40000);
|
||||||
|
|
||||||
pci_config_set_vendor_id(p->dev->config, PCI_VENDOR_ID_HITACHI);
|
pci_config_set_vendor_id(p->dev->config, PCI_VENDOR_ID_HITACHI);
|
||||||
pci_config_set_device_id(p->dev->config, PCI_DEVICE_ID_HITACHI_SH7751R);
|
pci_config_set_device_id(p->dev->config, PCI_DEVICE_ID_HITACHI_SH7751R);
|
||||||
|
@@ -87,7 +87,7 @@ static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
|
|||||||
break;
|
break;
|
||||||
case SYBORG_VIRTIO_HOST_FEATURES:
|
case SYBORG_VIRTIO_HOST_FEATURES:
|
||||||
ret = vdev->get_features(vdev);
|
ret = vdev->get_features(vdev);
|
||||||
ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
|
ret |= vdev->binding->get_features(s);
|
||||||
break;
|
break;
|
||||||
case SYBORG_VIRTIO_GUEST_FEATURES:
|
case SYBORG_VIRTIO_GUEST_FEATURES:
|
||||||
ret = vdev->features;
|
ret = vdev->features;
|
||||||
@@ -242,8 +242,16 @@ static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
|
|||||||
qemu_set_irq(proxy->irq, level != 0);
|
qemu_set_irq(proxy->irq, level != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned syborg_virtio_get_features(void *opaque)
|
||||||
|
{
|
||||||
|
unsigned ret = 0;
|
||||||
|
ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static VirtIOBindings syborg_virtio_bindings = {
|
static VirtIOBindings syborg_virtio_bindings = {
|
||||||
.notify = syborg_virtio_update_irq
|
.notify = syborg_virtio_update_irq,
|
||||||
|
.get_features = syborg_virtio_get_features,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
|
static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
|
||||||
|
@@ -148,7 +148,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
|
|||||||
|
|
||||||
/* Use values found on a real PowerMac */
|
/* Use values found on a real PowerMac */
|
||||||
/* Uninorth main bus */
|
/* Uninorth main bus */
|
||||||
dev = qdev_create(NULL, "Uni-north main");
|
dev = qdev_create(NULL, "uni-north");
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
s = sysbus_from_qdev(dev);
|
s = sysbus_from_qdev(dev);
|
||||||
d = FROM_SYSBUS(UNINState, s);
|
d = FROM_SYSBUS(UNINState, s);
|
||||||
@@ -157,7 +157,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
|
|||||||
pic, 11 << 3, 4);
|
pic, 11 << 3, 4);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
pci_create_simple(d->host_state.bus, 11 << 3, "Uni-north main");
|
pci_create_simple(d->host_state.bus, 11 << 3, "uni-north");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sysbus_mmio_map(s, 0, 0xf2800000);
|
sysbus_mmio_map(s, 0, 0xf2800000);
|
||||||
@@ -166,12 +166,12 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
|
|||||||
/* DEC 21154 bridge */
|
/* DEC 21154 bridge */
|
||||||
#if 0
|
#if 0
|
||||||
/* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
|
/* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
|
||||||
pci_create_simple(d->host_state.bus, 12 << 3, "DEC 21154");
|
pci_create_simple(d->host_state.bus, 12 << 3, "dec-21154");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Uninorth AGP bus */
|
/* Uninorth AGP bus */
|
||||||
pci_create_simple(d->host_state.bus, 11 << 3, "Uni-north AGP");
|
pci_create_simple(d->host_state.bus, 11 << 3, "uni-north-agp");
|
||||||
dev = qdev_create(NULL, "Uni-north AGP");
|
dev = qdev_create(NULL, "uni-north-agp");
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
s = sysbus_from_qdev(dev);
|
s = sysbus_from_qdev(dev);
|
||||||
sysbus_mmio_map(s, 0, 0xf0800000);
|
sysbus_mmio_map(s, 0, 0xf0800000);
|
||||||
@@ -180,8 +180,8 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
|
|||||||
/* Uninorth internal bus */
|
/* Uninorth internal bus */
|
||||||
#if 0
|
#if 0
|
||||||
/* XXX: not needed for now */
|
/* XXX: not needed for now */
|
||||||
pci_create_simple(d->host_state.bus, 14 << 3, "Uni-north internal");
|
pci_create_simple(d->host_state.bus, 14 << 3, "uni-north-pci");
|
||||||
dev = qdev_create(NULL, "Uni-north internal");
|
dev = qdev_create(NULL, "uni-north-pci");
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
s = sysbus_from_qdev(dev);
|
s = sysbus_from_qdev(dev);
|
||||||
sysbus_mmio_map(s, 0, 0xf4800000);
|
sysbus_mmio_map(s, 0, 0xf4800000);
|
||||||
@@ -260,41 +260,41 @@ static int unin_internal_pci_host_init(PCIDevice *d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static PCIDeviceInfo unin_main_pci_host_info = {
|
static PCIDeviceInfo unin_main_pci_host_info = {
|
||||||
.qdev.name = "Uni-north main",
|
.qdev.name = "uni-north",
|
||||||
.qdev.size = sizeof(PCIDevice),
|
.qdev.size = sizeof(PCIDevice),
|
||||||
.init = unin_main_pci_host_init,
|
.init = unin_main_pci_host_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static PCIDeviceInfo dec_21154_pci_host_info = {
|
static PCIDeviceInfo dec_21154_pci_host_info = {
|
||||||
.qdev.name = "DEC 21154",
|
.qdev.name = "dec-21154",
|
||||||
.qdev.size = sizeof(PCIDevice),
|
.qdev.size = sizeof(PCIDevice),
|
||||||
.init = dec_21154_pci_host_init,
|
.init = dec_21154_pci_host_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static PCIDeviceInfo unin_agp_pci_host_info = {
|
static PCIDeviceInfo unin_agp_pci_host_info = {
|
||||||
.qdev.name = "Uni-north AGP",
|
.qdev.name = "uni-north-agp",
|
||||||
.qdev.size = sizeof(PCIDevice),
|
.qdev.size = sizeof(PCIDevice),
|
||||||
.init = unin_agp_pci_host_init,
|
.init = unin_agp_pci_host_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static PCIDeviceInfo unin_internal_pci_host_info = {
|
static PCIDeviceInfo unin_internal_pci_host_info = {
|
||||||
.qdev.name = "Uni-north internal",
|
.qdev.name = "uni-north-pci",
|
||||||
.qdev.size = sizeof(PCIDevice),
|
.qdev.size = sizeof(PCIDevice),
|
||||||
.init = unin_internal_pci_host_init,
|
.init = unin_internal_pci_host_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void unin_register_devices(void)
|
static void unin_register_devices(void)
|
||||||
{
|
{
|
||||||
sysbus_register_dev("Uni-north main", sizeof(UNINState),
|
sysbus_register_dev("uni-north", sizeof(UNINState),
|
||||||
pci_unin_main_init_device);
|
pci_unin_main_init_device);
|
||||||
pci_qdev_register(&unin_main_pci_host_info);
|
pci_qdev_register(&unin_main_pci_host_info);
|
||||||
sysbus_register_dev("DEC 21154", sizeof(UNINState),
|
sysbus_register_dev("dec-21154", sizeof(UNINState),
|
||||||
pci_dec_21154_init_device);
|
pci_dec_21154_init_device);
|
||||||
pci_qdev_register(&dec_21154_pci_host_info);
|
pci_qdev_register(&dec_21154_pci_host_info);
|
||||||
sysbus_register_dev("Uni-north AGP", sizeof(UNINState),
|
sysbus_register_dev("uni-north-agp", sizeof(UNINState),
|
||||||
pci_unin_agp_init_device);
|
pci_unin_agp_init_device);
|
||||||
pci_qdev_register(&unin_agp_pci_host_info);
|
pci_qdev_register(&unin_agp_pci_host_info);
|
||||||
sysbus_register_dev("Uni-north internal", sizeof(UNINState),
|
sysbus_register_dev("uni-north-pci", sizeof(UNINState),
|
||||||
pci_unin_internal_init_device);
|
pci_unin_internal_init_device);
|
||||||
pci_qdev_register(&unin_internal_pci_host_info);
|
pci_qdev_register(&unin_internal_pci_host_info);
|
||||||
}
|
}
|
||||||
|
@@ -630,7 +630,7 @@ USBDevice *usb_bt_init(HCIInfo *hci)
|
|||||||
|
|
||||||
if (!hci)
|
if (!hci)
|
||||||
return NULL;
|
return NULL;
|
||||||
dev = usb_create_simple(NULL /* FIXME */, "QEMU BT dongle");
|
dev = usb_create_simple(NULL /* FIXME */, "usb-bt-dongle");
|
||||||
s = DO_UPCAST(struct USBBtState, dev, dev);
|
s = DO_UPCAST(struct USBBtState, dev, dev);
|
||||||
s->dev.opaque = s;
|
s->dev.opaque = s;
|
||||||
|
|
||||||
@@ -645,7 +645,8 @@ USBDevice *usb_bt_init(HCIInfo *hci)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct USBDeviceInfo bt_info = {
|
static struct USBDeviceInfo bt_info = {
|
||||||
.qdev.name = "QEMU BT dongle",
|
.product_desc = "QEMU BT dongle",
|
||||||
|
.qdev.name = "usb-bt-dongle",
|
||||||
.qdev.size = sizeof(struct USBBtState),
|
.qdev.size = sizeof(struct USBBtState),
|
||||||
.init = usb_bt_initfn,
|
.init = usb_bt_initfn,
|
||||||
.handle_packet = usb_generic_handle_packet,
|
.handle_packet = usb_generic_handle_packet,
|
||||||
|
13
hw/usb-bus.c
13
hw/usb-bus.c
@@ -43,7 +43,7 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
|||||||
USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
|
USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
pstrcpy(dev->devname, sizeof(dev->devname), qdev->info->name);
|
pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc);
|
||||||
dev->info = info;
|
dev->info = info;
|
||||||
dev->auto_attach = 1;
|
dev->auto_attach = 1;
|
||||||
rc = dev->info->init(dev);
|
rc = dev->info->init(dev);
|
||||||
@@ -131,7 +131,7 @@ static void do_attach(USBDevice *dev)
|
|||||||
|
|
||||||
if (dev->attached) {
|
if (dev->attached) {
|
||||||
fprintf(stderr, "Warning: tried to attach usb device %s twice\n",
|
fprintf(stderr, "Warning: tried to attach usb device %s twice\n",
|
||||||
dev->devname);
|
dev->product_desc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dev->attached++;
|
dev->attached++;
|
||||||
@@ -153,7 +153,7 @@ int usb_device_attach(USBDevice *dev)
|
|||||||
|
|
||||||
if (bus->nfree == 1) {
|
if (bus->nfree == 1) {
|
||||||
/* Create a new hub and chain it on. */
|
/* Create a new hub and chain it on. */
|
||||||
hub = usb_create_simple(bus, "QEMU USB Hub");
|
hub = usb_create_simple(bus, "usb-hub");
|
||||||
}
|
}
|
||||||
do_attach(dev);
|
do_attach(dev);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -166,7 +166,7 @@ int usb_device_detach(USBDevice *dev)
|
|||||||
|
|
||||||
if (!dev->attached) {
|
if (!dev->attached) {
|
||||||
fprintf(stderr, "Warning: tried to detach unattached usb device %s\n",
|
fprintf(stderr, "Warning: tried to detach unattached usb device %s\n",
|
||||||
dev->devname);
|
dev->product_desc);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
dev->attached--;
|
dev->attached--;
|
||||||
@@ -228,7 +228,7 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
|
|||||||
|
|
||||||
monitor_printf(mon, "%*saddr %d.%d, speed %s, name %s%s\n",
|
monitor_printf(mon, "%*saddr %d.%d, speed %s, name %s%s\n",
|
||||||
indent, "", bus->busnr, dev->addr,
|
indent, "", bus->busnr, dev->addr,
|
||||||
usb_speed(dev->speed), dev->devname,
|
usb_speed(dev->speed), dev->product_desc,
|
||||||
dev->attached ? ", attached" : "");
|
dev->attached ? ", attached" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +249,8 @@ void usb_info(Monitor *mon)
|
|||||||
if (!dev)
|
if (!dev)
|
||||||
continue;
|
continue;
|
||||||
monitor_printf(mon, " Device %d.%d, Speed %s Mb/s, Product %s\n",
|
monitor_printf(mon, " Device %d.%d, Speed %s Mb/s, Product %s\n",
|
||||||
bus->busnr, dev->addr, usb_speed(dev->speed), dev->devname);
|
bus->busnr, dev->addr, usb_speed(dev->speed),
|
||||||
|
dev->product_desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
hw/usb-hid.c
14
hw/usb-hid.c
@@ -701,7 +701,7 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value,
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
/* product description */
|
/* product description */
|
||||||
ret = set_usb_string(data, s->dev.devname);
|
ret = set_usb_string(data, s->dev.product_desc);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
/* vendor description */
|
/* vendor description */
|
||||||
@@ -880,8 +880,8 @@ void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
|
|||||||
|
|
||||||
static struct USBDeviceInfo hid_info[] = {
|
static struct USBDeviceInfo hid_info[] = {
|
||||||
{
|
{
|
||||||
.qdev.name = "QEMU USB Tablet",
|
.product_desc = "QEMU USB Tablet",
|
||||||
.qdev.alias = "usb-tablet",
|
.qdev.name = "usb-tablet",
|
||||||
.usbdevice_name = "tablet",
|
.usbdevice_name = "tablet",
|
||||||
.qdev.size = sizeof(USBHIDState),
|
.qdev.size = sizeof(USBHIDState),
|
||||||
.init = usb_tablet_initfn,
|
.init = usb_tablet_initfn,
|
||||||
@@ -891,8 +891,8 @@ static struct USBDeviceInfo hid_info[] = {
|
|||||||
.handle_data = usb_hid_handle_data,
|
.handle_data = usb_hid_handle_data,
|
||||||
.handle_destroy = usb_hid_handle_destroy,
|
.handle_destroy = usb_hid_handle_destroy,
|
||||||
},{
|
},{
|
||||||
.qdev.name = "QEMU USB Mouse",
|
.product_desc = "QEMU USB Mouse",
|
||||||
.qdev.alias = "usb-mouse",
|
.qdev.name = "usb-mouse",
|
||||||
.usbdevice_name = "mouse",
|
.usbdevice_name = "mouse",
|
||||||
.qdev.size = sizeof(USBHIDState),
|
.qdev.size = sizeof(USBHIDState),
|
||||||
.init = usb_mouse_initfn,
|
.init = usb_mouse_initfn,
|
||||||
@@ -902,8 +902,8 @@ static struct USBDeviceInfo hid_info[] = {
|
|||||||
.handle_data = usb_hid_handle_data,
|
.handle_data = usb_hid_handle_data,
|
||||||
.handle_destroy = usb_hid_handle_destroy,
|
.handle_destroy = usb_hid_handle_destroy,
|
||||||
},{
|
},{
|
||||||
.qdev.name = "QEMU USB Keyboard",
|
.product_desc = "QEMU USB Keyboard",
|
||||||
.qdev.alias = "usb-kbd",
|
.qdev.name = "usb-kbd",
|
||||||
.usbdevice_name = "keyboard",
|
.usbdevice_name = "keyboard",
|
||||||
.qdev.size = sizeof(USBHIDState),
|
.qdev.size = sizeof(USBHIDState),
|
||||||
.init = usb_keyboard_initfn,
|
.init = usb_keyboard_initfn,
|
||||||
|
@@ -544,7 +544,8 @@ static int usb_hub_initfn(USBDevice *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct USBDeviceInfo hub_info = {
|
static struct USBDeviceInfo hub_info = {
|
||||||
.qdev.name = "QEMU USB Hub",
|
.product_desc = "QEMU USB Hub",
|
||||||
|
.qdev.name = "usb-hub",
|
||||||
.qdev.size = sizeof(USBHubState),
|
.qdev.size = sizeof(USBHubState),
|
||||||
.init = usb_hub_initfn,
|
.init = usb_hub_initfn,
|
||||||
.handle_packet = usb_hub_handle_packet,
|
.handle_packet = usb_hub_handle_packet,
|
||||||
|
@@ -591,7 +591,7 @@ static USBDevice *usb_msd_init(const char *filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* create guest device */
|
/* create guest device */
|
||||||
dev = usb_create(NULL /* FIXME */, "QEMU USB MSD");
|
dev = usb_create(NULL /* FIXME */, "usb-storage");
|
||||||
qdev_prop_set_drive(&dev->qdev, "drive", dinfo);
|
qdev_prop_set_drive(&dev->qdev, "drive", dinfo);
|
||||||
if (qdev_init(&dev->qdev) < 0)
|
if (qdev_init(&dev->qdev) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -600,8 +600,8 @@ static USBDevice *usb_msd_init(const char *filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct USBDeviceInfo msd_info = {
|
static struct USBDeviceInfo msd_info = {
|
||||||
.qdev.name = "QEMU USB MSD",
|
.product_desc = "QEMU USB MSD",
|
||||||
.qdev.alias = "usb-storage",
|
.qdev.name = "usb-storage",
|
||||||
.qdev.size = sizeof(MSDState),
|
.qdev.size = sizeof(MSDState),
|
||||||
.init = usb_msd_initfn,
|
.init = usb_msd_initfn,
|
||||||
.handle_packet = usb_generic_handle_packet,
|
.handle_packet = usb_generic_handle_packet,
|
||||||
|
81
hw/usb-net.c
81
hw/usb-net.c
@@ -1420,8 +1420,7 @@ static void usbnet_cleanup(VLANClientState *nc)
|
|||||||
{
|
{
|
||||||
USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
|
USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
|
||||||
|
|
||||||
rndis_clear_responsequeue(s);
|
s->nic = NULL;
|
||||||
qemu_free(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_net_handle_destroy(USBDevice *dev)
|
static void usb_net_handle_destroy(USBDevice *dev)
|
||||||
@@ -1429,9 +1428,18 @@ static void usb_net_handle_destroy(USBDevice *dev)
|
|||||||
USBNetState *s = (USBNetState *) dev;
|
USBNetState *s = (USBNetState *) dev;
|
||||||
|
|
||||||
/* TODO: remove the nd_table[] entry */
|
/* TODO: remove the nd_table[] entry */
|
||||||
|
rndis_clear_responsequeue(s);
|
||||||
qemu_del_vlan_client(&s->nic->nc);
|
qemu_del_vlan_client(&s->nic->nc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NetClientInfo net_usbnet_info = {
|
||||||
|
.type = NET_CLIENT_TYPE_NIC,
|
||||||
|
.size = sizeof(NICState),
|
||||||
|
.can_receive = usbnet_can_receive,
|
||||||
|
.receive = usbnet_receive,
|
||||||
|
.cleanup = usbnet_cleanup,
|
||||||
|
};
|
||||||
|
|
||||||
static int usb_net_initfn(USBDevice *dev)
|
static int usb_net_initfn(USBDevice *dev)
|
||||||
{
|
{
|
||||||
USBNetState *s = DO_UPCAST(USBNetState, dev, dev);
|
USBNetState *s = DO_UPCAST(USBNetState, dev, dev);
|
||||||
@@ -1447,47 +1455,50 @@ static int usb_net_initfn(USBDevice *dev)
|
|||||||
s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */;
|
s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */;
|
||||||
s->filter = 0;
|
s->filter = 0;
|
||||||
s->vendorid = 0x1234;
|
s->vendorid = 0x1234;
|
||||||
|
|
||||||
|
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
||||||
|
s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
|
||||||
|
s->dev.qdev.info->name, s->dev.qdev.id, s);
|
||||||
|
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
|
||||||
|
snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),
|
||||||
|
"%02x%02x%02x%02x%02x%02x",
|
||||||
|
0x40,
|
||||||
|
s->conf.macaddr.a[1],
|
||||||
|
s->conf.macaddr.a[2],
|
||||||
|
s->conf.macaddr.a[3],
|
||||||
|
s->conf.macaddr.a[4],
|
||||||
|
s->conf.macaddr.a[5]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NetClientInfo net_usbnet_info = {
|
static USBDevice *usb_net_init(const char *cmdline)
|
||||||
.type = NET_CLIENT_TYPE_NIC,
|
|
||||||
.size = sizeof(NICState),
|
|
||||||
.can_receive = usbnet_can_receive,
|
|
||||||
.receive = usbnet_receive,
|
|
||||||
.cleanup = usbnet_cleanup,
|
|
||||||
};
|
|
||||||
|
|
||||||
USBDevice *usb_net_init(NICInfo *nd)
|
|
||||||
{
|
{
|
||||||
USBDevice *dev;
|
USBDevice *dev;
|
||||||
USBNetState *s;
|
QemuOpts *opts;
|
||||||
|
int idx;
|
||||||
|
|
||||||
dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Network Interface");
|
opts = qemu_opts_parse(&qemu_net_opts, cmdline, NULL);
|
||||||
s = DO_UPCAST(USBNetState, dev, dev);
|
if (!opts) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
qemu_opt_set(opts, "type", "nic");
|
||||||
|
qemu_opt_set(opts, "model", "usb");
|
||||||
|
|
||||||
memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
|
idx = net_client_init(NULL, opts, 0);
|
||||||
s->conf.vlan = nd->vlan;
|
if (idx == -1) {
|
||||||
s->conf.peer = nd->netdev;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
|
dev = usb_create(NULL /* FIXME */, "usb-net");
|
||||||
nd->model, nd->name, s);
|
qdev_set_nic_properties(&dev->qdev, &nd_table[idx]);
|
||||||
|
qdev_init_nofail(&dev->qdev);
|
||||||
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
|
return dev;
|
||||||
|
|
||||||
snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),
|
|
||||||
"%02x%02x%02x%02x%02x%02x",
|
|
||||||
0x40, s->conf.macaddr.a[1], s->conf.macaddr.a[2],
|
|
||||||
s->conf.macaddr.a[3], s->conf.macaddr.a[4], s->conf.macaddr.a[5]);
|
|
||||||
fprintf(stderr, "usbnet: initialized mac %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
||||||
s->conf.macaddr.a[0], s->conf.macaddr.a[1], s->conf.macaddr.a[2],
|
|
||||||
s->conf.macaddr.a[3], s->conf.macaddr.a[4], s->conf.macaddr.a[5]);
|
|
||||||
|
|
||||||
return (USBDevice *) s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct USBDeviceInfo net_info = {
|
static struct USBDeviceInfo net_info = {
|
||||||
.qdev.name = "QEMU USB Network Interface",
|
.product_desc = "QEMU USB Network Interface",
|
||||||
|
.qdev.name = "usb-net",
|
||||||
.qdev.size = sizeof(USBNetState),
|
.qdev.size = sizeof(USBNetState),
|
||||||
.init = usb_net_initfn,
|
.init = usb_net_initfn,
|
||||||
.handle_packet = usb_generic_handle_packet,
|
.handle_packet = usb_generic_handle_packet,
|
||||||
@@ -1495,6 +1506,12 @@ static struct USBDeviceInfo net_info = {
|
|||||||
.handle_control = usb_net_handle_control,
|
.handle_control = usb_net_handle_control,
|
||||||
.handle_data = usb_net_handle_data,
|
.handle_data = usb_net_handle_data,
|
||||||
.handle_destroy = usb_net_handle_destroy,
|
.handle_destroy = usb_net_handle_destroy,
|
||||||
|
.usbdevice_name = "net",
|
||||||
|
.usbdevice_init = usb_net_init,
|
||||||
|
.qdev.props = (Property[]) {
|
||||||
|
DEFINE_NIC_PROPERTIES(USBNetState, conf),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void usb_net_register_devices(void)
|
static void usb_net_register_devices(void)
|
||||||
|
@@ -1736,7 +1736,7 @@ static int usb_ohci_initfn_pci(struct PCIDevice *dev)
|
|||||||
|
|
||||||
void usb_ohci_init_pci(struct PCIBus *bus, int devfn)
|
void usb_ohci_init_pci(struct PCIBus *bus, int devfn)
|
||||||
{
|
{
|
||||||
pci_create_simple(bus, devfn, "OHCI USB PCI");
|
pci_create_simple(bus, devfn, "pci-ohci");
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
|
void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
|
||||||
@@ -1762,8 +1762,7 @@ void usb_ohci_init_sm501(uint32_t mmio_base, uint32_t localmem_base,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static PCIDeviceInfo ohci_info = {
|
static PCIDeviceInfo ohci_info = {
|
||||||
.qdev.name = "OHCI USB PCI",
|
.qdev.name = "pci-ohci",
|
||||||
.qdev.alias = "pci-ohci",
|
|
||||||
.qdev.desc = "Apple USB Controller",
|
.qdev.desc = "Apple USB Controller",
|
||||||
.qdev.size = sizeof(OHCIPCIState),
|
.qdev.size = sizeof(OHCIPCIState),
|
||||||
.init = usb_ohci_initfn_pci,
|
.init = usb_ohci_initfn_pci,
|
||||||
|
@@ -497,12 +497,28 @@ static int usb_serial_can_read(void *opaque)
|
|||||||
static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
|
static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
|
||||||
{
|
{
|
||||||
USBSerialState *s = opaque;
|
USBSerialState *s = opaque;
|
||||||
int first_size = RECV_BUF - s->recv_ptr;
|
int first_size, start;
|
||||||
if (first_size > size)
|
|
||||||
first_size = size;
|
/* room in the buffer? */
|
||||||
memcpy(s->recv_buf + s->recv_ptr + s->recv_used, buf, first_size);
|
if (size > (RECV_BUF - s->recv_used))
|
||||||
if (size > first_size)
|
size = RECV_BUF - s->recv_used;
|
||||||
memcpy(s->recv_buf, buf + first_size, size - first_size);
|
|
||||||
|
start = s->recv_ptr + s->recv_used;
|
||||||
|
if (start < RECV_BUF) {
|
||||||
|
/* copy data to end of buffer */
|
||||||
|
first_size = RECV_BUF - start;
|
||||||
|
if (first_size > size)
|
||||||
|
first_size = size;
|
||||||
|
|
||||||
|
memcpy(s->recv_buf + start, buf, first_size);
|
||||||
|
|
||||||
|
/* wrap around to front if needed */
|
||||||
|
if (size > first_size)
|
||||||
|
memcpy(s->recv_buf, buf + first_size, size - first_size);
|
||||||
|
} else {
|
||||||
|
start -= RECV_BUF;
|
||||||
|
memcpy(s->recv_buf + start, buf, size);
|
||||||
|
}
|
||||||
s->recv_used += size;
|
s->recv_used += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,13 +593,13 @@ static USBDevice *usb_serial_init(const char *filename)
|
|||||||
if (!cdrv)
|
if (!cdrv)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
dev = usb_create(NULL /* FIXME */, "QEMU USB Serial");
|
dev = usb_create(NULL /* FIXME */, "usb-serial");
|
||||||
qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
|
qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
|
||||||
if (vendorid)
|
if (vendorid)
|
||||||
qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid);
|
qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid);
|
||||||
if (productid)
|
if (productid)
|
||||||
qdev_prop_set_uint16(&dev->qdev, "productid", productid);
|
qdev_prop_set_uint16(&dev->qdev, "productid", productid);
|
||||||
qdev_init(&dev->qdev);
|
qdev_init_nofail(&dev->qdev);
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
@@ -597,16 +613,16 @@ static USBDevice *usb_braille_init(const char *unused)
|
|||||||
if (!cdrv)
|
if (!cdrv)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
dev = usb_create(NULL /* FIXME */, "QEMU USB Braille");
|
dev = usb_create(NULL /* FIXME */, "usb-braille");
|
||||||
qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
|
qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
|
||||||
qdev_init(&dev->qdev);
|
qdev_init_nofail(&dev->qdev);
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct USBDeviceInfo serial_info = {
|
static struct USBDeviceInfo serial_info = {
|
||||||
.qdev.name = "QEMU USB Serial",
|
.product_desc = "QEMU USB Serial",
|
||||||
.qdev.alias = "usb-serial",
|
.qdev.name = "usb-serial",
|
||||||
.qdev.size = sizeof(USBSerialState),
|
.qdev.size = sizeof(USBSerialState),
|
||||||
.init = usb_serial_initfn,
|
.init = usb_serial_initfn,
|
||||||
.handle_packet = usb_generic_handle_packet,
|
.handle_packet = usb_generic_handle_packet,
|
||||||
@@ -625,8 +641,8 @@ static struct USBDeviceInfo serial_info = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct USBDeviceInfo braille_info = {
|
static struct USBDeviceInfo braille_info = {
|
||||||
.qdev.name = "QEMU USB Braille",
|
.product_desc = "QEMU USB Braille",
|
||||||
.qdev.alias = "usb-braille",
|
.qdev.name = "usb-braille",
|
||||||
.qdev.size = sizeof(USBSerialState),
|
.qdev.size = sizeof(USBSerialState),
|
||||||
.init = usb_serial_initfn,
|
.init = usb_serial_initfn,
|
||||||
.handle_packet = usb_generic_handle_packet,
|
.handle_packet = usb_generic_handle_packet,
|
||||||
|
@@ -677,9 +677,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
|
|||||||
|
|
||||||
ret = async->packet.len;
|
ret = async->packet.len;
|
||||||
|
|
||||||
if (td->ctrl & TD_CTRL_IOC)
|
|
||||||
*int_mask |= 0x01;
|
|
||||||
|
|
||||||
if (td->ctrl & TD_CTRL_IOS)
|
if (td->ctrl & TD_CTRL_IOS)
|
||||||
td->ctrl &= ~TD_CTRL_ACTIVE;
|
td->ctrl &= ~TD_CTRL_ACTIVE;
|
||||||
|
|
||||||
@@ -693,6 +690,8 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
|
|||||||
here. The docs are somewhat unclear, but win2k relies on this
|
here. The docs are somewhat unclear, but win2k relies on this
|
||||||
behavior. */
|
behavior. */
|
||||||
td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
|
td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
|
||||||
|
if (td->ctrl & TD_CTRL_IOC)
|
||||||
|
*int_mask |= 0x01;
|
||||||
|
|
||||||
if (pid == USB_TOKEN_IN) {
|
if (pid == USB_TOKEN_IN) {
|
||||||
if (len > max_len) {
|
if (len > max_len) {
|
||||||
@@ -750,6 +749,8 @@ out:
|
|||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
td->ctrl &= ~TD_CTRL_ACTIVE;
|
td->ctrl &= ~TD_CTRL_ACTIVE;
|
||||||
s->status |= UHCI_STS_USBERR;
|
s->status |= UHCI_STS_USBERR;
|
||||||
|
if (td->ctrl & TD_CTRL_IOC)
|
||||||
|
*int_mask |= 0x01;
|
||||||
uhci_update_irq(s);
|
uhci_update_irq(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1111,12 +1112,12 @@ static int usb_uhci_piix4_initfn(PCIDevice *dev)
|
|||||||
|
|
||||||
static PCIDeviceInfo uhci_info[] = {
|
static PCIDeviceInfo uhci_info[] = {
|
||||||
{
|
{
|
||||||
.qdev.name = "PIIX3 USB-UHCI",
|
.qdev.name = "piix3-usb-uhci",
|
||||||
.qdev.size = sizeof(UHCIState),
|
.qdev.size = sizeof(UHCIState),
|
||||||
.qdev.vmsd = &vmstate_uhci,
|
.qdev.vmsd = &vmstate_uhci,
|
||||||
.init = usb_uhci_piix3_initfn,
|
.init = usb_uhci_piix3_initfn,
|
||||||
},{
|
},{
|
||||||
.qdev.name = "PIIX4 USB-UHCI",
|
.qdev.name = "piix4-usb-uhci",
|
||||||
.qdev.size = sizeof(UHCIState),
|
.qdev.size = sizeof(UHCIState),
|
||||||
.qdev.vmsd = &vmstate_uhci,
|
.qdev.vmsd = &vmstate_uhci,
|
||||||
.init = usb_uhci_piix4_initfn,
|
.init = usb_uhci_piix4_initfn,
|
||||||
@@ -1133,10 +1134,10 @@ device_init(uhci_register);
|
|||||||
|
|
||||||
void usb_uhci_piix3_init(PCIBus *bus, int devfn)
|
void usb_uhci_piix3_init(PCIBus *bus, int devfn)
|
||||||
{
|
{
|
||||||
pci_create_simple(bus, devfn, "PIIX3 USB-UHCI");
|
pci_create_simple(bus, devfn, "piix3-usb-uhci");
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_uhci_piix4_init(PCIBus *bus, int devfn)
|
void usb_uhci_piix4_init(PCIBus *bus, int devfn)
|
||||||
{
|
{
|
||||||
pci_create_simple(bus, devfn, "PIIX4 USB-UHCI");
|
pci_create_simple(bus, devfn, "piix4-usb-uhci");
|
||||||
}
|
}
|
||||||
|
@@ -409,8 +409,9 @@ static int usb_wacom_initfn(USBDevice *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct USBDeviceInfo wacom_info = {
|
static struct USBDeviceInfo wacom_info = {
|
||||||
.qdev.name = "QEMU PenPartner Tablet",
|
.product_desc = "QEMU PenPartner Tablet",
|
||||||
.qdev.alias = "wacom-tablet",
|
.qdev.name = "usb-wacom-tablet",
|
||||||
|
.qdev.desc = "QEMU PenPartner Tablet",
|
||||||
.usbdevice_name = "wacom-tablet",
|
.usbdevice_name = "wacom-tablet",
|
||||||
.qdev.size = sizeof(USBWacomState),
|
.qdev.size = sizeof(USBWacomState),
|
||||||
.init = usb_wacom_initfn,
|
.init = usb_wacom_initfn,
|
||||||
|
7
hw/usb.h
7
hw/usb.h
@@ -132,7 +132,7 @@ struct USBDevice {
|
|||||||
|
|
||||||
int speed;
|
int speed;
|
||||||
uint8_t addr;
|
uint8_t addr;
|
||||||
char devname[32];
|
char product_desc[32];
|
||||||
int auto_attach;
|
int auto_attach;
|
||||||
int attached;
|
int attached;
|
||||||
|
|
||||||
@@ -185,6 +185,8 @@ struct USBDeviceInfo {
|
|||||||
*/
|
*/
|
||||||
int (*handle_data)(USBDevice *dev, USBPacket *p);
|
int (*handle_data)(USBDevice *dev, USBPacket *p);
|
||||||
|
|
||||||
|
const char *product_desc;
|
||||||
|
|
||||||
/* handle legacy -usbdevice command line options */
|
/* handle legacy -usbdevice command line options */
|
||||||
const char *usbdevice_name;
|
const char *usbdevice_name;
|
||||||
USBDevice *(*usbdevice_init)(const char *params);
|
USBDevice *(*usbdevice_init)(const char *params);
|
||||||
@@ -256,9 +258,6 @@ void usb_host_info(Monitor *mon);
|
|||||||
/* usb-hid.c */
|
/* usb-hid.c */
|
||||||
void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *));
|
void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *));
|
||||||
|
|
||||||
/* usb-net.c */
|
|
||||||
USBDevice *usb_net_init(NICInfo *nd);
|
|
||||||
|
|
||||||
/* usb-bt.c */
|
/* usb-bt.c */
|
||||||
USBDevice *usb_bt_init(HCIInfo *hci);
|
USBDevice *usb_bt_init(HCIInfo *hci);
|
||||||
|
|
||||||
|
@@ -42,11 +42,7 @@ int isa_vga_init(void)
|
|||||||
s->ds = graphic_console_init(s->update, s->invalidate,
|
s->ds = graphic_console_init(s->update, s->invalidate,
|
||||||
s->screen_dump, s->text_update, s);
|
s->screen_dump, s->text_update, s);
|
||||||
|
|
||||||
#ifdef CONFIG_BOCHS_VBE
|
vga_init_vbe(s);
|
||||||
/* XXX: use optimized standard vga accesses */
|
|
||||||
cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
|
|
||||||
VGA_RAM_SIZE, s->vram_offset);
|
|
||||||
#endif
|
|
||||||
/* ROM BIOS */
|
/* ROM BIOS */
|
||||||
rom_add_vga(VGABIOS_FILENAME);
|
rom_add_vga(VGABIOS_FILENAME);
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -106,12 +106,7 @@ static int pci_vga_initfn(PCIDevice *dev)
|
|||||||
PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
|
PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_BOCHS_VBE
|
vga_init_vbe(s);
|
||||||
/* XXX: use optimized standard vga accesses */
|
|
||||||
cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
|
|
||||||
VGA_RAM_SIZE, s->vram_offset);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ROM BIOS */
|
/* ROM BIOS */
|
||||||
rom_add_vga(VGABIOS_FILENAME);
|
rom_add_vga(VGABIOS_FILENAME);
|
||||||
return 0;
|
return 0;
|
||||||
|
46
hw/vga.c
46
hw/vga.c
@@ -1581,6 +1581,14 @@ static void vga_sync_dirty_bitmap(VGACommonState *s)
|
|||||||
cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
|
cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
|
||||||
cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
|
cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BOCHS_VBE
|
||||||
|
if (s->vbe_mapped) {
|
||||||
|
cpu_physical_sync_dirty_bitmap(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
|
||||||
|
VBE_DISPI_LFB_PHYSICAL_ADDRESS + s->vram_size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_dirty_log_start(VGACommonState *s)
|
void vga_dirty_log_start(VGACommonState *s)
|
||||||
@@ -1592,6 +1600,35 @@ void vga_dirty_log_start(VGACommonState *s)
|
|||||||
kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
|
kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
|
||||||
kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
|
kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BOCHS_VBE
|
||||||
|
if (kvm_enabled() && s->vbe_mapped) {
|
||||||
|
kvm_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void vga_dirty_log_stop(VGACommonState *s)
|
||||||
|
{
|
||||||
|
if (kvm_enabled() && s->map_addr)
|
||||||
|
kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
|
||||||
|
|
||||||
|
if (kvm_enabled() && s->lfb_vram_mapped) {
|
||||||
|
kvm_log_stop(isa_mem_base + 0xa0000, 0x80000);
|
||||||
|
kvm_log_stop(isa_mem_base + 0xa8000, 0x80000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BOCHS_VBE
|
||||||
|
if (kvm_enabled() && s->vbe_mapped) {
|
||||||
|
kvm_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void vga_dirty_log_restart(VGACommonState *s)
|
||||||
|
{
|
||||||
|
vga_dirty_log_stop(s);
|
||||||
|
vga_dirty_log_start(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2294,6 +2331,15 @@ void vga_init(VGACommonState *s)
|
|||||||
qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
|
qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vga_init_vbe(VGACommonState *s)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_BOCHS_VBE
|
||||||
|
/* XXX: use optimized standard vga accesses */
|
||||||
|
cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
|
||||||
|
VGA_RAM_SIZE, s->vram_offset);
|
||||||
|
s->vbe_mapped = 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
/********************************************************/
|
/********************************************************/
|
||||||
/* vga screen dump */
|
/* vga screen dump */
|
||||||
|
|
||||||
|
@@ -71,8 +71,8 @@
|
|||||||
uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; \
|
uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; \
|
||||||
uint32_t vbe_start_addr; \
|
uint32_t vbe_start_addr; \
|
||||||
uint32_t vbe_line_offset; \
|
uint32_t vbe_line_offset; \
|
||||||
uint32_t vbe_bank_mask;
|
uint32_t vbe_bank_mask; \
|
||||||
|
int vbe_mapped;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define VGA_STATE_COMMON_BOCHS_VBE
|
#define VGA_STATE_COMMON_BOCHS_VBE
|
||||||
@@ -194,6 +194,8 @@ void vga_init(VGACommonState *s);
|
|||||||
void vga_common_reset(VGACommonState *s);
|
void vga_common_reset(VGACommonState *s);
|
||||||
|
|
||||||
void vga_dirty_log_start(VGACommonState *s);
|
void vga_dirty_log_start(VGACommonState *s);
|
||||||
|
void vga_dirty_log_stop(VGACommonState *s);
|
||||||
|
void vga_dirty_log_restart(VGACommonState *s);
|
||||||
|
|
||||||
extern const VMStateDescription vmstate_vga_common;
|
extern const VMStateDescription vmstate_vga_common;
|
||||||
uint32_t vga_ioport_read(void *opaque, uint32_t addr);
|
uint32_t vga_ioport_read(void *opaque, uint32_t addr);
|
||||||
@@ -217,6 +219,7 @@ void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1,
|
|||||||
unsigned int color_xor);
|
unsigned int color_xor);
|
||||||
|
|
||||||
int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
|
int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
|
||||||
|
void vga_init_vbe(VGACommonState *s);
|
||||||
|
|
||||||
extern const uint8_t sr_mask[8];
|
extern const uint8_t sr_mask[8];
|
||||||
extern const uint8_t gr_mask[16];
|
extern const uint8_t gr_mask[16];
|
||||||
|
@@ -272,7 +272,7 @@ static void do_multiwrite(BlockDriverState *bs, BlockRequest *blkreq,
|
|||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
for (i = 0; i < num_writes; i++) {
|
for (i = 0; i < num_writes; i++) {
|
||||||
if (blkreq[i].error) {
|
if (blkreq[i].error) {
|
||||||
virtio_blk_req_complete(blkreq[i].opaque, VIRTIO_BLK_S_IOERR);
|
virtio_blk_rw_complete(blkreq[i].opaque, -EIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,7 +316,46 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
|
|||||||
acb = bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov,
|
acb = bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov,
|
||||||
req->qiov.size / 512, virtio_blk_rw_complete, req);
|
req->qiov.size / 512, virtio_blk_rw_complete, req);
|
||||||
if (!acb) {
|
if (!acb) {
|
||||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
|
virtio_blk_rw_complete(req, -EIO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct MultiReqBuffer {
|
||||||
|
BlockRequest blkreq[32];
|
||||||
|
int num_writes;
|
||||||
|
BlockDriverState *old_bs;
|
||||||
|
} MultiReqBuffer;
|
||||||
|
|
||||||
|
static void virtio_blk_handle_request(VirtIOBlockReq *req,
|
||||||
|
MultiReqBuffer *mrb)
|
||||||
|
{
|
||||||
|
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
|
||||||
|
fprintf(stderr, "virtio-blk missing headers\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
|
||||||
|
req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
|
||||||
|
fprintf(stderr, "virtio-blk header not in correct element\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
req->out = (void *)req->elem.out_sg[0].iov_base;
|
||||||
|
req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
|
||||||
|
|
||||||
|
if (req->out->type & VIRTIO_BLK_T_FLUSH) {
|
||||||
|
virtio_blk_handle_flush(req);
|
||||||
|
} else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
|
||||||
|
virtio_blk_handle_scsi(req);
|
||||||
|
} else if (req->out->type & VIRTIO_BLK_T_OUT) {
|
||||||
|
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
|
||||||
|
req->elem.out_num - 1);
|
||||||
|
virtio_blk_handle_write(mrb->blkreq, &mrb->num_writes,
|
||||||
|
req, &mrb->old_bs);
|
||||||
|
} else {
|
||||||
|
qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
|
||||||
|
req->elem.in_num - 1);
|
||||||
|
virtio_blk_handle_read(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,42 +363,17 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
{
|
{
|
||||||
VirtIOBlock *s = to_virtio_blk(vdev);
|
VirtIOBlock *s = to_virtio_blk(vdev);
|
||||||
VirtIOBlockReq *req;
|
VirtIOBlockReq *req;
|
||||||
BlockRequest blkreq[32];
|
MultiReqBuffer mrb = {
|
||||||
int num_writes = 0;
|
.num_writes = 0,
|
||||||
BlockDriverState *old_bs = NULL;
|
.old_bs = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
while ((req = virtio_blk_get_request(s))) {
|
while ((req = virtio_blk_get_request(s))) {
|
||||||
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
|
virtio_blk_handle_request(req, &mrb);
|
||||||
fprintf(stderr, "virtio-blk missing headers\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
|
|
||||||
req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
|
|
||||||
fprintf(stderr, "virtio-blk header not in correct element\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
req->out = (void *)req->elem.out_sg[0].iov_base;
|
|
||||||
req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
|
|
||||||
|
|
||||||
if (req->out->type & VIRTIO_BLK_T_FLUSH) {
|
|
||||||
virtio_blk_handle_flush(req);
|
|
||||||
} else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
|
|
||||||
virtio_blk_handle_scsi(req);
|
|
||||||
} else if (req->out->type & VIRTIO_BLK_T_OUT) {
|
|
||||||
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
|
|
||||||
req->elem.out_num - 1);
|
|
||||||
virtio_blk_handle_write(blkreq, &num_writes, req, &old_bs);
|
|
||||||
} else {
|
|
||||||
qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
|
|
||||||
req->elem.in_num - 1);
|
|
||||||
virtio_blk_handle_read(req);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_writes > 0) {
|
if (mrb.num_writes > 0) {
|
||||||
do_multiwrite(old_bs, blkreq, num_writes);
|
do_multiwrite(mrb.old_bs, mrb.blkreq, mrb.num_writes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -373,6 +387,10 @@ static void virtio_blk_dma_restart_bh(void *opaque)
|
|||||||
{
|
{
|
||||||
VirtIOBlock *s = opaque;
|
VirtIOBlock *s = opaque;
|
||||||
VirtIOBlockReq *req = s->rq;
|
VirtIOBlockReq *req = s->rq;
|
||||||
|
MultiReqBuffer mrb = {
|
||||||
|
.num_writes = 0,
|
||||||
|
.old_bs = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
qemu_bh_delete(s->bh);
|
qemu_bh_delete(s->bh);
|
||||||
s->bh = NULL;
|
s->bh = NULL;
|
||||||
@@ -380,10 +398,13 @@ static void virtio_blk_dma_restart_bh(void *opaque)
|
|||||||
s->rq = NULL;
|
s->rq = NULL;
|
||||||
|
|
||||||
while (req) {
|
while (req) {
|
||||||
bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov,
|
virtio_blk_handle_request(req, &mrb);
|
||||||
req->qiov.size / 512, virtio_blk_rw_complete, req);
|
|
||||||
req = req->next;
|
req = req->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mrb.num_writes > 0) {
|
||||||
|
do_multiwrite(mrb.old_bs, mrb.blkreq, mrb.num_writes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason)
|
static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason)
|
||||||
|
@@ -384,7 +384,15 @@ static int virtio_net_has_buffers(VirtIONet *n, int bufsize)
|
|||||||
(n->mergeable_rx_bufs &&
|
(n->mergeable_rx_bufs &&
|
||||||
!virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) {
|
!virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) {
|
||||||
virtio_queue_set_notification(n->rx_vq, 1);
|
virtio_queue_set_notification(n->rx_vq, 1);
|
||||||
return 0;
|
|
||||||
|
/* To avoid a race condition where the guest has made some buffers
|
||||||
|
* available after the above check but before notification was
|
||||||
|
* enabled, check for available buffers again.
|
||||||
|
*/
|
||||||
|
if (virtio_queue_empty(n->rx_vq) ||
|
||||||
|
(n->mergeable_rx_bufs &&
|
||||||
|
!virtqueue_avail_bytes(n->rx_vq, bufsize, 0)))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtio_queue_set_notification(n->rx_vq, 0);
|
virtio_queue_set_notification(n->rx_vq, 0);
|
||||||
|
@@ -236,9 +236,7 @@ static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
|
|||||||
switch (addr) {
|
switch (addr) {
|
||||||
case VIRTIO_PCI_HOST_FEATURES:
|
case VIRTIO_PCI_HOST_FEATURES:
|
||||||
ret = vdev->get_features(vdev);
|
ret = vdev->get_features(vdev);
|
||||||
ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
|
ret |= vdev->binding->get_features(proxy);
|
||||||
ret |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
|
|
||||||
ret |= (1 << VIRTIO_F_BAD_FEATURE);
|
|
||||||
break;
|
break;
|
||||||
case VIRTIO_PCI_GUEST_FEATURES:
|
case VIRTIO_PCI_GUEST_FEATURES:
|
||||||
ret = vdev->features;
|
ret = vdev->features;
|
||||||
@@ -374,7 +372,7 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
|
|||||||
|
|
||||||
if (PCI_COMMAND == address) {
|
if (PCI_COMMAND == address) {
|
||||||
if (!(val & PCI_COMMAND_MASTER)) {
|
if (!(val & PCI_COMMAND_MASTER)) {
|
||||||
proxy->vdev->status &= !VIRTIO_CONFIG_S_DRIVER_OK;
|
proxy->vdev->status &= ~VIRTIO_CONFIG_S_DRIVER_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,12 +380,22 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
|
|||||||
msix_write_config(pci_dev, address, val, len);
|
msix_write_config(pci_dev, address, val, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned virtio_pci_get_features(void *opaque)
|
||||||
|
{
|
||||||
|
unsigned ret = 0;
|
||||||
|
ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
|
||||||
|
ret |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
|
||||||
|
ret |= (1 << VIRTIO_F_BAD_FEATURE);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static const VirtIOBindings virtio_pci_bindings = {
|
static const VirtIOBindings virtio_pci_bindings = {
|
||||||
.notify = virtio_pci_notify,
|
.notify = virtio_pci_notify,
|
||||||
.save_config = virtio_pci_save_config,
|
.save_config = virtio_pci_save_config,
|
||||||
.load_config = virtio_pci_load_config,
|
.load_config = virtio_pci_load_config,
|
||||||
.save_queue = virtio_pci_save_queue,
|
.save_queue = virtio_pci_save_queue,
|
||||||
.load_queue = virtio_pci_load_queue,
|
.load_queue = virtio_pci_load_queue,
|
||||||
|
.get_features = virtio_pci_get_features,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
|
static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
|
||||||
@@ -510,14 +518,6 @@ static int virtio_net_init_pci(PCIDevice *pci_dev)
|
|||||||
|
|
||||||
/* make the actual value visible */
|
/* make the actual value visible */
|
||||||
proxy->nvectors = vdev->nvectors;
|
proxy->nvectors = vdev->nvectors;
|
||||||
|
|
||||||
if (!pci_dev->qdev.hotplugged) {
|
|
||||||
static int loaded = 0;
|
|
||||||
if (!loaded) {
|
|
||||||
rom_add_option("pxe-virtio.bin");
|
|
||||||
loaded = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,6 +561,7 @@ static PCIDeviceInfo virtio_info[] = {
|
|||||||
.qdev.size = sizeof(VirtIOPCIProxy),
|
.qdev.size = sizeof(VirtIOPCIProxy),
|
||||||
.init = virtio_net_init_pci,
|
.init = virtio_net_init_pci,
|
||||||
.exit = virtio_net_exit_pci,
|
.exit = virtio_net_exit_pci,
|
||||||
|
.romfile = "pxe-virtio.bin",
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
|
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
|
||||||
DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
|
DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
|
||||||
|
11
hw/virtio.c
11
hw/virtio.c
@@ -651,6 +651,9 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
|
|||||||
int virtio_load(VirtIODevice *vdev, QEMUFile *f)
|
int virtio_load(VirtIODevice *vdev, QEMUFile *f)
|
||||||
{
|
{
|
||||||
int num, i, ret;
|
int num, i, ret;
|
||||||
|
uint32_t features;
|
||||||
|
uint32_t supported_features = vdev->get_features(vdev) |
|
||||||
|
vdev->binding->get_features(vdev->binding_opaque);
|
||||||
|
|
||||||
if (vdev->binding->load_config) {
|
if (vdev->binding->load_config) {
|
||||||
ret = vdev->binding->load_config(vdev->binding_opaque, f);
|
ret = vdev->binding->load_config(vdev->binding_opaque, f);
|
||||||
@@ -661,7 +664,13 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
|
|||||||
qemu_get_8s(f, &vdev->status);
|
qemu_get_8s(f, &vdev->status);
|
||||||
qemu_get_8s(f, &vdev->isr);
|
qemu_get_8s(f, &vdev->isr);
|
||||||
qemu_get_be16s(f, &vdev->queue_sel);
|
qemu_get_be16s(f, &vdev->queue_sel);
|
||||||
qemu_get_be32s(f, &vdev->features);
|
qemu_get_be32s(f, &features);
|
||||||
|
if (features & ~supported_features) {
|
||||||
|
fprintf(stderr, "Features 0x%x unsupported. Allowed features: 0x%x\n",
|
||||||
|
features, supported_features);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
vdev->features = features;
|
||||||
vdev->config_len = qemu_get_be32(f);
|
vdev->config_len = qemu_get_be32(f);
|
||||||
qemu_get_buffer(f, vdev->config, vdev->config_len);
|
qemu_get_buffer(f, vdev->config, vdev->config_len);
|
||||||
|
|
||||||
|
@@ -31,6 +31,11 @@
|
|||||||
/* We've given up on this device. */
|
/* We've given up on this device. */
|
||||||
#define VIRTIO_CONFIG_S_FAILED 0x80
|
#define VIRTIO_CONFIG_S_FAILED 0x80
|
||||||
|
|
||||||
|
/* Some virtio feature bits (currently bits 28 through 31) are reserved for the
|
||||||
|
* transport being used (eg. virtio_ring), the rest are per-device feature bits. */
|
||||||
|
#define VIRTIO_TRANSPORT_F_START 28
|
||||||
|
#define VIRTIO_TRANSPORT_F_END 32
|
||||||
|
|
||||||
/* We notify when the ring is completely used, even if the guest is suppressing
|
/* We notify when the ring is completely used, even if the guest is suppressing
|
||||||
* callbacks */
|
* callbacks */
|
||||||
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
|
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
|
||||||
@@ -82,6 +87,7 @@ typedef struct {
|
|||||||
void (*save_queue)(void * opaque, int n, QEMUFile *f);
|
void (*save_queue)(void * opaque, int n, QEMUFile *f);
|
||||||
int (*load_config)(void * opaque, QEMUFile *f);
|
int (*load_config)(void * opaque, QEMUFile *f);
|
||||||
int (*load_queue)(void * opaque, int n, QEMUFile *f);
|
int (*load_queue)(void * opaque, int n, QEMUFile *f);
|
||||||
|
unsigned (*get_features)(void * opaque);
|
||||||
} VirtIOBindings;
|
} VirtIOBindings;
|
||||||
|
|
||||||
#define VIRTIO_PCI_QUEUE_MAX 16
|
#define VIRTIO_PCI_QUEUE_MAX 16
|
||||||
|
@@ -22,6 +22,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
|
#include "loader.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
#include "vmware_vga.h"
|
#include "vmware_vga.h"
|
||||||
@@ -66,6 +67,11 @@ struct vmsvga_state_s {
|
|||||||
int syncing;
|
int syncing;
|
||||||
int fb_size;
|
int fb_size;
|
||||||
|
|
||||||
|
ram_addr_t fifo_offset;
|
||||||
|
uint8_t *fifo_ptr;
|
||||||
|
unsigned int fifo_size;
|
||||||
|
target_phys_addr_t fifo_base;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint32_t *fifo;
|
uint32_t *fifo;
|
||||||
struct __attribute__((__packed__)) {
|
struct __attribute__((__packed__)) {
|
||||||
@@ -461,7 +467,7 @@ struct vmsvga_cursor_definition_s {
|
|||||||
int hot_x;
|
int hot_x;
|
||||||
int hot_y;
|
int hot_y;
|
||||||
uint32_t mask[1024];
|
uint32_t mask[1024];
|
||||||
uint32_t image[1024];
|
uint32_t image[4096];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SVGA_BITMAP_SIZE(w, h) ((((w) + 31) >> 5) * (h))
|
#define SVGA_BITMAP_SIZE(w, h) ((((w) + 31) >> 5) * (h))
|
||||||
@@ -556,6 +562,13 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
|
|||||||
cursor.height = y = vmsvga_fifo_read(s);
|
cursor.height = y = vmsvga_fifo_read(s);
|
||||||
vmsvga_fifo_read(s);
|
vmsvga_fifo_read(s);
|
||||||
cursor.bpp = vmsvga_fifo_read(s);
|
cursor.bpp = vmsvga_fifo_read(s);
|
||||||
|
|
||||||
|
if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask ||
|
||||||
|
SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) {
|
||||||
|
args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
|
||||||
|
goto badcmd;
|
||||||
|
}
|
||||||
|
|
||||||
for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args ++)
|
for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args ++)
|
||||||
cursor.mask[args] = vmsvga_fifo_read_raw(s);
|
cursor.mask[args] = vmsvga_fifo_read_raw(s);
|
||||||
for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args ++)
|
for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args ++)
|
||||||
@@ -679,7 +692,7 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
|
|||||||
return 0x0;
|
return 0x0;
|
||||||
|
|
||||||
case SVGA_REG_VRAM_SIZE:
|
case SVGA_REG_VRAM_SIZE:
|
||||||
return s->vga.vram_size - SVGA_FIFO_SIZE;
|
return s->vga.vram_size;
|
||||||
|
|
||||||
case SVGA_REG_FB_SIZE:
|
case SVGA_REG_FB_SIZE:
|
||||||
return s->fb_size;
|
return s->fb_size;
|
||||||
@@ -700,10 +713,10 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
|
|||||||
return caps;
|
return caps;
|
||||||
|
|
||||||
case SVGA_REG_MEM_START:
|
case SVGA_REG_MEM_START:
|
||||||
return s->vram_base + s->vga.vram_size - SVGA_FIFO_SIZE;
|
return s->fifo_base;
|
||||||
|
|
||||||
case SVGA_REG_MEM_SIZE:
|
case SVGA_REG_MEM_SIZE:
|
||||||
return SVGA_FIFO_SIZE;
|
return s->fifo_size;
|
||||||
|
|
||||||
case SVGA_REG_CONFIG_DONE:
|
case SVGA_REG_CONFIG_DONE:
|
||||||
return s->config;
|
return s->config;
|
||||||
@@ -765,8 +778,12 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
|
|||||||
s->height = -1;
|
s->height = -1;
|
||||||
s->invalidated = 1;
|
s->invalidated = 1;
|
||||||
s->vga.invalidate(&s->vga);
|
s->vga.invalidate(&s->vga);
|
||||||
if (s->enable)
|
if (s->enable) {
|
||||||
s->fb_size = ((s->depth + 7) >> 3) * s->new_width * s->new_height;
|
s->fb_size = ((s->depth + 7) >> 3) * s->new_width * s->new_height;
|
||||||
|
vga_dirty_log_stop(&s->vga);
|
||||||
|
} else {
|
||||||
|
vga_dirty_log_start(&s->vga);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SVGA_REG_WIDTH:
|
case SVGA_REG_WIDTH:
|
||||||
@@ -789,7 +806,7 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
|
|||||||
|
|
||||||
case SVGA_REG_CONFIG_DONE:
|
case SVGA_REG_CONFIG_DONE:
|
||||||
if (value) {
|
if (value) {
|
||||||
s->fifo = (uint32_t *) &s->vga.vram_ptr[s->vga.vram_size - SVGA_FIFO_SIZE];
|
s->fifo = (uint32_t *) s->fifo_ptr;
|
||||||
/* Check range and alignment. */
|
/* Check range and alignment. */
|
||||||
if ((CMD(min) | CMD(max) |
|
if ((CMD(min) | CMD(max) |
|
||||||
CMD(next_cmd) | CMD(stop)) & 3)
|
CMD(next_cmd) | CMD(stop)) & 3)
|
||||||
@@ -909,8 +926,8 @@ static void vmsvga_reset(struct vmsvga_state_s *s)
|
|||||||
s->width = -1;
|
s->width = -1;
|
||||||
s->height = -1;
|
s->height = -1;
|
||||||
s->svgaid = SVGA_ID;
|
s->svgaid = SVGA_ID;
|
||||||
s->depth = 24;
|
s->depth = ds_get_bits_per_pixel(s->vga.ds);
|
||||||
s->bypp = (s->depth + 7) >> 3;
|
s->bypp = ds_get_bytes_per_pixel(s->vga.ds);
|
||||||
s->cursor.on = 0;
|
s->cursor.on = 0;
|
||||||
s->redraw_fifo_first = 0;
|
s->redraw_fifo_first = 0;
|
||||||
s->redraw_fifo_last = 0;
|
s->redraw_fifo_last = 0;
|
||||||
@@ -942,6 +959,8 @@ static void vmsvga_reset(struct vmsvga_state_s *s)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
s->syncing = 0;
|
s->syncing = 0;
|
||||||
|
|
||||||
|
vga_dirty_log_start(&s->vga);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vmsvga_invalidate_display(void *opaque)
|
static void vmsvga_invalidate_display(void *opaque)
|
||||||
@@ -1058,7 +1077,7 @@ static int vmsvga_post_load(void *opaque, int version_id)
|
|||||||
|
|
||||||
s->invalidated = 1;
|
s->invalidated = 1;
|
||||||
if (s->config)
|
if (s->config)
|
||||||
s->fifo = (uint32_t *) &s->vga.vram_ptr[s->vga.vram_size - SVGA_FIFO_SIZE];
|
s->fifo = (uint32_t *) s->fifo_ptr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1108,22 +1127,25 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
|
|||||||
s->scratch_size = SVGA_SCRATCH_SIZE;
|
s->scratch_size = SVGA_SCRATCH_SIZE;
|
||||||
s->scratch = qemu_malloc(s->scratch_size * 4);
|
s->scratch = qemu_malloc(s->scratch_size * 4);
|
||||||
|
|
||||||
vmsvga_reset(s);
|
|
||||||
|
|
||||||
vga_common_init(&s->vga, vga_ram_size);
|
|
||||||
vga_init(&s->vga);
|
|
||||||
vmstate_register(0, &vmstate_vga_common, &s->vga);
|
|
||||||
|
|
||||||
s->vga.ds = graphic_console_init(vmsvga_update_display,
|
s->vga.ds = graphic_console_init(vmsvga_update_display,
|
||||||
vmsvga_invalidate_display,
|
vmsvga_invalidate_display,
|
||||||
vmsvga_screen_dump,
|
vmsvga_screen_dump,
|
||||||
vmsvga_text_update, s);
|
vmsvga_text_update, s);
|
||||||
|
|
||||||
#ifdef CONFIG_BOCHS_VBE
|
|
||||||
/* XXX: use optimized standard vga accesses */
|
s->fifo_size = SVGA_FIFO_SIZE;
|
||||||
cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
|
s->fifo_offset = qemu_ram_alloc(s->fifo_size);
|
||||||
vga_ram_size, s->vga.vram_offset);
|
s->fifo_ptr = qemu_get_ram_ptr(s->fifo_offset);
|
||||||
#endif
|
|
||||||
|
vga_common_init(&s->vga, vga_ram_size);
|
||||||
|
vga_init(&s->vga);
|
||||||
|
vmstate_register(0, &vmstate_vga_common, &s->vga);
|
||||||
|
|
||||||
|
vga_init_vbe(&s->vga);
|
||||||
|
|
||||||
|
rom_add_vga(VGABIOS_FILENAME);
|
||||||
|
|
||||||
|
vmsvga_reset(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pci_vmsvga_map_ioport(PCIDevice *pci_dev, int region_num,
|
static void pci_vmsvga_map_ioport(PCIDevice *pci_dev, int region_num,
|
||||||
@@ -1162,6 +1184,23 @@ static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
|
|||||||
#endif
|
#endif
|
||||||
cpu_register_physical_memory(s->vram_base, s->vga.vram_size,
|
cpu_register_physical_memory(s->vram_base, s->vga.vram_size,
|
||||||
iomemtype);
|
iomemtype);
|
||||||
|
|
||||||
|
s->vga.map_addr = addr;
|
||||||
|
s->vga.map_end = addr + s->vga.vram_size;
|
||||||
|
vga_dirty_log_restart(&s->vga);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_vmsvga_map_fifo(PCIDevice *pci_dev, int region_num,
|
||||||
|
pcibus_t addr, pcibus_t size, int type)
|
||||||
|
{
|
||||||
|
struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
|
||||||
|
struct vmsvga_state_s *s = &d->chip;
|
||||||
|
ram_addr_t iomemtype;
|
||||||
|
|
||||||
|
s->fifo_base = addr;
|
||||||
|
iomemtype = s->fifo_offset | IO_MEM_RAM;
|
||||||
|
cpu_register_physical_memory(s->fifo_base, s->fifo_size,
|
||||||
|
iomemtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pci_vmsvga_initfn(PCIDevice *dev)
|
static int pci_vmsvga_initfn(PCIDevice *dev)
|
||||||
@@ -1187,6 +1226,9 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
|
|||||||
pci_register_bar(&s->card, 1, VGA_RAM_SIZE,
|
pci_register_bar(&s->card, 1, VGA_RAM_SIZE,
|
||||||
PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_mem);
|
PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_mem);
|
||||||
|
|
||||||
|
pci_register_bar(&s->card, 2, SVGA_FIFO_SIZE,
|
||||||
|
PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_fifo);
|
||||||
|
|
||||||
vmsvga_init(&s->chip, VGA_RAM_SIZE);
|
vmsvga_init(&s->chip, VGA_RAM_SIZE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1194,11 +1236,11 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
|
|||||||
|
|
||||||
void pci_vmsvga_init(PCIBus *bus)
|
void pci_vmsvga_init(PCIBus *bus)
|
||||||
{
|
{
|
||||||
pci_create_simple(bus, -1, "QEMUware SVGA");
|
pci_create_simple(bus, -1, "vmware-svga");
|
||||||
}
|
}
|
||||||
|
|
||||||
static PCIDeviceInfo vmsvga_info = {
|
static PCIDeviceInfo vmsvga_info = {
|
||||||
.qdev.name = "QEMUware SVGA",
|
.qdev.name = "vmware-svga",
|
||||||
.qdev.size = sizeof(struct pci_vmsvga_state_s),
|
.qdev.size = sizeof(struct pci_vmsvga_state_s),
|
||||||
.qdev.vmsd = &vmstate_vmware_vga,
|
.qdev.vmsd = &vmstate_vmware_vga,
|
||||||
.init = pci_vmsvga_initfn,
|
.init = pci_vmsvga_initfn,
|
||||||
|
16
json-lexer.c
16
json-lexer.c
@@ -54,6 +54,9 @@ enum json_lexer_state {
|
|||||||
IN_ESCAPE,
|
IN_ESCAPE,
|
||||||
IN_ESCAPE_L,
|
IN_ESCAPE_L,
|
||||||
IN_ESCAPE_LL,
|
IN_ESCAPE_LL,
|
||||||
|
IN_ESCAPE_I,
|
||||||
|
IN_ESCAPE_I6,
|
||||||
|
IN_ESCAPE_I64,
|
||||||
IN_ESCAPE_DONE,
|
IN_ESCAPE_DONE,
|
||||||
IN_WHITESPACE,
|
IN_WHITESPACE,
|
||||||
IN_OPERATOR_DONE,
|
IN_OPERATOR_DONE,
|
||||||
@@ -223,6 +226,18 @@ static const uint8_t json_lexer[][256] = {
|
|||||||
['l'] = IN_ESCAPE_LL,
|
['l'] = IN_ESCAPE_LL,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[IN_ESCAPE_I64] = {
|
||||||
|
['d'] = IN_ESCAPE_DONE,
|
||||||
|
},
|
||||||
|
|
||||||
|
[IN_ESCAPE_I6] = {
|
||||||
|
['4'] = IN_ESCAPE_I64,
|
||||||
|
},
|
||||||
|
|
||||||
|
[IN_ESCAPE_I] = {
|
||||||
|
['6'] = IN_ESCAPE_I6,
|
||||||
|
},
|
||||||
|
|
||||||
[IN_ESCAPE] = {
|
[IN_ESCAPE] = {
|
||||||
['d'] = IN_ESCAPE_DONE,
|
['d'] = IN_ESCAPE_DONE,
|
||||||
['i'] = IN_ESCAPE_DONE,
|
['i'] = IN_ESCAPE_DONE,
|
||||||
@@ -230,6 +245,7 @@ static const uint8_t json_lexer[][256] = {
|
|||||||
['s'] = IN_ESCAPE_DONE,
|
['s'] = IN_ESCAPE_DONE,
|
||||||
['f'] = IN_ESCAPE_DONE,
|
['f'] = IN_ESCAPE_DONE,
|
||||||
['l'] = IN_ESCAPE_L,
|
['l'] = IN_ESCAPE_L,
|
||||||
|
['I'] = IN_ESCAPE_I,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* top level rule */
|
/* top level rule */
|
||||||
|
@@ -266,7 +266,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l
|
|||||||
|
|
||||||
peek = qlist_peek(working);
|
peek = qlist_peek(working);
|
||||||
key = parse_value(ctxt, &working, ap);
|
key = parse_value(ctxt, &working, ap);
|
||||||
if (qobject_type(key) != QTYPE_QSTRING) {
|
if (!key || qobject_type(key) != QTYPE_QSTRING) {
|
||||||
parse_error(ctxt, peek, "key is not a string in object");
|
parse_error(ctxt, peek, "key is not a string in object");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -476,7 +476,8 @@ static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *a
|
|||||||
obj = QOBJECT(qint_from_int(va_arg(*ap, int)));
|
obj = QOBJECT(qint_from_int(va_arg(*ap, int)));
|
||||||
} else if (token_is_escape(token, "%ld")) {
|
} else if (token_is_escape(token, "%ld")) {
|
||||||
obj = QOBJECT(qint_from_int(va_arg(*ap, long)));
|
obj = QOBJECT(qint_from_int(va_arg(*ap, long)));
|
||||||
} else if (token_is_escape(token, "%lld")) {
|
} else if (token_is_escape(token, "%lld") ||
|
||||||
|
token_is_escape(token, "%I64d")) {
|
||||||
obj = QOBJECT(qint_from_int(va_arg(*ap, long long)));
|
obj = QOBJECT(qint_from_int(va_arg(*ap, long long)));
|
||||||
} else if (token_is_escape(token, "%s")) {
|
} else if (token_is_escape(token, "%s")) {
|
||||||
obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
|
obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
|
||||||
|
@@ -593,6 +593,7 @@ static int do_strex(CPUARMState *env)
|
|||||||
}
|
}
|
||||||
rc = 0;
|
rc = 0;
|
||||||
fail:
|
fail:
|
||||||
|
env->regs[15] += 4;
|
||||||
env->regs[(env->exclusive_info >> 4) & 0xf] = rc;
|
env->regs[(env->exclusive_info >> 4) & 0xf] = rc;
|
||||||
done:
|
done:
|
||||||
end_exclusive();
|
end_exclusive();
|
||||||
@@ -2683,7 +2684,7 @@ int main(int argc, char **argv, char **envp)
|
|||||||
#endif
|
#endif
|
||||||
#elif defined(TARGET_PPC)
|
#elif defined(TARGET_PPC)
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
cpu_model = "970";
|
cpu_model = "970fx";
|
||||||
#else
|
#else
|
||||||
cpu_model = "750";
|
cpu_model = "750";
|
||||||
#endif
|
#endif
|
||||||
|
@@ -112,10 +112,6 @@ MigrationState *unix_start_outgoing_migration(Monitor *mon,
|
|||||||
|
|
||||||
socket_set_nonblock(s->fd);
|
socket_set_nonblock(s->fd);
|
||||||
|
|
||||||
if (!detach) {
|
|
||||||
migrate_fd_monitor_suspend(s, mon);
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
|
ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
@@ -128,7 +124,13 @@ MigrationState *unix_start_outgoing_migration(Monitor *mon,
|
|||||||
if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
|
if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
|
||||||
dprintf("connect failed\n");
|
dprintf("connect failed\n");
|
||||||
goto err_after_open;
|
goto err_after_open;
|
||||||
} else if (ret >= 0)
|
}
|
||||||
|
|
||||||
|
if (!detach) {
|
||||||
|
migrate_fd_monitor_suspend(s, mon);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret >= 0)
|
||||||
migrate_fd_connect(s);
|
migrate_fd_connect(s);
|
||||||
|
|
||||||
return &s->mig_state;
|
return &s->mig_state;
|
||||||
|
119
migration.c
119
migration.c
@@ -19,6 +19,7 @@
|
|||||||
#include "block.h"
|
#include "block.h"
|
||||||
#include "qemu_socket.h"
|
#include "qemu_socket.h"
|
||||||
#include "block-migration.h"
|
#include "block-migration.h"
|
||||||
|
#include "qemu-objects.h"
|
||||||
|
|
||||||
//#define DEBUG_MIGRATION
|
//#define DEBUG_MIGRATION
|
||||||
|
|
||||||
@@ -105,7 +106,7 @@ void do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
s->cancel(s);
|
s->cancel(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
void do_migrate_set_speed(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
double d;
|
double d;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
@@ -163,37 +164,123 @@ void do_migrate_set_downtime(Monitor *mon, const QDict *qdict)
|
|||||||
max_downtime = (uint64_t)d;
|
max_downtime = (uint64_t)d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_info_migrate(Monitor *mon)
|
static void migrate_print_status(Monitor *mon, const char *name,
|
||||||
|
const QDict *status_dict)
|
||||||
{
|
{
|
||||||
|
QDict *qdict;
|
||||||
|
|
||||||
|
qdict = qobject_to_qdict(qdict_get(status_dict, name));
|
||||||
|
|
||||||
|
monitor_printf(mon, "transferred %s: %" PRIu64 " kbytes\n", name,
|
||||||
|
qdict_get_int(qdict, "transferred") >> 10);
|
||||||
|
monitor_printf(mon, "remaining %s: %" PRIu64 " kbytes\n", name,
|
||||||
|
qdict_get_int(qdict, "remaining") >> 10);
|
||||||
|
monitor_printf(mon, "total %s: %" PRIu64 " kbytes\n", name,
|
||||||
|
qdict_get_int(qdict, "total") >> 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_info_migrate_print(Monitor *mon, const QObject *data)
|
||||||
|
{
|
||||||
|
QDict *qdict;
|
||||||
|
|
||||||
|
qdict = qobject_to_qdict(data);
|
||||||
|
|
||||||
|
monitor_printf(mon, "Migration status: %s\n",
|
||||||
|
qdict_get_str(qdict, "status"));
|
||||||
|
|
||||||
|
if (qdict_haskey(qdict, "ram")) {
|
||||||
|
migrate_print_status(mon, "ram", qdict);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qdict_haskey(qdict, "disk")) {
|
||||||
|
migrate_print_status(mon, "disk", qdict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void migrate_put_status(QDict *qdict, const char *name,
|
||||||
|
uint64_t trans, uint64_t rem, uint64_t total)
|
||||||
|
{
|
||||||
|
QObject *obj;
|
||||||
|
|
||||||
|
obj = qobject_from_jsonf("{ 'transferred': %" PRId64 ", "
|
||||||
|
"'remaining': %" PRId64 ", "
|
||||||
|
"'total': %" PRId64 " }", trans, rem, total);
|
||||||
|
assert(obj != NULL);
|
||||||
|
|
||||||
|
qdict_put_obj(qdict, name, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do_info_migrate(): Migration status
|
||||||
|
*
|
||||||
|
* Return a QDict. If migration is active there will be another
|
||||||
|
* QDict with RAM migration status and if block migration is active
|
||||||
|
* another one with block migration status.
|
||||||
|
*
|
||||||
|
* The main QDict contains the following:
|
||||||
|
*
|
||||||
|
* - "status": migration status
|
||||||
|
* - "ram": only present if "status" is "active", it is a QDict with the
|
||||||
|
* following RAM information (in bytes):
|
||||||
|
* - "transferred": amount transferred
|
||||||
|
* - "remaining": amount remaining
|
||||||
|
* - "total": total
|
||||||
|
* - "disk": only present if "status" is "active" and it is a block migration,
|
||||||
|
* it is a QDict with the following disk information (in bytes):
|
||||||
|
* - "transferred": amount transferred
|
||||||
|
* - "remaining": amount remaining
|
||||||
|
* - "total": total
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* 1. Migration is "completed":
|
||||||
|
*
|
||||||
|
* { "status": "completed" }
|
||||||
|
*
|
||||||
|
* 2. Migration is "active" and it is not a block migration:
|
||||||
|
*
|
||||||
|
* { "status": "active",
|
||||||
|
* "ram": { "transferred": 123, "remaining": 123, "total": 246 } }
|
||||||
|
*
|
||||||
|
* 3. Migration is "active" and it is a block migration:
|
||||||
|
*
|
||||||
|
* { "status": "active",
|
||||||
|
* "ram": { "total": 1057024, "remaining": 1053304, "transferred": 3720 },
|
||||||
|
* "disk": { "total": 20971520, "remaining": 20880384, "transferred": 91136 }}
|
||||||
|
*/
|
||||||
|
void do_info_migrate(Monitor *mon, QObject **ret_data)
|
||||||
|
{
|
||||||
|
QDict *qdict;
|
||||||
MigrationState *s = current_migration;
|
MigrationState *s = current_migration;
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
monitor_printf(mon, "Migration status: ");
|
|
||||||
switch (s->get_status(s)) {
|
switch (s->get_status(s)) {
|
||||||
case MIG_STATE_ACTIVE:
|
case MIG_STATE_ACTIVE:
|
||||||
monitor_printf(mon, "active\n");
|
qdict = qdict_new();
|
||||||
monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n", ram_bytes_transferred() >> 10);
|
qdict_put(qdict, "status", qstring_from_str("active"));
|
||||||
monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n", ram_bytes_remaining() >> 10);
|
|
||||||
monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n", ram_bytes_total() >> 10);
|
migrate_put_status(qdict, "ram", ram_bytes_transferred(),
|
||||||
|
ram_bytes_remaining(), ram_bytes_total());
|
||||||
|
|
||||||
if (blk_mig_active()) {
|
if (blk_mig_active()) {
|
||||||
monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n",
|
migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(),
|
||||||
blk_mig_bytes_transferred() >> 10);
|
blk_mig_bytes_remaining(),
|
||||||
monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n",
|
blk_mig_bytes_total());
|
||||||
blk_mig_bytes_remaining() >> 10);
|
|
||||||
monitor_printf(mon, "total disk: %" PRIu64 " kbytes\n",
|
|
||||||
blk_mig_bytes_total() >> 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*ret_data = QOBJECT(qdict);
|
||||||
break;
|
break;
|
||||||
case MIG_STATE_COMPLETED:
|
case MIG_STATE_COMPLETED:
|
||||||
monitor_printf(mon, "completed\n");
|
*ret_data = qobject_from_jsonf("{ 'status': 'completed' }");
|
||||||
break;
|
break;
|
||||||
case MIG_STATE_ERROR:
|
case MIG_STATE_ERROR:
|
||||||
monitor_printf(mon, "failed\n");
|
*ret_data = qobject_from_jsonf("{ 'status': 'failed' }");
|
||||||
break;
|
break;
|
||||||
case MIG_STATE_CANCELLED:
|
case MIG_STATE_CANCELLED:
|
||||||
monitor_printf(mon, "cancelled\n");
|
*ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
assert(*ret_data != NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -56,13 +56,15 @@ void do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
|
|||||||
|
|
||||||
void do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data);
|
void do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data);
|
||||||
|
|
||||||
void do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data);
|
void do_migrate_set_speed(Monitor *mon, const QDict *qdict);
|
||||||
|
|
||||||
uint64_t migrate_max_downtime(void);
|
uint64_t migrate_max_downtime(void);
|
||||||
|
|
||||||
void do_migrate_set_downtime(Monitor *mon, const QDict *qdict);
|
void do_migrate_set_downtime(Monitor *mon, const QDict *qdict);
|
||||||
|
|
||||||
void do_info_migrate(Monitor *mon);
|
void do_info_migrate_print(Monitor *mon, const QObject *data);
|
||||||
|
|
||||||
|
void do_info_migrate(Monitor *mon, QObject **ret_data);
|
||||||
|
|
||||||
int exec_start_incoming_migration(const char *host_port);
|
int exec_start_incoming_migration(const char *host_port);
|
||||||
|
|
||||||
|
474
monitor.c
474
monitor.c
@@ -140,6 +140,9 @@ static inline int monitor_ctrl_mode(const Monitor *mon)
|
|||||||
|
|
||||||
static void monitor_read_command(Monitor *mon, int show_prompt)
|
static void monitor_read_command(Monitor *mon, int show_prompt)
|
||||||
{
|
{
|
||||||
|
if (!mon->rs)
|
||||||
|
return;
|
||||||
|
|
||||||
readline_start(mon->rs, "(qemu) ", 0, monitor_command_cb, NULL);
|
readline_start(mon->rs, "(qemu) ", 0, monitor_command_cb, NULL);
|
||||||
if (show_prompt)
|
if (show_prompt)
|
||||||
readline_show_prompt(mon->rs);
|
readline_show_prompt(mon->rs);
|
||||||
@@ -148,7 +151,10 @@ static void monitor_read_command(Monitor *mon, int show_prompt)
|
|||||||
static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
|
static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
|
||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
if (mon->rs) {
|
if (monitor_ctrl_mode(mon)) {
|
||||||
|
qemu_error_new(QERR_MISSING_PARAMETER, "password");
|
||||||
|
return -EINVAL;
|
||||||
|
} else if (mon->rs) {
|
||||||
readline_start(mon->rs, "Password: ", 1, readline_func, opaque);
|
readline_start(mon->rs, "Password: ", 1, readline_func, opaque);
|
||||||
/* prompt is printed on return from the command handler */
|
/* prompt is printed on return from the command handler */
|
||||||
return 0;
|
return 0;
|
||||||
@@ -171,9 +177,6 @@ static void monitor_puts(Monitor *mon, const char *str)
|
|||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
if (!mon)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
c = *str++;
|
c = *str++;
|
||||||
if (c == '\0')
|
if (c == '\0')
|
||||||
@@ -189,6 +192,9 @@ static void monitor_puts(Monitor *mon, const char *str)
|
|||||||
|
|
||||||
void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
|
void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
|
if (!mon)
|
||||||
|
return;
|
||||||
|
|
||||||
if (mon->mc && !mon->mc->print_enabled) {
|
if (mon->mc && !mon->mc->print_enabled) {
|
||||||
qemu_error_new(QERR_UNDEFINED_ERROR);
|
qemu_error_new(QERR_UNDEFINED_ERROR);
|
||||||
} else {
|
} else {
|
||||||
@@ -254,24 +260,6 @@ static inline int monitor_has_error(const Monitor *mon)
|
|||||||
return mon->error != NULL;
|
return mon->error != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void monitor_print_qobject(Monitor *mon, const QObject *data)
|
|
||||||
{
|
|
||||||
switch (qobject_type(data)) {
|
|
||||||
case QTYPE_QSTRING:
|
|
||||||
monitor_printf(mon, "%s",qstring_get_str(qobject_to_qstring(data)));
|
|
||||||
break;
|
|
||||||
case QTYPE_QINT:
|
|
||||||
monitor_printf(mon, "%" PRId64,qint_get_int(qobject_to_qint(data)));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
monitor_printf(mon, "ERROR: unsupported type: %d",
|
|
||||||
qobject_type(data));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
monitor_puts(mon, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void monitor_json_emitter(Monitor *mon, const QObject *data)
|
static void monitor_json_emitter(Monitor *mon, const QObject *data)
|
||||||
{
|
{
|
||||||
QString *json;
|
QString *json;
|
||||||
@@ -298,10 +286,12 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data)
|
|||||||
qobject_incref(data);
|
qobject_incref(data);
|
||||||
qdict_put_obj(qmp, "return", data);
|
qdict_put_obj(qmp, "return", data);
|
||||||
} else {
|
} else {
|
||||||
qdict_put(qmp, "return", qstring_from_str("OK"));
|
/* return an empty QDict by default */
|
||||||
|
qdict_put(qmp, "return", qdict_new());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* error response */
|
/* error response */
|
||||||
|
qdict_put(mon->error->error, "desc", qerror_human(mon->error));
|
||||||
qdict_put(qmp, "error", mon->error->error);
|
qdict_put(qmp, "error", mon->error->error);
|
||||||
QINCREF(mon->error->error);
|
QINCREF(mon->error->error);
|
||||||
QDECREF(mon->error);
|
QDECREF(mon->error);
|
||||||
@@ -344,13 +334,10 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
|
|||||||
{
|
{
|
||||||
QDict *qmp;
|
QDict *qmp;
|
||||||
const char *event_name;
|
const char *event_name;
|
||||||
Monitor *mon = cur_mon;
|
Monitor *mon;
|
||||||
|
|
||||||
assert(event < QEVENT_MAX);
|
assert(event < QEVENT_MAX);
|
||||||
|
|
||||||
if (!monitor_ctrl_mode(mon))
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case QEVENT_DEBUG:
|
case QEVENT_DEBUG:
|
||||||
event_name = "DEBUG";
|
event_name = "DEBUG";
|
||||||
@@ -375,10 +362,16 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
|
|||||||
qmp = qdict_new();
|
qmp = qdict_new();
|
||||||
timestamp_put(qmp);
|
timestamp_put(qmp);
|
||||||
qdict_put(qmp, "event", qstring_from_str(event_name));
|
qdict_put(qmp, "event", qstring_from_str(event_name));
|
||||||
if (data)
|
if (data) {
|
||||||
|
qobject_incref(data);
|
||||||
qdict_put_obj(qmp, "data", data);
|
qdict_put_obj(qmp, "data", data);
|
||||||
|
}
|
||||||
|
|
||||||
monitor_json_emitter(mon, QOBJECT(qmp));
|
QLIST_FOREACH(mon, &mon_list, entry) {
|
||||||
|
if (monitor_ctrl_mode(mon)) {
|
||||||
|
monitor_json_emitter(mon, QOBJECT(qmp));
|
||||||
|
}
|
||||||
|
}
|
||||||
QDECREF(qmp);
|
QDECREF(qmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,24 +493,91 @@ help:
|
|||||||
help_cmd(mon, "info");
|
help_cmd(mon, "info");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void do_info_version_print(Monitor *mon, const QObject *data)
|
||||||
|
{
|
||||||
|
QDict *qdict;
|
||||||
|
|
||||||
|
qdict = qobject_to_qdict(data);
|
||||||
|
|
||||||
|
monitor_printf(mon, "%s%s\n", qdict_get_str(qdict, "qemu"),
|
||||||
|
qdict_get_str(qdict, "package"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* do_info_version(): Show QEMU version
|
* do_info_version(): Show QEMU version
|
||||||
|
*
|
||||||
|
* Return a QDict with the following information:
|
||||||
|
*
|
||||||
|
* - "qemu": QEMU's version
|
||||||
|
* - "package": package's version
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* { "qemu": "0.11.50", "package": "" }
|
||||||
*/
|
*/
|
||||||
static void do_info_version(Monitor *mon, QObject **ret_data)
|
static void do_info_version(Monitor *mon, QObject **ret_data)
|
||||||
{
|
{
|
||||||
*ret_data = QOBJECT(qstring_from_str(QEMU_VERSION QEMU_PKGVERSION));
|
*ret_data = qobject_from_jsonf("{ 'qemu': %s, 'package': %s }",
|
||||||
|
QEMU_VERSION, QEMU_PKGVERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_info_name(Monitor *mon)
|
static void do_info_name_print(Monitor *mon, const QObject *data)
|
||||||
{
|
{
|
||||||
if (qemu_name)
|
QDict *qdict;
|
||||||
monitor_printf(mon, "%s\n", qemu_name);
|
|
||||||
|
qdict = qobject_to_qdict(data);
|
||||||
|
if (qdict_size(qdict) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor_printf(mon, "%s\n", qdict_get_str(qdict, "name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do_info_name(): Show VM name
|
||||||
|
*
|
||||||
|
* Return a QDict with the following information:
|
||||||
|
*
|
||||||
|
* - "name": VM's name (optional)
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* { "name": "qemu-name" }
|
||||||
|
*/
|
||||||
|
static void do_info_name(Monitor *mon, QObject **ret_data)
|
||||||
|
{
|
||||||
|
*ret_data = qemu_name ? qobject_from_jsonf("{'name': %s }", qemu_name) :
|
||||||
|
qobject_from_jsonf("{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QObject *get_cmd_dict(const char *name)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
/* Remove '|' from some commands */
|
||||||
|
p = strchr(name, '|');
|
||||||
|
if (p) {
|
||||||
|
p++;
|
||||||
|
} else {
|
||||||
|
p = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return qobject_from_jsonf("{ 'name': %s }", p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* do_info_commands(): List QMP available commands
|
* do_info_commands(): List QMP available commands
|
||||||
*
|
*
|
||||||
* Return a QList of QStrings.
|
* Each command is represented by a QDict, the returned QObject is a QList
|
||||||
|
* of all commands.
|
||||||
|
*
|
||||||
|
* The QDict contains:
|
||||||
|
*
|
||||||
|
* - "name": command's name
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* { [ { "name": "query-balloon" }, { "name": "system_powerdown" } ] }
|
||||||
*/
|
*/
|
||||||
static void do_info_commands(Monitor *mon, QObject **ret_data)
|
static void do_info_commands(Monitor *mon, QObject **ret_data)
|
||||||
{
|
{
|
||||||
@@ -528,7 +588,7 @@ static void do_info_commands(Monitor *mon, QObject **ret_data)
|
|||||||
|
|
||||||
for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
|
for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
|
||||||
if (monitor_handler_ported(cmd) && !compare_cmd(cmd->name, "info")) {
|
if (monitor_handler_ported(cmd) && !compare_cmd(cmd->name, "info")) {
|
||||||
qlist_append(cmd_list, qstring_from_str(cmd->name));
|
qlist_append_obj(cmd_list, get_cmd_dict(cmd->name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +596,7 @@ static void do_info_commands(Monitor *mon, QObject **ret_data)
|
|||||||
if (monitor_handler_ported(cmd)) {
|
if (monitor_handler_ported(cmd)) {
|
||||||
char buf[128];
|
char buf[128];
|
||||||
snprintf(buf, sizeof(buf), "query-%s", cmd->name);
|
snprintf(buf, sizeof(buf), "query-%s", cmd->name);
|
||||||
qlist_append(cmd_list, qstring_from_str(buf));
|
qlist_append_obj(cmd_list, get_cmd_dict(buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,20 +604,56 @@ static void do_info_commands(Monitor *mon, QObject **ret_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
static void do_info_hpet(Monitor *mon)
|
static void do_info_hpet_print(Monitor *mon, const QObject *data)
|
||||||
{
|
{
|
||||||
monitor_printf(mon, "HPET is %s by QEMU\n",
|
monitor_printf(mon, "HPET is %s by QEMU\n",
|
||||||
(no_hpet) ? "disabled" : "enabled");
|
qdict_get_bool(qobject_to_qdict(data), "enabled") ?
|
||||||
|
"enabled" : "disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do_info_hpet(): Show HPET state
|
||||||
|
*
|
||||||
|
* Return a QDict with the following information:
|
||||||
|
*
|
||||||
|
* - "enabled": true if hpet if enabled, false otherwise
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* { "enabled": true }
|
||||||
|
*/
|
||||||
|
static void do_info_hpet(Monitor *mon, QObject **ret_data)
|
||||||
|
{
|
||||||
|
*ret_data = qobject_from_jsonf("{ 'enabled': %i }", !no_hpet);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void do_info_uuid(Monitor *mon)
|
static void do_info_uuid_print(Monitor *mon, const QObject *data)
|
||||||
{
|
{
|
||||||
monitor_printf(mon, UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1],
|
monitor_printf(mon, "%s\n", qdict_get_str(qobject_to_qdict(data), "UUID"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do_info_uuid(): Show VM UUID
|
||||||
|
*
|
||||||
|
* Return a QDict with the following information:
|
||||||
|
*
|
||||||
|
* - "UUID": Universally Unique Identifier
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* { "UUID": "550e8400-e29b-41d4-a716-446655440000" }
|
||||||
|
*/
|
||||||
|
static void do_info_uuid(Monitor *mon, QObject **ret_data)
|
||||||
|
{
|
||||||
|
char uuid[64];
|
||||||
|
|
||||||
|
snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1],
|
||||||
qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
|
qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
|
||||||
qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
|
qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
|
||||||
qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
|
qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
|
||||||
qemu_uuid[14], qemu_uuid[15]);
|
qemu_uuid[14], qemu_uuid[15]);
|
||||||
|
*ret_data = qobject_from_jsonf("{ 'UUID': %s }", uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the current CPU defined by the user */
|
/* get the current CPU defined by the user */
|
||||||
@@ -607,8 +703,9 @@ static void print_cpu_iter(QObject *obj, void *opaque)
|
|||||||
assert(qobject_type(obj) == QTYPE_QDICT);
|
assert(qobject_type(obj) == QTYPE_QDICT);
|
||||||
cpu = qobject_to_qdict(obj);
|
cpu = qobject_to_qdict(obj);
|
||||||
|
|
||||||
if (strcmp(qdict_get_str(cpu, "current"), "yes") == 0)
|
if (qdict_get_bool(cpu, "current")) {
|
||||||
active = '*';
|
active = '*';
|
||||||
|
}
|
||||||
|
|
||||||
monitor_printf(mon, "%c CPU #%d: ", active, (int)qdict_get_int(cpu, "CPU"));
|
monitor_printf(mon, "%c CPU #%d: ", active, (int)qdict_get_int(cpu, "CPU"));
|
||||||
|
|
||||||
@@ -628,8 +725,9 @@ static void print_cpu_iter(QObject *obj, void *opaque)
|
|||||||
(target_long) qdict_get_int(cpu, "PC"));
|
(target_long) qdict_get_int(cpu, "PC"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (strcmp(qdict_get_str(cpu, "halted"), "yes") == 0)
|
if (qdict_get_bool(cpu, "halted")) {
|
||||||
monitor_printf(mon, " (halted)");
|
monitor_printf(mon, " (halted)");
|
||||||
|
}
|
||||||
|
|
||||||
monitor_printf(mon, "\n");
|
monitor_printf(mon, "\n");
|
||||||
}
|
}
|
||||||
@@ -646,12 +744,21 @@ static void monitor_print_cpus(Monitor *mon, const QObject *data)
|
|||||||
/**
|
/**
|
||||||
* do_info_cpus(): Show CPU information
|
* do_info_cpus(): Show CPU information
|
||||||
*
|
*
|
||||||
* Return a QList with a QDict for each CPU.
|
* Return a QList. Each CPU is represented by a QDict, which contains:
|
||||||
*
|
*
|
||||||
* For example:
|
* - "cpu": CPU index
|
||||||
|
* - "current": true if this is the current CPU, false otherwise
|
||||||
|
* - "halted": true if the cpu is halted, false otherwise
|
||||||
|
* - Current program counter. The key's name depends on the architecture:
|
||||||
|
* "pc": i386/x86)64
|
||||||
|
* "nip": PPC
|
||||||
|
* "pc" and "npc": sparc
|
||||||
|
* "PC": mips
|
||||||
*
|
*
|
||||||
* [ { "CPU": 0, "current": "yes", "pc": 0x..., "halted": "no" },
|
* Example:
|
||||||
* { "CPU": 1, "current": "no", "pc": 0x..., "halted": "yes" } ]
|
*
|
||||||
|
* [ { "CPU": 0, "current": true, "halted": false, "pc": 3227107138 },
|
||||||
|
* { "CPU": 1, "current": false, "halted": true, "pc": 7108165 } ]
|
||||||
*/
|
*/
|
||||||
static void do_info_cpus(Monitor *mon, QObject **ret_data)
|
static void do_info_cpus(Monitor *mon, QObject **ret_data)
|
||||||
{
|
{
|
||||||
@@ -664,14 +771,17 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data)
|
|||||||
mon_get_cpu();
|
mon_get_cpu();
|
||||||
|
|
||||||
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||||
const char *answer;
|
QDict *cpu;
|
||||||
QDict *cpu = qdict_new();
|
QObject *obj;
|
||||||
|
|
||||||
cpu_synchronize_state(env);
|
cpu_synchronize_state(env);
|
||||||
|
|
||||||
qdict_put(cpu, "CPU", qint_from_int(env->cpu_index));
|
obj = qobject_from_jsonf("{ 'CPU': %d, 'current': %i, 'halted': %i }",
|
||||||
answer = (env == mon->mon_cpu) ? "yes" : "no";
|
env->cpu_index, env == mon->mon_cpu,
|
||||||
qdict_put(cpu, "current", qstring_from_str(answer));
|
env->halted);
|
||||||
|
assert(obj != NULL);
|
||||||
|
|
||||||
|
cpu = qobject_to_qdict(obj);
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
qdict_put(cpu, "pc", qint_from_int(env->eip + env->segs[R_CS].base));
|
qdict_put(cpu, "pc", qint_from_int(env->eip + env->segs[R_CS].base));
|
||||||
@@ -683,8 +793,6 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data)
|
|||||||
#elif defined(TARGET_MIPS)
|
#elif defined(TARGET_MIPS)
|
||||||
qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC));
|
qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC));
|
||||||
#endif
|
#endif
|
||||||
answer = env->halted ? "yes" : "no";
|
|
||||||
qdict_put(cpu, "halted", qstring_from_str(answer));
|
|
||||||
|
|
||||||
qlist_append(cpu_list, cpu);
|
qlist_append(cpu_list, cpu);
|
||||||
}
|
}
|
||||||
@@ -745,11 +853,12 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
|
|||||||
if (bdrv_is_inserted(bs)) {
|
if (bdrv_is_inserted(bs)) {
|
||||||
if (!force) {
|
if (!force) {
|
||||||
if (!bdrv_is_removable(bs)) {
|
if (!bdrv_is_removable(bs)) {
|
||||||
monitor_printf(mon, "device is not removable\n");
|
qemu_error_new(QERR_DEVICE_NOT_REMOVABLE,
|
||||||
|
bdrv_get_device_name(bs));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (bdrv_is_locked(bs)) {
|
if (bdrv_is_locked(bs)) {
|
||||||
monitor_printf(mon, "device is locked\n");
|
qemu_error_new(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -762,16 +871,32 @@ static void do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
{
|
{
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
int force = qdict_get_int(qdict, "force");
|
int force = qdict_get_int(qdict, "force");
|
||||||
const char *filename = qdict_get_str(qdict, "filename");
|
const char *filename = qdict_get_str(qdict, "device");
|
||||||
|
|
||||||
bs = bdrv_find(filename);
|
bs = bdrv_find(filename);
|
||||||
if (!bs) {
|
if (!bs) {
|
||||||
monitor_printf(mon, "device not found\n");
|
qemu_error_new(QERR_DEVICE_NOT_FOUND, filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
eject_device(mon, bs, force);
|
eject_device(mon, bs, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void do_block_set_passwd(Monitor *mon, const QDict *qdict,
|
||||||
|
QObject **ret_data)
|
||||||
|
{
|
||||||
|
BlockDriverState *bs;
|
||||||
|
|
||||||
|
bs = bdrv_find(qdict_get_str(qdict, "device"));
|
||||||
|
if (!bs) {
|
||||||
|
qemu_error_new(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bdrv_set_key(bs, qdict_get_str(qdict, "password")) < 0) {
|
||||||
|
qemu_error_new(QERR_INVALID_PASSWORD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void do_change_block(Monitor *mon, const char *device,
|
static void do_change_block(Monitor *mon, const char *device,
|
||||||
const char *filename, const char *fmt)
|
const char *filename, const char *fmt)
|
||||||
{
|
{
|
||||||
@@ -780,13 +905,13 @@ static void do_change_block(Monitor *mon, const char *device,
|
|||||||
|
|
||||||
bs = bdrv_find(device);
|
bs = bdrv_find(device);
|
||||||
if (!bs) {
|
if (!bs) {
|
||||||
monitor_printf(mon, "device not found\n");
|
qemu_error_new(QERR_DEVICE_NOT_FOUND, device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fmt) {
|
if (fmt) {
|
||||||
drv = bdrv_find_whitelisted_format(fmt);
|
drv = bdrv_find_whitelisted_format(fmt);
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
monitor_printf(mon, "invalid format %s\n", fmt);
|
qemu_error_new(QERR_INVALID_BLOCK_FORMAT, fmt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -796,12 +921,17 @@ static void do_change_block(Monitor *mon, const char *device,
|
|||||||
monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
|
monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void change_vnc_password(const char *password)
|
||||||
|
{
|
||||||
|
if (vnc_display_password(NULL, password) < 0)
|
||||||
|
qemu_error_new(QERR_SET_PASSWD_FAILED);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void change_vnc_password_cb(Monitor *mon, const char *password,
|
static void change_vnc_password_cb(Monitor *mon, const char *password,
|
||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
if (vnc_display_password(NULL, password) < 0)
|
change_vnc_password(password);
|
||||||
monitor_printf(mon, "could not set VNC server password\n");
|
|
||||||
|
|
||||||
monitor_read_command(mon, 1);
|
monitor_read_command(mon, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,17 +943,20 @@ static void do_change_vnc(Monitor *mon, const char *target, const char *arg)
|
|||||||
char password[9];
|
char password[9];
|
||||||
strncpy(password, arg, sizeof(password));
|
strncpy(password, arg, sizeof(password));
|
||||||
password[sizeof(password) - 1] = '\0';
|
password[sizeof(password) - 1] = '\0';
|
||||||
change_vnc_password_cb(mon, password, NULL);
|
change_vnc_password(password);
|
||||||
} else {
|
} else {
|
||||||
monitor_read_password(mon, change_vnc_password_cb, NULL);
|
monitor_read_password(mon, change_vnc_password_cb, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (vnc_display_open(NULL, target) < 0)
|
if (vnc_display_open(NULL, target) < 0)
|
||||||
monitor_printf(mon, "could not start VNC server on %s\n", target);
|
qemu_error_new(QERR_VNC_SERVER_FAILED, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_change(Monitor *mon, const QDict *qdict)
|
/**
|
||||||
|
* do_change(): Change a removable medium, or VNC configuration
|
||||||
|
*/
|
||||||
|
static void do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||||
{
|
{
|
||||||
const char *device = qdict_get_str(qdict, "device");
|
const char *device = qdict_get_str(qdict, "device");
|
||||||
const char *target = qdict_get_str(qdict, "target");
|
const char *target = qdict_get_str(qdict, "target");
|
||||||
@@ -1739,16 +1872,40 @@ static void tlb_info(Monitor *mon)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void do_info_kvm(Monitor *mon)
|
static void do_info_kvm_print(Monitor *mon, const QObject *data)
|
||||||
|
{
|
||||||
|
QDict *qdict;
|
||||||
|
|
||||||
|
qdict = qobject_to_qdict(data);
|
||||||
|
|
||||||
|
monitor_printf(mon, "kvm support: ");
|
||||||
|
if (qdict_get_bool(qdict, "present")) {
|
||||||
|
monitor_printf(mon, "%s\n", qdict_get_bool(qdict, "enabled") ?
|
||||||
|
"enabled" : "disabled");
|
||||||
|
} else {
|
||||||
|
monitor_printf(mon, "not compiled\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do_info_kvm(): Show KVM information
|
||||||
|
*
|
||||||
|
* Return a QDict with the following information:
|
||||||
|
*
|
||||||
|
* - "enabled": true if KVM support is enabled, false otherwise
|
||||||
|
* - "present": true if QEMU has KVM support, false otherwise
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* { "enabled": true, "present": true }
|
||||||
|
*/
|
||||||
|
static void do_info_kvm(Monitor *mon, QObject **ret_data)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KVM
|
#ifdef CONFIG_KVM
|
||||||
monitor_printf(mon, "kvm support: ");
|
*ret_data = qobject_from_jsonf("{ 'enabled': %i, 'present': true }",
|
||||||
if (kvm_enabled())
|
kvm_enabled());
|
||||||
monitor_printf(mon, "enabled\n");
|
|
||||||
else
|
|
||||||
monitor_printf(mon, "disabled\n");
|
|
||||||
#else
|
#else
|
||||||
monitor_printf(mon, "kvm support: not compiled\n");
|
*ret_data = qobject_from_jsonf("{ 'enabled': false, 'present': false }");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1866,16 +2023,59 @@ static void do_inject_nmi(Monitor *mon, const QDict *qdict)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void do_info_status(Monitor *mon)
|
static void do_info_status_print(Monitor *mon, const QObject *data)
|
||||||
{
|
{
|
||||||
if (vm_running) {
|
QDict *qdict;
|
||||||
if (singlestep) {
|
|
||||||
monitor_printf(mon, "VM status: running (single step mode)\n");
|
qdict = qobject_to_qdict(data);
|
||||||
} else {
|
|
||||||
monitor_printf(mon, "VM status: running\n");
|
monitor_printf(mon, "VM status: ");
|
||||||
|
if (qdict_get_bool(qdict, "running")) {
|
||||||
|
monitor_printf(mon, "running");
|
||||||
|
if (qdict_get_bool(qdict, "singlestep")) {
|
||||||
|
monitor_printf(mon, " (single step mode)");
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
monitor_printf(mon, "VM status: paused\n");
|
monitor_printf(mon, "paused");
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor_printf(mon, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do_info_status(): VM status
|
||||||
|
*
|
||||||
|
* Return a QDict with the following information:
|
||||||
|
*
|
||||||
|
* - "running": true if the VM is running, or false if it is paused
|
||||||
|
* - "singlestep": true if the VM is in single step mode, false otherwise
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* { "running": true, "singlestep": false }
|
||||||
|
*/
|
||||||
|
static void do_info_status(Monitor *mon, QObject **ret_data)
|
||||||
|
{
|
||||||
|
*ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i }",
|
||||||
|
vm_running, singlestep);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ram_addr_t balloon_get_value(void)
|
||||||
|
{
|
||||||
|
ram_addr_t actual;
|
||||||
|
|
||||||
|
if (kvm_enabled() && !kvm_has_sync_mmu()) {
|
||||||
|
qemu_error_new(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
actual = qemu_balloon_status();
|
||||||
|
if (actual == 0) {
|
||||||
|
qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return actual;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1883,31 +2083,42 @@ static void do_info_status(Monitor *mon)
|
|||||||
*/
|
*/
|
||||||
static void do_balloon(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
static void do_balloon(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||||
{
|
{
|
||||||
int value = qdict_get_int(qdict, "value");
|
if (balloon_get_value()) {
|
||||||
ram_addr_t target = value;
|
/* ballooning is active */
|
||||||
qemu_balloon(target << 20);
|
qemu_balloon(qdict_get_int(qdict, "value"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void monitor_print_balloon(Monitor *mon, const QObject *data)
|
static void monitor_print_balloon(Monitor *mon, const QObject *data)
|
||||||
{
|
{
|
||||||
monitor_printf(mon, "balloon: actual=%d\n",
|
QDict *qdict;
|
||||||
(int)qint_get_int(qobject_to_qint(data)));
|
|
||||||
|
qdict = qobject_to_qdict(data);
|
||||||
|
|
||||||
|
monitor_printf(mon, "balloon: actual=%" PRId64 "\n",
|
||||||
|
qdict_get_int(qdict, "balloon") >> 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* do_info_balloon(): Balloon information
|
* do_info_balloon(): Balloon information
|
||||||
|
*
|
||||||
|
* Return a QDict with the following information:
|
||||||
|
*
|
||||||
|
* - "balloon": current balloon value in bytes
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* { "balloon": 1073741824 }
|
||||||
*/
|
*/
|
||||||
static void do_info_balloon(Monitor *mon, QObject **ret_data)
|
static void do_info_balloon(Monitor *mon, QObject **ret_data)
|
||||||
{
|
{
|
||||||
ram_addr_t actual;
|
ram_addr_t actual;
|
||||||
|
|
||||||
actual = qemu_balloon_status();
|
actual = balloon_get_value();
|
||||||
if (kvm_enabled() && !kvm_has_sync_mmu())
|
if (actual != 0) {
|
||||||
qemu_error_new(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
|
*ret_data = qobject_from_jsonf("{ 'balloon': %" PRId64 "}",
|
||||||
else if (actual == 0)
|
(int64_t) actual);
|
||||||
qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon");
|
}
|
||||||
else
|
|
||||||
*ret_data = QOBJECT(qint_from_int((int)(actual >> 20)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static qemu_acl *find_acl(Monitor *mon, const char *name)
|
static qemu_acl *find_acl(Monitor *mon, const char *name)
|
||||||
@@ -2043,19 +2254,21 @@ static void do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
|
|
||||||
fd = qemu_chr_get_msgfd(mon->chr);
|
fd = qemu_chr_get_msgfd(mon->chr);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
monitor_printf(mon, "getfd: no file descriptor supplied via SCM_RIGHTS\n");
|
qemu_error_new(QERR_FD_NOT_SUPPLIED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemu_isdigit(fdname[0])) {
|
if (qemu_isdigit(fdname[0])) {
|
||||||
monitor_printf(mon, "getfd: monitor names may not begin with a number\n");
|
qemu_error_new(QERR_INVALID_PARAMETER, "fdname");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = dup(fd);
|
fd = dup(fd);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
monitor_printf(mon, "Failed to dup() file descriptor: %s\n",
|
if (errno == EMFILE)
|
||||||
strerror(errno));
|
qemu_error_new(QERR_TOO_MANY_FILES);
|
||||||
|
else
|
||||||
|
qemu_error_new(QERR_UNDEFINED_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2093,8 +2306,7 @@ static void do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor_printf(mon, "Failed to find file descriptor named %s\n",
|
qemu_error_new(QERR_FD_NOT_FOUND, fdname);
|
||||||
fdname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_loadvm(Monitor *mon, const QDict *qdict)
|
static void do_loadvm(Monitor *mon, const QDict *qdict)
|
||||||
@@ -2144,7 +2356,7 @@ static const mon_cmd_t info_cmds[] = {
|
|||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show the version of QEMU",
|
.help = "show the version of QEMU",
|
||||||
.user_print = monitor_print_qobject,
|
.user_print = do_info_version_print,
|
||||||
.mhandler.info_new = do_info_version,
|
.mhandler.info_new = do_info_version,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2167,21 +2379,24 @@ static const mon_cmd_t info_cmds[] = {
|
|||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show the character devices",
|
.help = "show the character devices",
|
||||||
.mhandler.info = qemu_chr_info,
|
.user_print = qemu_chr_info_print,
|
||||||
|
.mhandler.info_new = qemu_chr_info,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "block",
|
.name = "block",
|
||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show the block devices",
|
.help = "show the block devices",
|
||||||
.mhandler.info = bdrv_info,
|
.user_print = bdrv_info_print,
|
||||||
|
.mhandler.info_new = bdrv_info,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "blockstats",
|
.name = "blockstats",
|
||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show block device statistics",
|
.help = "show block device statistics",
|
||||||
.mhandler.info = bdrv_info_stats,
|
.user_print = bdrv_stats_print,
|
||||||
|
.mhandler.info_new = bdrv_info_stats,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "registers",
|
.name = "registers",
|
||||||
@@ -2248,7 +2463,8 @@ static const mon_cmd_t info_cmds[] = {
|
|||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show state of HPET",
|
.help = "show state of HPET",
|
||||||
.mhandler.info = do_info_hpet,
|
.user_print = do_info_hpet_print,
|
||||||
|
.mhandler.info_new = do_info_hpet,
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
@@ -2263,7 +2479,8 @@ static const mon_cmd_t info_cmds[] = {
|
|||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show KVM information",
|
.help = "show KVM information",
|
||||||
.mhandler.info = do_info_kvm,
|
.user_print = do_info_kvm_print,
|
||||||
|
.mhandler.info_new = do_info_kvm,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "numa",
|
.name = "numa",
|
||||||
@@ -2312,7 +2529,8 @@ static const mon_cmd_t info_cmds[] = {
|
|||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show the current VM status (running|paused)",
|
.help = "show the current VM status (running|paused)",
|
||||||
.mhandler.info = do_info_status,
|
.user_print = do_info_status_print,
|
||||||
|
.mhandler.info_new = do_info_status,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "pcmcia",
|
.name = "pcmcia",
|
||||||
@@ -2326,28 +2544,32 @@ static const mon_cmd_t info_cmds[] = {
|
|||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show which guest mouse is receiving events",
|
.help = "show which guest mouse is receiving events",
|
||||||
.mhandler.info = do_info_mice,
|
.user_print = do_info_mice_print,
|
||||||
|
.mhandler.info_new = do_info_mice,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "vnc",
|
.name = "vnc",
|
||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show the vnc server status",
|
.help = "show the vnc server status",
|
||||||
.mhandler.info = do_info_vnc,
|
.user_print = do_info_vnc_print,
|
||||||
|
.mhandler.info_new = do_info_vnc,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "name",
|
.name = "name",
|
||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show the current VM name",
|
.help = "show the current VM name",
|
||||||
.mhandler.info = do_info_name,
|
.user_print = do_info_name_print,
|
||||||
|
.mhandler.info_new = do_info_name,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "uuid",
|
.name = "uuid",
|
||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show the current VM UUID",
|
.help = "show the current VM UUID",
|
||||||
.mhandler.info = do_info_uuid,
|
.user_print = do_info_uuid_print,
|
||||||
|
.mhandler.info_new = do_info_uuid,
|
||||||
},
|
},
|
||||||
#if defined(TARGET_PPC)
|
#if defined(TARGET_PPC)
|
||||||
{
|
{
|
||||||
@@ -2372,7 +2594,8 @@ static const mon_cmd_t info_cmds[] = {
|
|||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show migration status",
|
.help = "show migration status",
|
||||||
.mhandler.info = do_info_migrate,
|
.user_print = do_info_migrate_print,
|
||||||
|
.mhandler.info_new = do_info_migrate,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "balloon",
|
.name = "balloon",
|
||||||
@@ -3279,6 +3502,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
|
|||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
case 'l':
|
case 'l':
|
||||||
|
case 'M':
|
||||||
{
|
{
|
||||||
int64_t val;
|
int64_t val;
|
||||||
|
|
||||||
@@ -3309,6 +3533,8 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
|
|||||||
monitor_printf(mon, "\'%s\' has failed: ", cmdname);
|
monitor_printf(mon, "\'%s\' has failed: ", cmdname);
|
||||||
monitor_printf(mon, "integer is for 32-bit values\n");
|
monitor_printf(mon, "integer is for 32-bit values\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
} else if (c == 'M') {
|
||||||
|
val <<= 20;
|
||||||
}
|
}
|
||||||
qdict_put(qdict, key, qint_from_int(val));
|
qdict_put(qdict, key, qint_from_int(val));
|
||||||
}
|
}
|
||||||
@@ -3644,7 +3870,7 @@ static int monitor_can_read(void *opaque)
|
|||||||
{
|
{
|
||||||
Monitor *mon = opaque;
|
Monitor *mon = opaque;
|
||||||
|
|
||||||
return (mon->suspend_cnt == 0) ? 128 : 0;
|
return (mon->suspend_cnt == 0) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct CmdArgs {
|
typedef struct CmdArgs {
|
||||||
@@ -3713,6 +3939,7 @@ static int check_arg(const CmdArgs *cmd_args, QDict *args)
|
|||||||
}
|
}
|
||||||
case 'i':
|
case 'i':
|
||||||
case 'l':
|
case 'l':
|
||||||
|
case 'M':
|
||||||
if (qobject_type(value) != QTYPE_QINT) {
|
if (qobject_type(value) != QTYPE_QINT) {
|
||||||
qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "int");
|
qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "int");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -3850,7 +4077,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
|
|||||||
qobject_from_jsonf("{ 'item': %s }", info_item));
|
qobject_from_jsonf("{ 'item': %s }", info_item));
|
||||||
} else {
|
} else {
|
||||||
cmd = monitor_find_command(cmd_name);
|
cmd = monitor_find_command(cmd_name);
|
||||||
if (!cmd) {
|
if (!cmd || !monitor_handler_ported(cmd)) {
|
||||||
qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
|
qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
|
||||||
goto err_input;
|
goto err_input;
|
||||||
}
|
}
|
||||||
@@ -4008,24 +4235,6 @@ static void monitor_event(void *opaque, int event)
|
|||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const char *monitor_cmdline_parse(const char *cmdline, int *flags)
|
|
||||||
{
|
|
||||||
const char *dev;
|
|
||||||
|
|
||||||
if (strstart(cmdline, "control,", &dev)) {
|
|
||||||
if (strstart(dev, "vc", NULL)) {
|
|
||||||
fprintf(stderr, "qemu: control mode is for low-level interaction ");
|
|
||||||
fprintf(stderr, "cannot be used with device 'vc'\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
*flags &= ~MONITOR_USE_READLINE;
|
|
||||||
*flags |= MONITOR_USE_CONTROL;
|
|
||||||
return dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmdline;
|
|
||||||
}
|
|
||||||
|
|
||||||
void monitor_init(CharDriverState *chr, int flags)
|
void monitor_init(CharDriverState *chr, int flags)
|
||||||
{
|
{
|
||||||
static int is_first_init = 1;
|
static int is_first_init = 1;
|
||||||
@@ -4087,6 +4296,11 @@ void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (monitor_ctrl_mode(mon)) {
|
||||||
|
qemu_error_new(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
|
monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
|
||||||
bdrv_get_encrypted_filename(bs));
|
bdrv_get_encrypted_filename(bs));
|
||||||
|
|
||||||
|
@@ -24,7 +24,6 @@ typedef enum MonitorEvent {
|
|||||||
} MonitorEvent;
|
} MonitorEvent;
|
||||||
|
|
||||||
void monitor_protocol_event(MonitorEvent event, QObject *data);
|
void monitor_protocol_event(MonitorEvent event, QObject *data);
|
||||||
const char *monitor_cmdline_parse(const char *cmdline, int *flags);
|
|
||||||
void monitor_init(CharDriverState *chr, int flags);
|
void monitor_init(CharDriverState *chr, int flags);
|
||||||
|
|
||||||
int monitor_suspend(Monitor *mon);
|
int monitor_suspend(Monitor *mon);
|
||||||
|
89
net.c
89
net.c
@@ -39,6 +39,8 @@
|
|||||||
static QTAILQ_HEAD(, VLANState) vlans;
|
static QTAILQ_HEAD(, VLANState) vlans;
|
||||||
static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
|
static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
|
||||||
|
|
||||||
|
int default_net = 1;
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/* network device redirectors */
|
/* network device redirectors */
|
||||||
|
|
||||||
@@ -94,7 +96,7 @@ int parse_host_src_port(struct sockaddr_in *haddr,
|
|||||||
struct sockaddr_in *saddr,
|
struct sockaddr_in *saddr,
|
||||||
const char *input_str)
|
const char *input_str)
|
||||||
{
|
{
|
||||||
char *str = strdup(input_str);
|
char *str = qemu_strdup(input_str);
|
||||||
char *host_str = str;
|
char *host_str = str;
|
||||||
char *src_str;
|
char *src_str;
|
||||||
const char *src_str2;
|
const char *src_str2;
|
||||||
@@ -810,9 +812,6 @@ static int net_init_nic(QemuOpts *opts,
|
|||||||
}
|
}
|
||||||
|
|
||||||
nd->used = 1;
|
nd->used = 1;
|
||||||
if (vlan) {
|
|
||||||
nd->vlan->nb_guest_devs++;
|
|
||||||
}
|
|
||||||
nb_nics++;
|
nb_nics++;
|
||||||
|
|
||||||
return idx;
|
return idx;
|
||||||
@@ -1126,20 +1125,6 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void net_client_uninit(NICInfo *nd)
|
|
||||||
{
|
|
||||||
if (nd->vlan) {
|
|
||||||
nd->vlan->nb_guest_devs--;
|
|
||||||
}
|
|
||||||
nb_nics--;
|
|
||||||
|
|
||||||
qemu_free(nd->model);
|
|
||||||
qemu_free(nd->name);
|
|
||||||
qemu_free(nd->devaddr);
|
|
||||||
|
|
||||||
nd->used = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int net_host_check_device(const char *device)
|
static int net_host_check_device(const char *device)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -1202,39 +1187,26 @@ void net_host_device_remove(Monitor *mon, const QDict *qdict)
|
|||||||
qemu_del_vlan_client(vc);
|
qemu_del_vlan_client(vc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void net_set_boot_mask(int net_boot_mask)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Only the first four NICs may be bootable */
|
|
||||||
net_boot_mask = net_boot_mask & 0xF;
|
|
||||||
|
|
||||||
for (i = 0; i < nb_nics; i++) {
|
|
||||||
if (net_boot_mask & (1 << i)) {
|
|
||||||
nd_table[i].bootable = 1;
|
|
||||||
net_boot_mask &= ~(1 << i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (net_boot_mask) {
|
|
||||||
fprintf(stderr, "Cannot boot from non-existent NIC\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_info_network(Monitor *mon)
|
void do_info_network(Monitor *mon)
|
||||||
{
|
{
|
||||||
VLANState *vlan;
|
VLANState *vlan;
|
||||||
|
VLANClientState *vc;
|
||||||
|
|
||||||
QTAILQ_FOREACH(vlan, &vlans, next) {
|
QTAILQ_FOREACH(vlan, &vlans, next) {
|
||||||
VLANClientState *vc;
|
|
||||||
|
|
||||||
monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
|
monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
|
||||||
|
|
||||||
QTAILQ_FOREACH(vc, &vlan->clients, next) {
|
QTAILQ_FOREACH(vc, &vlan->clients, next) {
|
||||||
monitor_printf(mon, " %s: %s\n", vc->name, vc->info_str);
|
monitor_printf(mon, " %s: %s\n", vc->name, vc->info_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
monitor_printf(mon, "Devices not on any VLAN:\n");
|
||||||
|
QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
|
||||||
|
monitor_printf(mon, " %s: %s", vc->name, vc->info_str);
|
||||||
|
if (vc->peer) {
|
||||||
|
monitor_printf(mon, " peer=%s", vc->peer->name);
|
||||||
|
}
|
||||||
|
monitor_printf(mon, "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_set_link(Monitor *mon, const QDict *qdict)
|
void do_set_link(Monitor *mon, const QDict *qdict)
|
||||||
@@ -1251,6 +1223,7 @@ void do_set_link(Monitor *mon, const QDict *qdict)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
vc = qemu_find_netdev(name);
|
||||||
done:
|
done:
|
||||||
|
|
||||||
if (!vc) {
|
if (!vc) {
|
||||||
@@ -1287,20 +1260,41 @@ void net_cleanup(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void net_check_clients(void)
|
void net_check_clients(void)
|
||||||
{
|
{
|
||||||
VLANState *vlan;
|
VLANState *vlan;
|
||||||
|
VLANClientState *vc;
|
||||||
|
int has_nic, has_host_dev;
|
||||||
|
|
||||||
QTAILQ_FOREACH(vlan, &vlans, next) {
|
QTAILQ_FOREACH(vlan, &vlans, next) {
|
||||||
if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
|
QTAILQ_FOREACH(vc, &vlan->clients, next) {
|
||||||
continue;
|
switch (vc->info->type) {
|
||||||
if (vlan->nb_guest_devs == 0)
|
case NET_CLIENT_TYPE_NIC:
|
||||||
|
has_nic = 1;
|
||||||
|
break;
|
||||||
|
case NET_CLIENT_TYPE_SLIRP:
|
||||||
|
case NET_CLIENT_TYPE_TAP:
|
||||||
|
case NET_CLIENT_TYPE_SOCKET:
|
||||||
|
case NET_CLIENT_TYPE_VDE:
|
||||||
|
has_host_dev = 1;
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (has_host_dev && !has_nic)
|
||||||
fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
|
fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
|
||||||
if (vlan->nb_host_devs == 0)
|
if (has_nic && !has_host_dev)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Warning: vlan %d is not connected to host network\n",
|
"Warning: vlan %d is not connected to host network\n",
|
||||||
vlan->id);
|
vlan->id);
|
||||||
}
|
}
|
||||||
|
QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
|
||||||
|
if (!vc->peer) {
|
||||||
|
fprintf(stderr, "Warning: %s %s has no peer\n",
|
||||||
|
vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev",
|
||||||
|
vc->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int net_init_client(QemuOpts *opts, void *dummy)
|
static int net_init_client(QemuOpts *opts, void *dummy)
|
||||||
@@ -1317,7 +1311,7 @@ static int net_init_netdev(QemuOpts *opts, void *dummy)
|
|||||||
|
|
||||||
int net_init_clients(void)
|
int net_init_clients(void)
|
||||||
{
|
{
|
||||||
if (QTAILQ_EMPTY(&qemu_net_opts.head)) {
|
if (default_net) {
|
||||||
/* if no clients, we use a default config */
|
/* if no clients, we use a default config */
|
||||||
qemu_opts_set(&qemu_net_opts, NULL, "type", "nic");
|
qemu_opts_set(&qemu_net_opts, NULL, "type", "nic");
|
||||||
#ifdef CONFIG_SLIRP
|
#ifdef CONFIG_SLIRP
|
||||||
@@ -1335,8 +1329,6 @@ int net_init_clients(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
net_check_clients();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1353,5 +1345,6 @@ int net_client_parse(QemuOptsList *opts_list, const char *optarg)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default_net = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
5
net.h
5
net.h
@@ -76,7 +76,6 @@ struct VLANState {
|
|||||||
int id;
|
int id;
|
||||||
QTAILQ_HEAD(, VLANClientState) clients;
|
QTAILQ_HEAD(, VLANClientState) clients;
|
||||||
QTAILQ_ENTRY(VLANState) next;
|
QTAILQ_ENTRY(VLANState) next;
|
||||||
unsigned int nb_guest_devs, nb_host_devs;
|
|
||||||
NetQueue *send_queue;
|
NetQueue *send_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -139,6 +138,7 @@ struct NICInfo {
|
|||||||
|
|
||||||
extern int nb_nics;
|
extern int nb_nics;
|
||||||
extern NICInfo nd_table[MAX_NICS];
|
extern NICInfo nd_table[MAX_NICS];
|
||||||
|
extern int default_net;
|
||||||
|
|
||||||
/* BT HCI info */
|
/* BT HCI info */
|
||||||
|
|
||||||
@@ -159,11 +159,10 @@ extern const char *legacy_tftp_prefix;
|
|||||||
extern const char *legacy_bootp_filename;
|
extern const char *legacy_bootp_filename;
|
||||||
|
|
||||||
int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev);
|
int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev);
|
||||||
void net_client_uninit(NICInfo *nd);
|
|
||||||
int net_client_parse(QemuOptsList *opts_list, const char *str);
|
int net_client_parse(QemuOptsList *opts_list, const char *str);
|
||||||
int net_init_clients(void);
|
int net_init_clients(void);
|
||||||
|
void net_check_clients(void);
|
||||||
void net_cleanup(void);
|
void net_cleanup(void);
|
||||||
void net_set_boot_mask(int boot_mask);
|
|
||||||
void net_host_device_add(Monitor *mon, const QDict *qdict);
|
void net_host_device_add(Monitor *mon, const QDict *qdict);
|
||||||
void net_host_device_remove(Monitor *mon, const QDict *qdict);
|
void net_host_device_remove(Monitor *mon, const QDict *qdict);
|
||||||
|
|
||||||
|
@@ -728,10 +728,6 @@ int net_init_slirp(QemuOpts *opts,
|
|||||||
qemu_free(config);
|
qemu_free(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret != -1 && vlan) {
|
|
||||||
vlan->nb_host_devs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_free(vnet);
|
qemu_free(vnet);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@@ -569,9 +569,5 @@ int net_init_socket(QemuOpts *opts,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vlan) {
|
|
||||||
vlan->nb_host_devs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -714,10 +714,6 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vlan) {
|
|
||||||
vlan->nb_host_devs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -441,9 +441,5 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vlan) {
|
|
||||||
vlan->nb_host_devs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -127,9 +127,5 @@ int net_init_vde(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vlan) {
|
|
||||||
vlan->nb_host_devs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
18
osdep.c
18
osdep.c
@@ -262,13 +262,15 @@ int qemu_pipe(int pipefd[2])
|
|||||||
|
|
||||||
#ifdef CONFIG_PIPE2
|
#ifdef CONFIG_PIPE2
|
||||||
ret = pipe2(pipefd, O_CLOEXEC);
|
ret = pipe2(pipefd, O_CLOEXEC);
|
||||||
#else
|
if (ret != -1 || errno != ENOSYS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ret = pipe(pipefd);
|
ret = pipe(pipefd);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
qemu_set_cloexec(pipefd[0]);
|
qemu_set_cloexec(pipefd[0]);
|
||||||
qemu_set_cloexec(pipefd[1]);
|
qemu_set_cloexec(pipefd[1]);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -283,12 +285,14 @@ int qemu_socket(int domain, int type, int protocol)
|
|||||||
|
|
||||||
#ifdef SOCK_CLOEXEC
|
#ifdef SOCK_CLOEXEC
|
||||||
ret = socket(domain, type | SOCK_CLOEXEC, protocol);
|
ret = socket(domain, type | SOCK_CLOEXEC, protocol);
|
||||||
#else
|
if (ret != -1 || errno != EINVAL) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ret = socket(domain, type, protocol);
|
ret = socket(domain, type, protocol);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
qemu_set_cloexec(ret);
|
qemu_set_cloexec(ret);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -302,12 +306,14 @@ int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
|||||||
|
|
||||||
#ifdef CONFIG_ACCEPT4
|
#ifdef CONFIG_ACCEPT4
|
||||||
ret = accept4(s, addr, addrlen, SOCK_CLOEXEC);
|
ret = accept4(s, addr, addrlen, SOCK_CLOEXEC);
|
||||||
#else
|
if (ret != -1 || errno != ENOSYS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ret = accept(s, addr, addrlen);
|
ret = accept(s, addr, addrlen);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
qemu_set_cloexec(ret);
|
qemu_set_cloexec(ret);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user