Compare commits
	
		
			341 Commits
		
	
	
		
			qom-cpu-fo
			...
			v0.12.5-qe
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 69903f803a | ||
|  | 174f225e9d | ||
|  | e916448940 | ||
|  | bb44e0bbce | ||
|  | 191d44fc43 | ||
|  | a2f0cbaa58 | ||
|  | a9d9a66f13 | ||
|  | 37060c28e5 | ||
|  | 7205c21e76 | ||
|  | ceef722d01 | ||
|  | dfe0bb55ee | ||
|  | 6fd82592ce | ||
|  | 39187b5192 | ||
|  | 729862401d | ||
|  | 34d0d68bdf | ||
|  | 82e9cbeb0d | ||
|  | 2020dd5535 | ||
|  | 0c0f53e25c | ||
|  | 3dbe0714dd | ||
|  | 9067bac11d | ||
|  | 74471f3742 | ||
|  | 370f80376a | ||
|  | ed3aac289a | ||
|  | 11b52a6536 | ||
|  | b6185fc79c | ||
|  | 8fd7d5438e | ||
|  | a513171f80 | ||
|  | ff9e177617 | ||
|  | db3519a9ec | ||
|  | 258e351d12 | ||
|  | cd14f4d346 | ||
|  | df631629b1 | ||
|  | af0269b036 | ||
|  | d37dbf988d | ||
|  | cc7ed88f28 | ||
|  | 07442ab4a1 | ||
|  | dbe6a18d82 | ||
|  | 7dd007c2ed | ||
|  | 9c6a8f503d | ||
|  | 0c459361a1 | ||
|  | 72d3457e8d | ||
|  | e1f0c1d05d | ||
|  | 74bcc51b99 | ||
|  | 7e4f956056 | ||
|  | 1fb9798b69 | ||
|  | 9f6a84bc43 | ||
|  | 8cef921d18 | ||
|  | b04c3db504 | ||
|  | d04d7cf158 | ||
|  | 2b8bdd5c7f | ||
|  | 2a44494726 | ||
|  | 8f30db54d9 | ||
|  | b09ac1abe7 | ||
|  | 012d4869c1 | ||
|  | 3597c9c1d5 | ||
|  | 3b4bef0696 | ||
|  | d899303743 | ||
|  | 5773685183 | ||
|  | d40ba77ebf | ||
|  | a8c46d182c | ||
|  | d80e20a1c3 | ||
|  | 1ce4fad939 | ||
|  | 9167a242db | ||
|  | 09e96924ec | ||
|  | 69ff4e9dbd | ||
|  | 0434349d6a | ||
|  | e007221223 | ||
|  | 4622317288 | ||
|  | ffac613ff9 | ||
|  | aba5288247 | ||
|  | 4f7cb96931 | ||
|  | fafc2e4b33 | ||
|  | 83ef70f24a | ||
|  | de17c16e1f | ||
|  | 9462695b64 | ||
|  | 5eb089588e | ||
|  | 2039f70c23 | ||
|  | 082a9fc256 | ||
|  | 36a013c956 | ||
|  | c4c4b32b81 | ||
|  | 804b6ab08d | ||
|  | 81b168a702 | ||
|  | 5c6892078a | ||
|  | 18a21890ff | ||
|  | 6629fa6473 | ||
|  | 2a7996ce0e | ||
|  | 8ec131fb59 | ||
|  | 30d061750d | ||
|  | c5f5dc5bad | ||
|  | d2df336c58 | ||
|  | b299b12b17 | ||
|  | c248df6161 | ||
|  | 7d5625d5f7 | ||
|  | cc21d131e3 | ||
|  | 41a5bda61f | ||
|  | 5163f6e864 | ||
|  | 6173d56bdc | ||
|  | f39942d217 | ||
|  | 5dde87088f | ||
|  | 3fa017e24b | ||
|  | 35924dbe8c | ||
|  | 88aa905668 | ||
|  | b93c5c84c8 | ||
|  | f203baee5b | ||
|  | 5e3be62385 | ||
|  | b391493bc6 | ||
|  | 57f9f4c9f5 | ||
|  | 7ebc79037c | ||
|  | ea299062eb | ||
|  | e03dd1a6c2 | ||
|  | 535d2eb34a | ||
|  | beb8eab90c | ||
|  | 8d67694fbf | ||
|  | 02510b2436 | ||
|  | b57a2297f2 | ||
|  | 43fab08210 | ||
|  | 915080e6b1 | ||
|  | 9f59ddcc4f | ||
|  | 999ceb2c1d | ||
|  | 307331a42a | ||
|  | 6728dd464b | ||
|  | bb45bcc8de | ||
|  | 096109c804 | ||
|  | 7ae1fcc88c | ||
|  | 299e0bc52a | ||
|  | 74f0529e24 | ||
|  | 614971158c | ||
|  | afa328b1b2 | ||
|  | 868dab5dc2 | ||
|  | 29bb3bf350 | ||
|  | dbf45b44b7 | ||
|  | d0d888bc6d | ||
|  | 19abbad0da | ||
|  | f48aba6de7 | ||
|  | cb2ae96bf6 | ||
|  | 848f874ca1 | ||
|  | a1a86bf902 | ||
|  | c727a05459 | ||
|  | eb05143e24 | ||
|  | 0c709e6195 | ||
|  | dc88aa49b4 | ||
|  | dc2ffbf6d8 | ||
|  | d3bf9367f2 | ||
|  | c502715a74 | ||
|  | b9a61d2154 | ||
|  | 9525204c5d | ||
|  | f79d556b4f | ||
|  | 41ae9ece21 | ||
|  | 40480d2bf4 | ||
|  | e389e937a7 | ||
|  | 73b48d914f | ||
|  | 3999bf3244 | ||
|  | a3441a43a6 | ||
|  | 49a3aaac4a | ||
|  | 027866ce23 | ||
|  | 04babf6c6f | ||
|  | d2b8117310 | ||
|  | 0c4b9aef7b | ||
|  | 431c829f33 | ||
|  | be7398ec06 | ||
|  | be59ce1f48 | ||
|  | eacad66dbe | ||
|  | 66dbb62824 | ||
|  | d47d251286 | ||
|  | 348af56fae | ||
|  | 09866b9baa | ||
|  | e1daf40e3e | ||
|  | de3ea06d59 | ||
|  | fe46a160ce | ||
|  | 8033c42abd | ||
|  | 4713c69fa2 | ||
|  | d68bf60838 | ||
|  | 57fa5ca551 | ||
|  | 8610774f79 | ||
|  | 76ba04832b | ||
|  | 644f5de21b | ||
|  | dcc0da8297 | ||
|  | 41193c50fa | ||
|  | da0266005a | ||
|  | eacdccbb3e | ||
|  | 65e8c51928 | ||
|  | e470436f19 | ||
|  | b60c2c74f3 | ||
|  | fe1b69708c | ||
|  | a1678e85db | ||
|  | 8212d18cf5 | ||
|  | 6c412ddf1c | ||
|  | 862ad4be53 | ||
|  | aac2ad563a | ||
|  | eb41f58a4e | ||
|  | 5543b41167 | ||
|  | 31d85f6a6b | ||
|  | 9c49a2533c | ||
|  | c6faf5fd73 | ||
|  | 069def25cb | ||
|  | 3733a1e804 | ||
|  | 5b06a3f785 | ||
|  | baaf73aaac | ||
|  | 345c22aa80 | ||
|  | 26bb2a0865 | ||
|  | e6ea832410 | ||
|  | 22d0cc8d38 | ||
|  | 898829d5c7 | ||
|  | 72bb3c7571 | ||
|  | 48c437f0ab | ||
|  | 07d00c2174 | ||
|  | 3243a06f51 | ||
|  | 1c3f96be38 | ||
|  | df9e7219db | ||
|  | e83421f511 | ||
|  | 2b311b3cce | ||
|  | 4b5db3749c | ||
|  | a1497a782c | ||
|  | 3c547d7bb7 | ||
|  | 3b43502e3a | ||
|  | 078517421f | ||
|  | afc7055619 | ||
|  | 53425683d4 | ||
|  | ef5a63186a | ||
|  | 4a0e0accd7 | ||
|  | 73e47683de | ||
|  | 115e94a31e | ||
|  | 5fd5f6999d | ||
|  | 602e97b725 | ||
|  | 97b766dfcd | ||
|  | fb8cf78db6 | ||
|  | c5238ac21b | ||
|  | 99917a99cd | ||
|  | 55ed56908f | ||
|  | 139e310025 | ||
|  | bed93b1dcb | ||
|  | 73b4ac5cd8 | ||
|  | 00e8277b83 | ||
|  | a8ea3a357b | ||
|  | f8051485c1 | ||
|  | 807c80b259 | ||
|  | 686a3c3dc2 | ||
|  | a381d8277c | ||
|  | 8647b09bfd | ||
|  | 9153014fa0 | ||
|  | f6d4446ea8 | ||
|  | f1e247ee6b | ||
|  | a49668769d | ||
|  | 97d949d9da | ||
|  | 040093b1a5 | ||
|  | 5d4e53dc81 | ||
|  | 3ebee80226 | ||
|  | c56651312b | ||
|  | 869ca150e7 | ||
|  | 910628f396 | ||
|  | 251241dc90 | ||
|  | 03a23e5c6e | ||
|  | a68fc29ceb | ||
|  | 0014803d23 | ||
|  | 5118f7b47c | ||
|  | 1c1d7bda2c | ||
|  | bdae662c94 | ||
|  | 0108d4e323 | ||
|  | 4305793bad | ||
|  | d2d51eeff0 | ||
|  | 3be42b28c1 | ||
|  | ee70ef8771 | ||
|  | 5f9fe0f8d0 | ||
|  | 7589acc9e8 | ||
|  | 94f539bdac | ||
|  | e637fd2386 | ||
|  | 6e785bee32 | ||
|  | f883e4f7b8 | ||
|  | 5daa7bb7a4 | ||
|  | b0a84d0525 | ||
|  | f1f84ba223 | ||
|  | db830f26cb | ||
|  | 61a606dade | ||
|  | 2d95575edb | ||
|  | d707483ce3 | ||
|  | e2deb622c2 | ||
|  | 6e792a557e | ||
|  | ea2138cf90 | ||
|  | 992f3cb78e | ||
|  | 828b2ff676 | ||
|  | a231a8272c | ||
|  | f2604b35dc | ||
|  | fc05630f1f | ||
|  | ad960ddbce | ||
|  | 239a69680c | ||
|  | f4f1df70f2 | ||
|  | 782e9e6554 | ||
|  | 64de0113f1 | ||
|  | 84db615abc | ||
|  | 7c6a56cc63 | ||
|  | a20600b917 | ||
|  | 4986fd4111 | ||
|  | 96639424e2 | ||
|  | 6ac733bf09 | ||
|  | 25d82d3311 | ||
|  | f9800fe5a0 | ||
|  | 542d991b4c | ||
|  | d1d6963eba | ||
|  | 7058b807cd | ||
|  | f49d2561cb | ||
|  | a63e5f1971 | ||
|  | ebbc8a3d8e | ||
|  | 08b2d3ba9a | ||
|  | 72fbd9f97c | ||
|  | 5b6d0419d9 | ||
|  | 9df9eeeb18 | ||
|  | 5b6321a237 | ||
|  | 5e0c455842 | ||
|  | 4d687b13cf | ||
|  | d7b8193716 | ||
|  | 2e51813417 | ||
|  | 90f445e1c9 | ||
|  | 143d288cba | ||
|  | 13a2ccc46f | ||
|  | ea2b7d7079 | ||
|  | 0b52786ce1 | ||
|  | e36469149a | ||
|  | e5fc266be5 | ||
|  | 3e4cd634cc | ||
|  | 06976f82e7 | ||
|  | fe7c6c90a8 | ||
|  | 960a4b537a | ||
|  | c756b1e762 | ||
|  | 06921ec84f | ||
|  | 8cb1cec656 | ||
|  | a46657d185 | ||
|  | 28acf422cb | ||
|  | a7d5da8857 | ||
|  | 931a548be3 | ||
|  | bcddbd0f6a | ||
|  | b3dfdb5a3b | ||
|  | 6ccc51fd20 | ||
|  | 0ea5709a32 | ||
|  | 67a2698dac | ||
|  | eea4acfa5c | ||
|  | c99d32efe6 | ||
|  | 9fa7591beb | ||
|  | 066263f377 | ||
|  | 20c1a35211 | ||
|  | ea6112b165 | ||
|  | e222100afe | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -48,4 +48,5 @@ pc-bios/bios-pq/status | |||||||
| pc-bios/vgabios-pq/status | pc-bios/vgabios-pq/status | ||||||
| pc-bios/optionrom/multiboot.bin | pc-bios/optionrom/multiboot.bin | ||||||
| pc-bios/optionrom/multiboot.raw | pc-bios/optionrom/multiboot.raw | ||||||
|  | pc-bios/optionrom/extboot.bin | ||||||
| .stgit-* | .stgit-* | ||||||
|   | |||||||
							
								
								
									
										257
									
								
								Changelog
									
									
									
									
									
								
							
							
						
						
									
										257
									
								
								Changelog
									
									
									
									
									
								
							| @@ -1,3 +1,260 @@ | |||||||
|  | version 0.12.5 | ||||||
|  |  - audio/alsa: Handle SND_PCM_STATE_SETUP in alsa_poll_handler | ||||||
|  |  - block: Handle multiwrite errors only when all requests have completed | ||||||
|  |  - block: Fix early failure in multiwrite | ||||||
|  |  - vpc: Use bdrv_(p)write_sync for metadata writes | ||||||
|  |  - vmdk: Use bdrv_(p)write_sync for metadata writes | ||||||
|  |  - qcow2: Use bdrv_(p)write_sync for metadata writes | ||||||
|  |  - qcow: Use bdrv_(p)write_sync for metadata writes | ||||||
|  |  - block: Add bdrv_(p)write_sync | ||||||
|  |  - qcow2: Restore L1 entry on l2_allocate failure | ||||||
|  |  - block/vdi: Fix image opening and creation for odd disk sizes | ||||||
|  |  - block/vpc: Fix conversion from size to disk geometry | ||||||
|  |  - qcow2: Remove abort on free_clusters failure | ||||||
|  |  - vmdk: Fix COW | ||||||
|  |  - qcow2: Fix creation of large images | ||||||
|  |  - vmdk: fix double free | ||||||
|  |  - qemu-options: add documentation for stdio signal=on|off | ||||||
|  |  - target-arm : fix parallel saturated subtraction implementation | ||||||
|  |  - target-arm : fix thumb2 parallel add/sub opcode decoding | ||||||
|  |  - target-arm: fix addsub/subadd implementation | ||||||
|  |  - target-i386: fix xchg rax,r8 | ||||||
|  |  - block/vvfat.c: fix warnings with _FORTIFY_SOURCE | ||||||
|  |  - audio/alsa: Spelling typo (paramters) | ||||||
|  |  - target-mips: fix DINSU instruction | ||||||
|  |  - Correct definitions for FD_CMD_SAVE and FD_CMD_RESTORE | ||||||
|  |  - qcow2: Fix corruption after error in update_refcount | ||||||
|  |  - qcow2: Fix corruption after refblock allocation | ||||||
|  |  - block: Fix multiwrite with overlapping requests | ||||||
|  |  - qcow2: Fix error handling in l2_allocate | ||||||
|  |  - qcow2: Clear L2 table cache after write error | ||||||
|  |  - ide: Fix ide_dma_cancel | ||||||
|  |  - usb-bus: fix no params | ||||||
|  |  - Avoid crash on '-usbdevice <device>' without parameters | ||||||
|  |  - Fix -usbdevice crash | ||||||
|  |  - Fix multiboot compilation | ||||||
|  |  - Fix missing symbols in .rel/.rela.plt sections | ||||||
|  |  - target-ppc: fix RFI by clearing some bits of MSR | ||||||
|  |  - Fix typo in balloon help | ||||||
|  |  - arm_timer: fix oneshot mode | ||||||
|  |  - arm_timer: reload timer when enabled | ||||||
|  |  - qemu-sockets: avoid strlen of NULL pointer | ||||||
|  |  - block: fix aio_flush segfaults for read-only protocols (e.g. curl) | ||||||
|  |  - virtio-blk: fix barrier support | ||||||
|  |  - block: fix sector comparism in multiwrite_req_compare | ||||||
|  |  - pci: irq_state vmstate breakage | ||||||
|  |  - qemu-img: use the heap instead of the huge stack array for win32 | ||||||
|  |  | ||||||
|  | version 0.12.4 | ||||||
|  |  - Workaround for broken OSS_GETVERSION on FreeBSD, part two (Juergen Lock) | ||||||
|  |  - oss: fix fragment setting (malc) | ||||||
|  |  - oss: issue OSS_GETVERSION ioctl only when needed (malc) | ||||||
|  |  - oss: refactor code around policy setting (malc) | ||||||
|  |  - oss: workaround for cases when OSS_GETVERSION is not defined (malc) | ||||||
|  |  - block: Free iovec arrays allocated by multiwrite_merge() (Stefan Hajnoczi) | ||||||
|  |  - lsi: fix segfault in lsi_command_complete (Gerd Hoffmann) | ||||||
|  |  - lsi: pass lsi_request to lsi_reselect (Gerd Hoffmann) | ||||||
|  |  - lsi: move dma_len+dma_buf into lsi_request (Gerd Hoffmann) | ||||||
|  |  - lsi: move current_dev into lsi_request (Gerd Hoffmann) | ||||||
|  |  - lsi: have lsi_request for the whole life time of the request. (Gerd Hoffmann) | ||||||
|  |  - lsi: use QTAILQ for lsi_queue (Gerd Hoffmann) | ||||||
|  |  - tcp/mips: Change TCG_AREG0 (fp -> s0) (Stefan Weil) | ||||||
|  |  - sh_pci: fix memory and I/O access (Aurelien Jarno) | ||||||
|  |  - Fix incoming migration with iothread (Marcelo Tosatti) | ||||||
|  |  - Fix SIGFPE for vnc display of width/height = 1 (Chris Webb) | ||||||
|  |  - net: remove broken net_set_boot_mask() boot device validation (Eduardo Habkost) | ||||||
|  |  - qcow2: Remove request from in-flight list after error (Kevin Wolf) | ||||||
|  |  - qcow2: Don't ignore immediate read/write failures (Kevin Wolf) | ||||||
|  |  - block: Fix multiwrite memory leak in error case (Kevin Wolf) | ||||||
|  |  - block: Fix error code in multiwrite for immediate failures (Kevin Wolf) | ||||||
|  |  - block: Fix multiwrite error handling (Kevin Wolf) | ||||||
|  |  - scsi-disk: fix buffer overflow (Gerd Hoffmann) | ||||||
|  |  - qcow2: Rewrite alloc_refcount_block/grow_refcount_table (Kevin Wolf) | ||||||
|  |  - qcow2: Factor next_refcount_table_size out (Kevin Wolf) | ||||||
|  |  - block: avoid creating too large iovecs in multiwrite_merge (Christoph Hellwig) | ||||||
|  |  - json-parser: Fix segfault on malformed input (Kevin Wolf) | ||||||
|  |  - linux-user: switch default ppc64 CPU to 970fx from 970 (Aurelien Jarno) | ||||||
|  |  - target-sh4: MMU: fix store queue addresses (Aurelien Jarno) | ||||||
|  |  - target-sh4: MMU: fix ITLB priviledge check (Aurelien Jarno) | ||||||
|  |  - target-sh4: MMU: fix mem_idx computation (Aurelien Jarno) | ||||||
|  |  - sh7750: handle MMUCR TI bit (Aurelien Jarno) | ||||||
|  |  - UHCI spurious interrut fix (Paul Brook) | ||||||
|  |  - tcg/mips: fix branch offset during retranslation (Aurelien Jarno) | ||||||
|  |  - tcg/arm: correctly save/restore registers in prologue/epilogue (Aurelien Jarno) | ||||||
|  |  - workaround for cmd646 bmdma register access while no dma is active (Igor V. Kovalenko) | ||||||
|  |  - Fix corner case in chardev udp: parameter (Jan Kiszka) | ||||||
|  |  - Don't set default monitor when there is a mux'ed one (Jan Kiszka) | ||||||
|  |  - spelling typo (compatibilty) in hw/fw_cfg.c (Vagrant Cascadian) | ||||||
|  |  - fdc: fix drive property handling. (Gerd Hoffmann) | ||||||
|  |  - target-i386: fix commit c22549204a6edc431e8e4358e61bd56386ff6957 (TeLeMan) | ||||||
|  |  - target-i386: fix SIB decoding with index = 4 (Aurelien Jarno) | ||||||
|  |  - Fix segfault with ram_size > 4095M without kvm (Ryan Harper) | ||||||
|  |  - target-i386: Fix long jumps/calls in long mode with REX.W set (malc) | ||||||
|  |  - target-i386: fix lddqu SSE instruction (Aurelien Jarno) | ||||||
|  |  - qemu-char.c: drop debug printfs from qemu_chr_parse_compat (Jan Kiszka) | ||||||
|  |  - fix undefined shifts by >32 (Paolo Bonzini) | ||||||
|  |  - Fix qemu -net user,hostfwd= example (Aurelien Jarno) | ||||||
|  |  | ||||||
|  | version 0.12.3 | ||||||
|  |   - kvm: Fix eflags corruption in kvm mode (Jan Kiszka) | ||||||
|  |   - qcow2: Fix access after end of array (Kevin Wolf) | ||||||
|  |   - ide save/restore pio/atapi cmd transfer fields and io buffer (Marcelo Tosatti) | ||||||
|  |   - net: Monitor command set_link finds only VLAN clients, fix (Markus Armbruster) | ||||||
|  |   - net: info network shows only VLAN clients, fix (Markus Armbruster) | ||||||
|  |   - net: net_check_clients() checks only VLAN clients, fix (Markus Armbruster) | ||||||
|  |   - net: Fix bogus "Warning: vlan 0 with no nics" with -device (Markus Armbruster) | ||||||
|  |   - net: net_check_clients() runs too early to see -device, fix (Markus Armbruster) | ||||||
|  |   - net: Remove unused net_client_uninit() (Markus Armbruster) | ||||||
|  |   - don't dereference NULL after failed strdup (Jim Meyering) | ||||||
|  |   - virtio-net: fix network stall under load (Tom Lendacky) | ||||||
|  |   - json: fix PRId64 on Win32 (Roy Tam) | ||||||
|  |   - fix inet_parse typo (Marcelo Tosatti) | ||||||
|  |   - iothread: fix vcpu stop with smp tcg (Marcelo Tosatti) | ||||||
|  |   - segfault due to buffer overrun in usb-serial (David S. Ahern) | ||||||
|  |   - qcow2: Fix signedness bugs (Kevin Wolf) | ||||||
|  |   - Do not ignore error, if open file failed (-serial /dev/tty) (Evgeniy Dushistov) | ||||||
|  |   - pc-bios: update to newer version of (stable) seabios (Anthony Liguori) | ||||||
|  |   - target-mips: fix ROTR and DROTR by zero (Aurelien Jarno) | ||||||
|  |   - target-mips: fix CpU exception for coprocessor 0 (Nathan Froyd) | ||||||
|  |   - tcg/mips: fix crash in tcg_out_qemu_ld() (Aurelien Jarno) | ||||||
|  |   - target-mips: don't call cpu_loop_exit() from helper.c (Aurelien Jarno) | ||||||
|  |   - virtio-blk: Fix error cases which ignored rerror/werror (Kevin Wolf) | ||||||
|  |   - virtio-blk: Fix restart after read error (Kevin Wolf) | ||||||
|  |   - virtio_blk: Factor virtio_blk_handle_request out (Kevin Wolf) | ||||||
|  |   - cirrus: Properly re-register cirrus_linear_io_addr on vram unmap (Jan Kiszka) | ||||||
|  |   - qcow2: Don't ignore qcow2_alloc_clusters return value (Kevin Wolf) | ||||||
|  |   - qcow2: Don't ignore update_refcount return value (Kevin Wolf) | ||||||
|  |   - qcow2: Allow updating no refcounts (Kevin Wolf) | ||||||
|  |   - qcow2: Improve error handling in update_refcount (Kevin Wolf) | ||||||
|  |   - qcow2: Fix error handling in grow_refcount_table (Kevin Wolf) | ||||||
|  |   - block: Return original error codes in bdrv_pread/write (Kevin Wolf) | ||||||
|  |   - qcow2: Return 0/-errno in qcow2_alloc_cluster_offset (Kevin Wolf) | ||||||
|  |   - qcow2: Return 0/-errno in get_cluster_table (Kevin Wolf) | ||||||
|  |   - qcow2: Fix error handling in qcow_save_vmstate (Kevin Wolf) | ||||||
|  |   - qcow2: Fix error handling in qcow2_grow_l1_table (Kevin Wolf) | ||||||
|  |   - win32/sdl: Fix toggle full screen (Herve Poussineau) | ||||||
|  |   - win32: pair qemu_memalign() with qemu_vfree() (Herve Poussineau) | ||||||
|  |   - vnc_refresh: calling vnc_update_client might free vs (Stefano Stabellini) | ||||||
|  |   - Musicpal: Fix descriptor walk in eth_send (Jan Kiszka) | ||||||
|  |   - Musicpal: Fix wm8750 I2C address (Jan Kiszka) | ||||||
|  |   - fix savevm command without id or tag (Marcelo Tosatti) | ||||||
|  |   - reduce number of reinjects on ACK (Gleb Natapov) | ||||||
|  |   - QMP: Fix asynchronous events delivery (Luiz Capitulino) | ||||||
|  |   - Documentation: Add missing documentation for qdev related command line options (Stefan Weil) | ||||||
|  |   - pc: add driver version compat properties (Gerd Hoffmann) | ||||||
|  |   - scsi: device version property (Gerd Hoffmann) | ||||||
|  |   - ide: device version property (Gerd Hoffmann) | ||||||
|  |   - QMP: Emit asynchronous events on all QMP monitors (Adam Litke) | ||||||
|  |   - Fix QEMU_WARN_UNUSED_RESULT (Kevin Wolf) | ||||||
|  |  | ||||||
|  | version 0.12.2: | ||||||
|  |   - Qemu's internal TFTP server breaks lock-step-iness of TFTP (Milan Plzik) | ||||||
|  |   - osdep.c: Fix accept4 fallback (Kevin Wolf) | ||||||
|  |   - pc: add rombar to compat properties for pc-0.10 and pc-0.11 (Gerd Hoffmann) | ||||||
|  |   - pci: allow loading roms via fw_cfg. (Gerd Hoffmann) | ||||||
|  |   - roms: rework rom loading via fw (Gerd Hoffmann) | ||||||
|  |   - fw_cfg: rom loader tweaks. (Gerd Hoffmann) | ||||||
|  |   - roms: minor fixes and cleanups. (Gerd Hoffmann) | ||||||
|  |   - pc: add machine type for 0.12 (Gerd Hoffmann) | ||||||
|  |   - loader: more ignores for rom intended to be loaded by the bios (Aurelien Jarno) | ||||||
|  |   - vnc_refresh: return if vd->timer is NULL (Stefano Stabellini) | ||||||
|  |   - QMP: Don't free async event's 'data' (Luiz Capitulino) | ||||||
|  |   - Handle TFTP ERROR from client (Thomas Horsten) | ||||||
|  |   - dmg: fix ->open failure (Christoph Hellwig) | ||||||
|  |   - virtio-pci: thinko fix (Michael S. Tsirkin) | ||||||
|  |   - pc-bios: Update README (SeaBIOS) (Stefan Weil) | ||||||
|  |   - vmware_vga: Check cursor dimensions passed from guest to avoid buffer overflow (Roland Dreier) | ||||||
|  |   - remove pending exception on vcpu reset. (Gleb Natapov) | ||||||
|  |   - Fix CPU topology initialization (Jiri Denemark) | ||||||
|  |   - MCE: Fix bug of IA32_MCG_STATUS after system reset (Huang Ying) | ||||||
|  |   - linuxboot: fix gdt address calculation (Avi Kivity) | ||||||
|  |   - QMP: Drop wrong assert() (Luiz Capitulino) | ||||||
|  |   - vnc: Fix artifacts in hextile decoding (Anthony Liguori) | ||||||
|  |   - target-i386: Fix "call im" on x86_64 when executing 32-bit code (Aurelien Jarno) | ||||||
|  |   - Add missing newline at the end of options list (Michael Tokarev) | ||||||
|  |   - Don't load options roms intended to be loaded by the bios in qemu (Avi Kivity) | ||||||
|  |   - USB: Improve usbdevice error messages (Scott Tsai) | ||||||
|  |   - cpu-all.h: fix cpu_get_real_ticks() #ifdef (Aurelien Jarno) | ||||||
|  |   - alpha: fix compile (Blue Swirl) | ||||||
|  |   - user_only: compile everything with -fpie (Kirill A. Shutemov) | ||||||
|  |   - fdc/sparc32: don't hang on detection under OBP (Artyom Tarasenko) | ||||||
|  |   - scsi-disk: Inquiry with allocation length of CDB < 36 (v4) (Artyom Tarasenko) | ||||||
|  |   - e1000: fix init values for command register (Michael S. Tsirkin) | ||||||
|  |  | ||||||
|  | version 0.12.1: | ||||||
|  |   - loader: fix rom loading at address 0 (fixes target-arm) (Aurelien Jarno) | ||||||
|  |   - loader: fix rom_copy (fixes multiboot) (Kevin Wolf) | ||||||
|  |  | ||||||
|  | version 0.12.0: | ||||||
|  |  | ||||||
|  |   - Update to SeaBIOS 0.5.0 | ||||||
|  |   - 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) | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								EXTERNAL_DEPENDENCIES
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								EXTERNAL_DEPENDENCIES
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | seabios 9fb3f4d950744e97cc655b7d7b523d8bf101e4a0 | ||||||
|  | vgabios 6e62666cfc19e7fd45dd0d7c3ad62fd8d0b5f67a | ||||||
							
								
								
									
										1
									
								
								KVM_VERSION
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								KVM_VERSION
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | qemu-kvm-0.12.5 | ||||||
							
								
								
									
										43
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								Makefile
									
									
									
									
									
								
							| @@ -63,6 +63,18 @@ config-host.h-timestamp: config-host.mak | |||||||
|  |  | ||||||
| SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS)) | SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS)) | ||||||
|  |  | ||||||
|  | ifeq ($(KVM_KMOD),yes) | ||||||
|  |  | ||||||
|  | .PHONEY: kvm-kmod | ||||||
|  |  | ||||||
|  | all: kvm-kmod | ||||||
|  |  | ||||||
|  | kvm-kmod: | ||||||
|  | 	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C kvm/kernel V="$(V)" ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | endif | ||||||
|  |  | ||||||
| subdir-%: $(GENERATED_HEADERS) | subdir-%: $(GENERATED_HEADERS) | ||||||
| 	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,) | 	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,) | ||||||
|  |  | ||||||
| @@ -70,7 +82,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 +93,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 | ||||||
|  |  | ||||||
| @@ -88,6 +106,7 @@ block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o | |||||||
| block-obj-y += nbd.o block.o aio.o aes.o osdep.o | block-obj-y += nbd.o block.o aio.o aes.o osdep.o | ||||||
| block-obj-$(CONFIG_POSIX) += posix-aio-compat.o | block-obj-$(CONFIG_POSIX) += posix-aio-compat.o | ||||||
| block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o | block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o | ||||||
|  | block-obj-$(CONFIG_POSIX) += compatfd.o | ||||||
|  |  | ||||||
| block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o | block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o | ||||||
| block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o | block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o | ||||||
| @@ -120,6 +139,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 +172,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 +248,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 | ||||||
| @@ -278,6 +296,8 @@ pxe-ne2k_pci.bin pxe-pcnet.bin \ | |||||||
| pxe-rtl8139.bin pxe-virtio.bin \ | pxe-rtl8139.bin pxe-virtio.bin \ | ||||||
| bamboo.dtb petalogix-s3adsp1800.dtb \ | bamboo.dtb petalogix-s3adsp1800.dtb \ | ||||||
| multiboot.bin linuxboot.bin | multiboot.bin linuxboot.bin | ||||||
|  | BLOBS += extboot.bin | ||||||
|  | BLOBS += vapic.bin | ||||||
| else | else | ||||||
| BLOBS= | BLOBS= | ||||||
| endif | endif | ||||||
| @@ -300,7 +320,12 @@ endif | |||||||
| ifneq ($(BLOBS),) | ifneq ($(BLOBS),) | ||||||
| 	$(INSTALL_DIR) "$(DESTDIR)$(datadir)" | 	$(INSTALL_DIR) "$(DESTDIR)$(datadir)" | ||||||
| 	set -e; for x in $(BLOBS); do \ | 	set -e; for x in $(BLOBS); do \ | ||||||
|  | 	    if [ -f $(SRC_PATH)/pc-bios/$$x ];then \ | ||||||
| 		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ | 		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ | ||||||
|  | 	    fi \ | ||||||
|  | 	    ; if [ -f pc-bios/optionrom/$$x ];then \ | ||||||
|  | 		$(INSTALL_DATA) pc-bios/optionrom/$$x "$(DESTDIR)$(datadir)"; \ | ||||||
|  | 	    fi \ | ||||||
| 	done | 	done | ||||||
| endif | endif | ||||||
| 	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps" | 	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps" | ||||||
| @@ -310,6 +335,9 @@ endif | |||||||
| 	for d in $(TARGET_DIRS); do \ | 	for d in $(TARGET_DIRS); do \ | ||||||
| 	$(MAKE) -C $$d $@ || exit 1 ; \ | 	$(MAKE) -C $$d $@ || exit 1 ; \ | ||||||
|         done |         done | ||||||
|  | ifeq ($(KVM_KMOD),yes) | ||||||
|  | 	$(MAKE) -C kvm/kernel $@ | ||||||
|  | endif | ||||||
|  |  | ||||||
| # various test targets | # various test targets | ||||||
| test speed: all | test speed: all | ||||||
| @@ -430,6 +458,7 @@ tarbin: | |||||||
| 	$(datadir)/pxe-rtl8139.bin \ | 	$(datadir)/pxe-rtl8139.bin \ | ||||||
| 	$(datadir)/pxe-pcnet.bin \ | 	$(datadir)/pxe-pcnet.bin \ | ||||||
| 	$(datadir)/pxe-e1000.bin \ | 	$(datadir)/pxe-e1000.bin \ | ||||||
|  | 	$(datadir)/extboot.bin \ | ||||||
| 	$(docdir)/qemu-doc.html \ | 	$(docdir)/qemu-doc.html \ | ||||||
| 	$(docdir)/qemu-tech.html \ | 	$(docdir)/qemu-tech.html \ | ||||||
| 	$(mandir)/man1/qemu.1 \ | 	$(mandir)/man1/qemu.1 \ | ||||||
|   | |||||||
| @@ -25,7 +25,9 @@ obj-$(CONFIG_ESCC) += escc.o | |||||||
| # PCI watchdog devices | # PCI watchdog devices | ||||||
| obj-y += wdt_i6300esb.o | obj-y += wdt_i6300esb.o | ||||||
|  |  | ||||||
| obj-y += msix.o | # MSI-X depends on kvm for interrupt injection, | ||||||
|  | # so moved it from Makefile.hw to Makefile.target for now | ||||||
|  | # obj-y += msix.o | ||||||
|  |  | ||||||
| # PCI network cards | # PCI network cards | ||||||
| obj-y += ne2000.o | obj-y += ne2000.o | ||||||
|   | |||||||
| @@ -30,6 +30,8 @@ LIBS+=-lm | |||||||
|  |  | ||||||
| kvm.o kvm-all.o: QEMU_CFLAGS+=$(KVM_CFLAGS) | kvm.o kvm-all.o: QEMU_CFLAGS+=$(KVM_CFLAGS) | ||||||
|  |  | ||||||
|  | CFLAGS += $(KVM_CFLAGS) | ||||||
|  |  | ||||||
| config-target.h: config-target.h-timestamp | config-target.h: config-target.h-timestamp | ||||||
| config-target.h-timestamp: config-target.mak | config-target.h-timestamp: config-target.mak | ||||||
|  |  | ||||||
| @@ -40,12 +42,18 @@ all: $(PROGS) | |||||||
|  |  | ||||||
| ######################################################### | ######################################################### | ||||||
| # cpu emulator library | # cpu emulator library | ||||||
| libobj-y = exec.o translate-all.o cpu-exec.o translate.o | libobj-y = exec.o cpu-exec.o | ||||||
| libobj-y += tcg/tcg.o | libobj-$(CONFIG_NO_CPU_EMULATION) += fake-exec.o | ||||||
|  | libobj-$(CONFIG_CPU_EMULATION) += translate-all.o translate.o | ||||||
|  | libobj-$(CONFIG_CPU_EMULATION) += tcg/tcg.o | ||||||
| libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o | libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o | ||||||
| libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o | libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o | ||||||
| libobj-y += op_helper.o helper.o | libobj-y += op_helper.o helper.o | ||||||
| libobj-$(CONFIG_NEED_MMU) += mmu.o | libobj-$(CONFIG_NEED_MMU) += mmu.o | ||||||
|  |  | ||||||
|  | libobj-$(CONFIG_KVM) += kvm-tpr-opt.o | ||||||
|  | libobj-$(CONFIG_KVM) += qemu-kvm-helper.o | ||||||
|  |  | ||||||
| libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o | libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o | ||||||
| libobj-$(TARGET_ALPHA) += alpha_palcode.o | libobj-$(TARGET_ALPHA) += alpha_palcode.o | ||||||
|  |  | ||||||
| @@ -82,6 +90,8 @@ op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) | |||||||
| # cpu_signal_handler() in cpu-exec.c. | # cpu_signal_handler() in cpu-exec.c. | ||||||
| signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS) | signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS) | ||||||
|  |  | ||||||
|  | qemu-kvm-helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) | ||||||
|  |  | ||||||
| ######################################################### | ######################################################### | ||||||
| # Linux user emulator target | # Linux user emulator target | ||||||
|  |  | ||||||
| @@ -158,6 +168,10 @@ obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o | |||||||
| # need to fix this properly | # need to fix this properly | ||||||
| obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o | obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o | ||||||
| obj-$(CONFIG_KVM) += kvm.o kvm-all.o | obj-$(CONFIG_KVM) += kvm.o kvm-all.o | ||||||
|  | # MSI-X depends on kvm for interrupt injection, | ||||||
|  | # so moved it from Makefile.hw to Makefile.target for now | ||||||
|  | obj-y += msix.o | ||||||
|  |  | ||||||
| obj-$(CONFIG_ISA_MMIO) += isa_mmio.o | obj-$(CONFIG_ISA_MMIO) += isa_mmio.o | ||||||
| LIBS+=-lz | LIBS+=-lz | ||||||
|  |  | ||||||
| @@ -194,12 +208,25 @@ obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o | |||||||
| obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o | obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o | ||||||
| obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o | obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o | ||||||
| obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o | obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o | ||||||
|  | obj-i386-y += extboot.o | ||||||
| obj-i386-y += ne2000-isa.o | obj-i386-y += ne2000-isa.o | ||||||
|  | obj-i386-y += testdev.o | ||||||
|  |  | ||||||
|  | obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o | ||||||
|  | obj-i386-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o | ||||||
|  |  | ||||||
|  | # Hardware support | ||||||
|  | obj-ia64-y += ide.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) | ||||||
|  | obj-ia64-y += fdc.o mc146818rtc.o serial.o i8259.o ipf.o | ||||||
|  | obj-ia64-y += cirrus_vga.o parallel.o acpi.o piix_pci.o | ||||||
|  | obj-ia64-y += usb-uhci.o | ||||||
|  | obj-ia64-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o | ||||||
|  |  | ||||||
| # shared objects | # shared objects | ||||||
| obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o | obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o | ||||||
| obj-ppc-y += ide/cmd646.o | obj-ppc-y += ide/cmd646.o | ||||||
| obj-ppc-y += vga.o vga-pci.o $(sound-obj-y) dma.o openpic.o | obj-ppc-y += vga.o vga-pci.o $(sound-obj-y) dma.o openpic.o | ||||||
|  | obj-ppc-y += cirrus_vga.o | ||||||
| # PREP target | # PREP target | ||||||
| obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o | obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o | ||||||
| obj-ppc-y += prep_pci.o ppc_prep.o ne2000-isa.o | obj-ppc-y += prep_pci.o ppc_prep.o ne2000-isa.o | ||||||
| @@ -295,6 +322,11 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o | |||||||
|  |  | ||||||
| obj-s390x-y = s390-virtio-bus.o s390-virtio.o | obj-s390x-y = s390-virtio-bus.o s390-virtio.o | ||||||
|  |  | ||||||
|  | ifeq ($(TARGET_ARCH), ia64) | ||||||
|  | firmware.o: firmware.c | ||||||
|  | 	$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< | ||||||
|  | endif | ||||||
|  |  | ||||||
| main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) | main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) | ||||||
|  |  | ||||||
| vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS) | vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS) | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								aio.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								aio.c
									
									
									
									
									
								
							| @@ -113,7 +113,9 @@ void qemu_aio_flush(void) | |||||||
|         qemu_aio_wait(); |         qemu_aio_wait(); | ||||||
|  |  | ||||||
|         QLIST_FOREACH(node, &aio_handlers, node) { |         QLIST_FOREACH(node, &aio_handlers, node) { | ||||||
|             ret |= node->io_flush(node->opaque); |             if (node->io_flush) { | ||||||
|  |                 ret |= node->io_flush(node->opaque); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } while (qemu_bh_poll() || ret > 0); |     } while (qemu_bh_poll() || ret > 0); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -213,6 +213,10 @@ static void alsa_poll_handler (void *opaque) | |||||||
|  |  | ||||||
|     state = snd_pcm_state (hlp->handle); |     state = snd_pcm_state (hlp->handle); | ||||||
|     switch (state) { |     switch (state) { | ||||||
|  |     case SND_PCM_STATE_SETUP: | ||||||
|  |         alsa_recover (hlp->handle); | ||||||
|  |         break; | ||||||
|  |  | ||||||
|     case SND_PCM_STATE_XRUN: |     case SND_PCM_STATE_XRUN: | ||||||
|         alsa_recover (hlp->handle); |         alsa_recover (hlp->handle); | ||||||
|         break; |         break; | ||||||
| @@ -665,7 +669,7 @@ static int alsa_open (int in, struct alsa_params_req *req, | |||||||
|         (obt->fmt != req->fmt || |         (obt->fmt != req->fmt || | ||||||
|          obt->nchannels != req->nchannels || |          obt->nchannels != req->nchannels || | ||||||
|          obt->freq != req->freq)) { |          obt->freq != req->freq)) { | ||||||
|         dolog ("Audio paramters for %s\n", typ); |         dolog ("Audio parameters for %s\n", typ); | ||||||
|         alsa_dump_info (req, obt); |         alsa_dump_info (req, obt); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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, | ||||||
|   | |||||||
							
								
								
									
										376
									
								
								block.c
									
									
									
									
									
								
							
							
						
						
									
										376
									
								
								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> | ||||||
| @@ -451,6 +452,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, | |||||||
|             (flags & (BDRV_O_CACHE_MASK|BDRV_O_NATIVE_AIO)); |             (flags & (BDRV_O_CACHE_MASK|BDRV_O_NATIVE_AIO)); | ||||||
|     else |     else | ||||||
|         open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT); |         open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT); | ||||||
|  |  | ||||||
|  |     bs->open_flags = open_flags; | ||||||
|     if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) |     if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) | ||||||
|         ret = -ENOTSUP; |         ret = -ENOTSUP; | ||||||
|     else |     else | ||||||
| @@ -690,6 +693,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 +702,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 +715,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 +725,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 +738,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 +747,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 +762,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,15 +772,52 @@ 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; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Writes to the file and ensures that no writes are reordered across this | ||||||
|  |  * request (acts as a barrier) | ||||||
|  |  * | ||||||
|  |  * Returns 0 on success, -errno in error cases. | ||||||
|  |  */ | ||||||
|  | int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset, | ||||||
|  |     const void *buf, int count) | ||||||
|  | { | ||||||
|  |     int ret; | ||||||
|  |  | ||||||
|  |     ret = bdrv_pwrite(bs, offset, buf, count); | ||||||
|  |     if (ret < 0) { | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* No flush needed for cache=writethrough, it uses O_DSYNC */ | ||||||
|  |     if ((bs->open_flags & BDRV_O_CACHE_MASK) != 0) { | ||||||
|  |         bdrv_flush(bs); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Writes to the file and ensures that no writes are reordered across this | ||||||
|  |  * request (acts as a barrier) | ||||||
|  |  * | ||||||
|  |  * Returns 0 on success, -errno in error cases. | ||||||
|  |  */ | ||||||
|  | int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num, | ||||||
|  |     const uint8_t *buf, int nb_sectors) | ||||||
|  | { | ||||||
|  |     return bdrv_pwrite_sync(bs, BDRV_SECTOR_SIZE * sector_num, | ||||||
|  |         buf, BDRV_SECTOR_SIZE * nb_sectors); | ||||||
|  | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Truncate file to 'offset' bytes (needed only for file protocols) |  * Truncate file to 'offset' bytes (needed only for file protocols) | ||||||
|  */ |  */ | ||||||
| @@ -1139,61 +1181,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 +1647,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,23 +1659,32 @@ 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); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     mcb->num_requests--; |     mcb->num_requests--; | ||||||
|     if (mcb->num_requests == 0) { |     if (mcb->num_requests == 0) { | ||||||
|         if (mcb->error == 0) { |         multiwrite_user_cb(mcb); | ||||||
|             multiwrite_user_cb(mcb); |  | ||||||
|         } |  | ||||||
|         qemu_free(mcb); |         qemu_free(mcb); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static int multiwrite_req_compare(const void *a, const void *b) | static int multiwrite_req_compare(const void *a, const void *b) | ||||||
| { | { | ||||||
|     return (((BlockRequest*) a)->sector - ((BlockRequest*) b)->sector); |     const BlockRequest *req1 = a, *req2 = b; | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * Note that we can't simply subtract req2->sector from req1->sector | ||||||
|  |      * here as that could overflow the return value. | ||||||
|  |      */ | ||||||
|  |     if (req1->sector > req2->sector) { | ||||||
|  |         return 1; | ||||||
|  |     } else if (req1->sector < req2->sector) { | ||||||
|  |         return -1; | ||||||
|  |     } else { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -1524,6 +1720,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)); | ||||||
| @@ -1547,7 +1747,7 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs, | |||||||
|             // Add the second request |             // Add the second request | ||||||
|             qemu_iovec_concat(qiov, reqs[i].qiov, reqs[i].qiov->size); |             qemu_iovec_concat(qiov, reqs[i].qiov, reqs[i].qiov->size); | ||||||
|  |  | ||||||
|             reqs[outidx].nb_sectors += reqs[i].nb_sectors; |             reqs[outidx].nb_sectors = qiov->size >> 9; | ||||||
|             reqs[outidx].qiov = qiov; |             reqs[outidx].qiov = qiov; | ||||||
|  |  | ||||||
|             mcb->callbacks[i].free_qiov = reqs[outidx].qiov; |             mcb->callbacks[i].free_qiov = reqs[outidx].qiov; | ||||||
| @@ -1599,8 +1799,29 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs) | |||||||
|     // Check for mergable requests |     // Check for mergable requests | ||||||
|     num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb); |     num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb); | ||||||
|  |  | ||||||
|     // Run the aio requests |     /* | ||||||
|  |      * Run the aio requests. As soon as one request can't be submitted | ||||||
|  |      * successfully, fail all requests that are not yet submitted (we must | ||||||
|  |      * return failure for all requests anyway) | ||||||
|  |      * | ||||||
|  |      * num_requests cannot be set to the right value immediately: If | ||||||
|  |      * bdrv_aio_writev fails for some request, num_requests would be too high | ||||||
|  |      * and therefore multiwrite_cb() would never recognize the multiwrite | ||||||
|  |      * request as completed. We also cannot use the loop variable i to set it | ||||||
|  |      * when the first request fails because the callback may already have been | ||||||
|  |      * called for previously submitted requests. Thus, num_requests must be | ||||||
|  |      * incremented for each request that is submitted. | ||||||
|  |      * | ||||||
|  |      * The problem that callbacks may be called early also means that we need | ||||||
|  |      * to take care that num_requests doesn't become 0 before all requests are | ||||||
|  |      * submitted - multiwrite_cb() would consider the multiwrite request | ||||||
|  |      * completed. A dummy request that is "completed" by a manual call to | ||||||
|  |      * multiwrite_cb() takes care of this. | ||||||
|  |      */ | ||||||
|  |     mcb->num_requests = 1; | ||||||
|  |  | ||||||
|     for (i = 0; i < num_reqs; i++) { |     for (i = 0; i < num_reqs; i++) { | ||||||
|  |         mcb->num_requests++; | ||||||
|         acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov, |         acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov, | ||||||
|             reqs[i].nb_sectors, multiwrite_cb, mcb); |             reqs[i].nb_sectors, multiwrite_cb, mcb); | ||||||
|  |  | ||||||
| @@ -1608,22 +1829,25 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs) | |||||||
|             // We can only fail the whole thing if no request has been |             // We can only fail the whole thing if no request has been | ||||||
|             // 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 (i == 0) { | ||||||
|                 reqs[i].error = EIO; |  | ||||||
|                 goto fail; |                 goto fail; | ||||||
|             } else { |             } else { | ||||||
|                 mcb->error = EIO; |                 multiwrite_cb(mcb, -EIO); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|         } else { |  | ||||||
|             mcb->num_requests++; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /* Complete the dummy request */ | ||||||
|  |     multiwrite_cb(mcb, 0); | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
|  |  | ||||||
| fail: | fail: | ||||||
|     free(mcb); |     for (i = 0; i < mcb->num_callbacks; i++) { | ||||||
|  |         reqs[i].error = -EIO; | ||||||
|  |     } | ||||||
|  |     qemu_free(mcb); | ||||||
|     return -1; |     return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								block.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								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); | ||||||
| @@ -74,6 +77,10 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, | |||||||
|                void *buf, int count); |                void *buf, int count); | ||||||
| int bdrv_pwrite(BlockDriverState *bs, int64_t offset, | int bdrv_pwrite(BlockDriverState *bs, int64_t offset, | ||||||
|                 const void *buf, int count); |                 const void *buf, int count); | ||||||
|  | int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset, | ||||||
|  |     const void *buf, int count); | ||||||
|  | int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num, | ||||||
|  |     const uint8_t *buf, int nb_sectors); | ||||||
| int bdrv_truncate(BlockDriverState *bs, int64_t offset); | int bdrv_truncate(BlockDriverState *bs, int64_t offset); | ||||||
| int64_t bdrv_getlength(BlockDriverState *bs); | int64_t bdrv_getlength(BlockDriverState *bs); | ||||||
| void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); | void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); | ||||||
|   | |||||||
| @@ -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, | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								block/qcow.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								block/qcow.c
									
									
									
									
									
								
							| @@ -277,8 +277,9 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, | |||||||
|         /* update the L1 entry */ |         /* update the L1 entry */ | ||||||
|         s->l1_table[l1_index] = l2_offset; |         s->l1_table[l1_index] = l2_offset; | ||||||
|         tmp = cpu_to_be64(l2_offset); |         tmp = cpu_to_be64(l2_offset); | ||||||
|         if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), |         if (bdrv_pwrite_sync(s->hd, | ||||||
|                         &tmp, sizeof(tmp)) != sizeof(tmp)) |                 s->l1_table_offset + l1_index * sizeof(tmp), | ||||||
|  |                 &tmp, sizeof(tmp)) < 0) | ||||||
|             return 0; |             return 0; | ||||||
|         new_l2_table = 1; |         new_l2_table = 1; | ||||||
|     } |     } | ||||||
| @@ -306,8 +307,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, | |||||||
|     l2_table = s->l2_cache + (min_index << s->l2_bits); |     l2_table = s->l2_cache + (min_index << s->l2_bits); | ||||||
|     if (new_l2_table) { |     if (new_l2_table) { | ||||||
|         memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); |         memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); | ||||||
|         if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != |         if (bdrv_pwrite_sync(s->hd, l2_offset, l2_table, | ||||||
|             s->l2_size * sizeof(uint64_t)) |                 s->l2_size * sizeof(uint64_t)) < 0) | ||||||
|             return 0; |             return 0; | ||||||
|     } else { |     } else { | ||||||
|         if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != |         if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != | ||||||
| @@ -372,8 +373,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, | |||||||
|         /* update L2 table */ |         /* update L2 table */ | ||||||
|         tmp = cpu_to_be64(cluster_offset); |         tmp = cpu_to_be64(cluster_offset); | ||||||
|         l2_table[l2_index] = tmp; |         l2_table[l2_index] = tmp; | ||||||
|         if (bdrv_pwrite(s->hd, |         if (bdrv_pwrite_sync(s->hd, l2_offset + l2_index * sizeof(tmp), | ||||||
|                         l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp)) |                 &tmp, sizeof(tmp)) < 0) | ||||||
|             return 0; |             return 0; | ||||||
|     } |     } | ||||||
|     return cluster_offset; |     return cluster_offset; | ||||||
| @@ -821,8 +822,9 @@ static int qcow_make_empty(BlockDriverState *bs) | |||||||
|     int ret; |     int ret; | ||||||
|  |  | ||||||
|     memset(s->l1_table, 0, l1_length); |     memset(s->l1_table, 0, l1_length); | ||||||
|     if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0) |     if (bdrv_pwrite_sync(s->hd, s->l1_table_offset, s->l1_table, | ||||||
| 	return -1; |             l1_length) < 0) | ||||||
|  |         return -1; | ||||||
|     ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length); |     ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length); | ||||||
|     if (ret < 0) |     if (ret < 0) | ||||||
|         return ret; |         return ret; | ||||||
|   | |||||||
| @@ -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,11 +55,15 @@ 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]); | ||||||
|     ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2); |     ret = bdrv_pwrite_sync(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2); | ||||||
|     if (ret != new_l1_size2) |     if (ret < 0) | ||||||
|         goto fail; |         goto fail; | ||||||
|     for(i = 0; i < s->l1_size; i++) |     for(i = 0; i < s->l1_size; i++) | ||||||
|         new_l1_table[i] = be64_to_cpu(new_l1_table[i]); |         new_l1_table[i] = be64_to_cpu(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_sync(s->hd, offsetof(QCowHeader, l1_size), data,sizeof(data)); | ||||||
|                 sizeof(data)) != sizeof(data)) |     if (ret < 0) { | ||||||
|         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; | ||||||
| } | } | ||||||
|  |  | ||||||
| void qcow2_l2_cache_reset(BlockDriverState *bs) | void qcow2_l2_cache_reset(BlockDriverState *bs) | ||||||
| @@ -182,17 +188,17 @@ static int write_l1_entry(BDRVQcowState *s, int l1_index) | |||||||
| { | { | ||||||
|     uint64_t buf[L1_ENTRIES_PER_SECTOR]; |     uint64_t buf[L1_ENTRIES_PER_SECTOR]; | ||||||
|     int l1_start_index; |     int l1_start_index; | ||||||
|     int i; |     int i, ret; | ||||||
|  |  | ||||||
|     l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1); |     l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1); | ||||||
|     for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) { |     for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) { | ||||||
|         buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]); |         buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (bdrv_pwrite(s->hd, s->l1_table_offset + 8 * l1_start_index, |     ret = bdrv_pwrite_sync(s->hd, s->l1_table_offset + 8 * l1_start_index, | ||||||
|         buf, sizeof(buf)) != sizeof(buf)) |         buf, sizeof(buf)); | ||||||
|     { |     if (ret < 0) { | ||||||
|         return -1; |         return ret; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| @@ -213,18 +219,16 @@ 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; | ||||||
|  |     int ret; | ||||||
|  |  | ||||||
|     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) { | ||||||
|     /* update the L1 entry */ |  | ||||||
|  |  | ||||||
|     s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED; |  | ||||||
|     if (write_l1_entry(s, l1_index) < 0) { |  | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -241,13 +245,20 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index) | |||||||
|         if (bdrv_pread(s->hd, old_l2_offset, |         if (bdrv_pread(s->hd, old_l2_offset, | ||||||
|                        l2_table, s->l2_size * sizeof(uint64_t)) != |                        l2_table, s->l2_size * sizeof(uint64_t)) != | ||||||
|             s->l2_size * sizeof(uint64_t)) |             s->l2_size * sizeof(uint64_t)) | ||||||
|             return NULL; |             goto fail; | ||||||
|     } |     } | ||||||
|     /* write the l2 table to the file */ |     /* write the l2 table to the file */ | ||||||
|     if (bdrv_pwrite(s->hd, l2_offset, |     ret = bdrv_pwrite_sync(s->hd, l2_offset, l2_table, | ||||||
|                     l2_table, s->l2_size * sizeof(uint64_t)) != |         s->l2_size * sizeof(uint64_t)); | ||||||
|         s->l2_size * sizeof(uint64_t)) |     if (ret < 0) { | ||||||
|         return NULL; |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* update the L1 entry */ | ||||||
|  |     s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED; | ||||||
|  |     if (write_l1_entry(s, l1_index) < 0) { | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* update the l2 cache entry */ |     /* update the l2 cache entry */ | ||||||
|  |  | ||||||
| @@ -255,6 +266,11 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index) | |||||||
|     s->l2_cache_counts[min_index] = 1; |     s->l2_cache_counts[min_index] = 1; | ||||||
|  |  | ||||||
|     return l2_table; |     return l2_table; | ||||||
|  |  | ||||||
|  | fail: | ||||||
|  |     s->l1_table[l1_index] = old_l2_offset; | ||||||
|  |     qcow2_l2_cache_reset(bs); | ||||||
|  |     return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size, | static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size, | ||||||
| @@ -370,8 +386,8 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect, | |||||||
|                         s->cluster_data, n, 1, |                         s->cluster_data, n, 1, | ||||||
|                         &s->aes_encrypt_key); |                         &s->aes_encrypt_key); | ||||||
|     } |     } | ||||||
|     ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start, |     ret = bdrv_write_sync(s->hd, (cluster_offset >> 9) + n_start, | ||||||
|                      s->cluster_data, n); |         s->cluster_data, n); | ||||||
|     if (ret < 0) |     if (ret < 0) | ||||||
|         return ret; |         return ret; | ||||||
|     return 0; |     return 0; | ||||||
| @@ -479,8 +495,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 +512,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 +524,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 +545,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 +567,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 +584,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); | ||||||
|  |  | ||||||
| @@ -574,10 +599,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, | |||||||
|     /* compressed clusters never have the copied flag */ |     /* compressed clusters never have the copied flag */ | ||||||
|  |  | ||||||
|     l2_table[l2_index] = cpu_to_be64(cluster_offset); |     l2_table[l2_index] = cpu_to_be64(cluster_offset); | ||||||
|     if (bdrv_pwrite(s->hd, |     if (bdrv_pwrite_sync(s->hd, | ||||||
|                     l2_offset + l2_index * sizeof(uint64_t), |                     l2_offset + l2_index * sizeof(uint64_t), | ||||||
|                     l2_table + l2_index, |                     l2_table + l2_index, | ||||||
|                     sizeof(uint64_t)) != sizeof(uint64_t)) |                     sizeof(uint64_t)) < 0) | ||||||
|         return 0; |         return 0; | ||||||
|  |  | ||||||
|     return cluster_offset; |     return cluster_offset; | ||||||
| @@ -595,22 +620,23 @@ static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table, | |||||||
|     int start_offset = (8 * l2_index) & ~511; |     int start_offset = (8 * l2_index) & ~511; | ||||||
|     int end_offset = (8 * (l2_index + num) + 511) & ~511; |     int end_offset = (8 * (l2_index + num) + 511) & ~511; | ||||||
|     size_t len = end_offset - start_offset; |     size_t len = end_offset - start_offset; | ||||||
|  |     int ret; | ||||||
|  |  | ||||||
|     if (bdrv_pwrite(s->hd, l2_offset + start_offset, &l2_table[l2_start_index], |     ret = bdrv_pwrite_sync(s->hd, l2_offset + start_offset, | ||||||
|         len) != len) |         &l2_table[l2_start_index], len); | ||||||
|     { |     if (ret < 0) { | ||||||
|         return -1; |         return ret; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     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 +659,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 | ||||||
| @@ -652,8 +679,9 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset, | |||||||
|                     (i << s->cluster_bits)) | QCOW_OFLAG_COPIED); |                     (i << s->cluster_bits)) | QCOW_OFLAG_COPIED); | ||||||
|      } |      } | ||||||
|  |  | ||||||
|     if (write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters) < 0) { |     ret = write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters); | ||||||
|         ret = -1; |     if (ret < 0) { | ||||||
|  |         qcow2_l2_cache_reset(bs); | ||||||
|         goto err; |         goto err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -670,30 +698,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 +743,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 +758,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 +774,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 +818,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 +830,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); | ||||||
|  |  | ||||||
| @@ -42,8 +42,8 @@ static int write_refcount_block(BDRVQcowState *s) | |||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (bdrv_pwrite(s->hd, s->refcount_block_cache_offset, |     if (bdrv_pwrite_sync(s->hd, s->refcount_block_cache_offset, | ||||||
|             s->refcount_block_cache, size) != size) |             s->refcount_block_cache, size) < 0) | ||||||
|     { |     { | ||||||
|         return -EIO; |         return -EIO; | ||||||
|     } |     } | ||||||
| @@ -123,121 +123,273 @@ 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) { |  | ||||||
|         if (cache_refcount_updates) { | #ifdef DEBUG_ALLOC2 | ||||||
|             write_refcount_block(s); |     fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64 | ||||||
|             cache_refcount_updates = 0; |         " at %" PRIx64 "\n", | ||||||
|         } |         refcount_table_index, cluster_index << s->cluster_bits, new_block); | ||||||
|         /* create a new refcount block */ | #endif | ||||||
|         /* Note: we cannot update the refcount now to avoid recursion */ |  | ||||||
|         offset = alloc_clusters_noref(bs, s->cluster_size); |     if (in_same_refcount_block(s, new_block, cluster_index << s->cluster_bits)) { | ||||||
|  |         /* Zero the new refcount block before updating it */ | ||||||
|         memset(s->refcount_block_cache, 0, 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); |         s->refcount_block_cache_offset = new_block; | ||||||
|         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; |         /* The block describes itself, need to update the cache */ | ||||||
|         s->refcount_block_cache_offset = offset; |         int block_index = (new_block >> s->cluster_bits) & | ||||||
|         update_refcount(bs, offset, s->cluster_size, 1); |             ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); | ||||||
|         cache_refcount_updates = cache; |         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; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         /* Initialize the new refcount block only after updating its refcount, | ||||||
|  |          * update_refcount uses the refcount cache itself */ | ||||||
|  |         memset(s->refcount_block_cache, 0, s->cluster_size); | ||||||
|  |         s->refcount_block_cache_offset = new_block; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return refcount_block_offset; |     /* Now the new refcount block needs to be written to disk */ | ||||||
|  |     ret = bdrv_pwrite_sync(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_sync(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_sync(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_sync(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_sync(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) | ||||||
| @@ -245,43 +397,52 @@ static int write_refcount_block_entries(BDRVQcowState *s, | |||||||
|     int64_t refcount_block_offset, int first_index, int last_index) |     int64_t refcount_block_offset, int first_index, int last_index) | ||||||
| { | { | ||||||
|     size_t size; |     size_t size; | ||||||
|  |     int ret; | ||||||
|  |  | ||||||
|     if (cache_refcount_updates) { |     if (cache_refcount_updates) { | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (first_index < 0) { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     first_index &= ~(REFCOUNTS_PER_SECTOR - 1); |     first_index &= ~(REFCOUNTS_PER_SECTOR - 1); | ||||||
|     last_index = (last_index + REFCOUNTS_PER_SECTOR) |     last_index = (last_index + REFCOUNTS_PER_SECTOR) | ||||||
|         & ~(REFCOUNTS_PER_SECTOR - 1); |         & ~(REFCOUNTS_PER_SECTOR - 1); | ||||||
|  |  | ||||||
|     size = (last_index - first_index) << REFCOUNT_SHIFT; |     size = (last_index - first_index) << REFCOUNT_SHIFT; | ||||||
|     if (bdrv_pwrite(s->hd, |     ret = bdrv_pwrite_sync(s->hd, | ||||||
|         refcount_block_offset + (first_index << REFCOUNT_SHIFT), |         refcount_block_offset + (first_index << REFCOUNT_SHIFT), | ||||||
|         &s->refcount_block_cache[first_index], size) != size) |         &s->refcount_block_cache[first_index], size); | ||||||
|     { |     if (ret < 0) { | ||||||
|         return -EIO; |         return ret; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* 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 +450,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 +468,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 +487,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 +568,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 +589,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 +607,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 +627,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)); | ||||||
|  |         /* TODO Remember the clusters to free them later and avoid leaking */ | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -549,9 +743,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 { | ||||||
| @@ -572,8 +772,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             if (l2_modified) { |             if (l2_modified) { | ||||||
|                 if (bdrv_pwrite(s->hd, |                 if (bdrv_pwrite_sync(s->hd, | ||||||
|                                 l2_offset, l2_table, l2_size) != l2_size) |                                 l2_offset, l2_table, l2_size) < 0) | ||||||
|                     goto fail; |                     goto fail; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -594,8 +794,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, | |||||||
|     if (l1_modified) { |     if (l1_modified) { | ||||||
|         for(i = 0; i < l1_size; i++) |         for(i = 0; i < l1_size; i++) | ||||||
|             cpu_to_be64s(&l1_table[i]); |             cpu_to_be64s(&l1_table[i]); | ||||||
|         if (bdrv_pwrite(s->hd, l1_table_offset, l1_table, |         if (bdrv_pwrite_sync(s->hd, l1_table_offset, l1_table, | ||||||
|                         l1_size2) != l1_size2) |                         l1_size2) < 0) | ||||||
|             goto fail; |             goto fail; | ||||||
|         for(i = 0; i < l1_size; i++) |         for(i = 0; i < l1_size; i++) | ||||||
|             be64_to_cpus(&l1_table[i]); |             be64_to_cpus(&l1_table[i]); | ||||||
|   | |||||||
| @@ -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; | ||||||
| @@ -155,25 +158,25 @@ static int qcow_write_snapshots(BlockDriverState *bs) | |||||||
|         h.id_str_size = cpu_to_be16(id_str_size); |         h.id_str_size = cpu_to_be16(id_str_size); | ||||||
|         h.name_size = cpu_to_be16(name_size); |         h.name_size = cpu_to_be16(name_size); | ||||||
|         offset = align_offset(offset, 8); |         offset = align_offset(offset, 8); | ||||||
|         if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h)) |         if (bdrv_pwrite_sync(s->hd, offset, &h, sizeof(h)) < 0) | ||||||
|             goto fail; |             goto fail; | ||||||
|         offset += sizeof(h); |         offset += sizeof(h); | ||||||
|         if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size) |         if (bdrv_pwrite_sync(s->hd, offset, sn->id_str, id_str_size) < 0) | ||||||
|             goto fail; |             goto fail; | ||||||
|         offset += id_str_size; |         offset += id_str_size; | ||||||
|         if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size) |         if (bdrv_pwrite_sync(s->hd, offset, sn->name, name_size) < 0) | ||||||
|             goto fail; |             goto fail; | ||||||
|         offset += name_size; |         offset += name_size; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* update the various header fields */ |     /* update the various header fields */ | ||||||
|     data64 = cpu_to_be64(snapshots_offset); |     data64 = cpu_to_be64(snapshots_offset); | ||||||
|     if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset), |     if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, snapshots_offset), | ||||||
|                     &data64, sizeof(data64)) != sizeof(data64)) |                     &data64, sizeof(data64)) < 0) | ||||||
|         goto fail; |         goto fail; | ||||||
|     data32 = cpu_to_be32(s->nb_snapshots); |     data32 = cpu_to_be32(s->nb_snapshots); | ||||||
|     if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots), |     if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, nb_snapshots), | ||||||
|                     &data32, sizeof(data32)) != sizeof(data32)) |                     &data32, sizeof(data32)) < 0) | ||||||
|         goto fail; |         goto fail; | ||||||
|  |  | ||||||
|     /* free the old snapshot table */ |     /* free the old snapshot table */ | ||||||
| @@ -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) { | ||||||
| @@ -275,9 +284,8 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) | |||||||
|     for(i = 0; i < s->l1_size; i++) { |     for(i = 0; i < s->l1_size; i++) { | ||||||
|         l1_table[i] = cpu_to_be64(s->l1_table[i]); |         l1_table[i] = cpu_to_be64(s->l1_table[i]); | ||||||
|     } |     } | ||||||
|     if (bdrv_pwrite(s->hd, sn->l1_table_offset, |     if (bdrv_pwrite_sync(s->hd, sn->l1_table_offset, | ||||||
|                     l1_table, s->l1_size * sizeof(uint64_t)) != |                     l1_table, s->l1_size * sizeof(uint64_t)) < 0) | ||||||
|         (s->l1_size * sizeof(uint64_t))) |  | ||||||
|         goto fail; |         goto fail; | ||||||
|     qemu_free(l1_table); |     qemu_free(l1_table); | ||||||
|     l1_table = NULL; |     l1_table = NULL; | ||||||
| @@ -326,8 +334,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) | |||||||
|     if (bdrv_pread(s->hd, sn->l1_table_offset, |     if (bdrv_pread(s->hd, sn->l1_table_offset, | ||||||
|                    s->l1_table, l1_size2) != l1_size2) |                    s->l1_table, l1_size2) != l1_size2) | ||||||
|         goto fail; |         goto fail; | ||||||
|     if (bdrv_pwrite(s->hd, s->l1_table_offset, |     if (bdrv_pwrite_sync(s->hd, s->l1_table_offset, | ||||||
|                     s->l1_table, l1_size2) != l1_size2) |                     s->l1_table, l1_size2) < 0) | ||||||
|         goto fail; |         goto fail; | ||||||
|     for(i = 0;i < s->l1_size; i++) { |     for(i = 0;i < s->l1_size; i++) { | ||||||
|         be64_to_cpus(&s->l1_table[i]); |         be64_to_cpus(&s->l1_table[i]); | ||||||
|   | |||||||
| @@ -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; | ||||||
| @@ -737,10 +747,11 @@ static int qcow_create2(const char *filename, int64_t total_size, | |||||||
| { | { | ||||||
|  |  | ||||||
|     int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits; |     int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits; | ||||||
|     int ref_clusters, backing_format_len = 0; |     int ref_clusters, reftable_clusters, backing_format_len = 0; | ||||||
|     int rounded_ext_bf_len = 0; |     int rounded_ext_bf_len = 0; | ||||||
|     QCowHeader header; |     QCowHeader header; | ||||||
|     uint64_t tmp, offset; |     uint64_t tmp, offset; | ||||||
|  |     uint64_t old_ref_clusters; | ||||||
|     QCowCreateState s1, *s = &s1; |     QCowCreateState s1, *s = &s1; | ||||||
|     QCowExtension ext_bf = {0, 0}; |     QCowExtension ext_bf = {0, 0}; | ||||||
|  |  | ||||||
| @@ -799,17 +810,37 @@ static int qcow_create2(const char *filename, int64_t total_size, | |||||||
|     header.l1_size = cpu_to_be32(l1_size); |     header.l1_size = cpu_to_be32(l1_size); | ||||||
|     offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size); |     offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size); | ||||||
|  |  | ||||||
|     s->refcount_table = qemu_mallocz(s->cluster_size); |     /* count how many refcount blocks needed */ | ||||||
|  |  | ||||||
|  | #define NUM_CLUSTERS(bytes) \ | ||||||
|  |     (((bytes) + (s->cluster_size) - 1) / (s->cluster_size)) | ||||||
|  |  | ||||||
|  |     ref_clusters = NUM_CLUSTERS(NUM_CLUSTERS(offset) * sizeof(uint16_t)); | ||||||
|  |  | ||||||
|  |     do { | ||||||
|  |         uint64_t image_clusters; | ||||||
|  |         old_ref_clusters = ref_clusters; | ||||||
|  |  | ||||||
|  |         /* Number of clusters used for the refcount table */ | ||||||
|  |         reftable_clusters = NUM_CLUSTERS(ref_clusters * sizeof(uint64_t)); | ||||||
|  |  | ||||||
|  |         /* Number of clusters that the whole image will have */ | ||||||
|  |         image_clusters = NUM_CLUSTERS(offset) + ref_clusters | ||||||
|  |             + reftable_clusters; | ||||||
|  |  | ||||||
|  |         /* Number of refcount blocks needed for the image */ | ||||||
|  |         ref_clusters = NUM_CLUSTERS(image_clusters * sizeof(uint16_t)); | ||||||
|  |  | ||||||
|  |     } while (ref_clusters != old_ref_clusters); | ||||||
|  |  | ||||||
|  |     s->refcount_table = qemu_mallocz(reftable_clusters * s->cluster_size); | ||||||
|  |  | ||||||
|     s->refcount_table_offset = offset; |     s->refcount_table_offset = offset; | ||||||
|     header.refcount_table_offset = cpu_to_be64(offset); |     header.refcount_table_offset = cpu_to_be64(offset); | ||||||
|     header.refcount_table_clusters = cpu_to_be32(1); |     header.refcount_table_clusters = cpu_to_be32(reftable_clusters); | ||||||
|     offset += s->cluster_size; |     offset += (reftable_clusters * s->cluster_size); | ||||||
|     s->refcount_block_offset = offset; |     s->refcount_block_offset = offset; | ||||||
|  |  | ||||||
|     /* count how many refcount blocks needed */ |  | ||||||
|     tmp = offset >> s->cluster_bits; |  | ||||||
|     ref_clusters = (tmp >> (s->cluster_bits - REFCOUNT_SHIFT)) + 1; |  | ||||||
|     for (i=0; i < ref_clusters; i++) { |     for (i=0; i < ref_clusters; i++) { | ||||||
|         s->refcount_table[i] = cpu_to_be64(offset); |         s->refcount_table[i] = cpu_to_be64(offset); | ||||||
|         offset += s->cluster_size; |         offset += s->cluster_size; | ||||||
| @@ -821,7 +852,8 @@ static int qcow_create2(const char *filename, int64_t total_size, | |||||||
|     qcow2_create_refcount_update(s, 0, header_size); |     qcow2_create_refcount_update(s, 0, header_size); | ||||||
|     qcow2_create_refcount_update(s, s->l1_table_offset, |     qcow2_create_refcount_update(s, s->l1_table_offset, | ||||||
|         l1_size * sizeof(uint64_t)); |         l1_size * sizeof(uint64_t)); | ||||||
|     qcow2_create_refcount_update(s, s->refcount_table_offset, s->cluster_size); |     qcow2_create_refcount_update(s, s->refcount_table_offset, | ||||||
|  |         reftable_clusters * s->cluster_size); | ||||||
|     qcow2_create_refcount_update(s, s->refcount_block_offset, |     qcow2_create_refcount_update(s, s->refcount_block_offset, | ||||||
|         ref_clusters * s->cluster_size); |         ref_clusters * s->cluster_size); | ||||||
|  |  | ||||||
| @@ -849,7 +881,8 @@ static int qcow_create2(const char *filename, int64_t total_size, | |||||||
|         write(fd, &tmp, sizeof(tmp)); |         write(fd, &tmp, sizeof(tmp)); | ||||||
|     } |     } | ||||||
|     lseek(fd, s->refcount_table_offset, SEEK_SET); |     lseek(fd, s->refcount_table_offset, SEEK_SET); | ||||||
|     write(fd, s->refcount_table, s->cluster_size); |     write(fd, s->refcount_table, | ||||||
|  |         reftable_clusters * s->cluster_size); | ||||||
|  |  | ||||||
|     lseek(fd, s->refcount_block_offset, SEEK_SET); |     lseek(fd, s->refcount_block_offset, SEEK_SET); | ||||||
|     write(fd, s->refcount_block, ref_clusters * s->cluster_size); |     write(fd, s->refcount_block, ref_clusters * s->cluster_size); | ||||||
| @@ -1056,12 +1089,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); | ||||||
|   | |||||||
| @@ -27,6 +27,8 @@ | |||||||
| #include "qemu-log.h" | #include "qemu-log.h" | ||||||
| #include "block_int.h" | #include "block_int.h" | ||||||
| #include "module.h" | #include "module.h" | ||||||
|  | #include "compatfd.h" | ||||||
|  | #include <assert.h> | ||||||
| #include "block/raw-posix-aio.h" | #include "block/raw-posix-aio.h" | ||||||
|  |  | ||||||
| #ifdef CONFIG_COCOA | #ifdef CONFIG_COCOA | ||||||
| @@ -595,7 +597,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); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								block/vdi.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								block/vdi.c
									
									
									
									
									
								
							| @@ -399,6 +399,15 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags) | |||||||
|     vdi_header_print(&header); |     vdi_header_print(&header); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |     if (header.disk_size % SECTOR_SIZE != 0) { | ||||||
|  |         /* 'VBoxManage convertfromraw' can create images with odd disk sizes. | ||||||
|  |            We accept them but round the disk size to the next multiple of | ||||||
|  |            SECTOR_SIZE. */ | ||||||
|  |         logout("odd disk size %" PRIu64 " B, round up\n", header.disk_size); | ||||||
|  |         header.disk_size += SECTOR_SIZE - 1; | ||||||
|  |         header.disk_size &= ~(SECTOR_SIZE - 1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (header.version != VDI_VERSION_1_1) { |     if (header.version != VDI_VERSION_1_1) { | ||||||
|         logout("unsupported version %u.%u\n", |         logout("unsupported version %u.%u\n", | ||||||
|                header.version >> 16, header.version & 0xffff); |                header.version >> 16, header.version & 0xffff); | ||||||
| @@ -417,9 +426,9 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags) | |||||||
|     } else if (header.block_size != 1 * MiB) { |     } else if (header.block_size != 1 * MiB) { | ||||||
|         logout("unsupported block size %u B\n", header.block_size); |         logout("unsupported block size %u B\n", header.block_size); | ||||||
|         goto fail; |         goto fail; | ||||||
|     } else if (header.disk_size != |     } else if (header.disk_size > | ||||||
|                (uint64_t)header.blocks_in_image * header.block_size) { |                (uint64_t)header.blocks_in_image * header.block_size) { | ||||||
|         logout("unexpected block number %u B\n", header.blocks_in_image); |         logout("unsupported disk size %" PRIu64 " B\n", header.disk_size); | ||||||
|         goto fail; |         goto fail; | ||||||
|     } else if (!uuid_is_null(header.uuid_link)) { |     } else if (!uuid_is_null(header.uuid_link)) { | ||||||
|         logout("link uuid != 0, unsupported\n"); |         logout("link uuid != 0, unsupported\n"); | ||||||
| @@ -831,7 +840,10 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options) | |||||||
|         return -errno; |         return -errno; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     blocks = bytes / block_size; |     /* We need enough blocks to store the given disk size, | ||||||
|  |        so always round up. */ | ||||||
|  |     blocks = (bytes + block_size - 1) / block_size; | ||||||
|  |  | ||||||
|     bmap_size = blocks * sizeof(uint32_t); |     bmap_size = blocks * sizeof(uint32_t); | ||||||
|     bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1)); |     bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1)); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										47
									
								
								block/vmdk.c
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								block/vmdk.c
									
									
									
									
									
								
							| @@ -87,14 +87,6 @@ typedef struct VmdkMetaData { | |||||||
|     int valid; |     int valid; | ||||||
| } VmdkMetaData; | } VmdkMetaData; | ||||||
|  |  | ||||||
| typedef struct ActiveBDRVState{ |  | ||||||
|     BlockDriverState *hd;            // active image handler |  | ||||||
|     uint64_t cluster_offset;         // current write offset |  | ||||||
| }ActiveBDRVState; |  | ||||||
|  |  | ||||||
| static ActiveBDRVState activeBDRV; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) | static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) | ||||||
| { | { | ||||||
|     uint32_t magic; |     uint32_t magic; | ||||||
| @@ -161,7 +153,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) | |||||||
|         pstrcat(desc, sizeof(desc), tmp_desc); |         pstrcat(desc, sizeof(desc), tmp_desc); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) |     if (bdrv_pwrite_sync(s->hd, 0x200, desc, DESC_SIZE) < 0) | ||||||
|         return -1; |         return -1; | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| @@ -285,7 +277,6 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file) | |||||||
|         goto fail_rgd; |         goto fail_rgd; | ||||||
|     if (write(snp_fd, rgd_buf, gd_size) == -1) |     if (write(snp_fd, rgd_buf, gd_size) == -1) | ||||||
|         goto fail_rgd; |         goto fail_rgd; | ||||||
|     qemu_free(rgd_buf); |  | ||||||
|  |  | ||||||
|     /* write GD */ |     /* write GD */ | ||||||
|     gd_buf = qemu_malloc(gd_size); |     gd_buf = qemu_malloc(gd_size); | ||||||
| @@ -298,6 +289,7 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file) | |||||||
|     if (write(snp_fd, gd_buf, gd_size) == -1) |     if (write(snp_fd, gd_buf, gd_size) == -1) | ||||||
|         goto fail_gd; |         goto fail_gd; | ||||||
|     qemu_free(gd_buf); |     qemu_free(gd_buf); | ||||||
|  |     qemu_free(rgd_buf); | ||||||
|  |  | ||||||
|     close(p_fd); |     close(p_fd); | ||||||
|     close(snp_fd); |     close(snp_fd); | ||||||
| @@ -458,30 +450,28 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, | |||||||
| static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset, | static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset, | ||||||
|                              uint64_t offset, int allocate) |                              uint64_t offset, int allocate) | ||||||
| { | { | ||||||
|     uint64_t parent_cluster_offset; |  | ||||||
|     BDRVVmdkState *s = bs->opaque; |     BDRVVmdkState *s = bs->opaque; | ||||||
|     uint8_t  whole_grain[s->cluster_sectors*512];        // 128 sectors * 512 bytes each = grain size 64KB |     uint8_t  whole_grain[s->cluster_sectors*512];        // 128 sectors * 512 bytes each = grain size 64KB | ||||||
|  |  | ||||||
|     // we will be here if it's first write on non-exist grain(cluster). |     // we will be here if it's first write on non-exist grain(cluster). | ||||||
|     // try to read from parent image, if exist |     // try to read from parent image, if exist | ||||||
|     if (bs->backing_hd) { |     if (bs->backing_hd) { | ||||||
|         BDRVVmdkState *ps = bs->backing_hd->opaque; |         int ret; | ||||||
|  |  | ||||||
|         if (!vmdk_is_cid_valid(bs)) |         if (!vmdk_is_cid_valid(bs)) | ||||||
|             return -1; |             return -1; | ||||||
|  |  | ||||||
|         parent_cluster_offset = get_cluster_offset(bs->backing_hd, NULL, |         ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain, | ||||||
|             offset, allocate); |             s->cluster_sectors); | ||||||
|  |         if (ret < 0) { | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if (parent_cluster_offset) { |         //Write grain only into the active image | ||||||
|             BDRVVmdkState *act_s = activeBDRV.hd->opaque; |         ret = bdrv_write(s->hd, cluster_offset, whole_grain, | ||||||
|  |             s->cluster_sectors); | ||||||
|             if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512) |         if (ret < 0) { | ||||||
|                 return -1; |             return -1; | ||||||
|  |  | ||||||
|             //Write grain only into the active image |  | ||||||
|             if (bdrv_pwrite(act_s->hd, activeBDRV.cluster_offset << 9, whole_grain, sizeof(whole_grain)) != sizeof(whole_grain)) |  | ||||||
|                 return -1; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return 0; |     return 0; | ||||||
| @@ -492,14 +482,14 @@ static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data) | |||||||
|     BDRVVmdkState *s = bs->opaque; |     BDRVVmdkState *s = bs->opaque; | ||||||
|  |  | ||||||
|     /* update L2 table */ |     /* update L2 table */ | ||||||
|     if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), |     if (bdrv_pwrite_sync(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), | ||||||
|                     &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset)) |                     &(m_data->offset), sizeof(m_data->offset)) < 0) | ||||||
|         return -1; |         return -1; | ||||||
|     /* update backup L2 table */ |     /* update backup L2 table */ | ||||||
|     if (s->l1_backup_table_offset != 0) { |     if (s->l1_backup_table_offset != 0) { | ||||||
|         m_data->l2_offset = s->l1_backup_table[m_data->l1_index]; |         m_data->l2_offset = s->l1_backup_table[m_data->l1_index]; | ||||||
|         if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), |         if (bdrv_pwrite_sync(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), | ||||||
|                         &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset)) |                         &(m_data->offset), sizeof(m_data->offset)) < 0) | ||||||
|             return -1; |             return -1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -567,9 +557,6 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, | |||||||
|             cluster_offset >>= 9; |             cluster_offset >>= 9; | ||||||
|             tmp = cpu_to_le32(cluster_offset); |             tmp = cpu_to_le32(cluster_offset); | ||||||
|             l2_table[l2_index] = tmp; |             l2_table[l2_index] = tmp; | ||||||
|             // Save the active image state |  | ||||||
|             activeBDRV.cluster_offset = cluster_offset; |  | ||||||
|             activeBDRV.hd = bs; |  | ||||||
|         } |         } | ||||||
|         /* First of all we write grain itself, to avoid race condition |         /* First of all we write grain itself, to avoid race condition | ||||||
|          * that may to corrupt the image. |          * that may to corrupt the image. | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								block/vpc.c
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								block/vpc.c
									
									
									
									
									
								
							| @@ -266,7 +266,7 @@ static inline int64_t get_sector_offset(BlockDriverState *bs, | |||||||
|  |  | ||||||
|         s->last_bitmap_offset = bitmap_offset; |         s->last_bitmap_offset = bitmap_offset; | ||||||
|         memset(bitmap, 0xff, s->bitmap_size); |         memset(bitmap, 0xff, s->bitmap_size); | ||||||
|         bdrv_pwrite(s->hd, bitmap_offset, bitmap, s->bitmap_size); |         bdrv_pwrite_sync(s->hd, bitmap_offset, bitmap, s->bitmap_size); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| //    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n", | //    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n", | ||||||
| @@ -316,7 +316,7 @@ static int rewrite_footer(BlockDriverState* bs) | |||||||
|     BDRVVPCState *s = bs->opaque; |     BDRVVPCState *s = bs->opaque; | ||||||
|     int64_t offset = s->free_data_block_offset; |     int64_t offset = s->free_data_block_offset; | ||||||
|  |  | ||||||
|     ret = bdrv_pwrite(s->hd, offset, s->footer_buf, HEADER_SIZE); |     ret = bdrv_pwrite_sync(s->hd, offset, s->footer_buf, HEADER_SIZE); | ||||||
|     if (ret < 0) |     if (ret < 0) | ||||||
|         return ret; |         return ret; | ||||||
|  |  | ||||||
| @@ -351,7 +351,8 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num) | |||||||
|  |  | ||||||
|     // Initialize the block's bitmap |     // Initialize the block's bitmap | ||||||
|     memset(bitmap, 0xff, s->bitmap_size); |     memset(bitmap, 0xff, s->bitmap_size); | ||||||
|     bdrv_pwrite(s->hd, s->free_data_block_offset, bitmap, s->bitmap_size); |     bdrv_pwrite_sync(s->hd, s->free_data_block_offset, bitmap, | ||||||
|  |         s->bitmap_size); | ||||||
|  |  | ||||||
|     // Write new footer (the old one will be overwritten) |     // Write new footer (the old one will be overwritten) | ||||||
|     s->free_data_block_offset += s->block_size + s->bitmap_size; |     s->free_data_block_offset += s->block_size + s->bitmap_size; | ||||||
| @@ -362,7 +363,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num) | |||||||
|     // Write BAT entry to disk |     // Write BAT entry to disk | ||||||
|     bat_offset = s->bat_offset + (4 * index); |     bat_offset = s->bat_offset + (4 * index); | ||||||
|     bat_value = be32_to_cpu(s->pagetable[index]); |     bat_value = be32_to_cpu(s->pagetable[index]); | ||||||
|     ret = bdrv_pwrite(s->hd, bat_offset, &bat_value, 4); |     ret = bdrv_pwrite_sync(s->hd, bat_offset, &bat_value, 4); | ||||||
|     if (ret < 0) |     if (ret < 0) | ||||||
|         goto fail; |         goto fail; | ||||||
|  |  | ||||||
| @@ -470,9 +471,7 @@ static int calculate_geometry(int64_t total_sectors, uint16_t* cyls, | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Note: Rounding up deviates from the Virtual PC behaviour |     *cyls = cyls_times_heads / *heads; | ||||||
|     // However, we need this to avoid truncating images in qemu-img convert |  | ||||||
|     *cyls = (cyls_times_heads + *heads - 1) / *heads; |  | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| @@ -484,9 +483,9 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options) | |||||||
|     struct vhd_dyndisk_header* dyndisk_header = |     struct vhd_dyndisk_header* dyndisk_header = | ||||||
|         (struct vhd_dyndisk_header*) buf; |         (struct vhd_dyndisk_header*) buf; | ||||||
|     int fd, i; |     int fd, i; | ||||||
|     uint16_t cyls; |     uint16_t cyls = 0; | ||||||
|     uint8_t heads; |     uint8_t heads = 0; | ||||||
|     uint8_t secs_per_cyl; |     uint8_t secs_per_cyl = 0; | ||||||
|     size_t block_size, num_bat_entries; |     size_t block_size, num_bat_entries; | ||||||
|     int64_t total_sectors = 0; |     int64_t total_sectors = 0; | ||||||
|  |  | ||||||
| @@ -503,9 +502,14 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options) | |||||||
|     if (fd < 0) |     if (fd < 0) | ||||||
|         return -EIO; |         return -EIO; | ||||||
|  |  | ||||||
|     // Calculate matching total_size and geometry |     /* Calculate matching total_size and geometry. Increase the number of | ||||||
|     if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl)) |        sectors requested until we get enough (or fail). */ | ||||||
|         return -EFBIG; |     for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) { | ||||||
|  |         if (calculate_geometry(total_sectors + i, | ||||||
|  |                                &cyls, &heads, &secs_per_cyl)) { | ||||||
|  |             return -EFBIG; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     total_sectors = (int64_t) cyls * heads * secs_per_cyl; |     total_sectors = (int64_t) cyls * heads * secs_per_cyl; | ||||||
|  |  | ||||||
|     // Prepare the Hard Disk Footer |     // Prepare the Hard Disk Footer | ||||||
|   | |||||||
| @@ -868,7 +868,8 @@ static int init_directories(BDRVVVFATState* s, | |||||||
|     { |     { | ||||||
| 	direntry_t* entry=array_get_next(&(s->directory)); | 	direntry_t* entry=array_get_next(&(s->directory)); | ||||||
| 	entry->attributes=0x28; /* archive | volume label */ | 	entry->attributes=0x28; /* archive | volume label */ | ||||||
| 	snprintf((char*)entry->name,11,"QEMU VVFAT"); | 	memcpy(entry->name,"QEMU VVF",8); | ||||||
|  | 	memcpy(entry->extension,"AT ",3); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* Now build FAT, and write back information into directory */ |     /* Now build FAT, and write back information into directory */ | ||||||
| @@ -882,7 +883,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 +1633,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 +1753,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 { | ||||||
| @@ -2256,7 +2257,11 @@ static int commit_one_file(BDRVVVFATState* s, | |||||||
| 	c = c1; | 	c = c1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ftruncate(fd, size); |     if (ftruncate(fd, size)) { | ||||||
|  |         perror("ftruncate()"); | ||||||
|  |         close(fd); | ||||||
|  |         return -4; | ||||||
|  |     } | ||||||
|     close(fd); |     close(fd); | ||||||
|  |  | ||||||
|     return commit_mappings(s, first_cluster, dir_index); |     return commit_mappings(s, first_cluster, dir_index); | ||||||
|   | |||||||
| @@ -127,6 +127,7 @@ struct BlockDriverState { | |||||||
|     int64_t total_sectors; /* if we are reading a disk image, give its |     int64_t total_sectors; /* if we are reading a disk image, give its | ||||||
|                               size in sectors */ |                               size in sectors */ | ||||||
|     int read_only; /* if true, the media is read only */ |     int read_only; /* if true, the media is read only */ | ||||||
|  |     int open_flags; /* flags used to open the file, re-used for re-open */ | ||||||
|     int removable; /* if true, the media can be removed */ |     int removable; /* if true, the media can be removed */ | ||||||
|     int locked;    /* if true, the media cannot temporarily be ejected */ |     int locked;    /* if true, the media cannot temporarily be ejected */ | ||||||
|     int encrypted; /* if true, the media is encrypted */ |     int encrypted; /* if true, the media is encrypted */ | ||||||
|   | |||||||
| @@ -34,7 +34,28 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop) | |||||||
|     asm volatile ("isync" : : : "memory"); |     asm volatile ("isync" : : : "memory"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Is this correct for PPC? | ||||||
|  |  */ | ||||||
|  | static inline void dma_flush_range(unsigned long start, unsigned long stop) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #elif defined(__ia64__) | ||||||
|  | static inline void flush_icache_range(unsigned long start, unsigned long stop) | ||||||
|  | { | ||||||
|  |     while (start < stop) { | ||||||
|  | 	asm volatile ("fc %0" :: "r"(start)); | ||||||
|  | 	start += 32; | ||||||
|  |     } | ||||||
|  |     asm volatile (";;sync.i;;srlz.i;;"); | ||||||
|  | } | ||||||
|  | #define dma_flush_range(start, end) flush_icache_range(start, end) | ||||||
|  | #define qemu_cache_utils_init(envp) do { (void) (envp); } while (0) | ||||||
| #else | #else | ||||||
|  | static inline void dma_flush_range(unsigned long start, unsigned long stop) | ||||||
|  | { | ||||||
|  | } | ||||||
| #define qemu_cache_utils_init(envp) do { (void) (envp); } while (0) | #define qemu_cache_utils_init(envp) do { (void) (envp); } while (0) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								compat/sys/eventfd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								compat/sys/eventfd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | #ifndef _COMPAT_SYS_EVENTFD | ||||||
|  | #define _COMPAT_SYS_EVENTFD | ||||||
|  |  | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <syscall.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static inline int eventfd (int count, int flags) | ||||||
|  | { | ||||||
|  |     return syscall(SYS_eventfd, count, flags); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										143
									
								
								compatfd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								compatfd.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | |||||||
|  | /* | ||||||
|  |  * signalfd/eventfd compatibility | ||||||
|  |  * | ||||||
|  |  * Copyright IBM, Corp. 2008 | ||||||
|  |  * | ||||||
|  |  * Authors: | ||||||
|  |  *  Anthony Liguori   <aliguori@us.ibm.com> | ||||||
|  |  * | ||||||
|  |  * This work is licensed under the terms of the GNU GPL, version 2.  See | ||||||
|  |  * the COPYING file in the top-level directory. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "qemu-common.h" | ||||||
|  | #include "compatfd.h" | ||||||
|  |  | ||||||
|  | #include <sys/syscall.h> | ||||||
|  | #include <pthread.h> | ||||||
|  |  | ||||||
|  | struct sigfd_compat_info | ||||||
|  | { | ||||||
|  |     sigset_t mask; | ||||||
|  |     int fd; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void *sigwait_compat(void *opaque) | ||||||
|  | { | ||||||
|  |     struct sigfd_compat_info *info = opaque; | ||||||
|  |     int err; | ||||||
|  |     sigset_t all; | ||||||
|  |  | ||||||
|  |     sigfillset(&all); | ||||||
|  |     sigprocmask(SIG_BLOCK, &all, NULL); | ||||||
|  |  | ||||||
|  |     do { | ||||||
|  |         siginfo_t siginfo; | ||||||
|  |  | ||||||
|  |         err = sigwaitinfo(&info->mask, &siginfo); | ||||||
|  |         if (err == -1 && errno == EINTR) { | ||||||
|  |             err = 0; | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (err > 0) { | ||||||
|  |             char buffer[128]; | ||||||
|  |             size_t offset = 0; | ||||||
|  |  | ||||||
|  |             memcpy(buffer, &err, sizeof(err)); | ||||||
|  |             while (offset < sizeof(buffer)) { | ||||||
|  |                 ssize_t len; | ||||||
|  |  | ||||||
|  |                 len = write(info->fd, buffer + offset, | ||||||
|  |                             sizeof(buffer) - offset); | ||||||
|  |                 if (len == -1 && errno == EINTR) | ||||||
|  |                     continue; | ||||||
|  |  | ||||||
|  |                 if (len <= 0) { | ||||||
|  |                     err = -1; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 offset += len; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } while (err >= 0); | ||||||
|  |  | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int qemu_signalfd_compat(const sigset_t *mask) | ||||||
|  | { | ||||||
|  |     pthread_attr_t attr; | ||||||
|  |     pthread_t tid; | ||||||
|  |     struct sigfd_compat_info *info; | ||||||
|  |     int fds[2]; | ||||||
|  |  | ||||||
|  |     info = malloc(sizeof(*info)); | ||||||
|  |     if (info == NULL) { | ||||||
|  |         errno = ENOMEM; | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (pipe(fds) == -1) { | ||||||
|  |         free(info); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     qemu_set_cloexec(fds[0]); | ||||||
|  |     qemu_set_cloexec(fds[1]); | ||||||
|  |  | ||||||
|  |     memcpy(&info->mask, mask, sizeof(*mask)); | ||||||
|  |     info->fd = fds[1]; | ||||||
|  |  | ||||||
|  |     pthread_attr_init(&attr); | ||||||
|  |     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | ||||||
|  |  | ||||||
|  |     pthread_create(&tid, &attr, sigwait_compat, info); | ||||||
|  |  | ||||||
|  |     pthread_attr_destroy(&attr); | ||||||
|  |  | ||||||
|  |     return fds[0]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int qemu_signalfd(const sigset_t *mask) | ||||||
|  | { | ||||||
|  | #if defined(CONFIG_SIGNALFD) | ||||||
|  |     int ret; | ||||||
|  |  | ||||||
|  |     ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8); | ||||||
|  |     if (ret != -1) { | ||||||
|  |         qemu_set_cloexec(ret); | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     return qemu_signalfd_compat(mask); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int qemu_eventfd(int *fds) | ||||||
|  | { | ||||||
|  |     int ret; | ||||||
|  |  | ||||||
|  | #if defined(CONFIG_EVENTFD) | ||||||
|  |     ret = syscall(SYS_eventfd, 0); | ||||||
|  |     if (ret >= 0) { | ||||||
|  |         fds[0] = ret; | ||||||
|  |         qemu_set_cloexec(ret); | ||||||
|  |         if ((fds[1] = dup(ret)) == -1) { | ||||||
|  |             close(ret); | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |         qemu_set_cloexec(fds[1]); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     ret = pipe(fds); | ||||||
|  |     if (ret != -1) { | ||||||
|  |         qemu_set_cloexec(fds[0]); | ||||||
|  |         qemu_set_cloexec(fds[1]); | ||||||
|  |     } | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								compatfd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								compatfd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | /* | ||||||
|  |  * signalfd/eventfd compatibility | ||||||
|  |  * | ||||||
|  |  * Copyright IBM, Corp. 2008 | ||||||
|  |  * | ||||||
|  |  * Authors: | ||||||
|  |  *  Anthony Liguori   <aliguori@us.ibm.com> | ||||||
|  |  * | ||||||
|  |  * This work is licensed under the terms of the GNU GPL, version 2.  See | ||||||
|  |  * the COPYING file in the top-level directory. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef QEMU_COMPATFD_H | ||||||
|  | #define QEMU_COMPATFD_H | ||||||
|  |  | ||||||
|  | #include <signal.h> | ||||||
|  |  | ||||||
|  | struct qemu_signalfd_siginfo { | ||||||
|  |     uint32_t ssi_signo;   /* Signal number */ | ||||||
|  |     int32_t  ssi_errno;   /* Error number (unused) */ | ||||||
|  |     int32_t  ssi_code;    /* Signal code */ | ||||||
|  |     uint32_t ssi_pid;     /* PID of sender */ | ||||||
|  |     uint32_t ssi_uid;     /* Real UID of sender */ | ||||||
|  |     int32_t  ssi_fd;      /* File descriptor (SIGIO) */ | ||||||
|  |     uint32_t ssi_tid;     /* Kernel timer ID (POSIX timers) */ | ||||||
|  |     uint32_t ssi_band;    /* Band event (SIGIO) */ | ||||||
|  |     uint32_t ssi_overrun; /* POSIX timer overrun count */ | ||||||
|  |     uint32_t ssi_trapno;  /* Trap number that caused signal */ | ||||||
|  |     int32_t  ssi_status;  /* Exit status or signal (SIGCHLD) */ | ||||||
|  |     int32_t  ssi_int;     /* Integer sent by sigqueue(2) */ | ||||||
|  |     uint64_t ssi_ptr;     /* Pointer sent by sigqueue(2) */ | ||||||
|  |     uint64_t ssi_utime;   /* User CPU time consumed (SIGCHLD) */ | ||||||
|  |     uint64_t ssi_stime;   /* System CPU time consumed (SIGCHLD) */ | ||||||
|  |     uint64_t ssi_addr;    /* Address that generated signal | ||||||
|  |                              (for hardware-generated signals) */ | ||||||
|  |     uint8_t  pad[48];     /* Pad size to 128 bytes (allow for | ||||||
|  |                              additional fields in the future) */ | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | int qemu_signalfd(const sigset_t *mask); | ||||||
|  |  | ||||||
|  | int qemu_eventfd(int *fds); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										204
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										204
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -160,7 +160,7 @@ else | |||||||
|   cpu=`uname -m` |   cpu=`uname -m` | ||||||
| fi | fi | ||||||
|  |  | ||||||
| target_list="" | target_list="x86_64-softmmu" | ||||||
| case "$cpu" in | case "$cpu" in | ||||||
|   alpha|cris|ia64|m68k|microblaze|ppc|ppc64|sparc64) |   alpha|cris|ia64|m68k|microblaze|ppc|ppc64|sparc64) | ||||||
|     cpu="$cpu" |     cpu="$cpu" | ||||||
| @@ -197,6 +197,16 @@ case "$cpu" in | |||||||
|   ;; |   ;; | ||||||
| esac | esac | ||||||
|  |  | ||||||
|  | kvm_version() { | ||||||
|  |     local fname="$(dirname "$0")/KVM_VERSION" | ||||||
|  |  | ||||||
|  |     if test -f "$fname"; then | ||||||
|  |         cat "$fname" | ||||||
|  |     else | ||||||
|  |         echo "qemu-kvm-devel" | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  |  | ||||||
| # Default value for a variable defining feature "foo". | # Default value for a variable defining feature "foo". | ||||||
| #  * foo="no"  feature will only be used if --enable-foo arg is given | #  * foo="no"  feature will only be used if --enable-foo arg is given | ||||||
| #  * foo=""    feature will be searched for, and if found, will be used | #  * foo=""    feature will be searched for, and if found, will be used | ||||||
| @@ -250,12 +260,18 @@ guest_base="" | |||||||
| uname_release="" | uname_release="" | ||||||
| io_thread="no" | io_thread="no" | ||||||
| mixemu="no" | mixemu="no" | ||||||
|  | kvm_trace="no" | ||||||
|  | kvm_cap_pit="" | ||||||
|  | kvm_cap_device_assignment="" | ||||||
| kerneldir="" | kerneldir="" | ||||||
| aix="no" | aix="no" | ||||||
| blobs="yes" | blobs="yes" | ||||||
| pkgversion="" | pkgversion=" ($(kvm_version))" | ||||||
|  | cpu_emulation="yes" | ||||||
|  | kvm_kmod="no" | ||||||
| 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 | ||||||
| @@ -388,6 +404,13 @@ AIX) | |||||||
|   if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then |   if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then | ||||||
|     audio_possible_drivers="$audio_possible_drivers fmod" |     audio_possible_drivers="$audio_possible_drivers fmod" | ||||||
|   fi |   fi | ||||||
|  |   if [ "$cpu" = "ia64" ] ; then | ||||||
|  |      xen="no" | ||||||
|  |      target_list="ia64-softmmu" | ||||||
|  |      cpu_emulation="no" | ||||||
|  |      gdbstub="no" | ||||||
|  |      slirp="no" | ||||||
|  |   fi | ||||||
| ;; | ;; | ||||||
| esac | esac | ||||||
|  |  | ||||||
| @@ -517,6 +540,14 @@ for opt do | |||||||
|   ;; |   ;; | ||||||
|   --enable-kvm) kvm="yes" |   --enable-kvm) kvm="yes" | ||||||
|   ;; |   ;; | ||||||
|  |   --disable-kvm-cap-pit) kvm_cap_pit="no" | ||||||
|  |   ;; | ||||||
|  |   --enable-kvm-cap-pit) kvm_cap_pit="yes" | ||||||
|  |   ;; | ||||||
|  |   --disable-kvm-cap-device-assignment) kvm_cap_device_assignment="no" | ||||||
|  |   ;; | ||||||
|  |   --enable-kvm-cap-device-assignment) kvm_cap_device_assignment="yes" | ||||||
|  |   ;; | ||||||
|   --enable-profiler) profiler="yes" |   --enable-profiler) profiler="yes" | ||||||
|   ;; |   ;; | ||||||
|   --enable-cocoa) |   --enable-cocoa) | ||||||
| @@ -594,12 +625,16 @@ for opt do | |||||||
|   ;; |   ;; | ||||||
|   --kerneldir=*) kerneldir="$optarg" |   --kerneldir=*) kerneldir="$optarg" | ||||||
|   ;; |   ;; | ||||||
|  |   --with-kvm-trace) kvm_trace="yes" | ||||||
|  |   ;; | ||||||
|   --with-pkgversion=*) pkgversion=" ($optarg)" |   --with-pkgversion=*) pkgversion=" ($optarg)" | ||||||
|   ;; |   ;; | ||||||
|   --disable-docs) docs="no" |   --disable-docs) docs="no" | ||||||
|   ;; |   ;; | ||||||
|   --enable-docs) docs="yes" |   --enable-docs) docs="yes" | ||||||
|   ;; |   ;; | ||||||
|  |   --disable-cpu-emulation) cpu_emulation="no" | ||||||
|  |   ;; | ||||||
|   *) echo "ERROR: unknown option $opt"; show_help="yes" |   *) echo "ERROR: unknown option $opt"; show_help="yes" | ||||||
|   ;; |   ;; | ||||||
|   esac |   esac | ||||||
| @@ -721,6 +756,10 @@ echo "  --disable-bluez          disable bluez stack connectivity" | |||||||
| echo "  --enable-bluez           enable bluez stack connectivity" | echo "  --enable-bluez           enable bluez stack connectivity" | ||||||
| echo "  --disable-kvm            disable KVM acceleration support" | echo "  --disable-kvm            disable KVM acceleration support" | ||||||
| echo "  --enable-kvm             enable KVM acceleration support" | echo "  --enable-kvm             enable KVM acceleration support" | ||||||
|  | echo "  --disable-cap-kvm-pit    disable KVM pit support" | ||||||
|  | echo "  --enable-cap-kvm-pit     enable KVM pit support" | ||||||
|  | echo "  --disable-cap-device-assignment    disable KVM device assignment support" | ||||||
|  | echo "  --enable-cap-device-assignment     enable KVM device assignment support" | ||||||
| echo "  --disable-nptl           disable usermode NPTL support" | echo "  --disable-nptl           disable usermode NPTL support" | ||||||
| echo "  --enable-nptl            enable usermode NPTL support" | echo "  --enable-nptl            enable usermode NPTL support" | ||||||
| echo "  --enable-system          enable all system emulation targets" | echo "  --enable-system          enable all system emulation targets" | ||||||
| @@ -752,6 +791,8 @@ echo "  --enable-linux-aio       enable Linux AIO support" | |||||||
| echo "  --enable-io-thread       enable IO thread" | echo "  --enable-io-thread       enable IO thread" | ||||||
| echo "  --disable-blobs          disable installing provided firmware blobs" | echo "  --disable-blobs          disable installing provided firmware blobs" | ||||||
| echo "  --kerneldir=PATH         look for kernel includes in PATH" | echo "  --kerneldir=PATH         look for kernel includes in PATH" | ||||||
|  | echo "  --with-kvm-trace         enable building the KVM module with the kvm trace option" | ||||||
|  | echo "  --disable-cpu-emulation  disables use of qemu cpu emulation code" | ||||||
| echo "" | echo "" | ||||||
| echo "NOTE: The object files are built at the place where configure is launched" | echo "NOTE: The object files are built at the place where configure is launched" | ||||||
| exit 1 | exit 1 | ||||||
| @@ -1383,8 +1424,22 @@ EOF | |||||||
|             kvm_cflags="$kvm_cflags -I$kerneldir/arch/$cpu/include" |             kvm_cflags="$kvm_cflags -I$kerneldir/arch/$cpu/include" | ||||||
|       fi |       fi | ||||||
|   else |   else | ||||||
|       kvm_cflags="" |       case "$cpu" in | ||||||
|  |       i386 | x86_64) | ||||||
|  |         kvm_arch="x86" | ||||||
|  |         ;; | ||||||
|  |       ppc) | ||||||
|  |         kvm_arch="powerpc" | ||||||
|  |         ;; | ||||||
|  |       *) | ||||||
|  |         kvm_arch="$cpu" | ||||||
|  |         ;; | ||||||
|  |       esac | ||||||
|  |       kvm_cflags="-I$source_path/kvm/include" | ||||||
|  |       kvm_cflags="$kvm_cflags -include $source_path/kvm/include/linux/config.h" | ||||||
|  |       kvm_cflags="$kvm_cflags -I$source_path/kvm/include/$kvm_arch" | ||||||
|   fi |   fi | ||||||
|  |   kvm_cflags="$kvm_cflags -idirafter $source_path/compat" | ||||||
|   if compile_prog "$kvm_cflags" "" ; then |   if compile_prog "$kvm_cflags" "" ; then | ||||||
|     kvm=yes |     kvm=yes | ||||||
|   else |   else | ||||||
| @@ -1406,6 +1461,75 @@ EOF | |||||||
|   fi |   fi | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  | ########################################## | ||||||
|  | # test for KVM_CAP_PIT | ||||||
|  |  | ||||||
|  | if test "$kvm_cap_pit" != "no" ; then | ||||||
|  |   if test "$kvm" = "no" -a "$kvm_cap_pit" = "yes" ; then | ||||||
|  |       feature_not_found "kvm_cap_pit (kvm is not enabled)" | ||||||
|  |   fi | ||||||
|  |   cat > $TMPC <<EOF | ||||||
|  | #include <linux/kvm.h> | ||||||
|  | #ifndef KVM_CAP_PIT | ||||||
|  | #error "kvm no pit capability" | ||||||
|  | #endif | ||||||
|  | int main(void) { return 0; } | ||||||
|  | EOF | ||||||
|  |   if compile_prog "$kvm_cflags" ""; then | ||||||
|  |     kvm_cap_pit=yes | ||||||
|  |   else | ||||||
|  |     if test "$kvm_cap_pit" = "yes" ; then | ||||||
|  |       feature_not_found "kvm_cap_pit" | ||||||
|  |     fi | ||||||
|  |     kvm_cap_pit=no | ||||||
|  |   fi | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | ########################################## | ||||||
|  | # test for KVM_CAP_DEVICE_ASSIGNMENT | ||||||
|  |  | ||||||
|  | if test "$kvm_cap_device_assignment" != "no" ; then | ||||||
|  |   if test "$kvm" = "no" -a "$kvm_cap_device_assignment" = "yes" ; then | ||||||
|  |       feature_not_found "kvm_cap_device_assignment (kvm is not enabled)" | ||||||
|  |   fi | ||||||
|  |   cat > $TMPC <<EOF | ||||||
|  | #include <linux/kvm.h> | ||||||
|  | #ifndef KVM_CAP_DEVICE_ASSIGNMENT | ||||||
|  | #error "kvm no device assignment capability" | ||||||
|  | #endif | ||||||
|  | int main(void) { return 0; } | ||||||
|  | EOF | ||||||
|  |   if compile_prog "$kvm_cflags" "" ; then | ||||||
|  |     kvm_cap_device_assignment=yes | ||||||
|  |   else | ||||||
|  |     if test "$kvm_cap_device_assignment" = "yes" ; then | ||||||
|  |       feature_not_found "kvm_cap_device_assigment" | ||||||
|  |     fi | ||||||
|  |     kvm_cap_device_assignment=no | ||||||
|  |   fi | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | ########################################## | ||||||
|  | # libpci probe for kvm_cap_device_assignment | ||||||
|  | if test $kvm_cap_device_assignment = "yes" ; then | ||||||
|  |   cat > $TMPC << EOF | ||||||
|  | #include <pci/pci.h> | ||||||
|  | #ifndef PCI_VENDOR_ID | ||||||
|  | #error NO LIBPCI | ||||||
|  | #endif | ||||||
|  | int main(void) { struct pci_access a; pci_init(&a); return 0; } | ||||||
|  | EOF | ||||||
|  |   if compile_prog "" "-lpci -lz" ; then | ||||||
|  |     libs_softmmu="-lpci -lz $libs_softmmu" | ||||||
|  |   else | ||||||
|  |     echo | ||||||
|  |     echo "Error: libpci check failed" | ||||||
|  |     echo "Disable KVM Device Assignment capability." | ||||||
|  |     echo | ||||||
|  |     kvm_cap_device_assignment=no | ||||||
|  |   fi | ||||||
|  | fi | ||||||
|  |  | ||||||
| ########################################## | ########################################## | ||||||
| # pthread probe | # pthread probe | ||||||
| PTHREADLIBS_LIST="-lpthread -lpthreadGC2" | PTHREADLIBS_LIST="-lpthread -lpthreadGC2" | ||||||
| @@ -1612,6 +1736,21 @@ if compile_prog "" "" ; then | |||||||
|   splice=yes |   splice=yes | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  | ########################################## | ||||||
|  | # signalfd probe | ||||||
|  | signalfd="no" | ||||||
|  | cat > $TMPC << EOF | ||||||
|  | #define _GNU_SOURCE | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <sys/syscall.h> | ||||||
|  | #include <signal.h> | ||||||
|  | int main(void) { return syscall(SYS_signalfd, -1, NULL, _NSIG / 8); } | ||||||
|  | EOF | ||||||
|  |  | ||||||
|  | if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then | ||||||
|  |   signalfd=yes | ||||||
|  | fi | ||||||
|  |  | ||||||
| # check if eventfd is supported | # check if eventfd is supported | ||||||
| eventfd=no | eventfd=no | ||||||
| cat > $TMPC << EOF | cat > $TMPC << EOF | ||||||
| @@ -1792,8 +1931,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 +1942,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 | ||||||
| @@ -1830,6 +1980,20 @@ else | |||||||
|   binsuffix="/bin" |   binsuffix="/bin" | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  | if test -f kvm/kernel/configure; then | ||||||
|  |     kvm_kmod="yes" | ||||||
|  |     kmod_args="" | ||||||
|  |     if test -n "$kerneldir"; then | ||||||
|  |         kmod_args="--kerneldir=$kerneldir" | ||||||
|  |     fi | ||||||
|  |     if test "$kvm_trace" = "yes"; then | ||||||
|  |         kmod_args="$kmod_args --with-kvm-trace" | ||||||
|  |     fi | ||||||
|  |     # hope there are no spaces in kmod_args; can't use arrays because of | ||||||
|  |     # dash. | ||||||
|  |     (cd kvm/kernel; ./configure $kmod_args) | ||||||
|  | fi | ||||||
|  |  | ||||||
| echo "Install prefix    $prefix" | echo "Install prefix    $prefix" | ||||||
| echo "BIOS directory    $prefix$datasuffix" | echo "BIOS directory    $prefix$datasuffix" | ||||||
| echo "binary directory  $prefix$binsuffix" | echo "binary directory  $prefix$binsuffix" | ||||||
| @@ -1873,6 +2037,7 @@ if test -n "$sparc_cpu"; then | |||||||
|     echo "Target Sparc Arch $sparc_cpu" |     echo "Target Sparc Arch $sparc_cpu" | ||||||
| fi | fi | ||||||
| echo "xen support       $xen" | echo "xen support       $xen" | ||||||
|  | echo "CPU emulation     $cpu_emulation" | ||||||
| echo "brlapi support    $brlapi" | echo "brlapi support    $brlapi" | ||||||
| echo "bluez  support    $bluez" | echo "bluez  support    $bluez" | ||||||
| echo "Documentation     $docs" | echo "Documentation     $docs" | ||||||
| @@ -1886,6 +2051,9 @@ echo "IO thread         $io_thread" | |||||||
| echo "Linux AIO support $linux_aio" | echo "Linux AIO support $linux_aio" | ||||||
| echo "Install blobs     $blobs" | echo "Install blobs     $blobs" | ||||||
| echo "KVM support       $kvm" | echo "KVM support       $kvm" | ||||||
|  | echo "KVM PIT support   $kvm_cap_pit" | ||||||
|  | echo "KVM device assig. $kvm_cap_device_assignment" | ||||||
|  | echo "KVM trace support $kvm_trace" | ||||||
| echo "fdt support       $fdt" | echo "fdt support       $fdt" | ||||||
| echo "preadv support    $preadv" | echo "preadv support    $preadv" | ||||||
| echo "fdatasync         $fdatasync" | echo "fdatasync         $fdatasync" | ||||||
| @@ -2092,6 +2260,9 @@ fi | |||||||
| if test "$fdt" = "yes" ; then | if test "$fdt" = "yes" ; then | ||||||
|   echo "CONFIG_FDT=y" >> $config_host_mak |   echo "CONFIG_FDT=y" >> $config_host_mak | ||||||
| fi | fi | ||||||
|  | if test "$signalfd" = "yes" ; then | ||||||
|  |   echo "CONFIG_SIGNALFD=y" >> $config_host_mak | ||||||
|  | fi | ||||||
| if test "$need_offsetof" = "yes" ; then | if test "$need_offsetof" = "yes" ; then | ||||||
|   echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak |   echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak | ||||||
| fi | fi | ||||||
| @@ -2101,6 +2272,11 @@ fi | |||||||
| if test "$fdatasync" = "yes" ; then | if test "$fdatasync" = "yes" ; then | ||||||
|   echo "CONFIG_FDATASYNC=y" >> $config_host_mak |   echo "CONFIG_FDATASYNC=y" >> $config_host_mak | ||||||
| fi | fi | ||||||
|  | if test $cpu_emulation = "yes"; then | ||||||
|  |   echo "CONFIG_CPU_EMULATION=y" >> $config_host_mak | ||||||
|  | else | ||||||
|  |   echo "CONFIG_NO_CPU_EMULATION=y" >> $config_host_mak | ||||||
|  | fi | ||||||
|  |  | ||||||
| # XXX: suppress that | # XXX: suppress that | ||||||
| if [ "$bsd" = "yes" ] ; then | if [ "$bsd" = "yes" ] ; then | ||||||
| @@ -2109,6 +2285,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) | ||||||
| @@ -2122,6 +2302,8 @@ bsd) | |||||||
| ;; | ;; | ||||||
| esac | esac | ||||||
|  |  | ||||||
|  | echo "KVM_KMOD=$kvm_kmod" >> $config_host_mak | ||||||
|  |  | ||||||
| tools= | tools= | ||||||
| if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then | if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then | ||||||
|   tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools" |   tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools" | ||||||
| @@ -2272,6 +2454,9 @@ case "$target_arch2" in | |||||||
|     TARGET_BASE_ARCH=i386 |     TARGET_BASE_ARCH=i386 | ||||||
|     target_phys_bits=64 |     target_phys_bits=64 | ||||||
|   ;; |   ;; | ||||||
|  |   ia64) | ||||||
|  |     target_phys_bits=64 | ||||||
|  |   ;; | ||||||
|   alpha) |   alpha) | ||||||
|     target_phys_bits=64 |     target_phys_bits=64 | ||||||
|   ;; |   ;; | ||||||
| @@ -2402,6 +2587,12 @@ case "$target_arch2" in | |||||||
|       \( "$target_arch2" = "i386"   -a "$cpu" = "x86_64" \) \) ; then |       \( "$target_arch2" = "i386"   -a "$cpu" = "x86_64" \) \) ; then | ||||||
|       echo "CONFIG_KVM=y" >> $config_target_mak |       echo "CONFIG_KVM=y" >> $config_target_mak | ||||||
|       echo "KVM_CFLAGS=$kvm_cflags" >> $config_target_mak |       echo "KVM_CFLAGS=$kvm_cflags" >> $config_target_mak | ||||||
|  |       if test $kvm_cap_pit = "yes" ; then | ||||||
|  |         echo "CONFIG_KVM_PIT=y" >> $config_target_mak | ||||||
|  |       fi | ||||||
|  |       if test $kvm_cap_device_assignment = "yes" ; then | ||||||
|  |         echo "CONFIG_KVM_DEVICE_ASSIGNMENT=y" >> $config_target_mak | ||||||
|  |       fi | ||||||
|     fi |     fi | ||||||
| esac | esac | ||||||
| echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak | echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak | ||||||
| @@ -2610,7 +2801,7 @@ if test "$source_path_used" = "yes" ; then | |||||||
| fi | fi | ||||||
|  |  | ||||||
| # temporary config to build submodules | # temporary config to build submodules | ||||||
| for rom in seabios vgabios ; do | for rom in seabios vgabios; do | ||||||
|     config_mak=roms/$rom/config.mak |     config_mak=roms/$rom/config.mak | ||||||
|     echo "# Automatically generated by configure - do not modify" >> $config_mak |     echo "# Automatically generated by configure - do not modify" >> $config_mak | ||||||
|     echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak |     echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak | ||||||
| @@ -2636,3 +2827,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 */ | ||||||
|   | |||||||
| @@ -849,6 +849,7 @@ extern int phys_ram_fd; | |||||||
| extern uint8_t *phys_ram_dirty; | extern uint8_t *phys_ram_dirty; | ||||||
| extern ram_addr_t ram_size; | extern ram_addr_t ram_size; | ||||||
| extern ram_addr_t last_ram_offset; | extern ram_addr_t last_ram_offset; | ||||||
|  | extern uint8_t *bios_mem; | ||||||
|  |  | ||||||
| /* physical memory access */ | /* physical memory access */ | ||||||
|  |  | ||||||
| @@ -1017,7 +1018,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 | ||||||
|   | |||||||
| @@ -34,6 +34,7 @@ void qemu_ram_free(ram_addr_t addr); | |||||||
| /* This should only be used for ram local to a device.  */ | /* This should only be used for ram local to a device.  */ | ||||||
| void *qemu_get_ram_ptr(ram_addr_t addr); | void *qemu_get_ram_ptr(ram_addr_t addr); | ||||||
| /* This should not be used by devices.  */ | /* This should not be used by devices.  */ | ||||||
|  | int do_qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr); | ||||||
| ram_addr_t qemu_ram_addr_from_host(void *ptr); | ram_addr_t qemu_ram_addr_from_host(void *ptr); | ||||||
|  |  | ||||||
| int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read, | int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read, | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								cpu-defs.h
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								cpu-defs.h
									
									
									
									
									
								
							| @@ -27,6 +27,7 @@ | |||||||
| #include <setjmp.h> | #include <setjmp.h> | ||||||
| #include <inttypes.h> | #include <inttypes.h> | ||||||
| #include <signal.h> | #include <signal.h> | ||||||
|  | #include <pthread.h> | ||||||
| #include "osdep.h" | #include "osdep.h" | ||||||
| #include "qemu-queue.h" | #include "qemu-queue.h" | ||||||
| #include "targphys.h" | #include "targphys.h" | ||||||
| @@ -134,6 +135,16 @@ typedef struct CPUWatchpoint { | |||||||
|     QTAILQ_ENTRY(CPUWatchpoint) entry; |     QTAILQ_ENTRY(CPUWatchpoint) entry; | ||||||
| } CPUWatchpoint; | } CPUWatchpoint; | ||||||
|  |  | ||||||
|  | /* forward decleration */ | ||||||
|  | struct qemu_work_item; | ||||||
|  |  | ||||||
|  | struct KVMCPUState { | ||||||
|  |     pthread_t thread; | ||||||
|  |     int signalled; | ||||||
|  |     struct qemu_work_item *queued_work_first, *queued_work_last; | ||||||
|  |     int regs_modified; | ||||||
|  | }; | ||||||
|  |  | ||||||
| #define CPU_TEMP_BUF_NLONGS 128 | #define CPU_TEMP_BUF_NLONGS 128 | ||||||
| #define CPU_COMMON                                                      \ | #define CPU_COMMON                                                      \ | ||||||
|     struct TranslationBlock *current_tb; /* currently executing TB  */  \ |     struct TranslationBlock *current_tb; /* currently executing TB  */  \ | ||||||
| @@ -146,8 +157,6 @@ typedef struct CPUWatchpoint { | |||||||
|     target_ulong mem_io_vaddr; /* target virtual addr at which the      \ |     target_ulong mem_io_vaddr; /* target virtual addr at which the      \ | ||||||
|                                      memory was accessed */             \ |                                      memory was accessed */             \ | ||||||
|     uint32_t halted; /* Nonzero if the CPU is in suspend state */       \ |     uint32_t halted; /* Nonzero if the CPU is in suspend state */       \ | ||||||
|     uint32_t stop;   /* Stop request */                                 \ |  | ||||||
|     uint32_t stopped; /* Artificially stopped */                        \ |  | ||||||
|     uint32_t interrupt_request;                                         \ |     uint32_t interrupt_request;                                         \ | ||||||
|     volatile sig_atomic_t exit_request;                                 \ |     volatile sig_atomic_t exit_request;                                 \ | ||||||
|     /* The meaning of the MMU modes is defined in the target code. */   \ |     /* The meaning of the MMU modes is defined in the target code. */   \ | ||||||
| @@ -188,6 +197,7 @@ typedef struct CPUWatchpoint { | |||||||
|     int nr_cores;  /* number of cores within this CPU package */        \ |     int nr_cores;  /* number of cores within this CPU package */        \ | ||||||
|     int nr_threads;/* number of threads within this CPU */              \ |     int nr_threads;/* number of threads within this CPU */              \ | ||||||
|     int running; /* Nonzero if cpu is currently running(usermode).  */  \ |     int running; /* Nonzero if cpu is currently running(usermode).  */  \ | ||||||
|  |     int thread_id;							\ | ||||||
|     /* user data */                                                     \ |     /* user data */                                                     \ | ||||||
|     void *opaque;                                                       \ |     void *opaque;                                                       \ | ||||||
|                                                                         \ |                                                                         \ | ||||||
| @@ -197,6 +207,9 @@ typedef struct CPUWatchpoint { | |||||||
|     const char *cpu_model_str;                                          \ |     const char *cpu_model_str;                                          \ | ||||||
|     struct KVMState *kvm_state;                                         \ |     struct KVMState *kvm_state;                                         \ | ||||||
|     struct kvm_run *kvm_run;                                            \ |     struct kvm_run *kvm_run;                                            \ | ||||||
|     int kvm_fd; |     int kvm_fd;                                                         \ | ||||||
|  |     uint32_t stop;   /* Stop request */                                 \ | ||||||
|  |     uint32_t stopped; /* Artificially stopped */                        \ | ||||||
|  |     struct KVMCPUState kvm_cpu_state; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								cpu-exec.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								cpu-exec.c
									
									
									
									
									
								
							| @@ -19,7 +19,9 @@ | |||||||
| #include "config.h" | #include "config.h" | ||||||
| #include "exec.h" | #include "exec.h" | ||||||
| #include "disas.h" | #include "disas.h" | ||||||
|  | #if !defined(TARGET_IA64) | ||||||
| #include "tcg.h" | #include "tcg.h" | ||||||
|  | #endif | ||||||
| #include "kvm.h" | #include "kvm.h" | ||||||
|  |  | ||||||
| #if !defined(CONFIG_SOFTMMU) | #if !defined(CONFIG_SOFTMMU) | ||||||
| @@ -38,6 +40,8 @@ | |||||||
| #endif | #endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| #if defined(__sparc__) && !defined(CONFIG_SOLARIS) | #if defined(__sparc__) && !defined(CONFIG_SOLARIS) | ||||||
| // Work around ugly bugs in glibc that mangle global register contents | // Work around ugly bugs in glibc that mangle global register contents | ||||||
| #undef env | #undef env | ||||||
| @@ -232,11 +236,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; | ||||||
| @@ -250,6 +256,7 @@ int cpu_exec(CPUState *env1) | |||||||
| #elif defined(TARGET_SH4) | #elif defined(TARGET_SH4) | ||||||
| #elif defined(TARGET_CRIS) | #elif defined(TARGET_CRIS) | ||||||
| #elif defined(TARGET_S390X) | #elif defined(TARGET_S390X) | ||||||
|  | #elif defined(TARGET_IA64) | ||||||
|     /* XXXXX */ |     /* XXXXX */ | ||||||
| #else | #else | ||||||
| #error unsupported target CPU | #error unsupported target CPU | ||||||
| @@ -317,6 +324,8 @@ int cpu_exec(CPUState *env1) | |||||||
|                     do_interrupt(env); |                     do_interrupt(env); | ||||||
| #elif defined(TARGET_M68K) | #elif defined(TARGET_M68K) | ||||||
|                     do_interrupt(0); |                     do_interrupt(0); | ||||||
|  | #elif defined(TARGET_IA64) | ||||||
|  | 		    do_interrupt(env); | ||||||
| #endif | #endif | ||||||
| #endif | #endif | ||||||
|                 } |                 } | ||||||
| @@ -672,6 +681,7 @@ int cpu_exec(CPUState *env1) | |||||||
| #elif defined(TARGET_MICROBLAZE) | #elif defined(TARGET_MICROBLAZE) | ||||||
| #elif defined(TARGET_MIPS) | #elif defined(TARGET_MIPS) | ||||||
| #elif defined(TARGET_SH4) | #elif defined(TARGET_SH4) | ||||||
|  | #elif defined(TARGET_IA64) | ||||||
| #elif defined(TARGET_ALPHA) | #elif defined(TARGET_ALPHA) | ||||||
| #elif defined(TARGET_CRIS) | #elif defined(TARGET_CRIS) | ||||||
| #elif defined(TARGET_S390X) | #elif defined(TARGET_S390X) | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								cutils.c
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								cutils.c
									
									
									
									
									
								
							| @@ -218,6 +218,11 @@ void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * No dma flushing needed here, as the aio code will call dma_bdrv_cb() | ||||||
|  |  * on completion as well, which will result in a call to | ||||||
|  |  * dma_bdrv_unmap() which will do the flushing .... | ||||||
|  |  */ | ||||||
| void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count) | void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count) | ||||||
| { | { | ||||||
|     const uint8_t *p = (const uint8_t *)buf; |     const uint8_t *p = (const uint8_t *)buf; | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -160,6 +160,10 @@ static BlockDriverAIOCB *dma_bdrv_io( | |||||||
|     dbs->is_write = is_write; |     dbs->is_write = is_write; | ||||||
|     dbs->bh = NULL; |     dbs->bh = NULL; | ||||||
|     qemu_iovec_init(&dbs->iov, sg->nsg); |     qemu_iovec_init(&dbs->iov, sg->nsg); | ||||||
|  |     /* | ||||||
|  |      * DMA flushing is handled in dma_bdrv_cb() calling dma_bdrv_unmap() | ||||||
|  |      * so we don't need to do that here. | ||||||
|  |      */ | ||||||
|     dma_bdrv_cb(dbs, 0); |     dma_bdrv_cb(dbs, 0); | ||||||
|     if (!dbs->acb) { |     if (!dbs->acb) { | ||||||
|         qemu_aio_release(dbs); |         qemu_aio_release(dbs); | ||||||
|   | |||||||
| @@ -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" | ||||||
|   | |||||||
							
								
								
									
										174
									
								
								exec.c
									
									
									
									
									
								
							
							
						
						
									
										174
									
								
								exec.c
									
									
									
									
									
								
							| @@ -34,7 +34,13 @@ | |||||||
| #include "cpu.h" | #include "cpu.h" | ||||||
| #include "exec-all.h" | #include "exec-all.h" | ||||||
| #include "qemu-common.h" | #include "qemu-common.h" | ||||||
|  | #include "cache-utils.h" | ||||||
|  |  | ||||||
|  | #if !defined(TARGET_IA64) | ||||||
| #include "tcg.h" | #include "tcg.h" | ||||||
|  | #endif | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| #include "hw/hw.h" | #include "hw/hw.h" | ||||||
| #include "osdep.h" | #include "osdep.h" | ||||||
| #include "kvm.h" | #include "kvm.h" | ||||||
| @@ -74,6 +80,8 @@ | |||||||
| #define TARGET_PHYS_ADDR_SPACE_BITS 42 | #define TARGET_PHYS_ADDR_SPACE_BITS 42 | ||||||
| #elif defined(TARGET_I386) | #elif defined(TARGET_I386) | ||||||
| #define TARGET_PHYS_ADDR_SPACE_BITS 36 | #define TARGET_PHYS_ADDR_SPACE_BITS 36 | ||||||
|  | #elif defined(TARGET_IA64) | ||||||
|  | #define TARGET_PHYS_ADDR_SPACE_BITS 36 | ||||||
| #else | #else | ||||||
| #define TARGET_PHYS_ADDR_SPACE_BITS 32 | #define TARGET_PHYS_ADDR_SPACE_BITS 32 | ||||||
| #endif | #endif | ||||||
| @@ -111,6 +119,7 @@ uint8_t *code_gen_ptr; | |||||||
| #if !defined(CONFIG_USER_ONLY) | #if !defined(CONFIG_USER_ONLY) | ||||||
| int phys_ram_fd; | int phys_ram_fd; | ||||||
| uint8_t *phys_ram_dirty; | uint8_t *phys_ram_dirty; | ||||||
|  | uint8_t *bios_mem; | ||||||
| static int in_migration; | static int in_migration; | ||||||
|  |  | ||||||
| typedef struct RAMBlock { | typedef struct RAMBlock { | ||||||
| @@ -412,6 +421,9 @@ static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]; | |||||||
|  |  | ||||||
| static void code_gen_alloc(unsigned long tb_size) | static void code_gen_alloc(unsigned long tb_size) | ||||||
| { | { | ||||||
|  |     if (kvm_enabled()) | ||||||
|  |         return; | ||||||
|  |  | ||||||
| #ifdef USE_STATIC_CODE_GEN_BUFFER | #ifdef USE_STATIC_CODE_GEN_BUFFER | ||||||
|     code_gen_buffer = static_code_gen_buffer; |     code_gen_buffer = static_code_gen_buffer; | ||||||
|     code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; |     code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; | ||||||
| @@ -588,6 +600,11 @@ void cpu_exec_init(CPUState *env) | |||||||
|     env->numa_node = 0; |     env->numa_node = 0; | ||||||
|     QTAILQ_INIT(&env->breakpoints); |     QTAILQ_INIT(&env->breakpoints); | ||||||
|     QTAILQ_INIT(&env->watchpoints); |     QTAILQ_INIT(&env->watchpoints); | ||||||
|  | #ifdef __WIN32 | ||||||
|  |     env->thread_id = GetCurrentProcessId(); | ||||||
|  | #else | ||||||
|  |     env->thread_id = getpid(); | ||||||
|  | #endif | ||||||
|     *penv = env; |     *penv = env; | ||||||
| #if defined(CONFIG_USER_ONLY) | #if defined(CONFIG_USER_ONLY) | ||||||
|     cpu_list_unlock(); |     cpu_list_unlock(); | ||||||
| @@ -1553,6 +1570,8 @@ void cpu_interrupt(CPUState *env, int mask) | |||||||
|  |  | ||||||
|     old_mask = env->interrupt_request; |     old_mask = env->interrupt_request; | ||||||
|     env->interrupt_request |= mask; |     env->interrupt_request |= mask; | ||||||
|  |     if (kvm_enabled() && !kvm_irqchip_in_kernel()) | ||||||
|  | 	kvm_update_interrupt_request(env); | ||||||
|  |  | ||||||
| #ifndef CONFIG_USER_ONLY | #ifndef CONFIG_USER_ONLY | ||||||
|     /* |     /* | ||||||
| @@ -1880,7 +1899,6 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, | |||||||
|  |  | ||||||
| int cpu_physical_memory_set_dirty_tracking(int enable) | int cpu_physical_memory_set_dirty_tracking(int enable) | ||||||
| { | { | ||||||
|     in_migration = enable; |  | ||||||
|     if (kvm_enabled()) { |     if (kvm_enabled()) { | ||||||
|         return kvm_set_migration_log(enable); |         return kvm_set_migration_log(enable); | ||||||
|     } |     } | ||||||
| @@ -2404,6 +2422,113 @@ void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) | |||||||
|         kvm_uncoalesce_mmio_region(addr, size); |         kvm_uncoalesce_mmio_region(addr, size); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #ifdef __linux__ | ||||||
|  |  | ||||||
|  | #include <sys/vfs.h> | ||||||
|  |  | ||||||
|  | #define HUGETLBFS_MAGIC       0x958458f6 | ||||||
|  |  | ||||||
|  | static long gethugepagesize(const char *path) | ||||||
|  | { | ||||||
|  |     struct statfs fs; | ||||||
|  |     int ret; | ||||||
|  |  | ||||||
|  |     do { | ||||||
|  | 	    ret = statfs(path, &fs); | ||||||
|  |     } while (ret != 0 && errno == EINTR); | ||||||
|  |  | ||||||
|  |     if (ret != 0) { | ||||||
|  | 	    perror("statfs"); | ||||||
|  | 	    return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (fs.f_type != HUGETLBFS_MAGIC) | ||||||
|  | 	    fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path); | ||||||
|  |  | ||||||
|  |     return fs.f_bsize; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void *file_ram_alloc(ram_addr_t memory, const char *path) | ||||||
|  | { | ||||||
|  |     char *filename; | ||||||
|  |     void *area; | ||||||
|  |     int fd; | ||||||
|  | #ifdef MAP_POPULATE | ||||||
|  |     int flags; | ||||||
|  | #endif | ||||||
|  |     unsigned long hpagesize; | ||||||
|  |     extern int mem_prealloc; | ||||||
|  |  | ||||||
|  |     if (!path) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     hpagesize = gethugepagesize(path); | ||||||
|  |     if (!hpagesize) { | ||||||
|  | 	return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (memory < hpagesize) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (kvm_enabled() && !kvm_has_sync_mmu()) { | ||||||
|  |         fprintf(stderr, "host lacks mmu notifiers, disabling --mem-path\n"); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (asprintf(&filename, "%s/kvm.XXXXXX", path) == -1) { | ||||||
|  | 	return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fd = mkstemp(filename); | ||||||
|  |     if (fd < 0) { | ||||||
|  | 	perror("mkstemp"); | ||||||
|  | 	free(filename); | ||||||
|  | 	return NULL; | ||||||
|  |     } | ||||||
|  |     unlink(filename); | ||||||
|  |     free(filename); | ||||||
|  |  | ||||||
|  |     memory = (memory+hpagesize-1) & ~(hpagesize-1); | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * ftruncate is not supported by hugetlbfs in older | ||||||
|  |      * hosts, so don't bother checking for errors. | ||||||
|  |      * If anything goes wrong with it under other filesystems, | ||||||
|  |      * mmap will fail. | ||||||
|  |      */ | ||||||
|  |     ftruncate(fd, memory); | ||||||
|  |  | ||||||
|  | #ifdef MAP_POPULATE | ||||||
|  |     /* NB: MAP_POPULATE won't exhaustively alloc all phys pages in the case | ||||||
|  |      * MAP_PRIVATE is requested.  For mem_prealloc we mmap as MAP_SHARED | ||||||
|  |      * to sidestep this quirk. | ||||||
|  |      */ | ||||||
|  |     flags = mem_prealloc ? MAP_POPULATE|MAP_SHARED : MAP_PRIVATE; | ||||||
|  |     area = mmap(0, memory, PROT_READ|PROT_WRITE, flags, fd, 0); | ||||||
|  | #else | ||||||
|  |     area = mmap(0, memory, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); | ||||||
|  | #endif | ||||||
|  |     if (area == MAP_FAILED) { | ||||||
|  | 	perror("alloc_mem_area: can't mmap hugetlbfs pages"); | ||||||
|  | 	close(fd); | ||||||
|  | 	return (NULL); | ||||||
|  |     } | ||||||
|  |     return area; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | static void *file_ram_alloc(ram_addr_t memory, const char *path) | ||||||
|  | { | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | extern const char *mem_path; | ||||||
|  |  | ||||||
| ram_addr_t qemu_ram_alloc(ram_addr_t size) | ram_addr_t qemu_ram_alloc(ram_addr_t size) | ||||||
| { | { | ||||||
|     RAMBlock *new_block; |     RAMBlock *new_block; | ||||||
| @@ -2411,16 +2536,20 @@ ram_addr_t qemu_ram_alloc(ram_addr_t size) | |||||||
|     size = TARGET_PAGE_ALIGN(size); |     size = TARGET_PAGE_ALIGN(size); | ||||||
|     new_block = qemu_malloc(sizeof(*new_block)); |     new_block = qemu_malloc(sizeof(*new_block)); | ||||||
|  |  | ||||||
|  |     new_block->host = file_ram_alloc(size, mem_path); | ||||||
|  |     if (!new_block->host) { | ||||||
| #if defined(TARGET_S390X) && defined(CONFIG_KVM) | #if defined(TARGET_S390X) && defined(CONFIG_KVM) | ||||||
|     /* XXX S390 KVM requires the topmost vma of the RAM to be < 256GB */ |     /* XXX S390 KVM requires the topmost vma of the RAM to be < 256GB */ | ||||||
|     new_block->host = mmap((void*)0x1000000, size, PROT_EXEC|PROT_READ|PROT_WRITE, |         new_block->host = mmap((void*)0x1000000, size, | ||||||
|                            MAP_SHARED | MAP_ANONYMOUS, -1, 0); |                                PROT_EXEC|PROT_READ|PROT_WRITE, | ||||||
|  |                                MAP_SHARED | MAP_ANONYMOUS, -1, 0); | ||||||
| #else | #else | ||||||
|     new_block->host = qemu_vmalloc(size); |         new_block->host = qemu_vmalloc(size); | ||||||
| #endif | #endif | ||||||
| #ifdef MADV_MERGEABLE | #ifdef MADV_MERGEABLE | ||||||
|     madvise(new_block->host, size, MADV_MERGEABLE); |         madvise(new_block->host, size, MADV_MERGEABLE); | ||||||
| #endif | #endif | ||||||
|  |     } | ||||||
|     new_block->offset = last_ram_offset; |     new_block->offset = last_ram_offset; | ||||||
|     new_block->length = size; |     new_block->length = size; | ||||||
|  |  | ||||||
| @@ -2482,9 +2611,7 @@ void *qemu_get_ram_ptr(ram_addr_t addr) | |||||||
|     return block->host + (addr - block->offset); |     return block->host + (addr - block->offset); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Some of the softmmu routines need to translate from a host pointer | int do_qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr) | ||||||
|    (typically a TLB entry) back to a ram offset.  */ |  | ||||||
| ram_addr_t qemu_ram_addr_from_host(void *ptr) |  | ||||||
| { | { | ||||||
|     RAMBlock *prev; |     RAMBlock *prev; | ||||||
|     RAMBlock **prevp; |     RAMBlock **prevp; | ||||||
| @@ -2501,11 +2628,23 @@ ram_addr_t qemu_ram_addr_from_host(void *ptr) | |||||||
|         prev = block; |         prev = block; | ||||||
|         block = block->next; |         block = block->next; | ||||||
|     } |     } | ||||||
|     if (!block) { |     if (!block) | ||||||
|  |         return -1; | ||||||
|  |     *ram_addr = block->offset + (host - block->host); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Some of the softmmu routines need to translate from a host pointer | ||||||
|  |    (typically a TLB entry) back to a ram offset.  */ | ||||||
|  | ram_addr_t qemu_ram_addr_from_host(void *ptr) | ||||||
|  | { | ||||||
|  |     ram_addr_t ram_addr; | ||||||
|  |  | ||||||
|  |     if (do_qemu_ram_addr_from_host(ptr, &ram_addr)) { | ||||||
|         fprintf(stderr, "Bad ram pointer %p\n", ptr); |         fprintf(stderr, "Bad ram pointer %p\n", ptr); | ||||||
|         abort(); |         abort(); | ||||||
|     } |     } | ||||||
|     return block->offset + (host - block->host); |     return ram_addr; | ||||||
| } | } | ||||||
|  |  | ||||||
| static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) | static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) | ||||||
| @@ -3091,6 +3230,11 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, | |||||||
|                     phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= |                     phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= | ||||||
|                         (0xff & ~CODE_DIRTY_FLAG); |                         (0xff & ~CODE_DIRTY_FLAG); | ||||||
|                 } |                 } | ||||||
|  | 		/* qemu doesn't execute guest code directly, but kvm does | ||||||
|  | 		   therefore flush instruction caches */ | ||||||
|  | 		if (kvm_enabled()) | ||||||
|  | 		    flush_icache_range((unsigned long)ptr, | ||||||
|  | 				       ((unsigned long)ptr)+l); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && |             if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && | ||||||
| @@ -3283,6 +3427,8 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, | |||||||
| void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, | void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, | ||||||
|                                int is_write, target_phys_addr_t access_len) |                                int is_write, target_phys_addr_t access_len) | ||||||
| { | { | ||||||
|  |     unsigned long flush_len = (unsigned long)access_len; | ||||||
|  |  | ||||||
|     if (buffer != bounce.buffer) { |     if (buffer != bounce.buffer) { | ||||||
|         if (is_write) { |         if (is_write) { | ||||||
|             ram_addr_t addr1 = qemu_ram_addr_from_host(buffer); |             ram_addr_t addr1 = qemu_ram_addr_from_host(buffer); | ||||||
| @@ -3300,14 +3446,16 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, | |||||||
|                 } |                 } | ||||||
|                 addr1 += l; |                 addr1 += l; | ||||||
|                 access_len -= l; |                 access_len -= l; | ||||||
|             } | 	    } | ||||||
|  | 	    dma_flush_range((unsigned long)buffer, | ||||||
|  | 			    (unsigned long)buffer + flush_len); | ||||||
|         } |         } | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     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(); | ||||||
| } | } | ||||||
| @@ -3668,7 +3816,9 @@ void dump_exec_info(FILE *f, | |||||||
|     cpu_fprintf(f, "TB flush count      %d\n", tb_flush_count); |     cpu_fprintf(f, "TB flush count      %d\n", tb_flush_count); | ||||||
|     cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count); |     cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count); | ||||||
|     cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count); |     cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count); | ||||||
|  | #ifdef CONFIG_PROFILER | ||||||
|     tcg_dump_info(f, cpu_fprintf); |     tcg_dump_info(f, cpu_fprintf); | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| #if !defined(CONFIG_USER_ONLY) | #if !defined(CONFIG_USER_ONLY) | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| #if defined(CONFIG_SOLARIS) | #if defined(CONFIG_SOLARIS) | ||||||
| #include <fenv.h> | #include <fenv.h> | ||||||
| #endif | #endif | ||||||
|  | #include "config-host.h" | ||||||
|  |  | ||||||
| void set_float_rounding_mode(int val STATUS_PARAM) | void set_float_rounding_mode(int val STATUS_PARAM) | ||||||
| { | { | ||||||
|   | |||||||
| @@ -34,6 +34,7 @@ | |||||||
| #include "sysemu.h" | #include "sysemu.h" | ||||||
| #include "gdbstub.h" | #include "gdbstub.h" | ||||||
| #endif | #endif | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| #define MAX_PACKET_LENGTH 4096 | #define MAX_PACKET_LENGTH 4096 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										71
									
								
								hw/acpi.c
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								hw/acpi.c
									
									
									
									
									
								
							| @@ -23,6 +23,8 @@ | |||||||
| #include "i2c.h" | #include "i2c.h" | ||||||
| #include "smbus.h" | #include "smbus.h" | ||||||
| #include "kvm.h" | #include "kvm.h" | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  | #include "string.h" | ||||||
|  |  | ||||||
| //#define DEBUG | //#define DEBUG | ||||||
|  |  | ||||||
| @@ -521,6 +523,13 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, | |||||||
|  |  | ||||||
|     pci_conf[0x40] = 0x01; /* PM io base read only bit */ |     pci_conf[0x40] = 0x01; /* PM io base read only bit */ | ||||||
|  |  | ||||||
|  | #if defined(TARGET_IA64) | ||||||
|  |     pci_conf[0x40] = 0x41; /* PM io base read only bit */ | ||||||
|  |     pci_conf[0x41] = 0x1f; | ||||||
|  |     pm_write_config(s, 0x80, 0x01, 1); /*Set default pm_io_base 0x1f40*/ | ||||||
|  |     s->pmcntrl = SCI_EN; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|     register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s); |     register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s); | ||||||
|     register_ioport_read(0xb2, 2, 1, pm_smi_readb, s); |     register_ioport_read(0xb2, 2, 1, pm_smi_readb, s); | ||||||
|  |  | ||||||
| @@ -559,12 +568,14 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, | |||||||
| } | } | ||||||
|  |  | ||||||
| #define GPE_BASE 0xafe0 | #define GPE_BASE 0xafe0 | ||||||
|  | #define PROC_BASE 0xaf00 | ||||||
| #define PCI_BASE 0xae00 | #define PCI_BASE 0xae00 | ||||||
| #define PCI_EJ_BASE 0xae08 | #define PCI_EJ_BASE 0xae08 | ||||||
|  |  | ||||||
| struct gpe_regs { | struct gpe_regs { | ||||||
|     uint16_t sts; /* status */ |     uint16_t sts; /* status */ | ||||||
|     uint16_t en;  /* enabled */ |     uint16_t en;  /* enabled */ | ||||||
|  |     uint8_t cpus_sts[32]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| struct pci_status { | struct pci_status { | ||||||
| @@ -587,6 +598,10 @@ static uint32_t gpe_readb(void *opaque, uint32_t addr) | |||||||
|     uint32_t val = 0; |     uint32_t val = 0; | ||||||
|     struct gpe_regs *g = opaque; |     struct gpe_regs *g = opaque; | ||||||
|     switch (addr) { |     switch (addr) { | ||||||
|  |         case PROC_BASE ... PROC_BASE+31: | ||||||
|  |             val = g->cpus_sts[addr - PROC_BASE]; | ||||||
|  |             break; | ||||||
|  |  | ||||||
|         case GPE_BASE: |         case GPE_BASE: | ||||||
|         case GPE_BASE + 1: |         case GPE_BASE + 1: | ||||||
|             val = gpe_read_val(g->sts, addr); |             val = gpe_read_val(g->sts, addr); | ||||||
| @@ -629,6 +644,10 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) | |||||||
| { | { | ||||||
|     struct gpe_regs *g = opaque; |     struct gpe_regs *g = opaque; | ||||||
|     switch (addr) { |     switch (addr) { | ||||||
|  |         case PROC_BASE ... PROC_BASE + 31: | ||||||
|  |             /* don't allow to change cpus_sts from inside a guest */ | ||||||
|  |             break; | ||||||
|  |  | ||||||
|         case GPE_BASE: |         case GPE_BASE: | ||||||
|         case GPE_BASE + 1: |         case GPE_BASE + 1: | ||||||
|             gpe_reset_val(&g->sts, addr, val); |             gpe_reset_val(&g->sts, addr, val); | ||||||
| @@ -712,22 +731,72 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val) | |||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static const char *model; | ||||||
|  |  | ||||||
| static int piix4_device_hotplug(PCIDevice *dev, int state); | static int piix4_device_hotplug(PCIDevice *dev, int state); | ||||||
|  |  | ||||||
| void piix4_acpi_system_hot_add_init(PCIBus *bus) | void piix4_acpi_system_hot_add_init(PCIBus *bus, const char *cpu_model) | ||||||
| { | { | ||||||
|  |     int i = 0, cpus = smp_cpus; | ||||||
|  |  | ||||||
|  |     while (cpus > 0) { | ||||||
|  |         gpe.cpus_sts[i++] = (cpus < 8) ? (1 << cpus) - 1 : 0xff; | ||||||
|  |         cpus -= 8; | ||||||
|  |     } | ||||||
|     register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, &gpe); |     register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, &gpe); | ||||||
|     register_ioport_read(GPE_BASE, 4, 1,  gpe_readb, &gpe); |     register_ioport_read(GPE_BASE, 4, 1,  gpe_readb, &gpe); | ||||||
|  |  | ||||||
|  |     register_ioport_write(PROC_BASE, 32, 1, gpe_writeb, &gpe); | ||||||
|  |     register_ioport_read(PROC_BASE, 32, 1,  gpe_readb, &gpe); | ||||||
|  |  | ||||||
|     register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, &pci0_status); |     register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, &pci0_status); | ||||||
|     register_ioport_read(PCI_BASE, 8, 4,  pcihotplug_read, &pci0_status); |     register_ioport_read(PCI_BASE, 8, 4,  pcihotplug_read, &pci0_status); | ||||||
|  |  | ||||||
|     register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus); |     register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus); | ||||||
|     register_ioport_read(PCI_EJ_BASE, 4, 4,  pciej_read, bus); |     register_ioport_read(PCI_EJ_BASE, 4, 4,  pciej_read, bus); | ||||||
|  |  | ||||||
|  |     model = cpu_model; | ||||||
|  |  | ||||||
|     pci_bus_hotplug(bus, piix4_device_hotplug); |     pci_bus_hotplug(bus, piix4_device_hotplug); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #if defined(TARGET_I386) | ||||||
|  | static void enable_processor(struct gpe_regs *g, int cpu) | ||||||
|  | { | ||||||
|  |     g->sts |= 4; | ||||||
|  |     g->cpus_sts[cpu/8] |= (1 << (cpu%8)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void disable_processor(struct gpe_regs *g, int cpu) | ||||||
|  | { | ||||||
|  |     g->sts |= 4; | ||||||
|  |     g->cpus_sts[cpu/8] &= ~(1 << (cpu%8)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void qemu_system_cpu_hot_add(int cpu, int state) | ||||||
|  | { | ||||||
|  |     CPUState *env; | ||||||
|  |  | ||||||
|  |     if (state && !qemu_get_cpu(cpu)) { | ||||||
|  |         env = pc_new_cpu(model); | ||||||
|  |         if (!env) { | ||||||
|  |             fprintf(stderr, "cpu %d creation failed\n", cpu); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         env->cpuid_apic_id = cpu; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (state) | ||||||
|  |         enable_processor(&gpe, cpu); | ||||||
|  |     else | ||||||
|  |         disable_processor(&gpe, cpu); | ||||||
|  |     if (gpe.en & 4) { | ||||||
|  |         qemu_set_irq(pm_state->irq, 1); | ||||||
|  |         qemu_set_irq(pm_state->irq, 0); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| static void enable_device(struct pci_status *p, struct gpe_regs *g, int slot) | static void enable_device(struct pci_status *p, struct gpe_regs *g, int slot) | ||||||
| { | { | ||||||
|     g->sts |= 2; |     g->sts |= 2; | ||||||
|   | |||||||
							
								
								
									
										144
									
								
								hw/apic.c
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								hw/apic.c
									
									
									
									
									
								
							| @@ -24,6 +24,8 @@ | |||||||
| #include "host-utils.h" | #include "host-utils.h" | ||||||
| #include "kvm.h" | #include "kvm.h" | ||||||
|  |  | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| //#define DEBUG_APIC | //#define DEBUG_APIC | ||||||
|  |  | ||||||
| /* APIC Local Vector Table */ | /* APIC Local Vector Table */ | ||||||
| @@ -299,8 +301,11 @@ void cpu_set_apic_base(CPUState *env, uint64_t val) | |||||||
| #endif | #endif | ||||||
|     if (!s) |     if (!s) | ||||||
|         return; |         return; | ||||||
|     s->apicbase = (val & 0xfffff000) | |     if (kvm_enabled() && kvm_irqchip_in_kernel()) | ||||||
|         (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); |         s->apicbase = val; | ||||||
|  |     else | ||||||
|  |         s->apicbase = (val & 0xfffff000) | | ||||||
|  |             (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); | ||||||
|     /* if disabled, cannot be enabled again */ |     /* if disabled, cannot be enabled again */ | ||||||
|     if (!(val & MSR_IA32_APICBASE_ENABLE)) { |     if (!(val & MSR_IA32_APICBASE_ENABLE)) { | ||||||
|         s->apicbase &= ~MSR_IA32_APICBASE_ENABLE; |         s->apicbase &= ~MSR_IA32_APICBASE_ENABLE; | ||||||
| @@ -393,6 +398,11 @@ int apic_get_irq_delivered(void) | |||||||
|     return apic_irq_delivered; |     return apic_irq_delivered; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void apic_set_irq_delivered(void) | ||||||
|  | { | ||||||
|  |     apic_irq_delivered = 1; | ||||||
|  | } | ||||||
|  |  | ||||||
| static void apic_set_irq(APICState *s, int vector_num, int trigger_mode) | static void apic_set_irq(APICState *s, int vector_num, int trigger_mode) | ||||||
| { | { | ||||||
|     apic_irq_delivered += !get_bit(s->irr, vector_num); |     apic_irq_delivered += !get_bit(s->irr, vector_num); | ||||||
| @@ -478,6 +488,7 @@ void apic_init_reset(CPUState *env) | |||||||
|     if (!s) |     if (!s) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
|  |     cpu_synchronize_state(env); | ||||||
|     s->tpr = 0; |     s->tpr = 0; | ||||||
|     s->spurious_vec = 0xff; |     s->spurious_vec = 0xff; | ||||||
|     s->log_dest = 0; |     s->log_dest = 0; | ||||||
| @@ -497,6 +508,13 @@ void apic_init_reset(CPUState *env) | |||||||
|     s->wait_for_sipi = 1; |     s->wait_for_sipi = 1; | ||||||
|  |  | ||||||
|     env->halted = !(s->apicbase & MSR_IA32_APICBASE_BSP); |     env->halted = !(s->apicbase & MSR_IA32_APICBASE_BSP); | ||||||
|  | #ifdef KVM_CAP_MP_STATE | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         env->mp_state | ||||||
|  |             = env->halted ? KVM_MP_STATE_UNINITIALIZED : KVM_MP_STATE_RUNNABLE; | ||||||
|  |         kvm_load_mpstate(env); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| static void apic_startup(APICState *s, int vector_num) | static void apic_startup(APICState *s, int vector_num) | ||||||
| @@ -864,6 +882,115 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #ifdef KVM_CAP_IRQCHIP | ||||||
|  |  | ||||||
|  | static inline uint32_t kapic_reg(struct kvm_lapic_state *kapic, int reg_id) | ||||||
|  | { | ||||||
|  |     return *((uint32_t *) (kapic->regs + (reg_id << 4))); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static inline void kapic_set_reg(struct kvm_lapic_state *kapic, | ||||||
|  |                                  int reg_id, uint32_t val) | ||||||
|  | { | ||||||
|  |     *((uint32_t *) (kapic->regs + (reg_id << 4))) = val; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void kvm_kernel_lapic_save_to_user(APICState *s) | ||||||
|  | { | ||||||
|  |     struct kvm_lapic_state apic; | ||||||
|  |     struct kvm_lapic_state *kapic = &apic; | ||||||
|  |     int i, v; | ||||||
|  |  | ||||||
|  |     kvm_get_lapic(s->cpu_env, kapic); | ||||||
|  |  | ||||||
|  |     s->id = kapic_reg(kapic, 0x2) >> 24; | ||||||
|  |     s->tpr = kapic_reg(kapic, 0x8); | ||||||
|  |     s->arb_id = kapic_reg(kapic, 0x9); | ||||||
|  |     s->log_dest = kapic_reg(kapic, 0xd) >> 24; | ||||||
|  |     s->dest_mode = kapic_reg(kapic, 0xe) >> 28; | ||||||
|  |     s->spurious_vec = kapic_reg(kapic, 0xf); | ||||||
|  |     for (i = 0; i < 8; i++) { | ||||||
|  |         s->isr[i] = kapic_reg(kapic, 0x10 + i); | ||||||
|  |         s->tmr[i] = kapic_reg(kapic, 0x18 + i); | ||||||
|  |         s->irr[i] = kapic_reg(kapic, 0x20 + i); | ||||||
|  |     } | ||||||
|  |     s->esr = kapic_reg(kapic, 0x28); | ||||||
|  |     s->icr[0] = kapic_reg(kapic, 0x30); | ||||||
|  |     s->icr[1] = kapic_reg(kapic, 0x31); | ||||||
|  |     for (i = 0; i < APIC_LVT_NB; i++) | ||||||
|  | 	s->lvt[i] = kapic_reg(kapic, 0x32 + i); | ||||||
|  |     s->initial_count = kapic_reg(kapic, 0x38); | ||||||
|  |     s->divide_conf = kapic_reg(kapic, 0x3e); | ||||||
|  |  | ||||||
|  |     v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); | ||||||
|  |     s->count_shift = (v + 1) & 7; | ||||||
|  |  | ||||||
|  |     s->initial_count_load_time = qemu_get_clock(vm_clock); | ||||||
|  |     apic_timer_update(s, s->initial_count_load_time); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void kvm_kernel_lapic_load_from_user(APICState *s) | ||||||
|  | { | ||||||
|  |     struct kvm_lapic_state apic; | ||||||
|  |     struct kvm_lapic_state *klapic = &apic; | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     memset(klapic, 0, sizeof apic); | ||||||
|  |     kapic_set_reg(klapic, 0x2, s->id << 24); | ||||||
|  |     kapic_set_reg(klapic, 0x8, s->tpr); | ||||||
|  |     kapic_set_reg(klapic, 0xd, s->log_dest << 24); | ||||||
|  |     kapic_set_reg(klapic, 0xe, s->dest_mode << 28 | 0x0fffffff); | ||||||
|  |     kapic_set_reg(klapic, 0xf, s->spurious_vec); | ||||||
|  |     for (i = 0; i < 8; i++) { | ||||||
|  |         kapic_set_reg(klapic, 0x10 + i, s->isr[i]); | ||||||
|  |         kapic_set_reg(klapic, 0x18 + i, s->tmr[i]); | ||||||
|  |         kapic_set_reg(klapic, 0x20 + i, s->irr[i]); | ||||||
|  |     } | ||||||
|  |     kapic_set_reg(klapic, 0x28, s->esr); | ||||||
|  |     kapic_set_reg(klapic, 0x30, s->icr[0]); | ||||||
|  |     kapic_set_reg(klapic, 0x31, s->icr[1]); | ||||||
|  |     for (i = 0; i < APIC_LVT_NB; i++) | ||||||
|  |         kapic_set_reg(klapic, 0x32 + i, s->lvt[i]); | ||||||
|  |     kapic_set_reg(klapic, 0x38, s->initial_count); | ||||||
|  |     kapic_set_reg(klapic, 0x3e, s->divide_conf); | ||||||
|  |  | ||||||
|  |     kvm_set_lapic(s->cpu_env, klapic); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | void qemu_kvm_load_lapic(CPUState *env) | ||||||
|  | { | ||||||
|  | #ifdef KVM_CAP_IRQCHIP | ||||||
|  |     if (kvm_enabled() && kvm_vcpu_inited(env) && kvm_irqchip_in_kernel()) { | ||||||
|  |         kvm_kernel_lapic_load_from_user(env->apic_state); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void apic_pre_save(void *opaque) | ||||||
|  | { | ||||||
|  | #ifdef KVM_CAP_IRQCHIP | ||||||
|  |     APICState *s = (void *)opaque; | ||||||
|  |  | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         kvm_kernel_lapic_save_to_user(s); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int apic_post_load(void *opaque, int version_id) | ||||||
|  | { | ||||||
|  | #ifdef KVM_CAP_IRQCHIP | ||||||
|  |     APICState *s = opaque; | ||||||
|  |  | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         kvm_kernel_lapic_load_from_user(s); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| /* This function is only used for old state version 1 and 2 */ | /* This function is only used for old state version 1 and 2 */ | ||||||
| static int apic_load_old(QEMUFile *f, void *opaque, int version_id) | static int apic_load_old(QEMUFile *f, void *opaque, int version_id) | ||||||
| { | { | ||||||
| @@ -900,6 +1027,9 @@ static int apic_load_old(QEMUFile *f, void *opaque, int version_id) | |||||||
|  |  | ||||||
|     if (version_id >= 2) |     if (version_id >= 2) | ||||||
|         qemu_get_timer(f, s->timer); |         qemu_get_timer(f, s->timer); | ||||||
|  |  | ||||||
|  |     qemu_kvm_load_lapic(s->cpu_env); | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -930,7 +1060,9 @@ static const VMStateDescription vmstate_apic = { | |||||||
|         VMSTATE_INT64(next_time, APICState), |         VMSTATE_INT64(next_time, APICState), | ||||||
|         VMSTATE_TIMER(timer, APICState), |         VMSTATE_TIMER(timer, APICState), | ||||||
|         VMSTATE_END_OF_LIST() |         VMSTATE_END_OF_LIST() | ||||||
|     } |     }, | ||||||
|  |     .pre_save = apic_pre_save, | ||||||
|  |     .post_load = apic_post_load, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static void apic_reset(void *opaque) | static void apic_reset(void *opaque) | ||||||
| @@ -955,6 +1087,7 @@ static void apic_reset(void *opaque) | |||||||
|          */ |          */ | ||||||
|         s->lvt[APIC_LVT_LINT0] = 0x700; |         s->lvt[APIC_LVT_LINT0] = 0x700; | ||||||
|     } |     } | ||||||
|  |     qemu_kvm_load_lapic(s->cpu_env); | ||||||
| } | } | ||||||
|  |  | ||||||
| static CPUReadMemoryFunc * const apic_mem_read[3] = { | static CPUReadMemoryFunc * const apic_mem_read[3] = { | ||||||
| @@ -998,6 +1131,11 @@ int apic_init(CPUState *env) | |||||||
|     vmstate_register(s->idx, &vmstate_apic, s); |     vmstate_register(s->idx, &vmstate_apic, s); | ||||||
|     qemu_register_reset(apic_reset, s); |     qemu_register_reset(apic_reset, s); | ||||||
|  |  | ||||||
|  |     /* apic_reset must be called before the vcpu threads are initialized and load | ||||||
|  |      * registers, in qemu-kvm. | ||||||
|  |      */ | ||||||
|  |     apic_reset(s); | ||||||
|  |  | ||||||
|     local_apics[s->idx] = s; |     local_apics[s->idx] = s; | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -71,7 +71,7 @@ static void arm_timer_recalibrate(arm_timer_state *s, int reload) | |||||||
| { | { | ||||||
|     uint32_t limit; |     uint32_t limit; | ||||||
|  |  | ||||||
|     if ((s->control & TIMER_CTRL_PERIODIC) == 0) { |     if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) { | ||||||
|         /* Free running.  */ |         /* Free running.  */ | ||||||
|         if (s->control & TIMER_CTRL_32BIT) |         if (s->control & TIMER_CTRL_32BIT) | ||||||
|             limit = 0xffffffff; |             limit = 0xffffffff; | ||||||
| @@ -113,7 +113,7 @@ static void arm_timer_write(void *opaque, target_phys_addr_t offset, | |||||||
|         case 1: freq >>= 4; break; |         case 1: freq >>= 4; break; | ||||||
|         case 2: freq >>= 8; break; |         case 2: freq >>= 8; break; | ||||||
|         } |         } | ||||||
|         arm_timer_recalibrate(s, 0); |         arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE); | ||||||
|         ptimer_set_freq(s->timer, freq); |         ptimer_set_freq(s->timer, freq); | ||||||
|         if (s->control & TIMER_CTRL_ENABLE) { |         if (s->control & TIMER_CTRL_ENABLE) { | ||||||
|             /* Restart the timer if still enabled.  */ |             /* Restart the timer if still enabled.  */ | ||||||
|   | |||||||
| @@ -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); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -32,6 +32,7 @@ | |||||||
| #include "console.h" | #include "console.h" | ||||||
| #include "vga_int.h" | #include "vga_int.h" | ||||||
| #include "kvm.h" | #include "kvm.h" | ||||||
|  | #include "qemu-kvm.h" | ||||||
| #include "loader.h" | #include "loader.h" | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -2552,6 +2553,7 @@ static CPUWriteMemoryFunc * const cirrus_linear_bitblt_write[3] = { | |||||||
|  |  | ||||||
| static void map_linear_vram(CirrusVGAState *s) | static void map_linear_vram(CirrusVGAState *s) | ||||||
| { | { | ||||||
|  |     vga_dirty_log_stop(&s->vga); | ||||||
|     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.lfb_addr; |         s->vga.map_addr = s->vga.lfb_addr; | ||||||
|         s->vga.map_end = s->vga.lfb_end; |         s->vga.map_end = s->vga.lfb_end; | ||||||
| @@ -2561,13 +2563,19 @@ static void map_linear_vram(CirrusVGAState *s) | |||||||
|     if (!s->vga.map_addr) |     if (!s->vga.map_addr) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
|  | #ifndef TARGET_IA64 | ||||||
|     s->vga.lfb_vram_mapped = 0; |     s->vga.lfb_vram_mapped = 0; | ||||||
|  |  | ||||||
|  |     cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000, | ||||||
|  |                                 (s->vga.vram_offset + s->cirrus_bank_base[0]) | IO_MEM_UNASSIGNED); | ||||||
|  |     cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000, | ||||||
|  |                                 (s->vga.vram_offset + s->cirrus_bank_base[1]) | IO_MEM_UNASSIGNED); | ||||||
|     if (!(s->cirrus_srcptr != s->cirrus_srcptr_end) |     if (!(s->cirrus_srcptr != s->cirrus_srcptr_end) | ||||||
|         && !((s->vga.sr[0x07] & 0x01) == 0) |         && !((s->vga.sr[0x07] & 0x01) == 0) | ||||||
|         && !((s->vga.gr[0x0B] & 0x14) == 0x14) |         && !((s->vga.gr[0x0B] & 0x14) == 0x14) | ||||||
|         && !(s->vga.gr[0x0B] & 0x02)) { |         && !(s->vga.gr[0x0B] & 0x02)) { | ||||||
|  |  | ||||||
|  |         vga_dirty_log_stop(&s->vga); | ||||||
|         cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000, |         cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000, | ||||||
|                                     (s->vga.vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM); |                                     (s->vga.vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM); | ||||||
|         cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000, |         cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000, | ||||||
| @@ -2579,17 +2587,23 @@ static void map_linear_vram(CirrusVGAState *s) | |||||||
|         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); | ||||||
|     } |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|     vga_dirty_log_start(&s->vga); |     vga_dirty_log_start(&s->vga); | ||||||
| } | } | ||||||
|  |  | ||||||
| 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) |     vga_dirty_log_stop(&s->vga); | ||||||
|  |     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); | ||||||
|  |  | ||||||
|  |     vga_dirty_log_start(&s->vga); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Compute the memory access functions */ | /* Compute the memory access functions */ | ||||||
| @@ -3143,6 +3157,8 @@ static void cirrus_pci_lfb_map(PCIDevice *d, int region_num, | |||||||
| { | { | ||||||
|     CirrusVGAState *s = &DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga; |     CirrusVGAState *s = &DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga; | ||||||
|  |  | ||||||
|  |     vga_dirty_log_stop(&s->vga); | ||||||
|  |  | ||||||
|     /* XXX: add byte swapping apertures */ |     /* XXX: add byte swapping apertures */ | ||||||
|     cpu_register_physical_memory(addr, s->vga.vram_size, |     cpu_register_physical_memory(addr, s->vga.vram_size, | ||||||
| 				 s->cirrus_linear_io_addr); | 				 s->cirrus_linear_io_addr); | ||||||
| @@ -3174,10 +3190,14 @@ static void pci_cirrus_write_config(PCIDevice *d, | |||||||
|     PCICirrusVGAState *pvs = DO_UPCAST(PCICirrusVGAState, dev, d); |     PCICirrusVGAState *pvs = DO_UPCAST(PCICirrusVGAState, dev, d); | ||||||
|     CirrusVGAState *s = &pvs->cirrus_vga; |     CirrusVGAState *s = &pvs->cirrus_vga; | ||||||
|  |  | ||||||
|  |     vga_dirty_log_stop(&s->vga); | ||||||
|  |  | ||||||
|     pci_default_write_config(d, address, val, len); |     pci_default_write_config(d, address, val, len); | ||||||
|     if (s->vga.map_addr && d->io_regions[0].addr == PCI_BAR_UNMAPPED) |     if (s->vga.map_addr && d->io_regions[0].addr == PCI_BAR_UNMAPPED) | ||||||
|         s->vga.map_addr = 0; |         s->vga.map_addr = 0; | ||||||
|     cirrus_update_memory_access(s); |     cirrus_update_memory_access(s); | ||||||
|  |  | ||||||
|  |     vga_dirty_log_start(&s->vga); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int pci_cirrus_vga_initfn(PCIDevice *dev) | static int pci_cirrus_vga_initfn(PCIDevice *dev) | ||||||
| @@ -3209,22 +3229,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, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										1379
									
								
								hw/device-assignment.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1379
									
								
								hw/device-assignment.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										117
									
								
								hw/device-assignment.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								hw/device-assignment.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2007, Neocleus Corporation. | ||||||
|  |  * Copyright (c) 2007, Intel Corporation. | ||||||
|  |  * | ||||||
|  |  * This program is free software; you can redistribute it and/or modify it | ||||||
|  |  * under the terms and conditions of the GNU General Public License, | ||||||
|  |  * version 2, as published by the Free Software Foundation. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope it will be useful, but WITHOUT | ||||||
|  |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||||
|  |  * more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License along with | ||||||
|  |  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||||||
|  |  * Place - Suite 330, Boston, MA 02111-1307 USA. | ||||||
|  |  * | ||||||
|  |  *  Data structures for storing PCI state | ||||||
|  |  * | ||||||
|  |  *  Adapted to kvm by Qumranet | ||||||
|  |  * | ||||||
|  |  *  Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) | ||||||
|  |  *  Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) | ||||||
|  |  *  Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) | ||||||
|  |  *  Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef __DEVICE_ASSIGNMENT_H__ | ||||||
|  | #define __DEVICE_ASSIGNMENT_H__ | ||||||
|  |  | ||||||
|  | #include <sys/mman.h> | ||||||
|  | #include "qemu-common.h" | ||||||
|  | #include "qemu-queue.h" | ||||||
|  | #include "pci.h" | ||||||
|  |  | ||||||
|  | /* From include/linux/pci.h in the kernel sources */ | ||||||
|  | #define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07)) | ||||||
|  |  | ||||||
|  | typedef struct PCIHostDevice { | ||||||
|  |     int bus; | ||||||
|  |     int dev; | ||||||
|  |     int func; | ||||||
|  | } PCIHostDevice; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     int type;           /* Memory or port I/O */ | ||||||
|  |     int valid; | ||||||
|  |     uint32_t base_addr; | ||||||
|  |     uint32_t size;    /* size of the region */ | ||||||
|  |     int resource_fd; | ||||||
|  | } PCIRegion; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t bus, dev, func; /* Bus inside domain, device and function */ | ||||||
|  |     int irq;                /* IRQ number */ | ||||||
|  |     uint16_t region_number; /* number of active regions */ | ||||||
|  |  | ||||||
|  |     /* Port I/O or MMIO Regions */ | ||||||
|  |     PCIRegion regions[PCI_NUM_REGIONS]; | ||||||
|  |     int config_fd; | ||||||
|  | } PCIDevRegions; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     pcibus_t e_physbase; | ||||||
|  |     uint32_t memory_index; | ||||||
|  |     union { | ||||||
|  |         void *r_virtbase;    /* mmapped access address for memory regions */ | ||||||
|  |         uint32_t r_baseport; /* the base guest port for I/O regions */ | ||||||
|  |     } u; | ||||||
|  |     int num;            /* our index within v_addrs[] */ | ||||||
|  |     pcibus_t e_size;    /* emulated size of region in bytes */ | ||||||
|  |     pcibus_t r_size;    /* real size of region in bytes */ | ||||||
|  | } AssignedDevRegion; | ||||||
|  |  | ||||||
|  | typedef struct AssignedDevice { | ||||||
|  |     PCIDevice dev; | ||||||
|  |     PCIHostDevice host; | ||||||
|  |     uint32_t use_iommu; | ||||||
|  |     int intpin; | ||||||
|  |     uint8_t debug_flags; | ||||||
|  |     AssignedDevRegion v_addrs[PCI_NUM_REGIONS]; | ||||||
|  |     PCIDevRegions real_device; | ||||||
|  |     int run; | ||||||
|  |     int girq; | ||||||
|  |     unsigned char h_busnr; | ||||||
|  |     unsigned int h_devfn; | ||||||
|  |     int irq_requested_type; | ||||||
|  |     int bound; | ||||||
|  |     struct pci_dev *pdev; | ||||||
|  |     struct { | ||||||
|  | #define ASSIGNED_DEVICE_CAP_MSI (1 << 0) | ||||||
|  | #define ASSIGNED_DEVICE_CAP_MSIX (1 << 1) | ||||||
|  |         uint32_t available; | ||||||
|  | #define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0) | ||||||
|  | #define ASSIGNED_DEVICE_MSIX_ENABLED (1 << 1) | ||||||
|  | #define ASSIGNED_DEVICE_MSIX_MASKED (1 << 2) | ||||||
|  |         uint32_t state; | ||||||
|  |     } cap; | ||||||
|  |     int irq_entries_nr; | ||||||
|  |     struct kvm_irq_routing_entry *entry; | ||||||
|  |     void *msix_table_page; | ||||||
|  |     target_phys_addr_t msix_table_addr; | ||||||
|  |     int mmio_index; | ||||||
|  |     int need_emulate_cmd; | ||||||
|  |     QLIST_ENTRY(AssignedDevice) next; | ||||||
|  | } AssignedDevice; | ||||||
|  |  | ||||||
|  | QemuOpts *add_assigned_device(const char *arg); | ||||||
|  | void add_assigned_devices(PCIBus *bus, const char **devices, int n_devices); | ||||||
|  | void assigned_dev_update_irqs(void); | ||||||
|  |  | ||||||
|  | #define MAX_DEV_ASSIGN_CMDLINE 8 | ||||||
|  |  | ||||||
|  | extern const char *assigned_devices[MAX_DEV_ASSIGN_CMDLINE]; | ||||||
|  | extern int assigned_devices_index; | ||||||
|  |  | ||||||
|  | #endif              /* __DEVICE_ASSIGNMENT_H__ */ | ||||||
							
								
								
									
										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(), | ||||||
|   | |||||||
							
								
								
									
										135
									
								
								hw/extboot.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								hw/extboot.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | |||||||
|  | /* | ||||||
|  |  * Extended boot option ROM support. | ||||||
|  |  * | ||||||
|  |  * Copyright IBM, Corp. 2007 | ||||||
|  |  * | ||||||
|  |  * Authors: | ||||||
|  |  *  Anthony Liguori   <aliguori@us.ibm.com> | ||||||
|  |  * | ||||||
|  |  * This work is licensed under the terms of the GNU GPL, version 2.  See | ||||||
|  |  * the COPYING file in the top-level directory. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "hw.h" | ||||||
|  | #include "pc.h" | ||||||
|  | #include "isa.h" | ||||||
|  | #include "block.h" | ||||||
|  |  | ||||||
|  | /* Extended Boot ROM suport */ | ||||||
|  |  | ||||||
|  | union extboot_cmd | ||||||
|  | { | ||||||
|  |     uint16_t type; | ||||||
|  |     struct { | ||||||
|  | 	uint16_t type; | ||||||
|  | 	uint16_t cylinders; | ||||||
|  | 	uint16_t heads; | ||||||
|  | 	uint16_t sectors; | ||||||
|  | 	uint64_t nb_sectors; | ||||||
|  |     } query_geometry; | ||||||
|  |     struct { | ||||||
|  | 	uint16_t type; | ||||||
|  | 	uint16_t nb_sectors; | ||||||
|  | 	uint16_t segment; | ||||||
|  | 	uint16_t offset; | ||||||
|  | 	uint64_t sector; | ||||||
|  |     } xfer; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void get_translated_chs(BlockDriverState *bs, int *c, int *h, int *s) | ||||||
|  | { | ||||||
|  |     bdrv_get_geometry_hint(bs, c, h, s); | ||||||
|  |  | ||||||
|  |     if (*c <= 1024) { | ||||||
|  | 	*c >>= 0; | ||||||
|  | 	*h <<= 0; | ||||||
|  |     } else if (*c <= 2048) { | ||||||
|  | 	*c >>= 1; | ||||||
|  | 	*h <<= 1; | ||||||
|  |     } else if (*c <= 4096) { | ||||||
|  | 	*c >>= 2; | ||||||
|  | 	*h <<= 2; | ||||||
|  |     } else if (*c <= 8192) { | ||||||
|  | 	*c >>= 3; | ||||||
|  | 	*h <<= 3; | ||||||
|  |     } else { | ||||||
|  | 	*c >>= 4; | ||||||
|  | 	*h <<= 4; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* what is the correct algorithm for this?? */ | ||||||
|  |     if (*h == 256) { | ||||||
|  | 	*h = 255; | ||||||
|  | 	*c = *c + 1; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static uint32_t extboot_read(void *opaque, uint32_t addr) | ||||||
|  | { | ||||||
|  |     int *pcmd = opaque; | ||||||
|  |     return *pcmd; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value) | ||||||
|  | { | ||||||
|  |     union extboot_cmd cmd; | ||||||
|  |     BlockDriverState *bs = opaque; | ||||||
|  |     int cylinders, heads, sectors, err; | ||||||
|  |     uint64_t nb_sectors; | ||||||
|  |     target_phys_addr_t pa = 0; | ||||||
|  |     int blen = 0; | ||||||
|  |     void *buf = NULL; | ||||||
|  |  | ||||||
|  |     cpu_physical_memory_read((value & 0xFFFF) << 4, (uint8_t *)&cmd, | ||||||
|  |                              sizeof(cmd)); | ||||||
|  |  | ||||||
|  |     if (cmd.type == 0x01 || cmd.type == 0x02) { | ||||||
|  | 	pa = cmd.xfer.segment * 16 + cmd.xfer.offset; | ||||||
|  |         blen = cmd.xfer.nb_sectors * 512; | ||||||
|  |         buf = qemu_memalign(512, blen); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     switch (cmd.type) { | ||||||
|  |     case 0x00: | ||||||
|  |         get_translated_chs(bs, &cylinders, &heads, §ors); | ||||||
|  | 	bdrv_get_geometry(bs, &nb_sectors); | ||||||
|  | 	cmd.query_geometry.cylinders = cylinders; | ||||||
|  | 	cmd.query_geometry.heads = heads; | ||||||
|  | 	cmd.query_geometry.sectors = sectors; | ||||||
|  | 	cmd.query_geometry.nb_sectors = nb_sectors; | ||||||
|  | 	break; | ||||||
|  |     case 0x01: | ||||||
|  | 	err = bdrv_read(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors); | ||||||
|  | 	if (err) | ||||||
|  | 	    printf("Read failed\n"); | ||||||
|  |  | ||||||
|  |         cpu_physical_memory_write(pa, buf, blen); | ||||||
|  |  | ||||||
|  | 	break; | ||||||
|  |     case 0x02: | ||||||
|  |         cpu_physical_memory_read(pa, buf, blen); | ||||||
|  |  | ||||||
|  | 	err = bdrv_write(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors); | ||||||
|  | 	if (err) | ||||||
|  | 	    printf("Write failed\n"); | ||||||
|  |  | ||||||
|  | 	break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     cpu_physical_memory_write((value & 0xFFFF) << 4, (uint8_t *)&cmd, | ||||||
|  |                               sizeof(cmd)); | ||||||
|  |     if (buf) | ||||||
|  |         qemu_free(buf); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void extboot_init(BlockDriverState *bs, int cmd) | ||||||
|  | { | ||||||
|  |     int *pcmd; | ||||||
|  |  | ||||||
|  |     pcmd = qemu_mallocz(sizeof(int)); | ||||||
|  |  | ||||||
|  |     *pcmd = cmd; | ||||||
|  |     register_ioport_read(0x404, 1, 1, extboot_read, pcmd); | ||||||
|  |     register_ioport_write(0x405, 1, 2, extboot_write_cmd, bs); | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								hw/fdc.c
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								hw/fdc.c
									
									
									
									
									
								
							| @@ -370,9 +370,9 @@ enum { | |||||||
|     FD_CMD_PART_ID = 0x18, |     FD_CMD_PART_ID = 0x18, | ||||||
|     FD_CMD_SCAN_LOW_OR_EQUAL = 0x19, |     FD_CMD_SCAN_LOW_OR_EQUAL = 0x19, | ||||||
|     FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d, |     FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d, | ||||||
|     FD_CMD_SAVE = 0x2c, |     FD_CMD_SAVE = 0x2e, | ||||||
|     FD_CMD_OPTION = 0x33, |     FD_CMD_OPTION = 0x33, | ||||||
|     FD_CMD_RESTORE = 0x4c, |     FD_CMD_RESTORE = 0x4e, | ||||||
|     FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e, |     FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e, | ||||||
|     FD_CMD_RELATIVE_SEEK_OUT = 0x8f, |     FD_CMD_RELATIVE_SEEK_OUT = 0x8f, | ||||||
|     FD_CMD_FORMAT_AND_WRITE = 0xcd, |     FD_CMD_FORMAT_AND_WRITE = 0xcd, | ||||||
| @@ -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); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								hw/hpet.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								hw/hpet.c
									
									
									
									
									
								
							| @@ -170,6 +170,11 @@ static int hpet_post_load(void *opaque, int version_id) | |||||||
|  |  | ||||||
|     /* Recalculate the offset between the main counter and guest time */ |     /* Recalculate the offset between the main counter and guest time */ | ||||||
|     s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock); |     s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock); | ||||||
|  |  | ||||||
|  |     if (hpet_in_legacy_mode()) { | ||||||
|  |         hpet_disable_pit(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -473,9 +478,11 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, | |||||||
|                 } |                 } | ||||||
|                 /* i8254 and RTC are disabled when HPET is in legacy mode */ |                 /* i8254 and RTC are disabled when HPET is in legacy mode */ | ||||||
|                 if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) { |                 if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) { | ||||||
|                     hpet_pit_disable(); |                     hpet_disable_pit(); | ||||||
|  |                     dprintf("qemu: hpet disabled pit\n"); | ||||||
|                 } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) { |                 } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) { | ||||||
|                     hpet_pit_enable(); |                     hpet_enable_pit(); | ||||||
|  |                     dprintf("qemu: hpet enabled pit\n"); | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|             case HPET_CFG + 4: |             case HPET_CFG + 4: | ||||||
| @@ -559,7 +566,7 @@ static void hpet_reset(void *opaque) { | |||||||
|          * hpet_reset is called due to system reset. At this point control must |          * hpet_reset is called due to system reset. At this point control must | ||||||
|          * be returned to pit until SW reenables hpet. |          * be returned to pit until SW reenables hpet. | ||||||
|          */ |          */ | ||||||
|         hpet_pit_enable(); |         hpet_enable_pit(); | ||||||
|     count = 1; |     count = 1; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								hw/hw.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								hw/hw.h
									
									
									
									
									
								
							| @@ -342,6 +342,10 @@ extern const VMStateInfo vmstate_info_uint16; | |||||||
| extern const VMStateInfo vmstate_info_uint32; | extern const VMStateInfo vmstate_info_uint32; | ||||||
| extern const VMStateInfo vmstate_info_uint64; | extern const VMStateInfo vmstate_info_uint64; | ||||||
|  |  | ||||||
|  | #ifdef __linux__ | ||||||
|  | extern const VMStateInfo vmstate_info_u64; | ||||||
|  | #endif | ||||||
|  |  | ||||||
| extern const VMStateInfo vmstate_info_timer; | extern const VMStateInfo vmstate_info_timer; | ||||||
| extern const VMStateInfo vmstate_info_ptimer; | extern const VMStateInfo vmstate_info_ptimer; | ||||||
| extern const VMStateInfo vmstate_info_buffer; | extern const VMStateInfo vmstate_info_buffer; | ||||||
| @@ -622,6 +626,15 @@ extern const VMStateDescription vmstate_i2c_slave; | |||||||
| #define VMSTATE_UINT64(_f, _s)                                        \ | #define VMSTATE_UINT64(_f, _s)                                        \ | ||||||
|     VMSTATE_UINT64_V(_f, _s, 0) |     VMSTATE_UINT64_V(_f, _s, 0) | ||||||
|  |  | ||||||
|  | /* This is needed because on linux __u64 is unsigned long long | ||||||
|  |    and on glibc uint64_t is unsigned long on 64 bits */ | ||||||
|  | #ifdef __linux__ | ||||||
|  | #define VMSTATE_U64_V(_f, _s, _v)                                     \ | ||||||
|  |     VMSTATE_SINGLE(_f, _s, _v, vmstate_info_u64, __u64) | ||||||
|  | #define VMSTATE_U64(_f, _s)                                           \ | ||||||
|  |     VMSTATE_U64_V(_f, _s, 0) | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #define VMSTATE_UINT8_EQUAL(_f, _s)                                   \ | #define VMSTATE_UINT8_EQUAL(_f, _s)                                   \ | ||||||
|     VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint8_equal, uint8_t) |     VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint8_equal, uint8_t) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										122
									
								
								hw/i8254-kvm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								hw/i8254-kvm.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU 8253/8254 interval timer emulation | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2004 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "hw.h" | ||||||
|  | #include "pc.h" | ||||||
|  | #include "isa.h" | ||||||
|  | #include "qemu-timer.h" | ||||||
|  | #include "i8254.h" | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
|  | extern VMStateDescription vmstate_pit; | ||||||
|  |  | ||||||
|  | static PITState pit_state; | ||||||
|  |  | ||||||
|  | static void kvm_pit_pre_save(void *opaque) | ||||||
|  | { | ||||||
|  |     PITState *s = (void *)opaque; | ||||||
|  |     struct kvm_pit_state2 pit2; | ||||||
|  |     struct kvm_pit_channel_state *c; | ||||||
|  |     struct PITChannelState *sc; | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     if(qemu_kvm_has_pit_state2()) { | ||||||
|  |         kvm_get_pit2(kvm_context, &pit2); | ||||||
|  |         s->flags = pit2.flags; | ||||||
|  |     } else { | ||||||
|  |         /* pit2 is superset of pit struct so just cast it and use it */ | ||||||
|  |         kvm_get_pit(kvm_context, (struct kvm_pit_state *)&pit2); | ||||||
|  |     } | ||||||
|  |     for (i = 0; i < 3; i++) { | ||||||
|  | 	c = &pit2.channels[i]; | ||||||
|  | 	sc = &s->channels[i]; | ||||||
|  | 	sc->count = c->count; | ||||||
|  | 	sc->latched_count = c->latched_count; | ||||||
|  | 	sc->count_latched = c->count_latched; | ||||||
|  | 	sc->status_latched = c->status_latched; | ||||||
|  | 	sc->status = c->status; | ||||||
|  | 	sc->read_state = c->read_state; | ||||||
|  | 	sc->write_state = c->write_state; | ||||||
|  | 	sc->write_latch = c->write_latch; | ||||||
|  | 	sc->rw_mode = c->rw_mode; | ||||||
|  | 	sc->mode = c->mode; | ||||||
|  | 	sc->bcd = c->bcd; | ||||||
|  | 	sc->gate = c->gate; | ||||||
|  | 	sc->count_load_time = c->count_load_time; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int kvm_pit_post_load(void *opaque, int version_id) | ||||||
|  | { | ||||||
|  |     PITState *s = opaque; | ||||||
|  |     struct kvm_pit_state2 pit2; | ||||||
|  |     struct kvm_pit_channel_state *c; | ||||||
|  |     struct PITChannelState *sc; | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     pit2.flags = s->flags; | ||||||
|  |     for (i = 0; i < 3; i++) { | ||||||
|  | 	c = &pit2.channels[i]; | ||||||
|  | 	sc = &s->channels[i]; | ||||||
|  | 	c->count = sc->count; | ||||||
|  | 	c->latched_count = sc->latched_count; | ||||||
|  | 	c->count_latched = sc->count_latched; | ||||||
|  | 	c->status_latched = sc->status_latched; | ||||||
|  | 	c->status = sc->status; | ||||||
|  | 	c->read_state = sc->read_state; | ||||||
|  | 	c->write_state = sc->write_state; | ||||||
|  | 	c->write_latch = sc->write_latch; | ||||||
|  | 	c->rw_mode = sc->rw_mode; | ||||||
|  | 	c->mode = sc->mode; | ||||||
|  | 	c->bcd = sc->bcd; | ||||||
|  | 	c->gate = sc->gate; | ||||||
|  | 	c->count_load_time = sc->count_load_time; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if(qemu_kvm_has_pit_state2()) { | ||||||
|  |         kvm_set_pit2(kvm_context, &pit2); | ||||||
|  |     } else { | ||||||
|  |         kvm_set_pit(kvm_context, (struct kvm_pit_state *)&pit2); | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dummy_timer(void *opaque) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PITState *kvm_pit_init(int base, qemu_irq irq) | ||||||
|  | { | ||||||
|  |     PITState *pit = &pit_state; | ||||||
|  |     PITChannelState *s; | ||||||
|  |  | ||||||
|  |     s = &pit->channels[0]; | ||||||
|  |     s->irq_timer = qemu_new_timer(vm_clock, dummy_timer, s); | ||||||
|  |     vmstate_pit.pre_save = kvm_pit_pre_save; | ||||||
|  |     vmstate_pit.post_load = kvm_pit_post_load; | ||||||
|  |     vmstate_register(base, &vmstate_pit, pit); | ||||||
|  |     qemu_register_reset(pit_reset, pit); | ||||||
|  |     pit_reset(pit); | ||||||
|  |  | ||||||
|  |     return pit; | ||||||
|  | } | ||||||
							
								
								
									
										137
									
								
								hw/i8254.c
									
									
									
									
									
								
							
							
						
						
									
										137
									
								
								hw/i8254.c
									
									
									
									
									
								
							| @@ -25,38 +25,11 @@ | |||||||
| #include "pc.h" | #include "pc.h" | ||||||
| #include "isa.h" | #include "isa.h" | ||||||
| #include "qemu-timer.h" | #include "qemu-timer.h" | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  | #include "i8254.h" | ||||||
|  |  | ||||||
| //#define DEBUG_PIT | //#define DEBUG_PIT | ||||||
|  |  | ||||||
| #define RW_STATE_LSB 1 |  | ||||||
| #define RW_STATE_MSB 2 |  | ||||||
| #define RW_STATE_WORD0 3 |  | ||||||
| #define RW_STATE_WORD1 4 |  | ||||||
|  |  | ||||||
| typedef struct PITChannelState { |  | ||||||
|     int count; /* can be 65536 */ |  | ||||||
|     uint16_t latched_count; |  | ||||||
|     uint8_t count_latched; |  | ||||||
|     uint8_t status_latched; |  | ||||||
|     uint8_t status; |  | ||||||
|     uint8_t read_state; |  | ||||||
|     uint8_t write_state; |  | ||||||
|     uint8_t write_latch; |  | ||||||
|     uint8_t rw_mode; |  | ||||||
|     uint8_t mode; |  | ||||||
|     uint8_t bcd; /* not supported */ |  | ||||||
|     uint8_t gate; /* timer start */ |  | ||||||
|     int64_t count_load_time; |  | ||||||
|     /* irq handling */ |  | ||||||
|     int64_t next_transition_time; |  | ||||||
|     QEMUTimer *irq_timer; |  | ||||||
|     qemu_irq irq; |  | ||||||
| } PITChannelState; |  | ||||||
|  |  | ||||||
| struct PITState { |  | ||||||
|     PITChannelState channels[3]; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| static PITState pit_state; | static PITState pit_state; | ||||||
|  |  | ||||||
| static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); | static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); | ||||||
| @@ -228,13 +201,18 @@ int pit_get_mode(PITState *pit, int channel) | |||||||
|     return s->mode; |     return s->mode; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline void pit_load_count(PITChannelState *s, int val) | static inline void pit_load_count(PITState *s, int val, int chan) | ||||||
| { | { | ||||||
|     if (val == 0) |     if (val == 0) | ||||||
|         val = 0x10000; |         val = 0x10000; | ||||||
|     s->count_load_time = qemu_get_clock(vm_clock); |     s->channels[chan].count_load_time = qemu_get_clock(vm_clock); | ||||||
|     s->count = val; |     s->channels[chan].count = val; | ||||||
|     pit_irq_timer_update(s, s->count_load_time); | #ifdef TARGET_I386 | ||||||
|  |     if (chan == 0 && pit_state.flags & PIT_FLAGS_HPET_LEGACY) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |     pit_irq_timer_update(&s->channels[chan], s->channels[chan].count_load_time); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* if already latched, do not latch again */ | /* if already latched, do not latch again */ | ||||||
| @@ -294,17 +272,17 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) | |||||||
|         switch(s->write_state) { |         switch(s->write_state) { | ||||||
|         default: |         default: | ||||||
|         case RW_STATE_LSB: |         case RW_STATE_LSB: | ||||||
|             pit_load_count(s, val); |             pit_load_count(pit, val, addr); | ||||||
|             break; |             break; | ||||||
|         case RW_STATE_MSB: |         case RW_STATE_MSB: | ||||||
|             pit_load_count(s, val << 8); |             pit_load_count(pit, val << 8, addr); | ||||||
|             break; |             break; | ||||||
|         case RW_STATE_WORD0: |         case RW_STATE_WORD0: | ||||||
|             s->write_latch = val; |             s->write_latch = val; | ||||||
|             s->write_state = RW_STATE_WORD1; |             s->write_state = RW_STATE_WORD1; | ||||||
|             break; |             break; | ||||||
|         case RW_STATE_WORD1: |         case RW_STATE_WORD1: | ||||||
|             pit_load_count(s, s->write_latch | (val << 8)); |             pit_load_count(pit, s->write_latch | (val << 8), addr); | ||||||
|             s->write_state = RW_STATE_WORD0; |             s->write_state = RW_STATE_WORD0; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @@ -364,6 +342,11 @@ static uint32_t pit_ioport_read(void *opaque, uint32_t addr) | |||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* global counters for time-drift fix */ | ||||||
|  | int64_t timer_acks=0, timer_interrupts=0, timer_ints_to_push=0; | ||||||
|  |  | ||||||
|  | extern int time_drift_fix; | ||||||
|  |  | ||||||
| static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) | static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) | ||||||
| { | { | ||||||
|     int64_t expire_time; |     int64_t expire_time; | ||||||
| @@ -374,16 +357,35 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) | |||||||
|     expire_time = pit_get_next_transition_time(s, current_time); |     expire_time = pit_get_next_transition_time(s, current_time); | ||||||
|     irq_level = pit_get_out1(s, current_time); |     irq_level = pit_get_out1(s, current_time); | ||||||
|     qemu_set_irq(s->irq, irq_level); |     qemu_set_irq(s->irq, irq_level); | ||||||
|  |     if (time_drift_fix && irq_level==1) { | ||||||
|  |         /* FIXME: fine tune timer_max_fix (max fix per tick).  | ||||||
|  |          *        Should it be 1 (double time), 2 , 4, 10 ?  | ||||||
|  |          *        Currently setting it to 5% of PIT-ticks-per-second (per PIT-tick) | ||||||
|  |          */ | ||||||
|  |         const long pit_ticks_per_sec = (s->count>0) ? (PIT_FREQ/s->count) : 0; | ||||||
|  |         const long timer_max_fix = pit_ticks_per_sec/20; | ||||||
|  |         const long delta = timer_interrupts - timer_acks; | ||||||
|  |         const long max_delta = pit_ticks_per_sec * 60; /* one minute */ | ||||||
|  |         if ((delta >  max_delta) && (pit_ticks_per_sec > 0)) { | ||||||
|  |             printf("time drift is too long, %ld seconds were lost\n", delta/pit_ticks_per_sec); | ||||||
|  |             timer_acks = timer_interrupts; | ||||||
|  |             timer_ints_to_push = 0; | ||||||
|  |         } else if (delta > 0) { | ||||||
|  |             timer_ints_to_push = MIN(delta, timer_max_fix); | ||||||
|  |         } | ||||||
|  |         timer_interrupts++; | ||||||
|  |     } | ||||||
| #ifdef DEBUG_PIT | #ifdef DEBUG_PIT | ||||||
|     printf("irq_level=%d next_delay=%f\n", |     printf("irq_level=%d next_delay=%f\n", | ||||||
|            irq_level, |            irq_level, | ||||||
|            (double)(expire_time - current_time) / get_ticks_per_sec()); |            (double)(expire_time - current_time) / get_ticks_per_sec()); | ||||||
| #endif | #endif | ||||||
|     s->next_transition_time = expire_time; |     s->next_transition_time = expire_time; | ||||||
|     if (expire_time != -1) |     if (expire_time != -1) { | ||||||
|         qemu_mod_timer(s->irq_timer, expire_time); |         qemu_mod_timer(s->irq_timer, expire_time); | ||||||
|     else |     } else { | ||||||
|         qemu_del_timer(s->irq_timer); |         qemu_del_timer(s->irq_timer); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static void pit_irq_timer(void *opaque) | static void pit_irq_timer(void *opaque) | ||||||
| @@ -423,9 +425,10 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id) | |||||||
|     PITChannelState *s; |     PITChannelState *s; | ||||||
|     int i; |     int i; | ||||||
|  |  | ||||||
|     if (version_id != 1) |     if (version_id != PIT_SAVEVM_VERSION) | ||||||
|         return -EINVAL; |         return -EINVAL; | ||||||
|  |  | ||||||
|  |     pit->flags = qemu_get_be32(f); | ||||||
|     for(i = 0; i < 3; i++) { |     for(i = 0; i < 3; i++) { | ||||||
|         s = &pit->channels[i]; |         s = &pit->channels[i]; | ||||||
|         s->count=qemu_get_be32(f); |         s->count=qemu_get_be32(f); | ||||||
| @@ -446,57 +449,85 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id) | |||||||
|             qemu_get_timer(f, s->irq_timer); |             qemu_get_timer(f, s->irq_timer); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static const VMStateDescription vmstate_pit = { | VMStateDescription vmstate_pit = { | ||||||
|     .name = "i8254", |     .name = "i8254", | ||||||
|     .version_id = 2, |     .version_id = 2, | ||||||
|     .minimum_version_id = 2, |     .minimum_version_id = 2, | ||||||
|     .minimum_version_id_old = 1, |     .minimum_version_id_old = 1, | ||||||
|     .load_state_old = pit_load_old, |     .load_state_old = pit_load_old, | ||||||
|     .fields      = (VMStateField []) { |     .fields      = (VMStateField []) { | ||||||
|  |         VMSTATE_UINT32(flags, PITState), | ||||||
|         VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState), |         VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState), | ||||||
|         VMSTATE_TIMER(channels[0].irq_timer, PITState), |         VMSTATE_TIMER(channels[0].irq_timer, PITState), | ||||||
|         VMSTATE_END_OF_LIST() |         VMSTATE_END_OF_LIST() | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static void pit_reset(void *opaque) | void pit_reset(void *opaque) | ||||||
| { | { | ||||||
|     PITState *pit = opaque; |     PITState *pit = opaque; | ||||||
|     PITChannelState *s; |     PITChannelState *s; | ||||||
|     int i; |     int i; | ||||||
|  |  | ||||||
|  | #ifdef TARGET_I386 | ||||||
|  |     pit->flags &= ~PIT_FLAGS_HPET_LEGACY; | ||||||
|  | #endif | ||||||
|     for(i = 0;i < 3; i++) { |     for(i = 0;i < 3; i++) { | ||||||
|         s = &pit->channels[i]; |         s = &pit->channels[i]; | ||||||
|         s->mode = 3; |         s->mode = 3; | ||||||
|         s->gate = (i != 2); |         s->gate = (i != 2); | ||||||
|         pit_load_count(s, 0); |         pit_load_count(pit, 0, i); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #ifdef TARGET_I386 | ||||||
| /* When HPET is operating in legacy mode, i8254 timer0 is disabled */ | /* When HPET is operating in legacy mode, i8254 timer0 is disabled */ | ||||||
| void hpet_pit_disable(void) { |  | ||||||
|     PITChannelState *s; | void hpet_disable_pit(void) | ||||||
|     s = &pit_state.channels[0]; | { | ||||||
|     if (s->irq_timer) |     PITChannelState *s = &pit_state.channels[0]; | ||||||
|         qemu_del_timer(s->irq_timer); |  | ||||||
|  |     if (kvm_enabled() && qemu_kvm_pit_in_kernel()) { | ||||||
|  |         if (qemu_kvm_has_pit_state2()) { | ||||||
|  |             kvm_hpet_disable_kpit(); | ||||||
|  |         } else { | ||||||
|  |              fprintf(stderr, "%s: kvm does not support pit_state2!\n", __FUNCTION__); | ||||||
|  |              exit(1); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         pit_state.flags |= PIT_FLAGS_HPET_LEGACY; | ||||||
|  |         if (s->irq_timer) { | ||||||
|  |             qemu_del_timer(s->irq_timer); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /* When HPET is reset or leaving legacy mode, it must reenable i8254 | /* When HPET is reset or leaving legacy mode, it must reenable i8254 | ||||||
|  * timer 0 |  * timer 0 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| void hpet_pit_enable(void) | void hpet_enable_pit(void) | ||||||
| { | { | ||||||
|     PITState *pit = &pit_state; |     PITState *pit = &pit_state; | ||||||
|     PITChannelState *s; |     PITChannelState *s = &pit->channels[0]; | ||||||
|     s = &pit->channels[0]; |  | ||||||
|     s->mode = 3; |     if (kvm_enabled() && qemu_kvm_pit_in_kernel()) { | ||||||
|     s->gate = 1; |         if (qemu_kvm_has_pit_state2()) { | ||||||
|     pit_load_count(s, 0); |             kvm_hpet_enable_kpit(); | ||||||
|  |         } else { | ||||||
|  |              fprintf(stderr, "%s: kvm does not support pit_state2!\n", __FUNCTION__); | ||||||
|  |              exit(1); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         pit_state.flags &= ~PIT_FLAGS_HPET_LEGACY; | ||||||
|  |         pit_load_count(pit, s->count, 0); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| PITState *pit_init(int base, qemu_irq irq) | PITState *pit_init(int base, qemu_irq irq) | ||||||
| { | { | ||||||
|   | |||||||
							
								
								
									
										69
									
								
								hw/i8254.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								hw/i8254.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU 8253/8254 interval timer emulation | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2004 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef QEMU_I8254_H | ||||||
|  | #define QEMU_I8254_H | ||||||
|  |  | ||||||
|  | #define PIT_SAVEVM_NAME "i8254" | ||||||
|  | #define PIT_SAVEVM_VERSION 2 | ||||||
|  |  | ||||||
|  | #define RW_STATE_LSB 1 | ||||||
|  | #define RW_STATE_MSB 2 | ||||||
|  | #define RW_STATE_WORD0 3 | ||||||
|  | #define RW_STATE_WORD1 4 | ||||||
|  |  | ||||||
|  | #define PIT_FLAGS_HPET_LEGACY  1 | ||||||
|  |  | ||||||
|  | typedef struct PITChannelState { | ||||||
|  |     int count; /* can be 65536 */ | ||||||
|  |     uint16_t latched_count; | ||||||
|  |     uint8_t count_latched; | ||||||
|  |     uint8_t status_latched; | ||||||
|  |     uint8_t status; | ||||||
|  |     uint8_t read_state; | ||||||
|  |     uint8_t write_state; | ||||||
|  |     uint8_t write_latch; | ||||||
|  |     uint8_t rw_mode; | ||||||
|  |     uint8_t mode; | ||||||
|  |     uint8_t bcd; /* not supported */ | ||||||
|  |     uint8_t gate; /* timer start */ | ||||||
|  |     int64_t count_load_time; | ||||||
|  |     /* irq handling */ | ||||||
|  |     int64_t next_transition_time; | ||||||
|  |     QEMUTimer *irq_timer; | ||||||
|  |     qemu_irq irq; | ||||||
|  | } PITChannelState; | ||||||
|  |  | ||||||
|  | struct PITState { | ||||||
|  |     PITChannelState channels[3]; | ||||||
|  |     uint32_t flags; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | void pit_save(QEMUFile *f, void *opaque); | ||||||
|  |  | ||||||
|  | int pit_load(QEMUFile *f, void *opaque, int version_id); | ||||||
|  |  | ||||||
|  | void pit_reset(void *opaque); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										144
									
								
								hw/i8259.c
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								hw/i8259.c
									
									
									
									
									
								
							| @@ -27,6 +27,8 @@ | |||||||
| #include "monitor.h" | #include "monitor.h" | ||||||
| #include "qemu-timer.h" | #include "qemu-timer.h" | ||||||
|  |  | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| /* debug PIC */ | /* debug PIC */ | ||||||
| //#define DEBUG_PIC | //#define DEBUG_PIC | ||||||
|  |  | ||||||
| @@ -181,7 +183,6 @@ int64_t irq_time[16]; | |||||||
| static void i8259_set_irq(void *opaque, int irq, int level) | static void i8259_set_irq(void *opaque, int irq, int level) | ||||||
| { | { | ||||||
|     PicState2 *s = opaque; |     PicState2 *s = opaque; | ||||||
|  |  | ||||||
| #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) | #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) | ||||||
|     if (level != irq_level[irq]) { |     if (level != irq_level[irq]) { | ||||||
| #if defined(DEBUG_PIC) | #if defined(DEBUG_PIC) | ||||||
| @@ -212,18 +213,35 @@ static inline void pic_intack(PicState *s, int irq) | |||||||
|     } else { |     } else { | ||||||
|         s->isr |= (1 << irq); |         s->isr |= (1 << irq); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* We don't clear a level sensitive interrupt here */ |     /* We don't clear a level sensitive interrupt here */ | ||||||
|     if (!(s->elcr & (1 << irq))) |     if (!(s->elcr & (1 << irq))) | ||||||
|         s->irr &= ~(1 << irq); |         s->irr &= ~(1 << irq); | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | extern int time_drift_fix; | ||||||
|  |  | ||||||
| int pic_read_irq(PicState2 *s) | int pic_read_irq(PicState2 *s) | ||||||
| { | { | ||||||
|     int irq, irq2, intno; |     int irq, irq2, intno; | ||||||
|  |  | ||||||
|     irq = pic_get_irq(&s->pics[0]); |     irq = pic_get_irq(&s->pics[0]); | ||||||
|     if (irq >= 0) { |     if (irq >= 0) { | ||||||
|  |  | ||||||
|         pic_intack(&s->pics[0], irq); |         pic_intack(&s->pics[0], irq); | ||||||
|  | #ifndef TARGET_IA64 | ||||||
|  | 	if (time_drift_fix && irq == 0) { | ||||||
|  | 	    extern int64_t timer_acks, timer_ints_to_push; | ||||||
|  | 	    timer_acks++; | ||||||
|  | 	    if (timer_ints_to_push > 0) { | ||||||
|  | 		timer_ints_to_push--; | ||||||
|  |                 /* simulate an edge irq0, like the one generated by i8254 */ | ||||||
|  |                 pic_set_irq1(&s->pics[0], 0, 0); | ||||||
|  |                 pic_set_irq1(&s->pics[0], 0, 1); | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|         if (irq == 2) { |         if (irq == 2) { | ||||||
|             irq2 = pic_get_irq(&s->pics[1]); |             irq2 = pic_get_irq(&s->pics[1]); | ||||||
|             if (irq2 >= 0) { |             if (irq2 >= 0) { | ||||||
| @@ -446,9 +464,33 @@ static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1) | |||||||
|     return s->elcr; |     return s->elcr; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void kvm_kernel_pic_save_to_user(PicState *s); | ||||||
|  | static int kvm_kernel_pic_load_from_user(PicState *s); | ||||||
|  |  | ||||||
|  | static void pic_pre_save(void *opaque) | ||||||
|  | { | ||||||
|  |     PicState *s = opaque; | ||||||
|  |  | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         kvm_kernel_pic_save_to_user(s); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int pic_post_load(void *opaque, int version_id) | ||||||
|  | { | ||||||
|  |     PicState *s = opaque; | ||||||
|  |  | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         kvm_kernel_pic_load_from_user(s); | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| static const VMStateDescription vmstate_pic = { | static const VMStateDescription vmstate_pic = { | ||||||
|     .name = "i8259", |     .name = "i8259", | ||||||
|     .version_id = 1, |     .version_id = 1, | ||||||
|  |     .pre_save = pic_pre_save, | ||||||
|  |     .post_load = pic_post_load, | ||||||
|     .minimum_version_id = 1, |     .minimum_version_id = 1, | ||||||
|     .minimum_version_id_old = 1, |     .minimum_version_id_old = 1, | ||||||
|     .fields      = (VMStateField []) { |     .fields      = (VMStateField []) { | ||||||
| @@ -535,3 +577,103 @@ qemu_irq *i8259_init(qemu_irq parent_irq) | |||||||
|     isa_pic = s; |     isa_pic = s; | ||||||
|     return qemu_allocate_irqs(i8259_set_irq, s, 16); |     return qemu_allocate_irqs(i8259_set_irq, s, 16); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void kvm_kernel_pic_save_to_user(PicState *s) | ||||||
|  | { | ||||||
|  | #ifdef KVM_CAP_IRQCHIP | ||||||
|  |     struct kvm_irqchip chip; | ||||||
|  |     struct kvm_pic_state *kpic; | ||||||
|  |  | ||||||
|  |     chip.chip_id = (&s->pics_state->pics[0] == s) ? | ||||||
|  |                    KVM_IRQCHIP_PIC_MASTER : | ||||||
|  |                    KVM_IRQCHIP_PIC_SLAVE; | ||||||
|  |     kvm_get_irqchip(kvm_context, &chip); | ||||||
|  |     kpic = &chip.chip.pic; | ||||||
|  |  | ||||||
|  |     s->last_irr = kpic->last_irr; | ||||||
|  |     s->irr = kpic->irr; | ||||||
|  |     s->imr = kpic->imr; | ||||||
|  |     s->isr = kpic->isr; | ||||||
|  |     s->priority_add = kpic->priority_add; | ||||||
|  |     s->irq_base = kpic->irq_base; | ||||||
|  |     s->read_reg_select = kpic->read_reg_select; | ||||||
|  |     s->poll = kpic->poll; | ||||||
|  |     s->special_mask = kpic->special_mask; | ||||||
|  |     s->init_state = kpic->init_state; | ||||||
|  |     s->auto_eoi = kpic->auto_eoi; | ||||||
|  |     s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi; | ||||||
|  |     s->special_fully_nested_mode = kpic->special_fully_nested_mode; | ||||||
|  |     s->init4 = kpic->init4; | ||||||
|  |     s->elcr = kpic->elcr; | ||||||
|  |     s->elcr_mask = kpic->elcr_mask; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int kvm_kernel_pic_load_from_user(PicState *s) | ||||||
|  | { | ||||||
|  | #ifdef KVM_CAP_IRQCHIP | ||||||
|  |     struct kvm_irqchip chip; | ||||||
|  |     struct kvm_pic_state *kpic; | ||||||
|  |  | ||||||
|  |     chip.chip_id = (&s->pics_state->pics[0] == s) ? | ||||||
|  |                    KVM_IRQCHIP_PIC_MASTER : | ||||||
|  |                    KVM_IRQCHIP_PIC_SLAVE; | ||||||
|  |     kpic = &chip.chip.pic; | ||||||
|  |  | ||||||
|  |     kpic->last_irr = s->last_irr; | ||||||
|  |     kpic->irr = s->irr; | ||||||
|  |     kpic->imr = s->imr; | ||||||
|  |     kpic->isr = s->isr; | ||||||
|  |     kpic->priority_add = s->priority_add; | ||||||
|  |     kpic->irq_base = s->irq_base; | ||||||
|  |     kpic->read_reg_select = s->read_reg_select; | ||||||
|  |     kpic->poll = s->poll; | ||||||
|  |     kpic->special_mask = s->special_mask; | ||||||
|  |     kpic->init_state = s->init_state; | ||||||
|  |     kpic->auto_eoi = s->auto_eoi; | ||||||
|  |     kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi; | ||||||
|  |     kpic->special_fully_nested_mode = s->special_fully_nested_mode; | ||||||
|  |     kpic->init4 = s->init4; | ||||||
|  |     kpic->elcr = s->elcr; | ||||||
|  |     kpic->elcr_mask = s->elcr_mask; | ||||||
|  |  | ||||||
|  |     kvm_set_irqchip(kvm_context, &chip); | ||||||
|  | #endif | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #ifdef KVM_CAP_IRQCHIP | ||||||
|  | static void kvm_i8259_set_irq(void *opaque, int irq, int level) | ||||||
|  | { | ||||||
|  |     int pic_ret; | ||||||
|  |     if (kvm_set_irq(irq, level, &pic_ret)) { | ||||||
|  |         if (pic_ret != 0) | ||||||
|  |             apic_set_irq_delivered(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void kvm_pic_init1(int io_addr, PicState *s) | ||||||
|  | { | ||||||
|  |     vmstate_register(io_addr, &vmstate_pic, s); | ||||||
|  |     qemu_register_reset(pic_reset, s); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | qemu_irq *kvm_i8259_init(qemu_irq parent_irq) | ||||||
|  | { | ||||||
|  |     PicState2 *s; | ||||||
|  |  | ||||||
|  |     s = qemu_mallocz(sizeof(PicState2)); | ||||||
|  |  | ||||||
|  |     kvm_pic_init1(0x20, &s->pics[0]); | ||||||
|  |     kvm_pic_init1(0xa0, &s->pics[1]); | ||||||
|  |     s->parent_irq = parent_irq; | ||||||
|  |     s->pics[0].pics_state = s; | ||||||
|  |     s->pics[1].pics_state = s; | ||||||
|  |     isa_pic = s; | ||||||
|  |     return qemu_allocate_irqs(kvm_i8259_set_irq, s, 24); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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() | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| @@ -2767,10 +2827,6 @@ static void ide_dma_restart(IDEState *s, int is_read) | |||||||
| void ide_dma_cancel(BMDMAState *bm) | void ide_dma_cancel(BMDMAState *bm) | ||||||
| { | { | ||||||
|     if (bm->status & BM_STATUS_DMAING) { |     if (bm->status & BM_STATUS_DMAING) { | ||||||
|         bm->status &= ~BM_STATUS_DMAING; |  | ||||||
|         /* cancel DMA request */ |  | ||||||
|         bm->unit = -1; |  | ||||||
|         bm->dma_cb = NULL; |  | ||||||
|         if (bm->aiocb) { |         if (bm->aiocb) { | ||||||
| #ifdef DEBUG_AIO | #ifdef DEBUG_AIO | ||||||
|             printf("aio_cancel\n"); |             printf("aio_cancel\n"); | ||||||
| @@ -2778,6 +2834,10 @@ void ide_dma_cancel(BMDMAState *bm) | |||||||
|             bdrv_aio_cancel(bm->aiocb); |             bdrv_aio_cancel(bm->aiocb); | ||||||
|             bm->aiocb = NULL; |             bm->aiocb = NULL; | ||||||
|         } |         } | ||||||
|  |         bm->status &= ~BM_STATUS_DMAING; | ||||||
|  |         /* cancel DMA request */ | ||||||
|  |         bm->unit = -1; | ||||||
|  |         bm->dma_cb = NULL; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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(), | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										93
									
								
								hw/ioapic.c
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								hw/ioapic.c
									
									
									
									
									
								
							| @@ -22,12 +22,16 @@ | |||||||
|  |  | ||||||
| #include "hw.h" | #include "hw.h" | ||||||
| #include "pc.h" | #include "pc.h" | ||||||
|  | #include "sysemu.h" | ||||||
| #include "qemu-timer.h" | #include "qemu-timer.h" | ||||||
| #include "host-utils.h" | #include "host-utils.h" | ||||||
|  |  | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| //#define DEBUG_IOAPIC | //#define DEBUG_IOAPIC | ||||||
|  |  | ||||||
| #define IOAPIC_NUM_PINS			0x18 | #define IOAPIC_NUM_PINS			0x18 | ||||||
|  | #define IOAPIC_DEFAULT_BASE_ADDRESS  0xfec00000 | ||||||
| #define IOAPIC_LVT_MASKED 		(1<<16) | #define IOAPIC_LVT_MASKED 		(1<<16) | ||||||
|  |  | ||||||
| #define IOAPIC_TRIGGER_EDGE		0 | #define IOAPIC_TRIGGER_EDGE		0 | ||||||
| @@ -45,6 +49,7 @@ | |||||||
| struct IOAPICState { | struct IOAPICState { | ||||||
|     uint8_t id; |     uint8_t id; | ||||||
|     uint8_t ioregsel; |     uint8_t ioregsel; | ||||||
|  |     uint64_t base_address; | ||||||
|  |  | ||||||
|     uint32_t irr; |     uint32_t irr; | ||||||
|     uint64_t ioredtbl[IOAPIC_NUM_PINS]; |     uint64_t ioredtbl[IOAPIC_NUM_PINS]; | ||||||
| @@ -94,8 +99,9 @@ void ioapic_set_irq(void *opaque, int vector, int level) | |||||||
|      * to GSI 2.  GSI maps to ioapic 1-1.  This is not |      * to GSI 2.  GSI maps to ioapic 1-1.  This is not | ||||||
|      * the cleanest way of doing it but it should work. */ |      * the cleanest way of doing it but it should work. */ | ||||||
|  |  | ||||||
|     if (vector == 0) |     if (vector == 0 && irq0override) { | ||||||
|         vector = 2; |         vector = 2; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (vector >= 0 && vector < IOAPIC_NUM_PINS) { |     if (vector >= 0 && vector < IOAPIC_NUM_PINS) { | ||||||
|         uint32_t mask = 1 << vector; |         uint32_t mask = 1 << vector; | ||||||
| @@ -191,14 +197,91 @@ static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void kvm_kernel_ioapic_save_to_user(IOAPICState *s) | ||||||
|  | { | ||||||
|  | #if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386) | ||||||
|  |     struct kvm_irqchip chip; | ||||||
|  |     struct kvm_ioapic_state *kioapic; | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     chip.chip_id = KVM_IRQCHIP_IOAPIC; | ||||||
|  |     kvm_get_irqchip(kvm_context, &chip); | ||||||
|  |     kioapic = &chip.chip.ioapic; | ||||||
|  |  | ||||||
|  |     s->id = kioapic->id; | ||||||
|  |     s->ioregsel = kioapic->ioregsel; | ||||||
|  |     s->base_address = kioapic->base_address; | ||||||
|  |     s->irr = kioapic->irr; | ||||||
|  |     for (i = 0; i < IOAPIC_NUM_PINS; i++) { | ||||||
|  |         s->ioredtbl[i] = kioapic->redirtbl[i].bits; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void kvm_kernel_ioapic_load_from_user(IOAPICState *s) | ||||||
|  | { | ||||||
|  | #if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386) | ||||||
|  |     struct kvm_irqchip chip; | ||||||
|  |     struct kvm_ioapic_state *kioapic; | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     chip.chip_id = KVM_IRQCHIP_IOAPIC; | ||||||
|  |     kioapic = &chip.chip.ioapic; | ||||||
|  |  | ||||||
|  |     kioapic->id = s->id; | ||||||
|  |     kioapic->ioregsel = s->ioregsel; | ||||||
|  |     kioapic->base_address = s->base_address; | ||||||
|  |     kioapic->irr = s->irr; | ||||||
|  |     for (i = 0; i < IOAPIC_NUM_PINS; i++) { | ||||||
|  |         kioapic->redirtbl[i].bits = s->ioredtbl[i]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     kvm_set_irqchip(kvm_context, &chip); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void ioapic_pre_save(void *opaque) | ||||||
|  | { | ||||||
|  |     IOAPICState *s = (void *)opaque; | ||||||
|  |   | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         kvm_kernel_ioapic_save_to_user(s); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int ioapic_pre_load(void *opaque) | ||||||
|  | { | ||||||
|  |     IOAPICState *s = opaque; | ||||||
|  |  | ||||||
|  |     /* in case we are doing version 1, we just set these to sane values */ | ||||||
|  |     s->base_address = IOAPIC_DEFAULT_BASE_ADDRESS; | ||||||
|  |     s->irr = 0; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int ioapic_post_load(void *opaque, int version_id) | ||||||
|  | { | ||||||
|  |     IOAPICState *s = opaque; | ||||||
|  |  | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         kvm_kernel_ioapic_load_from_user(s); | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| static const VMStateDescription vmstate_ioapic = { | static const VMStateDescription vmstate_ioapic = { | ||||||
|     .name = "ioapic", |     .name = "ioapic", | ||||||
|     .version_id = 1, |     .version_id = 2, | ||||||
|     .minimum_version_id = 1, |     .minimum_version_id = 1, | ||||||
|     .minimum_version_id_old = 1, |     .minimum_version_id_old = 1, | ||||||
|  |     .pre_load = ioapic_pre_load, | ||||||
|  |     .post_load = ioapic_post_load, | ||||||
|  |     .pre_save = ioapic_pre_save, | ||||||
|     .fields      = (VMStateField []) { |     .fields      = (VMStateField []) { | ||||||
|         VMSTATE_UINT8(id, IOAPICState), |         VMSTATE_UINT8(id, IOAPICState), | ||||||
|         VMSTATE_UINT8(ioregsel, IOAPICState), |         VMSTATE_UINT8(ioregsel, IOAPICState), | ||||||
|  |         VMSTATE_UINT64_V(base_address, IOAPICState, 2), | ||||||
|  |         VMSTATE_UINT32_V(irr, IOAPICState, 2), | ||||||
|         VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS), |         VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS), | ||||||
|         VMSTATE_END_OF_LIST() |         VMSTATE_END_OF_LIST() | ||||||
|     } |     } | ||||||
| @@ -210,8 +293,14 @@ static void ioapic_reset(void *opaque) | |||||||
|     int i; |     int i; | ||||||
|  |  | ||||||
|     memset(s, 0, sizeof(*s)); |     memset(s, 0, sizeof(*s)); | ||||||
|  |     s->base_address = IOAPIC_DEFAULT_BASE_ADDRESS; | ||||||
|     for(i = 0; i < IOAPIC_NUM_PINS; i++) |     for(i = 0; i < IOAPIC_NUM_PINS; i++) | ||||||
|         s->ioredtbl[i] = 1 << 16; /* mask LVT */ |         s->ioredtbl[i] = 1 << 16; /* mask LVT */ | ||||||
|  | #ifdef KVM_CAP_IRQCHIP | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         kvm_kernel_ioapic_load_from_user(s); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| static CPUReadMemoryFunc * const ioapic_mem_read[3] = { | static CPUReadMemoryFunc * const ioapic_mem_read[3] = { | ||||||
|   | |||||||
							
								
								
									
										713
									
								
								hw/ipf.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										713
									
								
								hw/ipf.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,713 @@ | |||||||
|  | /* | ||||||
|  |  * Itanium Platform Emulator derived from QEMU PC System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2004 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2007 Intel | ||||||
|  |  * Ported for IA64 Platform Zhang Xiantao <xiantao.zhang@intel.com> | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "hw.h" | ||||||
|  | #include "pc.h" | ||||||
|  | #include "fdc.h" | ||||||
|  | #include "pci.h" | ||||||
|  | #include "block.h" | ||||||
|  | #include "sysemu.h" | ||||||
|  | #include "audio/audio.h" | ||||||
|  | #include "net.h" | ||||||
|  | #include "smbus.h" | ||||||
|  | #include "boards.h" | ||||||
|  | #include "firmware.h" | ||||||
|  | #include "ia64intrin.h" | ||||||
|  | #include <unistd.h> | ||||||
|  | #include "device-assignment.h" | ||||||
|  | #include "virtio-blk.h" | ||||||
|  |  | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
|  | #define FW_FILENAME "Flash.fd" | ||||||
|  |  | ||||||
|  | /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */ | ||||||
|  | #define ACPI_DATA_SIZE       0x10000 | ||||||
|  |  | ||||||
|  | #define MAX_IDE_BUS 2 | ||||||
|  |  | ||||||
|  | static fdctrl_t *floppy_controller; | ||||||
|  | static RTCState *rtc_state; | ||||||
|  | static PCIDevice *i440fx_state; | ||||||
|  |  | ||||||
|  | static uint32_t ipf_to_legacy_io(target_phys_addr_t addr) | ||||||
|  | { | ||||||
|  |     return (uint32_t)(((addr&0x3ffffff) >> 12 << 2)|((addr) & 0x3)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void ipf_legacy_io_writeb(void *opaque, target_phys_addr_t addr, | ||||||
|  | 				 uint32_t val) { | ||||||
|  |     uint32_t port = ipf_to_legacy_io(addr); | ||||||
|  |  | ||||||
|  |     cpu_outb(0, port, val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void ipf_legacy_io_writew(void *opaque, target_phys_addr_t addr, | ||||||
|  | 				 uint32_t val) { | ||||||
|  |     uint32_t port = ipf_to_legacy_io(addr); | ||||||
|  |  | ||||||
|  |     cpu_outw(0, port, val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void ipf_legacy_io_writel(void *opaque, target_phys_addr_t addr, | ||||||
|  | 				 uint32_t val) { | ||||||
|  |     uint32_t port = ipf_to_legacy_io(addr); | ||||||
|  |  | ||||||
|  |     cpu_outl(0, port, val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static uint32_t ipf_legacy_io_readb(void *opaque, target_phys_addr_t addr) | ||||||
|  | { | ||||||
|  |     uint32_t port = ipf_to_legacy_io(addr); | ||||||
|  |  | ||||||
|  |     return cpu_inb(0, port); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static uint32_t ipf_legacy_io_readw(void *opaque, target_phys_addr_t addr) | ||||||
|  | { | ||||||
|  |     uint32_t port = ipf_to_legacy_io(addr); | ||||||
|  |  | ||||||
|  |     return cpu_inw(0, port); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static uint32_t ipf_legacy_io_readl(void *opaque, target_phys_addr_t addr) | ||||||
|  | { | ||||||
|  |     uint32_t port = ipf_to_legacy_io(addr); | ||||||
|  |  | ||||||
|  |     return cpu_inl(0, port); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static CPUReadMemoryFunc *ipf_legacy_io_read[3] = { | ||||||
|  |     ipf_legacy_io_readb, | ||||||
|  |     ipf_legacy_io_readw, | ||||||
|  |     ipf_legacy_io_readl, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static CPUWriteMemoryFunc *ipf_legacy_io_write[3] = { | ||||||
|  |     ipf_legacy_io_writeb, | ||||||
|  |     ipf_legacy_io_writew, | ||||||
|  |     ipf_legacy_io_writel, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void pic_irq_request(void *opaque, int irq, int level) | ||||||
|  | { | ||||||
|  |     fprintf(stderr,"pic_irq_request called!\n"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* PC cmos mappings */ | ||||||
|  |  | ||||||
|  | #define REG_EQUIPMENT_BYTE          0x14 | ||||||
|  |  | ||||||
|  | static int cmos_get_fd_drive_type(int fd0) | ||||||
|  | { | ||||||
|  |     int val; | ||||||
|  |  | ||||||
|  |     switch (fd0) { | ||||||
|  |     case 0: | ||||||
|  |         /* 1.44 Mb 3"5 drive */ | ||||||
|  |         val = 4; | ||||||
|  |         break; | ||||||
|  |     case 1: | ||||||
|  |         /* 2.88 Mb 3"5 drive */ | ||||||
|  |         val = 5; | ||||||
|  |         break; | ||||||
|  |     case 2: | ||||||
|  |         /* 1.2 Mb 5"5 drive */ | ||||||
|  |         val = 2; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         val = 0; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     return val; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd) | ||||||
|  | { | ||||||
|  |     RTCState *s = rtc_state; | ||||||
|  |     int cylinders, heads, sectors; | ||||||
|  |  | ||||||
|  |     bdrv_get_geometry_hint(hd, &cylinders, &heads, §ors); | ||||||
|  |     rtc_set_memory(s, type_ofs, 47); | ||||||
|  |     rtc_set_memory(s, info_ofs, cylinders); | ||||||
|  |     rtc_set_memory(s, info_ofs + 1, cylinders >> 8); | ||||||
|  |     rtc_set_memory(s, info_ofs + 2, heads); | ||||||
|  |     rtc_set_memory(s, info_ofs + 3, 0xff); | ||||||
|  |     rtc_set_memory(s, info_ofs + 4, 0xff); | ||||||
|  |     rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3)); | ||||||
|  |     rtc_set_memory(s, info_ofs + 6, cylinders); | ||||||
|  |     rtc_set_memory(s, info_ofs + 7, cylinders >> 8); | ||||||
|  |     rtc_set_memory(s, info_ofs + 8, sectors); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* convert boot_device letter to something recognizable by the bios */ | ||||||
|  | static int boot_device2nibble(char boot_device) | ||||||
|  | { | ||||||
|  |     switch(boot_device) { | ||||||
|  |     case 'a': | ||||||
|  |     case 'b': | ||||||
|  |         return 0x01; /* floppy boot */ | ||||||
|  |     case 'c': | ||||||
|  |         return 0x02; /* hard drive boot */ | ||||||
|  |     case 'd': | ||||||
|  |         return 0x03; /* CD-ROM boot */ | ||||||
|  |     case 'n': | ||||||
|  |         return 0x04; /* Network boot */ | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* hd_table must contain 4 block drivers */ | ||||||
|  | static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, | ||||||
|  |                       const char *boot_device, BlockDriverState **hd_table) | ||||||
|  | { | ||||||
|  |     RTCState *s = rtc_state; | ||||||
|  |     int nbds, bds[3] = { 0, }; | ||||||
|  |     int val; | ||||||
|  |     int fd0, fd1, nb; | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     /* various important CMOS locations needed by PC/Bochs bios */ | ||||||
|  |  | ||||||
|  |     /* memory size */ | ||||||
|  |     val = 640; /* base memory in K */ | ||||||
|  |     rtc_set_memory(s, 0x15, val); | ||||||
|  |     rtc_set_memory(s, 0x16, val >> 8); | ||||||
|  |  | ||||||
|  |     val = (ram_size / 1024) - 1024; | ||||||
|  |     if (val > 65535) | ||||||
|  |         val = 65535; | ||||||
|  |     rtc_set_memory(s, 0x17, val); | ||||||
|  |     rtc_set_memory(s, 0x18, val >> 8); | ||||||
|  |     rtc_set_memory(s, 0x30, val); | ||||||
|  |     rtc_set_memory(s, 0x31, val >> 8); | ||||||
|  |  | ||||||
|  |     if (above_4g_mem_size) { | ||||||
|  |         rtc_set_memory(s, 0x5b, (unsigned int)above_4g_mem_size >> 16); | ||||||
|  |         rtc_set_memory(s, 0x5c, (unsigned int)above_4g_mem_size >> 24); | ||||||
|  |         rtc_set_memory(s, 0x5d, above_4g_mem_size >> 32); | ||||||
|  |     } | ||||||
|  |     rtc_set_memory(s, 0x5f, smp_cpus - 1); | ||||||
|  |  | ||||||
|  |     if (ram_size > (16 * 1024 * 1024)) | ||||||
|  |         val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); | ||||||
|  |     else | ||||||
|  |         val = 0; | ||||||
|  |     if (val > 65535) | ||||||
|  |         val = 65535; | ||||||
|  |     rtc_set_memory(s, 0x34, val); | ||||||
|  |     rtc_set_memory(s, 0x35, val >> 8); | ||||||
|  |  | ||||||
|  |     /* set boot devices, and disable floppy signature check if requested */ | ||||||
|  | #define PC_MAX_BOOT_DEVICES 3 | ||||||
|  |     nbds = strlen(boot_device); | ||||||
|  |  | ||||||
|  |     if (nbds > PC_MAX_BOOT_DEVICES) { | ||||||
|  |         fprintf(stderr, "Too many boot devices for PC\n"); | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (i = 0; i < nbds; i++) { | ||||||
|  |         bds[i] = boot_device2nibble(boot_device[i]); | ||||||
|  |         if (bds[i] == 0) { | ||||||
|  |             fprintf(stderr, "Invalid boot device for PC: '%c'\n", | ||||||
|  |                     boot_device[i]); | ||||||
|  |             exit(1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]); | ||||||
|  |     rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ?  0x0 : 0x1)); | ||||||
|  |  | ||||||
|  |     /* floppy type */ | ||||||
|  |  | ||||||
|  |     fd0 = fdctrl_get_drive_type(floppy_controller, 0); | ||||||
|  |     fd1 = fdctrl_get_drive_type(floppy_controller, 1); | ||||||
|  |  | ||||||
|  |     val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1); | ||||||
|  |     rtc_set_memory(s, 0x10, val); | ||||||
|  |  | ||||||
|  |     val = 0; | ||||||
|  |     nb = 0; | ||||||
|  |     if (fd0 < 3) | ||||||
|  |         nb++; | ||||||
|  |     if (fd1 < 3) | ||||||
|  |         nb++; | ||||||
|  |  | ||||||
|  |     switch (nb) { | ||||||
|  |     case 0: | ||||||
|  |         break; | ||||||
|  |     case 1: | ||||||
|  |         val |= 0x01; /* 1 drive, ready for boot */ | ||||||
|  |         break; | ||||||
|  |     case 2: | ||||||
|  |         val |= 0x41; /* 2 drives, ready for boot */ | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     val |= 0x02; /* FPU is there */ | ||||||
|  |     val |= 0x04; /* PS/2 mouse installed */ | ||||||
|  |     rtc_set_memory(s, REG_EQUIPMENT_BYTE, val); | ||||||
|  |  | ||||||
|  |     /* hard drives */ | ||||||
|  |  | ||||||
|  |     rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0)); | ||||||
|  |     if (hd_table[0]) | ||||||
|  |         cmos_init_hd(0x19, 0x1b, hd_table[0]); | ||||||
|  |     if (hd_table[1]) | ||||||
|  |         cmos_init_hd(0x1a, 0x24, hd_table[1]); | ||||||
|  |  | ||||||
|  |     val = 0; | ||||||
|  |     for (i = 0; i < 4; i++) { | ||||||
|  |         if (hd_table[i]) { | ||||||
|  |             int cylinders, heads, sectors, translation; | ||||||
|  |             /* NOTE: bdrv_get_geometry_hint() returns the physical | ||||||
|  |                geometry.  It is always such that: 1 <= sects <= 63, 1 | ||||||
|  |                <= heads <= 16, 1 <= cylinders <= 16383. The BIOS | ||||||
|  |                geometry can be different if a translation is done. */ | ||||||
|  |             translation = bdrv_get_translation_hint(hd_table[i]); | ||||||
|  |             if (translation == BIOS_ATA_TRANSLATION_AUTO) { | ||||||
|  |                 bdrv_get_geometry_hint(hd_table[i], &cylinders, | ||||||
|  |                                        &heads, §ors); | ||||||
|  |                 if (cylinders <= 1024 && heads <= 16 && sectors <= 63) { | ||||||
|  |                     /* No translation. */ | ||||||
|  |                     translation = 0; | ||||||
|  |                 } else { | ||||||
|  |                     /* LBA translation. */ | ||||||
|  |                     translation = 1; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 translation--; | ||||||
|  |             } | ||||||
|  |             val |= translation << (i * 2); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     rtc_set_memory(s, 0x39, val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void main_cpu_reset(void *opaque) | ||||||
|  | { | ||||||
|  |     CPUState *env = opaque; | ||||||
|  |     cpu_reset(env); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const int ide_iobase[2] = { 0x1f0, 0x170 }; | ||||||
|  | static const int ide_iobase2[2] = { 0x3f6, 0x376 }; | ||||||
|  | static const int ide_irq[2] = { 14, 15 }; | ||||||
|  |  | ||||||
|  | #define NE2000_NB_MAX 6 | ||||||
|  |  | ||||||
|  | static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, | ||||||
|  |                                         0x360, 0x280, 0x380 }; | ||||||
|  | static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; | ||||||
|  |  | ||||||
|  | static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; | ||||||
|  | static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; | ||||||
|  |  | ||||||
|  | static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; | ||||||
|  | static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; | ||||||
|  |  | ||||||
|  | #ifdef HAS_AUDIO | ||||||
|  | static void audio_init (PCIBus *pci_bus, qemu_irq *pic) | ||||||
|  | { | ||||||
|  |     struct soundhw *c; | ||||||
|  |     int audio_enabled = 0; | ||||||
|  |  | ||||||
|  |     for (c = soundhw; !audio_enabled && c->name; ++c) { | ||||||
|  |         audio_enabled = c->enabled; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (audio_enabled) { | ||||||
|  |         AudioState *s; | ||||||
|  |  | ||||||
|  |         s = AUD_init (); | ||||||
|  |         if (s) { | ||||||
|  |             for (c = soundhw; c->name; ++c) { | ||||||
|  |                 if (c->enabled) { | ||||||
|  |                     if (c->isa) { | ||||||
|  |                         c->init.init_isa (s, pic); | ||||||
|  |                     } else { | ||||||
|  |                         if (pci_bus) { | ||||||
|  |                             c->init.init_pci (pci_bus, s); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic) | ||||||
|  | { | ||||||
|  |     static int nb_ne2k = 0; | ||||||
|  |  | ||||||
|  |     if (nb_ne2k == NE2000_NB_MAX) | ||||||
|  |         return; | ||||||
|  |     isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd); | ||||||
|  |     nb_ne2k++; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Itanium hardware initialisation */ | ||||||
|  | static void ipf_init1(ram_addr_t ram_size, | ||||||
|  |                       const char *boot_device, DisplayState *ds, | ||||||
|  |                       const char *kernel_filename, const char *kernel_cmdline, | ||||||
|  |                       const char *initrd_filename, | ||||||
|  |                       int pci_enabled, const char *cpu_model) | ||||||
|  | { | ||||||
|  |     char buf[1024]; | ||||||
|  |     int i; | ||||||
|  |     ram_addr_t ram_addr; | ||||||
|  |     ram_addr_t above_4g_mem_size = 0; | ||||||
|  |     PCIBus *pci_bus; | ||||||
|  |     PCIDevice *pci_dev; | ||||||
|  |     int piix3_devfn = -1; | ||||||
|  |     CPUState *env; | ||||||
|  |     qemu_irq *cpu_irq; | ||||||
|  |     qemu_irq *i8259; | ||||||
|  |     int page_size; | ||||||
|  |     int index; | ||||||
|  |     unsigned long ipf_legacy_io_base, ipf_legacy_io_mem; | ||||||
|  |     BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; | ||||||
|  |     BlockDriverState *fd[MAX_FD]; | ||||||
|  |  | ||||||
|  |     page_size = getpagesize(); | ||||||
|  |     if (page_size != TARGET_PAGE_SIZE) { | ||||||
|  | 	fprintf(stderr,"Error! Host page size != qemu target page size," | ||||||
|  |                 " you may need to change TARGET_PAGE_BITS in qemu!" | ||||||
|  |                 "host page size:0x%x\n", page_size); | ||||||
|  |         exit(-1); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     if (ram_size >= 0xc0000000 ) { | ||||||
|  |         above_4g_mem_size = ram_size - 0xc0000000; | ||||||
|  |         ram_size = 0xc0000000; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* init CPUs */ | ||||||
|  |     if (cpu_model == NULL) { | ||||||
|  |         cpu_model = "IA64"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for(i = 0; i < smp_cpus; i++) { | ||||||
|  |         env = cpu_init(cpu_model); | ||||||
|  |         if (!env) { | ||||||
|  |             fprintf(stderr, "Unable to find CPU definition\n"); | ||||||
|  |             exit(1); | ||||||
|  |         } | ||||||
|  |         if (i != 0) | ||||||
|  |             env->hflags |= HF_HALTED_MASK; | ||||||
|  |         register_savevm("cpu", i, 4, cpu_save, cpu_load, env); | ||||||
|  |         qemu_register_reset(main_cpu_reset, 0, env); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* allocate RAM */ | ||||||
|  |     if (kvm_enabled()) { | ||||||
|  |         ram_addr = qemu_ram_alloc(0xa0000); | ||||||
|  |         cpu_register_physical_memory(0, 0xa0000, ram_addr); | ||||||
|  |  | ||||||
|  |         ram_addr = qemu_ram_alloc(0x20000); // Workaround 0xa0000-0xc0000 | ||||||
|  |  | ||||||
|  |         ram_addr = qemu_ram_alloc(0x40000); | ||||||
|  |         cpu_register_physical_memory(0xc0000, 0x40000, ram_addr); | ||||||
|  |  | ||||||
|  |         ram_addr = qemu_ram_alloc(ram_size - 0x100000); | ||||||
|  |         cpu_register_physical_memory(0x100000, ram_size - 0x100000, ram_addr); | ||||||
|  |     } else { | ||||||
|  |         ram_addr = qemu_ram_alloc(ram_size); | ||||||
|  |         cpu_register_physical_memory(0, ram_size, ram_addr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* above 4giga memory allocation */ | ||||||
|  |     if (above_4g_mem_size > 0) { | ||||||
|  |         ram_addr = qemu_ram_alloc(above_4g_mem_size); | ||||||
|  |         cpu_register_physical_memory(0x100000000, above_4g_mem_size, ram_addr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /*Load firware to its proper position.*/ | ||||||
|  |     if (kvm_enabled()) { | ||||||
|  |         unsigned long  image_size; | ||||||
|  |         uint8_t *image = NULL; | ||||||
|  |         unsigned long nvram_addr; | ||||||
|  |         unsigned long nvram_fd = 0; | ||||||
|  |         unsigned long type = READ_FROM_NVRAM; | ||||||
|  |         unsigned long i = 0; | ||||||
|  |         unsigned long fw_offset; | ||||||
|  |         ram_addr_t fw_mem = qemu_ram_alloc(GFW_SIZE); | ||||||
|  |  | ||||||
|  |         snprintf(buf, sizeof(buf), "%s/%s", bios_dir, FW_FILENAME); | ||||||
|  |         image = read_image(buf, &image_size ); | ||||||
|  |         if (NULL == image || !image_size) { | ||||||
|  |             fprintf(stderr, "Error when reading Guest Firmware!\n"); | ||||||
|  |             fprintf(stderr, "Please check Guest firmware at %s\n", buf); | ||||||
|  |             exit(1); | ||||||
|  |         } | ||||||
|  |         fw_offset = GFW_START + GFW_SIZE - image_size; | ||||||
|  |  | ||||||
|  |         cpu_register_physical_memory(GFW_START, GFW_SIZE, fw_mem); | ||||||
|  |         cpu_physical_memory_write(fw_offset, image, image_size); | ||||||
|  |  | ||||||
|  |         free(image); | ||||||
|  |  | ||||||
|  |         if (nvram) { | ||||||
|  |             nvram_addr = NVRAM_START; | ||||||
|  |             nvram_fd = kvm_ia64_nvram_init(type); | ||||||
|  |             if (nvram_fd != -1) { | ||||||
|  |                 kvm_ia64_copy_from_nvram_to_GFW(nvram_fd); | ||||||
|  |                 close(nvram_fd); | ||||||
|  |             } | ||||||
|  |             i = atexit((void *)kvm_ia64_copy_from_GFW_to_nvram); | ||||||
|  |             if (i != 0) | ||||||
|  |                 fprintf(stderr, "cannot set exit function\n"); | ||||||
|  |         } else | ||||||
|  |             nvram_addr = 0; | ||||||
|  |  | ||||||
|  |         kvm_ia64_build_hob(ram_size + above_4g_mem_size, smp_cpus, nvram_addr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /*Register legacy io address space, size:64M*/ | ||||||
|  |     ipf_legacy_io_base = 0xE0000000; | ||||||
|  |     ipf_legacy_io_mem = cpu_register_io_memory(0, ipf_legacy_io_read, | ||||||
|  |                                                ipf_legacy_io_write, NULL); | ||||||
|  |     cpu_register_physical_memory(ipf_legacy_io_base, 64*1024*1024, | ||||||
|  |                                  ipf_legacy_io_mem); | ||||||
|  |  | ||||||
|  |     cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1); | ||||||
|  |     i8259 = kvm_i8259_init(cpu_irq[0]); | ||||||
|  |  | ||||||
|  |     if (pci_enabled) { | ||||||
|  |         pci_bus = i440fx_init(&i440fx_state, i8259); | ||||||
|  |         piix3_devfn = piix3_init(pci_bus, -1); | ||||||
|  |     } else { | ||||||
|  |         pci_bus = NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (cirrus_vga_enabled) { | ||||||
|  |         if (pci_enabled) | ||||||
|  |             pci_cirrus_vga_init(pci_bus); | ||||||
|  |         else | ||||||
|  |             isa_cirrus_vga_init(); | ||||||
|  |     } else { | ||||||
|  |         if (pci_enabled) | ||||||
|  |             pci_vga_init(pci_bus, 0, 0); | ||||||
|  |         else | ||||||
|  |             isa_vga_init(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     rtc_state = rtc_init(0x70, i8259[8], 2000); | ||||||
|  |  | ||||||
|  |     if (pci_enabled) { | ||||||
|  |         pic_set_alt_irq_func(isa_pic, NULL, NULL); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for(i = 0; i < MAX_SERIAL_PORTS; i++) { | ||||||
|  |         if (serial_hds[i]) { | ||||||
|  |             serial_init(serial_io[i], i8259[serial_irq[i]], 115200, | ||||||
|  |                         serial_hds[i]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for(i = 0; i < MAX_PARALLEL_PORTS; i++) { | ||||||
|  |         if (parallel_hds[i]) { | ||||||
|  |             parallel_init(parallel_io[i], i8259[parallel_irq[i]], | ||||||
|  |                           parallel_hds[i]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for(i = 0; i < nb_nics; i++) { | ||||||
|  |         NICInfo *nd = &nd_table[i]; | ||||||
|  |  | ||||||
|  |         if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) | ||||||
|  |             pc_init_ne2k_isa(nd, i8259); | ||||||
|  |         else | ||||||
|  |             pci_nic_init(nd, "e1000", NULL); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | #undef USE_HYPERCALL  //Disable it now, need to implement later! | ||||||
|  | #ifdef USE_HYPERCALL | ||||||
|  |     pci_hypercall_init(pci_bus); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { | ||||||
|  |         fprintf(stderr, "qemu: too many IDE bus\n"); | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { | ||||||
|  |         index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); | ||||||
|  | 	if (index != -1) | ||||||
|  | 	    hd[i] = drives_table[index].bdrv; | ||||||
|  | 	else | ||||||
|  | 	    hd[i] = NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (pci_enabled) { | ||||||
|  |         pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1, i8259); | ||||||
|  |     } else { | ||||||
|  |         for(i = 0; i < MAX_IDE_BUS; i++) { | ||||||
|  |             isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]], | ||||||
|  | 	                 hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     i8042_init(i8259[1], i8259[12], 0x60); | ||||||
|  |     DMA_init(0); | ||||||
|  | #ifdef HAS_AUDIO | ||||||
|  |     audio_init(pci_enabled ? pci_bus : NULL, i8259); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     for(i = 0; i < MAX_FD; i++) { | ||||||
|  |         index = drive_get_index(IF_FLOPPY, 0, i); | ||||||
|  | 	if (index != -1) | ||||||
|  | 	    fd[i] = drives_table[index].bdrv; | ||||||
|  | 	else | ||||||
|  | 	    fd[i] = NULL; | ||||||
|  |     } | ||||||
|  |     floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd); | ||||||
|  |  | ||||||
|  |     cmos_init(ram_size, above_4g_mem_size, boot_device, hd); | ||||||
|  |  | ||||||
|  |     if (pci_enabled && usb_enabled) { | ||||||
|  |         usb_uhci_piix3_init(pci_bus, piix3_devfn + 2); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (pci_enabled && acpi_enabled) { | ||||||
|  |         uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ | ||||||
|  |         i2c_bus *smbus; | ||||||
|  |  | ||||||
|  |         /* TODO: Populate SPD eeprom data.  */ | ||||||
|  |         smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]); | ||||||
|  |         for (i = 0; i < 8; i++) { | ||||||
|  |             DeviceState *eeprom; | ||||||
|  |             eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); | ||||||
|  |             qdev_set_prop_int(eeprom, "address", 0x50 + i); | ||||||
|  |             qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256)); | ||||||
|  |             qdev_init(eeprom); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (i440fx_state) { | ||||||
|  |         i440fx_init_memory_mappings(i440fx_state); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (pci_enabled) { | ||||||
|  | 	int max_bus; | ||||||
|  |         int bus; | ||||||
|  |  | ||||||
|  |         max_bus = drive_get_max_bus(IF_SCSI); | ||||||
|  | 	for (bus = 0; bus <= max_bus; bus++) { | ||||||
|  |             pci_create_simple(pci_bus, -1, "lsi53c895a"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     /* Add virtio block devices */ | ||||||
|  |     if (pci_enabled) { | ||||||
|  | 	int index; | ||||||
|  | 	int unit_id = 0; | ||||||
|  |  | ||||||
|  | 	while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { | ||||||
|  |             pci_dev = pci_create("virtio-blk-pci", | ||||||
|  |                                  drives_table[index].devaddr); | ||||||
|  |             qdev_init(&pci_dev->qdev); | ||||||
|  | 	    unit_id++; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT | ||||||
|  |     if (kvm_enabled()) | ||||||
|  | 	add_assigned_devices(pci_bus, assigned_devices, assigned_devices_index); | ||||||
|  | #endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */ | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void ipf_init_pci(ram_addr_t ram_size, | ||||||
|  |                          const char *boot_device, DisplayState *ds, | ||||||
|  |                          const char *kernel_filename, | ||||||
|  |                          const char *kernel_cmdline, | ||||||
|  |                          const char *initrd_filename, | ||||||
|  |                          const char *cpu_model) | ||||||
|  | { | ||||||
|  |     ipf_init1(ram_size, boot_device, ds, kernel_filename, | ||||||
|  |               kernel_cmdline, initrd_filename, 1, cpu_model); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QEMUMachine ipf_machine = { | ||||||
|  |     .name = "itanium", | ||||||
|  |     .desc = "Itanium Platform", | ||||||
|  |     .init = (QEMUMachineInitFunc *)ipf_init_pci, | ||||||
|  |     .max_cpus = 255, | ||||||
|  |     .is_default = 1, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void ipf_machine_init(void) | ||||||
|  | { | ||||||
|  |     qemu_register_machine(&ipf_machine); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | machine_init(ipf_machine_init); | ||||||
|  |  | ||||||
|  | #define IOAPIC_NUM_PINS 48 | ||||||
|  |  | ||||||
|  | static int ioapic_irq_count[IOAPIC_NUM_PINS]; | ||||||
|  |  | ||||||
|  | static int ioapic_map_irq(int devfn, int irq_num) | ||||||
|  | { | ||||||
|  |     int irq, dev; | ||||||
|  |     dev = devfn >> 3; | ||||||
|  |     irq = ((((dev << 2) + (dev >> 3) + irq_num) & 31) + 16); | ||||||
|  |     return irq; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Dummy function to provide match for call from hw/apic.c | ||||||
|  |  */ | ||||||
|  | void apic_set_irq_delivered(void) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ioapic_set_irq(void *opaque, int irq_num, int level) | ||||||
|  | { | ||||||
|  |     int vector, pic_ret; | ||||||
|  |  | ||||||
|  |     PCIDevice *pci_dev = (PCIDevice *)opaque; | ||||||
|  |     vector = ioapic_map_irq(pci_dev->devfn, irq_num); | ||||||
|  |  | ||||||
|  |     if (level) | ||||||
|  |         ioapic_irq_count[vector] += 1; | ||||||
|  |     else | ||||||
|  |         ioapic_irq_count[vector] -= 1; | ||||||
|  |  | ||||||
|  |     if (kvm_enabled()) { | ||||||
|  | 	if (kvm_set_irq(vector, ioapic_irq_count[vector] == 0, &pic_ret)) | ||||||
|  |             if (pic_ret != 0) | ||||||
|  |                 apic_set_irq_delivered(); | ||||||
|  | 	    return; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int ipf_map_irq(PCIDevice *pci_dev, int irq_num) | ||||||
|  | { | ||||||
|  | 	return ioapic_map_irq(pci_dev->devfn, irq_num); | ||||||
|  | } | ||||||
							
								
								
									
										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: | ||||||
|   | |||||||
							
								
								
									
										231
									
								
								hw/msix.c
									
									
									
									
									
								
							
							
						
						
									
										231
									
								
								hw/msix.c
									
									
									
									
									
								
							| @@ -14,12 +14,15 @@ | |||||||
| #include "hw.h" | #include "hw.h" | ||||||
| #include "msix.h" | #include "msix.h" | ||||||
| #include "pci.h" | #include "pci.h" | ||||||
|  | #define QEMU_KVM_NO_CPU | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| /* Declaration from linux/pci_regs.h */ | /* Declaration from linux/pci_regs.h */ | ||||||
| #define  PCI_CAP_ID_MSIX 0x11 /* MSI-X */ | #define  PCI_CAP_ID_MSIX 0x11 /* MSI-X */ | ||||||
| #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 +30,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 | ||||||
| @@ -60,6 +64,117 @@ | |||||||
| /* Flag for interrupt controller to declare MSI-X support */ | /* Flag for interrupt controller to declare MSI-X support */ | ||||||
| int msix_supported; | int msix_supported; | ||||||
|  |  | ||||||
|  | #ifdef CONFIG_KVM | ||||||
|  | /* KVM specific MSIX helpers */ | ||||||
|  | static void kvm_msix_free(PCIDevice *dev) | ||||||
|  | { | ||||||
|  |     int vector, changed = 0; | ||||||
|  |     for (vector = 0; vector < dev->msix_entries_nr; ++vector) { | ||||||
|  |         if (dev->msix_entry_used[vector]) { | ||||||
|  |             kvm_del_routing_entry(kvm_context, &dev->msix_irq_entries[vector]); | ||||||
|  |             changed = 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (changed) { | ||||||
|  |         kvm_commit_irq_routes(kvm_context); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void kvm_msix_routing_entry(PCIDevice *dev, unsigned vector, | ||||||
|  |                                    struct kvm_irq_routing_entry *entry) | ||||||
|  | { | ||||||
|  |     uint8_t *table_entry = dev->msix_table_page + vector * MSIX_ENTRY_SIZE; | ||||||
|  |     entry->type = KVM_IRQ_ROUTING_MSI; | ||||||
|  |     entry->flags = 0; | ||||||
|  |     entry->u.msi.address_lo = pci_get_long(table_entry + MSIX_MSG_ADDR); | ||||||
|  |     entry->u.msi.address_hi = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR); | ||||||
|  |     entry->u.msi.data = pci_get_long(table_entry + MSIX_MSG_DATA); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void kvm_msix_update(PCIDevice *dev, int vector, | ||||||
|  |                             int was_masked, int is_masked) | ||||||
|  | { | ||||||
|  |     struct kvm_irq_routing_entry e = {}, *entry; | ||||||
|  |     int mask_cleared = was_masked && !is_masked; | ||||||
|  |     /* It is only legal to change an entry when it is masked. Therefore, it is | ||||||
|  |      * enough to update the routing in kernel when mask is being cleared. */ | ||||||
|  |     if (!mask_cleared) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     if (!dev->msix_entry_used[vector]) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     entry = dev->msix_irq_entries + vector; | ||||||
|  |     e.gsi = entry->gsi; | ||||||
|  |     kvm_msix_routing_entry(dev, vector, &e); | ||||||
|  |     if (memcmp(&entry->u.msi, &e.u.msi, sizeof entry->u.msi)) { | ||||||
|  |         int r; | ||||||
|  |         r = kvm_update_routing_entry(kvm_context, entry, &e); | ||||||
|  |         if (r) { | ||||||
|  |             fprintf(stderr, "%s: kvm_update_routing_entry failed: %s\n", __func__, | ||||||
|  | 		    strerror(-r)); | ||||||
|  |             exit(1); | ||||||
|  |         } | ||||||
|  |         memcpy(&entry->u.msi, &e.u.msi, sizeof entry->u.msi); | ||||||
|  |         r = kvm_commit_irq_routes(kvm_context); | ||||||
|  |         if (r) { | ||||||
|  |             fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__, | ||||||
|  | 		    strerror(-r)); | ||||||
|  |             exit(1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int kvm_msix_add(PCIDevice *dev, unsigned vector) | ||||||
|  | { | ||||||
|  |     struct kvm_irq_routing_entry *entry = dev->msix_irq_entries + vector; | ||||||
|  |     int r; | ||||||
|  |  | ||||||
|  |     if (!kvm_has_gsi_routing(kvm_context)) { | ||||||
|  |         fprintf(stderr, "Warning: no MSI-X support found. " | ||||||
|  |                 "At least kernel 2.6.30 is required for MSI-X support.\n" | ||||||
|  |                ); | ||||||
|  |         return -EOPNOTSUPP; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     r = kvm_get_irq_route_gsi(kvm_context); | ||||||
|  |     if (r < 0) { | ||||||
|  |         fprintf(stderr, "%s: kvm_get_irq_route_gsi failed: %s\n", __func__, strerror(-r)); | ||||||
|  |         return r; | ||||||
|  |     } | ||||||
|  |     entry->gsi = r; | ||||||
|  |     kvm_msix_routing_entry(dev, vector, entry); | ||||||
|  |     r = kvm_add_routing_entry(kvm_context, entry); | ||||||
|  |     if (r < 0) { | ||||||
|  |         fprintf(stderr, "%s: kvm_add_routing_entry failed: %s\n", __func__, strerror(-r)); | ||||||
|  |         return r; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     r = kvm_commit_irq_routes(kvm_context); | ||||||
|  |     if (r < 0) { | ||||||
|  |         fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__, strerror(-r)); | ||||||
|  |         return r; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void kvm_msix_del(PCIDevice *dev, unsigned vector) | ||||||
|  | { | ||||||
|  |     if (dev->msix_entry_used[vector]) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     kvm_del_routing_entry(kvm_context, &dev->msix_irq_entries[vector]); | ||||||
|  |     kvm_commit_irq_routes(kvm_context); | ||||||
|  | } | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | static void kvm_msix_free(PCIDevice *dev) {} | ||||||
|  | static void kvm_msix_update(PCIDevice *dev, int vector, | ||||||
|  |                             int was_masked, int is_masked) {} | ||||||
|  | static int kvm_msix_add(PCIDevice *dev, unsigned vector) { return -1; } | ||||||
|  | static void kvm_msix_del(PCIDevice *dev, unsigned vector) {} | ||||||
|  | #endif | ||||||
|  |  | ||||||
| /* Add MSI-X capability to the config space for the device. */ | /* Add MSI-X capability to the config space for the device. */ | ||||||
| /* Given a bar and its size, add MSI-X table on top of it | /* Given a bar and its size, add MSI-X table on top of it | ||||||
|  * and fill MSI-X capability in the config space. |  * and fill MSI-X capability in the config space. | ||||||
| @@ -101,22 +216,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 +261,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, | ||||||
| @@ -169,11 +313,12 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr, | |||||||
|     PCIDevice *dev = opaque; |     PCIDevice *dev = opaque; | ||||||
|     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; | ||||||
|  |     int was_masked = msix_is_masked(dev, vector); | ||||||
|     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)) { |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|         msix_clr_pending(dev, vector); |         kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector)); | ||||||
|         msix_notify(dev, vector); |  | ||||||
|     } |     } | ||||||
|  |     msix_handle_mask_update(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, | ||||||
| @@ -231,6 +376,12 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, | |||||||
|     if (nentries > MSIX_MAX_ENTRIES) |     if (nentries > MSIX_MAX_ENTRIES) | ||||||
|         return -EINVAL; |         return -EINVAL; | ||||||
|  |  | ||||||
|  | #ifdef KVM_CAP_IRQCHIP | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         dev->msix_irq_entries = qemu_malloc(nentries * | ||||||
|  |                                             sizeof *dev->msix_irq_entries); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|     dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES * |     dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES * | ||||||
|                                         sizeof *dev->msix_entry_used); |                                         sizeof *dev->msix_entry_used); | ||||||
|  |  | ||||||
| @@ -267,6 +418,10 @@ static void msix_free_irq_entries(PCIDevice *dev) | |||||||
| { | { | ||||||
|     int vector; |     int vector; | ||||||
|  |  | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         kvm_msix_free(dev); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     for (vector = 0; vector < dev->msix_entries_nr; ++vector) { |     for (vector = 0; vector < dev->msix_entries_nr; ++vector) { | ||||||
|         dev->msix_entry_used[vector] = 0; |         dev->msix_entry_used[vector] = 0; | ||||||
|         msix_clr_pending(dev, vector); |         msix_clr_pending(dev, vector); | ||||||
| @@ -287,6 +442,8 @@ int msix_uninit(PCIDevice *dev) | |||||||
|     dev->msix_table_page = NULL; |     dev->msix_table_page = NULL; | ||||||
|     qemu_free(dev->msix_entry_used); |     qemu_free(dev->msix_entry_used); | ||||||
|     dev->msix_entry_used = NULL; |     dev->msix_entry_used = NULL; | ||||||
|  |     qemu_free(dev->msix_irq_entries); | ||||||
|  |     dev->msix_irq_entries = NULL; | ||||||
|     dev->cap_present &= ~QEMU_PCI_CAP_MSIX; |     dev->cap_present &= ~QEMU_PCI_CAP_MSIX; | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| @@ -295,10 +452,13 @@ void msix_save(PCIDevice *dev, QEMUFile *f) | |||||||
| { | { | ||||||
|     unsigned n = dev->msix_entries_nr; |     unsigned n = dev->msix_entries_nr; | ||||||
|  |  | ||||||
|     if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) { |     if (!msix_supported) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|     qemu_put_buffer(f, dev->msix_table_page, n * MSIX_ENTRY_SIZE); |     qemu_put_buffer(f, dev->msix_table_page, n * MSIX_ENTRY_SIZE); | ||||||
|     qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8); |     qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8); | ||||||
| } | } | ||||||
| @@ -308,6 +468,9 @@ void msix_load(PCIDevice *dev, QEMUFile *f) | |||||||
| { | { | ||||||
|     unsigned n = dev->msix_entries_nr; |     unsigned n = dev->msix_entries_nr; | ||||||
|  |  | ||||||
|  |     if (!msix_supported) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|     if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) { |     if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| @@ -327,7 +490,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); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -352,6 +515,13 @@ void msix_notify(PCIDevice *dev, unsigned vector) | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | #ifdef KVM_CAP_IRQCHIP | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         kvm_set_irq(dev->msix_irq_entries[vector].gsi, 1, NULL); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|     address = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR); |     address = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR); | ||||||
|     address = (address << 32) | pci_get_long(table_entry + MSIX_MSG_ADDR); |     address = (address << 32) | pci_get_long(table_entry + MSIX_MSG_ADDR); | ||||||
|     data = pci_get_long(table_entry + MSIX_MSG_DATA); |     data = pci_get_long(table_entry + MSIX_MSG_DATA); | ||||||
| @@ -363,8 +533,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); | ||||||
| } | } | ||||||
| @@ -380,9 +550,19 @@ void msix_reset(PCIDevice *dev) | |||||||
| /* Mark vector as used. */ | /* Mark vector as used. */ | ||||||
| int msix_vector_use(PCIDevice *dev, unsigned vector) | int msix_vector_use(PCIDevice *dev, unsigned vector) | ||||||
| { | { | ||||||
|  |     int ret; | ||||||
|     if (vector >= dev->msix_entries_nr) |     if (vector >= dev->msix_entries_nr) | ||||||
|         return -EINVAL; |         return -EINVAL; | ||||||
|     dev->msix_entry_used[vector]++; |     if (dev->msix_entry_used[vector]) { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         ret = kvm_msix_add(dev, vector); | ||||||
|  |         if (ret) { | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     ++dev->msix_entry_used[vector]; | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -395,6 +575,9 @@ void msix_vector_unuse(PCIDevice *dev, unsigned vector) | |||||||
|     if (--dev->msix_entry_used[vector]) { |     if (--dev->msix_entry_used[vector]) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|  |         kvm_msix_del(dev, vector); | ||||||
|  |     } | ||||||
|     msix_clr_pending(dev, vector); |     msix_clr_pending(dev, vector); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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]); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										140
									
								
								hw/pc.c
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								hw/pc.c
									
									
									
									
									
								
							| @@ -44,6 +44,9 @@ | |||||||
| #include "ide.h" | #include "ide.h" | ||||||
| #include "loader.h" | #include "loader.h" | ||||||
| #include "elf.h" | #include "elf.h" | ||||||
|  | #include "device-assignment.h" | ||||||
|  |  | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| /* output Bochs bios info messages */ | /* output Bochs bios info messages */ | ||||||
| //#define DEBUG_BIOS | //#define DEBUG_BIOS | ||||||
| @@ -52,6 +55,8 @@ | |||||||
| //#define DEBUG_MULTIBOOT | //#define DEBUG_MULTIBOOT | ||||||
|  |  | ||||||
| #define BIOS_FILENAME "bios.bin" | #define BIOS_FILENAME "bios.bin" | ||||||
|  | #define EXTBOOT_FILENAME "extboot.bin" | ||||||
|  | #define VAPIC_FILENAME "vapic.bin" | ||||||
|  |  | ||||||
| #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024) | #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024) | ||||||
|  |  | ||||||
| @@ -69,6 +74,8 @@ static RTCState *rtc_state; | |||||||
| static PITState *pit; | static PITState *pit; | ||||||
| static PCII440FXState *i440fx_state; | static PCII440FXState *i440fx_state; | ||||||
|  |  | ||||||
|  | qemu_irq *ioapic_irq_hack; | ||||||
|  |  | ||||||
| typedef struct isa_irq_state { | typedef struct isa_irq_state { | ||||||
|     qemu_irq *i8259; |     qemu_irq *i8259; | ||||||
|     qemu_irq *ioapic; |     qemu_irq *ioapic; | ||||||
| @@ -560,19 +567,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); | ||||||
|         } |         } | ||||||
| @@ -950,7 +959,7 @@ int cpu_is_bsp(CPUState *env) | |||||||
|     return env->cpuid_apic_id == 0; |     return env->cpuid_apic_id == 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static CPUState *pc_new_cpu(const char *cpu_model) | CPUState *pc_new_cpu(const char *cpu_model) | ||||||
| { | { | ||||||
|     CPUState *env; |     CPUState *env; | ||||||
|  |  | ||||||
| @@ -959,6 +968,7 @@ static CPUState *pc_new_cpu(const char *cpu_model) | |||||||
|         fprintf(stderr, "Unable to find x86 CPU definition\n"); |         fprintf(stderr, "Unable to find x86 CPU definition\n"); | ||||||
|         exit(1); |         exit(1); | ||||||
|     } |     } | ||||||
|  |     env->kvm_cpu_state.regs_modified = 1; | ||||||
|     if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) { |     if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) { | ||||||
|         env->cpuid_apic_id = env->cpu_index; |         env->cpuid_apic_id = env->cpu_index; | ||||||
|         /* APIC reset callback resets cpu */ |         /* APIC reset callback resets cpu */ | ||||||
| @@ -966,6 +976,11 @@ static CPUState *pc_new_cpu(const char *cpu_model) | |||||||
|     } else { |     } else { | ||||||
|         qemu_register_reset((QEMUResetHandler*)cpu_reset, env); |         qemu_register_reset((QEMUResetHandler*)cpu_reset, env); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /* kvm needs this to run after the apic is initialized. Otherwise, | ||||||
|  |      * it can access invalid state and crash. | ||||||
|  |      */ | ||||||
|  |     qemu_init_vcpu(env); | ||||||
|     return env; |     return env; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1013,6 +1028,9 @@ static void pc_init1(ram_addr_t ram_size, | |||||||
| #endif | #endif | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (kvm_enabled()) { | ||||||
|  |         kvm_set_boot_cpu_id(0); | ||||||
|  |     } | ||||||
|     for (i = 0; i < smp_cpus; i++) { |     for (i = 0; i < smp_cpus; i++) { | ||||||
|         env = pc_new_cpu(cpu_model); |         env = pc_new_cpu(cpu_model); | ||||||
|     } |     } | ||||||
| @@ -1020,18 +1038,11 @@ static void pc_init1(ram_addr_t ram_size, | |||||||
|     vmport_init(); |     vmport_init(); | ||||||
|  |  | ||||||
|     /* allocate RAM */ |     /* allocate RAM */ | ||||||
|     ram_addr = qemu_ram_alloc(0xa0000); |     ram_addr = qemu_ram_alloc(below_4g_mem_size); | ||||||
|     cpu_register_physical_memory(0, 0xa0000, ram_addr); |     cpu_register_physical_memory(0, 0xa0000, ram_addr); | ||||||
|  |  | ||||||
|     /* Allocate, even though we won't register, so we don't break the |  | ||||||
|      * phys_ram_base + PA assumption. This range includes vga (0xa0000 - 0xc0000), |  | ||||||
|      * and some bios areas, which will be registered later |  | ||||||
|      */ |  | ||||||
|     ram_addr = qemu_ram_alloc(0x100000 - 0xa0000); |  | ||||||
|     ram_addr = qemu_ram_alloc(below_4g_mem_size - 0x100000); |  | ||||||
|     cpu_register_physical_memory(0x100000, |     cpu_register_physical_memory(0x100000, | ||||||
|                  below_4g_mem_size - 0x100000, |                  below_4g_mem_size - 0x100000, | ||||||
|                  ram_addr); |                  ram_addr + 0x100000); | ||||||
|  |  | ||||||
|     /* above 4giga memory allocation */ |     /* above 4giga memory allocation */ | ||||||
|     if (above_4g_mem_size > 0) { |     if (above_4g_mem_size > 0) { | ||||||
| @@ -1073,11 +1084,17 @@ static void pc_init1(ram_addr_t ram_size, | |||||||
|     isa_bios_size = bios_size; |     isa_bios_size = bios_size; | ||||||
|     if (isa_bios_size > (128 * 1024)) |     if (isa_bios_size > (128 * 1024)) | ||||||
|         isa_bios_size = 128 * 1024; |         isa_bios_size = 128 * 1024; | ||||||
|  |     cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size, | ||||||
|  |                                  IO_MEM_UNASSIGNED); | ||||||
|  |     /* kvm tpr optimization needs the bios accessible for write, at least to qemu itself */ | ||||||
|     cpu_register_physical_memory(0x100000 - isa_bios_size, |     cpu_register_physical_memory(0x100000 - isa_bios_size, | ||||||
|                                  isa_bios_size, |                                  isa_bios_size, | ||||||
|                                  (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); |                                  (bios_offset + bios_size - isa_bios_size) /* | IO_MEM_ROM */); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     if (extboot_drive) { | ||||||
|  |         option_rom[nb_option_roms++] = qemu_strdup(EXTBOOT_FILENAME); | ||||||
|  |     } | ||||||
|  |     option_rom[nb_option_roms++] = qemu_strdup(VAPIC_FILENAME); | ||||||
|  |  | ||||||
|     rom_enable_driver_roms = 1; |     rom_enable_driver_roms = 1; | ||||||
|     option_rom_offset = qemu_ram_alloc(PC_ROM_SIZE); |     option_rom_offset = qemu_ram_alloc(PC_ROM_SIZE); | ||||||
| @@ -1088,6 +1105,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); | ||||||
| @@ -1098,10 +1116,18 @@ static void pc_init1(ram_addr_t ram_size, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1); |     cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1); | ||||||
|     i8259 = i8259_init(cpu_irq[0]); | #ifdef KVM_CAP_IRQCHIP | ||||||
|     isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state)); |     if (kvm_enabled() && kvm_irqchip_in_kernel()) { | ||||||
|     isa_irq_state->i8259 = i8259; |         isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state)); | ||||||
|     isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24); |         isa_irq = i8259 = kvm_i8259_init(cpu_irq[0]); | ||||||
|  |     } else | ||||||
|  | #endif | ||||||
|  |     { | ||||||
|  |         i8259 = i8259_init(cpu_irq[0]); | ||||||
|  |         isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state)); | ||||||
|  |         isa_irq_state->i8259 = i8259; | ||||||
|  |         isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (pci_enabled) { |     if (pci_enabled) { | ||||||
|         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq); |         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq); | ||||||
| @@ -1146,8 +1172,14 @@ static void pc_init1(ram_addr_t ram_size, | |||||||
|  |  | ||||||
|     if (pci_enabled) { |     if (pci_enabled) { | ||||||
|         isa_irq_state->ioapic = ioapic_init(); |         isa_irq_state->ioapic = ioapic_init(); | ||||||
|  |         ioapic_irq_hack = isa_irq; | ||||||
|     } |     } | ||||||
|     pit = pit_init(0x40, isa_reserve_irq(0)); | #ifdef CONFIG_KVM_PIT | ||||||
|  |     if (kvm_enabled() && qemu_kvm_pit_in_kernel()) | ||||||
|  | 	pit = kvm_pit_init(0x40, isa_reserve_irq(0)); | ||||||
|  |     else | ||||||
|  | #endif | ||||||
|  | 	pit = pit_init(0x40, isa_reserve_irq(0)); | ||||||
|     pcspk_init(pit); |     pcspk_init(pit); | ||||||
|     if (!no_hpet) { |     if (!no_hpet) { | ||||||
|         hpet_init(isa_irq); |         hpet_init(isa_irq); | ||||||
| @@ -1171,7 +1203,7 @@ static void pc_init1(ram_addr_t ram_size, | |||||||
|         if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) |         if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) | ||||||
|             pc_init_ne2k_isa(nd); |             pc_init_ne2k_isa(nd); | ||||||
|         else |         else | ||||||
|             pci_nic_init_nofail(nd, "e1000", NULL); |             pci_nic_init_nofail(nd, "rtl8139", NULL); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { |     if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { | ||||||
| @@ -1223,7 +1255,7 @@ static void pc_init1(ram_addr_t ram_size, | |||||||
|             qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256)); |             qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256)); | ||||||
|             qdev_init_nofail(eeprom); |             qdev_init_nofail(eeprom); | ||||||
|         } |         } | ||||||
|         piix4_acpi_system_hot_add_init(pci_bus); |         piix4_acpi_system_hot_add_init(pci_bus, cpu_model); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (i440fx_state) { |     if (i440fx_state) { | ||||||
| @@ -1240,6 +1272,18 @@ static void pc_init1(ram_addr_t ram_size, | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (extboot_drive) { | ||||||
|  | 	DriveInfo *info = extboot_drive; | ||||||
|  | 	int cyls, heads, secs; | ||||||
|  |  | ||||||
|  | 	if (info->type != IF_IDE && info->type != IF_VIRTIO) { | ||||||
|  | 	    bdrv_guess_geometry(info->bdrv, &cyls, &heads, &secs); | ||||||
|  | 	    bdrv_set_geometry_hint(info->bdrv, cyls, heads, secs); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	extboot_init(info->bdrv, 1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* Add virtio console devices */ |     /* Add virtio console devices */ | ||||||
|     if (pci_enabled) { |     if (pci_enabled) { | ||||||
|         for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) { |         for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) { | ||||||
| @@ -1248,6 +1292,12 @@ static void pc_init1(ram_addr_t ram_size, | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT | ||||||
|  |     if (kvm_enabled()) { | ||||||
|  |         add_assigned_devices(pci_bus, assigned_devices, assigned_devices_index); | ||||||
|  |     } | ||||||
|  | #endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */ | ||||||
| } | } | ||||||
|  |  | ||||||
| static void pc_init_pci(ram_addr_t ram_size, | static void pc_init_pci(ram_addr_t ram_size, | ||||||
| @@ -1285,7 +1335,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 +1343,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 +1392,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 +1419,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); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								hw/pc.h
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								hw/pc.h
									
									
									
									
									
								
							| @@ -28,6 +28,7 @@ extern PicState2 *isa_pic; | |||||||
| void pic_set_irq(int irq, int level); | void pic_set_irq(int irq, int level); | ||||||
| void pic_set_irq_new(void *opaque, int irq, int level); | void pic_set_irq_new(void *opaque, int irq, int level); | ||||||
| qemu_irq *i8259_init(qemu_irq parent_irq); | qemu_irq *i8259_init(qemu_irq parent_irq); | ||||||
|  | qemu_irq *kvm_i8259_init(qemu_irq parent_irq); | ||||||
| int pic_read_irq(PicState2 *s); | int pic_read_irq(PicState2 *s); | ||||||
| void pic_update_irq(PicState2 *s); | void pic_update_irq(PicState2 *s); | ||||||
| uint32_t pic_intack_read(PicState2 *s); | uint32_t pic_intack_read(PicState2 *s); | ||||||
| @@ -48,6 +49,7 @@ qemu_irq *ioapic_init(void); | |||||||
| void ioapic_set_irq(void *opaque, int vector, int level); | void ioapic_set_irq(void *opaque, int vector, int level); | ||||||
| void apic_reset_irq_delivered(void); | void apic_reset_irq_delivered(void); | ||||||
| int apic_get_irq_delivered(void); | int apic_get_irq_delivered(void); | ||||||
|  | void apic_set_irq_delivered(void); | ||||||
|  |  | ||||||
| /* i8254.c */ | /* i8254.c */ | ||||||
|  |  | ||||||
| @@ -62,8 +64,12 @@ int pit_get_initial_count(PITState *pit, int channel); | |||||||
| int pit_get_mode(PITState *pit, int channel); | int pit_get_mode(PITState *pit, int channel); | ||||||
| int pit_get_out(PITState *pit, int channel, int64_t current_time); | int pit_get_out(PITState *pit, int channel, int64_t current_time); | ||||||
|  |  | ||||||
| void hpet_pit_disable(void); | /* i8254-kvm.c */ | ||||||
| void hpet_pit_enable(void); |  | ||||||
|  | PITState *kvm_pit_init(int base, qemu_irq irq); | ||||||
|  |  | ||||||
|  | void hpet_disable_pit(void); | ||||||
|  | void hpet_enable_pit(void); | ||||||
|  |  | ||||||
| /* vmport.c */ | /* vmport.c */ | ||||||
| void vmport_init(void); | void vmport_init(void); | ||||||
| @@ -93,6 +99,7 @@ extern int fd_bootchk; | |||||||
|  |  | ||||||
| void ioport_set_a20(int enable); | void ioport_set_a20(int enable); | ||||||
| int ioport_get_a20(void); | int ioport_get_a20(void); | ||||||
|  | CPUState *pc_new_cpu(const char *cpu_model); | ||||||
|  |  | ||||||
| /* acpi.c */ | /* acpi.c */ | ||||||
| extern int acpi_enabled; | extern int acpi_enabled; | ||||||
| @@ -106,7 +113,7 @@ int acpi_table_add(const char *table_desc); | |||||||
| i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, | i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, | ||||||
|                        qemu_irq sci_irq); |                        qemu_irq sci_irq); | ||||||
| void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); | void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); | ||||||
| void piix4_acpi_system_hot_add_init(PCIBus *bus); | void piix4_acpi_system_hot_add_init(PCIBus *bus, const char *model); | ||||||
|  |  | ||||||
| /* hpet.c */ | /* hpet.c */ | ||||||
| extern int no_hpet; | extern int no_hpet; | ||||||
| @@ -116,6 +123,9 @@ void pcspk_init(PITState *); | |||||||
| int pcspk_audio_init(qemu_irq *pic); | int pcspk_audio_init(qemu_irq *pic); | ||||||
|  |  | ||||||
| /* piix_pci.c */ | /* piix_pci.c */ | ||||||
|  | /* config space register for IRQ routing */ | ||||||
|  | #define PIIX_CONFIG_IRQ_ROUTE 0x60 | ||||||
|  |  | ||||||
| struct PCII440FXState; | struct PCII440FXState; | ||||||
| typedef struct PCII440FXState PCII440FXState; | typedef struct PCII440FXState PCII440FXState; | ||||||
|  |  | ||||||
| @@ -127,6 +137,10 @@ void i440fx_init_memory_mappings(PCII440FXState *d); | |||||||
| extern PCIDevice *piix4_dev; | extern PCIDevice *piix4_dev; | ||||||
| int piix4_init(PCIBus *bus, int devfn); | int piix4_init(PCIBus *bus, int devfn); | ||||||
|  |  | ||||||
|  | int piix_get_irq(int pin); | ||||||
|  |  | ||||||
|  | int ipf_map_irq(PCIDevice *pci_dev, int irq_num); | ||||||
|  |  | ||||||
| /* vga.c */ | /* vga.c */ | ||||||
| enum vga_retrace_method { | enum vga_retrace_method { | ||||||
|     VGA_RETRACE_DUMB, |     VGA_RETRACE_DUMB, | ||||||
| @@ -149,5 +163,10 @@ void isa_cirrus_vga_init(void); | |||||||
|  |  | ||||||
| void isa_ne2000_init(int base, int irq, NICInfo *nd); | void isa_ne2000_init(int base, int irq, NICInfo *nd); | ||||||
|  |  | ||||||
|  | /* extboot.c */ | ||||||
|  |  | ||||||
|  | void extboot_init(BlockDriverState *bs, int cmd); | ||||||
|  |  | ||||||
| int cpu_is_bsp(CPUState *env); | int cpu_is_bsp(CPUState *env); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -33,6 +33,8 @@ | |||||||
| #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" | ||||||
|  | #include "device-assignment.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 +42,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 +95,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 +193,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 +226,54 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, | |||||||
|     return dev; |     return dev; | ||||||
| } | } | ||||||
|  |  | ||||||
| void pci_device_hot_add(Monitor *mon, const QDict *qdict) | #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT | ||||||
|  | static PCIDevice *qemu_pci_hot_assign_device(Monitor *mon, | ||||||
|  |                                              const char *devaddr, | ||||||
|  |                                              const char *opts_str) | ||||||
|  | { | ||||||
|  |     QemuOpts *opts; | ||||||
|  |     DeviceState *dev; | ||||||
|  |  | ||||||
|  |     opts = add_assigned_device(opts_str); | ||||||
|  |     if (opts == NULL) { | ||||||
|  |         monitor_printf(mon, "Error adding device; check syntax\n"); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     dev = qdev_device_add(opts); | ||||||
|  |     return DO_UPCAST(PCIDevice, qdev, dev); | ||||||
|  | } | ||||||
|  | #endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */ | ||||||
|  |  | ||||||
|  | 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"); | ||||||
| @@ -235,13 +296,19 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict) | |||||||
|         dev = qemu_pci_hot_add_nic(mon, pci_addr, opts); |         dev = qemu_pci_hot_add_nic(mon, pci_addr, opts); | ||||||
|     else if (strcmp(type, "storage") == 0) |     else if (strcmp(type, "storage") == 0) | ||||||
|         dev = qemu_pci_hot_add_storage(mon, pci_addr, opts); |         dev = qemu_pci_hot_add_storage(mon, pci_addr, opts); | ||||||
|  | #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT | ||||||
|  |     else if (strcmp(type, "host") == 0) | ||||||
|  |         dev = qemu_pci_hot_assign_device(mon, pci_addr, opts); | ||||||
|  | #endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */ | ||||||
|     else |     else | ||||||
|         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); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										348
									
								
								hw/pci.c
									
									
									
									
									
								
							
							
						
						
									
										348
									
								
								hw/pci.c
									
									
									
									
									
								
							| @@ -26,6 +26,10 @@ | |||||||
| #include "monitor.h" | #include "monitor.h" | ||||||
| #include "net.h" | #include "net.h" | ||||||
| #include "sysemu.h" | #include "sysemu.h" | ||||||
|  | #include "loader.h" | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  | #include "hw/pc.h" | ||||||
|  | #include "device-assignment.h" | ||||||
|  |  | ||||||
| //#define DEBUG_PCI | //#define DEBUG_PCI | ||||||
| #ifdef DEBUG_PCI | #ifdef DEBUG_PCI | ||||||
| @@ -62,12 +66,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 +110,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 +318,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, irq_state); | ||||||
|  |     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, irq_state); | ||||||
|  |  | ||||||
|  |     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 +365,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 +382,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 +396,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) | ||||||
| @@ -330,6 +426,7 @@ static int pci_set_default_subsystem_id(PCIDevice *pci_dev) | |||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  |  * Parse pci address in qemu command | ||||||
|  * Parse [[<domain>:]<bus>:]<slot>, return -1 on error |  * Parse [[<domain>:]<bus>:]<slot>, return -1 on error | ||||||
|  */ |  */ | ||||||
| static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp) | static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp) | ||||||
| @@ -378,6 +475,55 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *s | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Parse device bdf in device assignment command: | ||||||
|  |  * | ||||||
|  |  * -pcidevice host=bus:dev.func | ||||||
|  |  * | ||||||
|  |  * Parse <bus>:<slot>.<func> return -1 on error | ||||||
|  |  */ | ||||||
|  | int pci_parse_host_devaddr(const char *addr, int *busp, | ||||||
|  |                            int *slotp, int *funcp) | ||||||
|  | { | ||||||
|  |     const char *p; | ||||||
|  |     char *e; | ||||||
|  |     int val; | ||||||
|  |     int bus = 0, slot = 0, func = 0; | ||||||
|  |  | ||||||
|  |     p = addr; | ||||||
|  |     val = strtoul(p, &e, 16); | ||||||
|  |     if (e == p) | ||||||
|  | 	return -1; | ||||||
|  |     if (*e == ':') { | ||||||
|  | 	bus = val; | ||||||
|  | 	p = e + 1; | ||||||
|  | 	val = strtoul(p, &e, 16); | ||||||
|  | 	if (e == p) | ||||||
|  | 	    return -1; | ||||||
|  | 	if (*e == '.') { | ||||||
|  | 	    slot = val; | ||||||
|  | 	    p = e + 1; | ||||||
|  | 	    val = strtoul(p, &e, 16); | ||||||
|  | 	    if (e == p) | ||||||
|  | 		return -1; | ||||||
|  | 	    func = val; | ||||||
|  | 	} else | ||||||
|  | 	    return -1; | ||||||
|  |     } else | ||||||
|  | 	return -1; | ||||||
|  |  | ||||||
|  |     if (bus > 0xff || slot > 0x1f || func > 0x7) | ||||||
|  | 	return -1; | ||||||
|  |  | ||||||
|  |     if (*e) | ||||||
|  | 	return -1; | ||||||
|  |  | ||||||
|  |     *busp = bus; | ||||||
|  |     *slotp = slot; | ||||||
|  |     *funcp = func; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, | int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, | ||||||
|                      unsigned *slotp) |                      unsigned *slotp) | ||||||
| { | { | ||||||
| @@ -490,16 +636,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 +683,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) | ||||||
| @@ -849,25 +1000,80 @@ static void pci_update_mappings(PCIDevice *d) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| uint32_t pci_default_read_config(PCIDevice *d, | static uint32_t pci_read_config(PCIDevice *d, | ||||||
|                                  uint32_t address, int len) |                                 uint32_t address, int len) | ||||||
| { | { | ||||||
|     uint32_t val = 0; |     uint32_t val = 0; | ||||||
|     assert(len == 1 || len == 2 || len == 4); |  | ||||||
|     len = MIN(len, pci_config_size(d) - address); |     len = MIN(len, pci_config_size(d) - address); | ||||||
|     memcpy(&val, d->config + address, len); |     memcpy(&val, d->config + address, len); | ||||||
|     return le32_to_cpu(val); |     return le32_to_cpu(val); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | uint32_t pci_default_read_config(PCIDevice *d, | ||||||
|  |                                  uint32_t address, int len) | ||||||
|  | { | ||||||
|  |     assert(len == 1 || len == 2 || len == 4); | ||||||
|  |  | ||||||
|  |     if (pci_access_cap_config(d, address, len)) { | ||||||
|  |         return d->cap.config_read(d, address, len); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return pci_read_config(d, address, len); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void pci_write_config(PCIDevice *pci_dev, | ||||||
|  |                              uint32_t address, uint32_t val, int len) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |     for (i = 0; i < len; i++) { | ||||||
|  |         pci_dev->config[address + i] = val & 0xff; | ||||||
|  |         val >>= 8; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int pci_access_cap_config(PCIDevice *pci_dev, uint32_t address, int len) | ||||||
|  | { | ||||||
|  |     if (pci_dev->cap.supported && address >= pci_dev->cap.start && | ||||||
|  |             (address + len) < pci_dev->cap.start + pci_dev->cap.length) | ||||||
|  |         return 1; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t pci_default_cap_read_config(PCIDevice *pci_dev, | ||||||
|  |                                      uint32_t address, int len) | ||||||
|  | { | ||||||
|  |     return pci_read_config(pci_dev, address, len); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void pci_default_cap_write_config(PCIDevice *pci_dev, | ||||||
|  |                                   uint32_t address, uint32_t val, int len) | ||||||
|  | { | ||||||
|  |     pci_write_config(pci_dev, address, val, len); | ||||||
|  | } | ||||||
|  |  | ||||||
| void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) | void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) | ||||||
| { | { | ||||||
|     int i; |     int i; | ||||||
|     uint32_t config_size = pci_config_size(d); |     uint32_t config_size = pci_config_size(d); | ||||||
|  |  | ||||||
|  |     if (pci_access_cap_config(d, addr, l)) { | ||||||
|  |         d->cap.config_write(d, addr, val, l); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) { |     for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) { | ||||||
|         uint8_t wmask = d->wmask[addr + i]; |         uint8_t wmask = d->wmask[addr + i]; | ||||||
|         d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask); |         d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel() && | ||||||
|  |         addr >= PIIX_CONFIG_IRQ_ROUTE && | ||||||
|  | 	addr < PIIX_CONFIG_IRQ_ROUTE + 4) | ||||||
|  |         assigned_dev_update_irqs(); | ||||||
|  | #endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */ | ||||||
|  |  | ||||||
|     if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) || |     if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) || | ||||||
|         ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) || |         ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) || | ||||||
|         ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) || |         ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) || | ||||||
| @@ -882,23 +1088,24 @@ 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; | #if defined(TARGET_IA64) | ||||||
|     for (;;) { |     ioapic_set_irq(pci_dev, irq_num, level); | ||||||
|         bus = pci_dev->bus; | #endif | ||||||
|         irq_num = bus->map_irq(pci_dev, irq_num); |  | ||||||
|         if (bus->set_irq) |     pci_set_irq_state(pci_dev, irq_num, level); | ||||||
|             break; |     pci_update_irq_status(pci_dev); | ||||||
|         pci_dev = bus->parent_dev; |     pci_change_irq_level(pci_dev, irq_num, change); | ||||||
|     } | } | ||||||
|     bus->irq_count[irq_num] += change; |  | ||||||
|     bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); | int pci_map_irq(PCIDevice *pci_dev, int pin) | ||||||
|  | { | ||||||
|  |     return pci_dev->bus->map_irq(pci_dev, pin); | ||||||
| } | } | ||||||
|  |  | ||||||
| /***********************************************************/ | /***********************************************************/ | ||||||
| @@ -1270,9 +1477,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; | ||||||
| @@ -1319,6 +1534,37 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) | |||||||
|     return dev; |     return dev; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int pci_enable_capability_support(PCIDevice *pci_dev, | ||||||
|  |                                   uint32_t config_start, | ||||||
|  |                                   PCICapConfigReadFunc *config_read, | ||||||
|  |                                   PCICapConfigWriteFunc *config_write, | ||||||
|  |                                   PCICapConfigInitFunc *config_init) | ||||||
|  | { | ||||||
|  |     if (!pci_dev) | ||||||
|  |         return -ENODEV; | ||||||
|  |  | ||||||
|  |     pci_dev->config[0x06] |= 0x10; // status = capabilities | ||||||
|  |  | ||||||
|  |     if (config_start == 0) | ||||||
|  | 	pci_dev->cap.start = PCI_CAPABILITY_CONFIG_DEFAULT_START_ADDR; | ||||||
|  |     else if (config_start >= 0x40 && config_start < 0xff) | ||||||
|  |         pci_dev->cap.start = config_start; | ||||||
|  |     else | ||||||
|  |         return -EINVAL; | ||||||
|  |  | ||||||
|  |     if (config_read) | ||||||
|  |         pci_dev->cap.config_read = config_read; | ||||||
|  |     else | ||||||
|  |         pci_dev->cap.config_read = pci_default_cap_read_config; | ||||||
|  |     if (config_write) | ||||||
|  |         pci_dev->cap.config_write = config_write; | ||||||
|  |     else | ||||||
|  |         pci_dev->cap.config_write = pci_default_cap_write_config; | ||||||
|  |     pci_dev->cap.supported = 1; | ||||||
|  |     pci_dev->config[PCI_CAPABILITY_LIST] = pci_dev->cap.start; | ||||||
|  |     return config_init(pci_dev); | ||||||
|  | } | ||||||
|  |  | ||||||
| static int pci_find_space(PCIDevice *pdev, uint8_t size) | static int pci_find_space(PCIDevice *pdev, uint8_t size) | ||||||
| { | { | ||||||
|     int config_size = pci_config_size(pdev); |     int config_size = pci_config_size(pdev); | ||||||
| @@ -1350,6 +1596,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) | ||||||
| { | { | ||||||
|   | |||||||
							
								
								
									
										72
									
								
								hw/pci.h
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								hw/pci.h
									
									
									
									
									
								
							| @@ -5,11 +5,16 @@ | |||||||
|  |  | ||||||
| #include "qdev.h" | #include "qdev.h" | ||||||
|  |  | ||||||
|  | struct kvm_irq_routing_entry; | ||||||
|  |  | ||||||
| /* PCI includes legacy ISA access.  */ | /* PCI includes legacy ISA access.  */ | ||||||
| #include "isa.h" | #include "isa.h" | ||||||
|  |  | ||||||
| /* PCI bus */ | /* imported from <linux/pci.h> */ | ||||||
|  | #define PCI_SLOT(devfn)         (((devfn) >> 3) & 0x1f) | ||||||
|  | #define PCI_FUNC(devfn)         ((devfn) & 0x07) | ||||||
|  |  | ||||||
|  | /* PCI bus */ | ||||||
| extern target_phys_addr_t pci_mem_base; | extern target_phys_addr_t pci_mem_base; | ||||||
|  |  | ||||||
| #define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07)) | #define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07)) | ||||||
| @@ -82,6 +87,12 @@ typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, | |||||||
|                                 pcibus_t addr, pcibus_t size, int type); |                                 pcibus_t addr, pcibus_t size, int type); | ||||||
| typedef int PCIUnregisterFunc(PCIDevice *pci_dev); | typedef int PCIUnregisterFunc(PCIDevice *pci_dev); | ||||||
|  |  | ||||||
|  | typedef void PCICapConfigWriteFunc(PCIDevice *pci_dev, | ||||||
|  |                                    uint32_t address, uint32_t val, int len); | ||||||
|  | typedef uint32_t PCICapConfigReadFunc(PCIDevice *pci_dev, | ||||||
|  |                                       uint32_t address, int len); | ||||||
|  | typedef int PCICapConfigInitFunc(PCIDevice *pci_dev); | ||||||
|  |  | ||||||
| typedef struct PCIIORegion { | typedef struct PCIIORegion { | ||||||
|     pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ |     pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ | ||||||
| #define PCI_BAR_UNMAPPED (~(pcibus_t)0) | #define PCI_BAR_UNMAPPED (~(pcibus_t)0) | ||||||
| @@ -102,6 +113,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 */ | ||||||
| @@ -159,10 +171,19 @@ typedef struct PCIIORegion { | |||||||
| /* Bits in the PCI Status Register (PCI 2.3 spec) */ | /* Bits in the PCI Status Register (PCI 2.3 spec) */ | ||||||
| #define PCI_STATUS_RESERVED1	0x007 | #define PCI_STATUS_RESERVED1	0x007 | ||||||
| #define PCI_STATUS_INT_STATUS	0x008 | #define PCI_STATUS_INT_STATUS	0x008 | ||||||
|  | #ifndef PCI_STATUS_CAP_LIST | ||||||
| #define PCI_STATUS_CAP_LIST	0x010 | #define PCI_STATUS_CAP_LIST	0x010 | ||||||
|  | #endif | ||||||
|  | #ifndef PCI_STATUS_66MHZ | ||||||
| #define PCI_STATUS_66MHZ	0x020 | #define PCI_STATUS_66MHZ	0x020 | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #define PCI_STATUS_RESERVED2	0x040 | #define PCI_STATUS_RESERVED2	0x040 | ||||||
|  |  | ||||||
|  | #ifndef PCI_STATUS_FAST_BACK | ||||||
| #define PCI_STATUS_FAST_BACK	0x080 | #define PCI_STATUS_FAST_BACK	0x080 | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #define PCI_STATUS_DEVSEL	0x600 | #define PCI_STATUS_DEVSEL	0x600 | ||||||
|  |  | ||||||
| #define PCI_STATUS_RESERVED_MASK_LO (PCI_STATUS_RESERVED1 | \ | #define PCI_STATUS_RESERVED_MASK_LO (PCI_STATUS_RESERVED1 | \ | ||||||
| @@ -191,6 +212,11 @@ enum { | |||||||
|     QEMU_PCI_CAP_EXPRESS = 0x2, |     QEMU_PCI_CAP_EXPRESS = 0x2, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #define PCI_CAPABILITY_CONFIG_MAX_LENGTH 0x60 | ||||||
|  | #define PCI_CAPABILITY_CONFIG_DEFAULT_START_ADDR 0x40 | ||||||
|  | #define PCI_CAPABILITY_CONFIG_MSI_LENGTH 0x10 | ||||||
|  | #define PCI_CAPABILITY_CONFIG_MSIX_LENGTH 0x10 | ||||||
|  |  | ||||||
| struct PCIDevice { | struct PCIDevice { | ||||||
|     DeviceState qdev; |     DeviceState qdev; | ||||||
|     /* PCI config space */ |     /* PCI config space */ | ||||||
| @@ -220,7 +246,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 +267,28 @@ 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; | ||||||
|  |  | ||||||
|  |     /* How much space does an MSIX table need. */ | ||||||
|  |     /* The spec requires giving the table structure | ||||||
|  |      * a 4K aligned region all by itself. Align it to | ||||||
|  |      * target pages so that drivers can do passthrough | ||||||
|  |      * on the rest of the region. */ | ||||||
|  |     target_phys_addr_t msix_page_size; | ||||||
|  |  | ||||||
|  |     struct kvm_irq_routing_entry *msix_irq_entries; | ||||||
|  |  | ||||||
|  |     /* Device capability configuration space */ | ||||||
|  |     struct { | ||||||
|  |         int supported; | ||||||
|  |         unsigned int start, length; | ||||||
|  |         PCICapConfigReadFunc *config_read; | ||||||
|  |         PCICapConfigWriteFunc *config_write; | ||||||
|  |     } cap; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| PCIDevice *pci_register_device(PCIBus *bus, const char *name, | PCIDevice *pci_register_device(PCIBus *bus, const char *name, | ||||||
| @@ -252,6 +300,14 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, | |||||||
|                             pcibus_t size, int type, |                             pcibus_t size, int type, | ||||||
|                             PCIMapIORegionFunc *map_func); |                             PCIMapIORegionFunc *map_func); | ||||||
|  |  | ||||||
|  | int pci_enable_capability_support(PCIDevice *pci_dev, | ||||||
|  |                                   uint32_t config_start, | ||||||
|  |                                   PCICapConfigReadFunc *config_read, | ||||||
|  |                                   PCICapConfigWriteFunc *config_write, | ||||||
|  |                                   PCICapConfigInitFunc *config_init); | ||||||
|  |  | ||||||
|  | int pci_map_irq(PCIDevice *pci_dev, int pin); | ||||||
|  |  | ||||||
| int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); | int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); | ||||||
|  |  | ||||||
| void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); | void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); | ||||||
| @@ -260,13 +316,17 @@ void pci_reserve_capability(PCIDevice *pci_dev, uint8_t offset, uint8_t size); | |||||||
|  |  | ||||||
| uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id); | uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id); | ||||||
|  |  | ||||||
|  |  | ||||||
| uint32_t pci_default_read_config(PCIDevice *d, | uint32_t pci_default_read_config(PCIDevice *d, | ||||||
|                                  uint32_t address, int len); |                                  uint32_t address, int len); | ||||||
| void pci_default_write_config(PCIDevice *d, | void pci_default_write_config(PCIDevice *d, | ||||||
|                               uint32_t address, uint32_t val, int len); |                               uint32_t address, uint32_t val, int len); | ||||||
| void pci_device_save(PCIDevice *s, QEMUFile *f); | void pci_device_save(PCIDevice *s, QEMUFile *f); | ||||||
| int pci_device_load(PCIDevice *s, QEMUFile *f); | int pci_device_load(PCIDevice *s, QEMUFile *f); | ||||||
|  | uint32_t pci_default_cap_read_config(PCIDevice *pci_dev, | ||||||
|  |                                      uint32_t address, int len); | ||||||
|  | void pci_default_cap_write_config(PCIDevice *pci_dev, | ||||||
|  |                                   uint32_t address, uint32_t val, int len); | ||||||
|  | int pci_access_cap_config(PCIDevice *pci_dev, uint32_t address, int len); | ||||||
|  |  | ||||||
| typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); | typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); | ||||||
| typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); | typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); | ||||||
| @@ -295,6 +355,9 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr); | |||||||
| int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, | int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, | ||||||
|                      unsigned *slotp); |                      unsigned *slotp); | ||||||
|  |  | ||||||
|  | int pci_parse_host_devaddr(const char *addr, int *busp, | ||||||
|  |                            int *slotp, int *funcp); | ||||||
|  |  | ||||||
| void pci_info(Monitor *mon); | void pci_info(Monitor *mon); | ||||||
| PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did, | PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did, | ||||||
|                         pci_map_irq_fn map_irq, const char *name); |                         pci_map_irq_fn map_irq, const char *name); | ||||||
| @@ -379,6 +442,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); | ||||||
|   | |||||||
							
								
								
									
										48
									
								
								hw/pcspk.c
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								hw/pcspk.c
									
									
									
									
									
								
							| @@ -27,6 +27,8 @@ | |||||||
| #include "isa.h" | #include "isa.h" | ||||||
| #include "audio/audio.h" | #include "audio/audio.h" | ||||||
| #include "qemu-timer.h" | #include "qemu-timer.h" | ||||||
|  | #include "i8254.h" | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| #define PCSPK_BUF_LEN 1792 | #define PCSPK_BUF_LEN 1792 | ||||||
| #define PCSPK_SAMPLE_RATE 32000 | #define PCSPK_SAMPLE_RATE 32000 | ||||||
| @@ -48,6 +50,43 @@ typedef struct { | |||||||
| static const char *s_spk = "pcspk"; | static const char *s_spk = "pcspk"; | ||||||
| static PCSpkState pcspk_state; | static PCSpkState pcspk_state; | ||||||
|  |  | ||||||
|  | #ifdef CONFIG_KVM_PIT | ||||||
|  | static void kvm_get_pit_ch2(PITState *pit, | ||||||
|  |                             struct kvm_pit_state *inkernel_state) | ||||||
|  | { | ||||||
|  |     struct kvm_pit_state pit_state; | ||||||
|  |  | ||||||
|  |     if (kvm_enabled() && qemu_kvm_pit_in_kernel()) { | ||||||
|  |         kvm_get_pit(kvm_context, &pit_state); | ||||||
|  |         pit->channels[2].mode = pit_state.channels[2].mode; | ||||||
|  |         pit->channels[2].count = pit_state.channels[2].count; | ||||||
|  |         pit->channels[2].count_load_time = pit_state.channels[2].count_load_time; | ||||||
|  |         pit->channels[2].gate = pit_state.channels[2].gate; | ||||||
|  |         if (inkernel_state) { | ||||||
|  |             memcpy(inkernel_state, &pit_state, sizeof(*inkernel_state)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void kvm_set_pit_ch2(PITState *pit, | ||||||
|  |                             struct kvm_pit_state *inkernel_state) | ||||||
|  | { | ||||||
|  |     if (kvm_enabled() && qemu_kvm_pit_in_kernel()) { | ||||||
|  |         inkernel_state->channels[2].mode = pit->channels[2].mode; | ||||||
|  |         inkernel_state->channels[2].count = pit->channels[2].count; | ||||||
|  |         inkernel_state->channels[2].count_load_time = | ||||||
|  |             pit->channels[2].count_load_time; | ||||||
|  |         inkernel_state->channels[2].gate = pit->channels[2].gate; | ||||||
|  |         kvm_set_pit(kvm_context, inkernel_state); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | #else | ||||||
|  | static inline void kvm_get_pit_ch2(PITState *pit, | ||||||
|  |                                    struct kvm_pit_state *inkernel_state) { } | ||||||
|  | static inline void kvm_set_pit_ch2(PITState *pit, | ||||||
|  |                                    struct kvm_pit_state *inkernel_state) { } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| static inline void generate_samples(PCSpkState *s) | static inline void generate_samples(PCSpkState *s) | ||||||
| { | { | ||||||
|     unsigned int i; |     unsigned int i; | ||||||
| @@ -72,6 +111,8 @@ static void pcspk_callback(void *opaque, int free) | |||||||
|     PCSpkState *s = opaque; |     PCSpkState *s = opaque; | ||||||
|     unsigned int n; |     unsigned int n; | ||||||
|  |  | ||||||
|  |     kvm_get_pit_ch2(s->pit, NULL); | ||||||
|  |  | ||||||
|     if (pit_get_mode(s->pit, 2) != 3) |     if (pit_get_mode(s->pit, 2) != 3) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
| @@ -117,6 +158,8 @@ static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr) | |||||||
|     PCSpkState *s = opaque; |     PCSpkState *s = opaque; | ||||||
|     int out; |     int out; | ||||||
|  |  | ||||||
|  |     kvm_get_pit_ch2(s->pit, NULL); | ||||||
|  |  | ||||||
|     s->dummy_refresh_clock ^= (1 << 4); |     s->dummy_refresh_clock ^= (1 << 4); | ||||||
|     out = pit_get_out(s->pit, 2, qemu_get_clock(vm_clock)) << 5; |     out = pit_get_out(s->pit, 2, qemu_get_clock(vm_clock)) << 5; | ||||||
|  |  | ||||||
| @@ -125,9 +168,12 @@ static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr) | |||||||
|  |  | ||||||
| static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val) | static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val) | ||||||
| { | { | ||||||
|  |     struct kvm_pit_state inkernel_state; | ||||||
|     PCSpkState *s = opaque; |     PCSpkState *s = opaque; | ||||||
|     const int gate = val & 1; |     const int gate = val & 1; | ||||||
|  |  | ||||||
|  |     kvm_get_pit_ch2(s->pit, &inkernel_state); | ||||||
|  |  | ||||||
|     s->data_on = (val >> 1) & 1; |     s->data_on = (val >> 1) & 1; | ||||||
|     pit_set_gate(s->pit, 2, gate); |     pit_set_gate(s->pit, 2, gate); | ||||||
|     if (s->voice) { |     if (s->voice) { | ||||||
| @@ -135,6 +181,8 @@ static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val) | |||||||
|             s->play_pos = 0; |             s->play_pos = 0; | ||||||
|         AUD_set_active_out(s->voice, gate & s->data_on); |         AUD_set_active_out(s->voice, gate & s->data_on); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     kvm_set_pit_ch2(s->pit, &inkernel_state); | ||||||
| } | } | ||||||
|  |  | ||||||
| void pcspk_init(PITState *pit) | void pcspk_init(PITState *pit) | ||||||
|   | |||||||
| @@ -29,6 +29,8 @@ | |||||||
| #include "isa.h" | #include "isa.h" | ||||||
| #include "sysbus.h" | #include "sysbus.h" | ||||||
|  |  | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| typedef PCIHostState I440FXState; | typedef PCIHostState I440FXState; | ||||||
|  |  | ||||||
| typedef struct PIIX3State { | typedef struct PIIX3State { | ||||||
| @@ -88,6 +90,10 @@ static void i440fx_update_memory_mappings(PCII440FXState *d) | |||||||
|     int i, r; |     int i, r; | ||||||
|     uint32_t smram, addr; |     uint32_t smram, addr; | ||||||
|  |  | ||||||
|  |     if (kvm_enabled()) { | ||||||
|  |         /* FIXME: Support remappings and protection changes. */ | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|     update_pam(d, 0xf0000, 0x100000, (d->dev.config[0x59] >> 4) & 3); |     update_pam(d, 0xf0000, 0x100000, (d->dev.config[0x59] >> 4) & 3); | ||||||
|     for(i = 0; i < 12; i++) { |     for(i = 0; i < 12; i++) { | ||||||
|         r = (d->dev.config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3; |         r = (d->dev.config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3; | ||||||
| @@ -201,6 +207,8 @@ static int i440fx_initfn(PCIDevice *dev) | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static PIIX3State *piix3_dev; | ||||||
|  |  | ||||||
| PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *pic) | PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *pic) | ||||||
| { | { | ||||||
|     DeviceState *dev; |     DeviceState *dev; | ||||||
| @@ -226,6 +234,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq * | |||||||
|  |  | ||||||
|     *piix3_devfn = piix3->dev.devfn; |     *piix3_devfn = piix3->dev.devfn; | ||||||
|  |  | ||||||
|  |     piix3_dev = piix3; | ||||||
|  |  | ||||||
|     return b; |     return b; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -253,6 +263,13 @@ static void piix3_set_irq(void *opaque, int irq_num, int level) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int piix_get_irq(int pin) | ||||||
|  | { | ||||||
|  |     if (piix3_dev) | ||||||
|  |         return piix3_dev->dev.config[0x60+pin]; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| static void piix3_reset(void *opaque) | static void piix3_reset(void *opaque) | ||||||
| { | { | ||||||
|     PIIX3State *d = opaque; |     PIIX3State *d = opaque; | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
| #include "ppc405.h" | #include "ppc405.h" | ||||||
| #include "sysemu.h" | #include "sysemu.h" | ||||||
| #include "kvm.h" | #include "kvm.h" | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| #define PPC440EP_PCI_CONFIG     0xeec00000 | #define PPC440EP_PCI_CONFIG     0xeec00000 | ||||||
| #define PPC440EP_PCI_INTACK     0xeed00000 | #define PPC440EP_PCI_INTACK     0xeed00000 | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ | |||||||
| #include "device_tree.h" | #include "device_tree.h" | ||||||
| #include "loader.h" | #include "loader.h" | ||||||
| #include "elf.h" | #include "elf.h" | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| #define BINARY_DEVICE_TREE_FILE "bamboo.dtb" | #define BINARY_DEVICE_TREE_FILE "bamboo.dtb" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -31,6 +31,7 @@ | |||||||
| #include "ppce500.h" | #include "ppce500.h" | ||||||
| #include "loader.h" | #include "loader.h" | ||||||
| #include "elf.h" | #include "elf.h" | ||||||
|  | #include "qemu-kvm.h" | ||||||
|  |  | ||||||
| #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb" | #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb" | ||||||
| #define UIMAGE_LOAD_BASE           0 | #define UIMAGE_LOAD_BASE           0 | ||||||
|   | |||||||
| @@ -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, | ||||||
| }; | }; | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user