Compare commits
	
		
			341 Commits
		
	
	
		
			v0.13.0-rc
			...
			v0.12.5-qe
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					69903f803a | ||
| 
						 | 
					174f225e9d | ||
| 
						 | 
					e916448940 | ||
| 
						 | 
					bb44e0bbce | ||
| 
						 | 
					191d44fc43 | ||
| 
						 | 
					a2f0cbaa58 | ||
| 
						 | 
					a9d9a66f13 | ||
| 
						 | 
					37060c28e5 | ||
| 
						 | 
					7205c21e76 | ||
| 
						 | 
					ceef722d01 | ||
| 
						 | 
					dfe0bb55ee | ||
| 
						 | 
					6fd82592ce | ||
| 
						 | 
					39187b5192 | ||
| 
						 | 
					729862401d | ||
| 
						 | 
					34d0d68bdf | ||
| 
						 | 
					82e9cbeb0d | ||
| 
						 | 
					2020dd5535 | ||
| 
						 | 
					0c0f53e25c | ||
| 
						 | 
					3dbe0714dd | ||
| 
						 | 
					9067bac11d | ||
| 
						 | 
					74471f3742 | ||
| 
						 | 
					370f80376a | ||
| 
						 | 
					ed3aac289a | ||
| 
						 | 
					11b52a6536 | ||
| 
						 | 
					b6185fc79c | ||
| 
						 | 
					8fd7d5438e | ||
| 
						 | 
					a513171f80 | ||
| 
						 | 
					ff9e177617 | ||
| 
						 | 
					db3519a9ec | ||
| 
						 | 
					258e351d12 | ||
| 
						 | 
					cd14f4d346 | ||
| 
						 | 
					df631629b1 | ||
| 
						 | 
					af0269b036 | ||
| 
						 | 
					d37dbf988d | ||
| 
						 | 
					cc7ed88f28 | ||
| 
						 | 
					07442ab4a1 | ||
| 
						 | 
					dbe6a18d82 | ||
| 
						 | 
					7dd007c2ed | ||
| 
						 | 
					9c6a8f503d | ||
| 
						 | 
					0c459361a1 | ||
| 
						 | 
					72d3457e8d | ||
| 
						 | 
					e1f0c1d05d | ||
| 
						 | 
					74bcc51b99 | ||
| 
						 | 
					7e4f956056 | ||
| 
						 | 
					1fb9798b69 | ||
| 
						 | 
					9f6a84bc43 | ||
| 
						 | 
					8cef921d18 | ||
| 
						 | 
					b04c3db504 | ||
| 
						 | 
					d04d7cf158 | ||
| 
						 | 
					2b8bdd5c7f | ||
| 
						 | 
					2a44494726 | ||
| 
						 | 
					8f30db54d9 | ||
| 
						 | 
					b09ac1abe7 | ||
| 
						 | 
					012d4869c1 | ||
| 
						 | 
					3597c9c1d5 | ||
| 
						 | 
					3b4bef0696 | ||
| 
						 | 
					d899303743 | ||
| 
						 | 
					5773685183 | ||
| 
						 | 
					d40ba77ebf | ||
| 
						 | 
					a8c46d182c | ||
| 
						 | 
					d80e20a1c3 | ||
| 
						 | 
					1ce4fad939 | ||
| 
						 | 
					9167a242db | ||
| 
						 | 
					09e96924ec | ||
| 
						 | 
					69ff4e9dbd | ||
| 
						 | 
					0434349d6a | ||
| 
						 | 
					e007221223 | ||
| 
						 | 
					4622317288 | ||
| 
						 | 
					ffac613ff9 | ||
| 
						 | 
					aba5288247 | ||
| 
						 | 
					4f7cb96931 | ||
| 
						 | 
					fafc2e4b33 | ||
| 
						 | 
					83ef70f24a | ||
| 
						 | 
					de17c16e1f | ||
| 
						 | 
					9462695b64 | ||
| 
						 | 
					5eb089588e | ||
| 
						 | 
					2039f70c23 | ||
| 
						 | 
					082a9fc256 | ||
| 
						 | 
					36a013c956 | ||
| 
						 | 
					c4c4b32b81 | ||
| 
						 | 
					804b6ab08d | ||
| 
						 | 
					81b168a702 | ||
| 
						 | 
					5c6892078a | ||
| 
						 | 
					18a21890ff | ||
| 
						 | 
					6629fa6473 | ||
| 
						 | 
					2a7996ce0e | ||
| 
						 | 
					8ec131fb59 | ||
| 
						 | 
					30d061750d | ||
| 
						 | 
					c5f5dc5bad | ||
| 
						 | 
					d2df336c58 | ||
| 
						 | 
					b299b12b17 | ||
| 
						 | 
					c248df6161 | ||
| 
						 | 
					7d5625d5f7 | ||
| 
						 | 
					cc21d131e3 | ||
| 
						 | 
					41a5bda61f | ||
| 
						 | 
					5163f6e864 | ||
| 
						 | 
					6173d56bdc | ||
| 
						 | 
					f39942d217 | ||
| 
						 | 
					5dde87088f | ||
| 
						 | 
					3fa017e24b | ||
| 
						 | 
					35924dbe8c | ||
| 
						 | 
					88aa905668 | ||
| 
						 | 
					b93c5c84c8 | ||
| 
						 | 
					f203baee5b | ||
| 
						 | 
					5e3be62385 | ||
| 
						 | 
					b391493bc6 | ||
| 
						 | 
					57f9f4c9f5 | ||
| 
						 | 
					7ebc79037c | ||
| 
						 | 
					ea299062eb | ||
| 
						 | 
					e03dd1a6c2 | ||
| 
						 | 
					535d2eb34a | ||
| 
						 | 
					beb8eab90c | ||
| 
						 | 
					8d67694fbf | ||
| 
						 | 
					02510b2436 | ||
| 
						 | 
					b57a2297f2 | ||
| 
						 | 
					43fab08210 | ||
| 
						 | 
					915080e6b1 | ||
| 
						 | 
					9f59ddcc4f | ||
| 
						 | 
					999ceb2c1d | ||
| 
						 | 
					307331a42a | ||
| 
						 | 
					6728dd464b | ||
| 
						 | 
					bb45bcc8de | ||
| 
						 | 
					096109c804 | ||
| 
						 | 
					7ae1fcc88c | ||
| 
						 | 
					299e0bc52a | ||
| 
						 | 
					74f0529e24 | ||
| 
						 | 
					614971158c | ||
| 
						 | 
					afa328b1b2 | ||
| 
						 | 
					868dab5dc2 | ||
| 
						 | 
					29bb3bf350 | ||
| 
						 | 
					dbf45b44b7 | ||
| 
						 | 
					d0d888bc6d | ||
| 
						 | 
					19abbad0da | ||
| 
						 | 
					f48aba6de7 | ||
| 
						 | 
					cb2ae96bf6 | ||
| 
						 | 
					848f874ca1 | ||
| 
						 | 
					a1a86bf902 | ||
| 
						 | 
					c727a05459 | ||
| 
						 | 
					eb05143e24 | ||
| 
						 | 
					0c709e6195 | ||
| 
						 | 
					dc88aa49b4 | ||
| 
						 | 
					dc2ffbf6d8 | ||
| 
						 | 
					d3bf9367f2 | ||
| 
						 | 
					c502715a74 | ||
| 
						 | 
					b9a61d2154 | ||
| 
						 | 
					9525204c5d | ||
| 
						 | 
					f79d556b4f | ||
| 
						 | 
					41ae9ece21 | ||
| 
						 | 
					40480d2bf4 | ||
| 
						 | 
					e389e937a7 | ||
| 
						 | 
					73b48d914f | ||
| 
						 | 
					3999bf3244 | ||
| 
						 | 
					a3441a43a6 | ||
| 
						 | 
					49a3aaac4a | ||
| 
						 | 
					027866ce23 | ||
| 
						 | 
					04babf6c6f | ||
| 
						 | 
					d2b8117310 | ||
| 
						 | 
					0c4b9aef7b | ||
| 
						 | 
					431c829f33 | ||
| 
						 | 
					be7398ec06 | ||
| 
						 | 
					be59ce1f48 | ||
| 
						 | 
					eacad66dbe | ||
| 
						 | 
					66dbb62824 | ||
| 
						 | 
					d47d251286 | ||
| 
						 | 
					348af56fae | ||
| 
						 | 
					09866b9baa | ||
| 
						 | 
					e1daf40e3e | ||
| 
						 | 
					de3ea06d59 | ||
| 
						 | 
					fe46a160ce | ||
| 
						 | 
					8033c42abd | ||
| 
						 | 
					4713c69fa2 | ||
| 
						 | 
					d68bf60838 | ||
| 
						 | 
					57fa5ca551 | ||
| 
						 | 
					8610774f79 | ||
| 
						 | 
					76ba04832b | ||
| 
						 | 
					644f5de21b | ||
| 
						 | 
					dcc0da8297 | ||
| 
						 | 
					41193c50fa | ||
| 
						 | 
					da0266005a | ||
| 
						 | 
					eacdccbb3e | ||
| 
						 | 
					65e8c51928 | ||
| 
						 | 
					e470436f19 | ||
| 
						 | 
					b60c2c74f3 | ||
| 
						 | 
					fe1b69708c | ||
| 
						 | 
					a1678e85db | ||
| 
						 | 
					8212d18cf5 | ||
| 
						 | 
					6c412ddf1c | ||
| 
						 | 
					862ad4be53 | ||
| 
						 | 
					aac2ad563a | ||
| 
						 | 
					eb41f58a4e | ||
| 
						 | 
					5543b41167 | ||
| 
						 | 
					31d85f6a6b | ||
| 
						 | 
					9c49a2533c | ||
| 
						 | 
					c6faf5fd73 | ||
| 
						 | 
					069def25cb | ||
| 
						 | 
					3733a1e804 | ||
| 
						 | 
					5b06a3f785 | ||
| 
						 | 
					baaf73aaac | ||
| 
						 | 
					345c22aa80 | ||
| 
						 | 
					26bb2a0865 | ||
| 
						 | 
					e6ea832410 | ||
| 
						 | 
					22d0cc8d38 | ||
| 
						 | 
					898829d5c7 | ||
| 
						 | 
					72bb3c7571 | ||
| 
						 | 
					48c437f0ab | ||
| 
						 | 
					07d00c2174 | ||
| 
						 | 
					3243a06f51 | ||
| 
						 | 
					1c3f96be38 | ||
| 
						 | 
					df9e7219db | ||
| 
						 | 
					e83421f511 | ||
| 
						 | 
					2b311b3cce | ||
| 
						 | 
					4b5db3749c | ||
| 
						 | 
					a1497a782c | ||
| 
						 | 
					3c547d7bb7 | ||
| 
						 | 
					3b43502e3a | ||
| 
						 | 
					078517421f | ||
| 
						 | 
					afc7055619 | ||
| 
						 | 
					53425683d4 | ||
| 
						 | 
					ef5a63186a | ||
| 
						 | 
					4a0e0accd7 | ||
| 
						 | 
					73e47683de | ||
| 
						 | 
					115e94a31e | ||
| 
						 | 
					5fd5f6999d | ||
| 
						 | 
					602e97b725 | ||
| 
						 | 
					97b766dfcd | ||
| 
						 | 
					fb8cf78db6 | ||
| 
						 | 
					c5238ac21b | ||
| 
						 | 
					99917a99cd | ||
| 
						 | 
					55ed56908f | ||
| 
						 | 
					139e310025 | ||
| 
						 | 
					bed93b1dcb | ||
| 
						 | 
					73b4ac5cd8 | ||
| 
						 | 
					00e8277b83 | ||
| 
						 | 
					a8ea3a357b | ||
| 
						 | 
					f8051485c1 | ||
| 
						 | 
					807c80b259 | ||
| 
						 | 
					686a3c3dc2 | ||
| 
						 | 
					a381d8277c | ||
| 
						 | 
					8647b09bfd | ||
| 
						 | 
					9153014fa0 | ||
| 
						 | 
					f6d4446ea8 | ||
| 
						 | 
					f1e247ee6b | ||
| 
						 | 
					a49668769d | ||
| 
						 | 
					97d949d9da | ||
| 
						 | 
					040093b1a5 | ||
| 
						 | 
					5d4e53dc81 | ||
| 
						 | 
					3ebee80226 | ||
| 
						 | 
					c56651312b | ||
| 
						 | 
					869ca150e7 | ||
| 
						 | 
					910628f396 | ||
| 
						 | 
					251241dc90 | ||
| 
						 | 
					03a23e5c6e | ||
| 
						 | 
					a68fc29ceb | ||
| 
						 | 
					0014803d23 | ||
| 
						 | 
					5118f7b47c | ||
| 
						 | 
					1c1d7bda2c | ||
| 
						 | 
					bdae662c94 | ||
| 
						 | 
					0108d4e323 | ||
| 
						 | 
					4305793bad | ||
| 
						 | 
					d2d51eeff0 | ||
| 
						 | 
					3be42b28c1 | ||
| 
						 | 
					ee70ef8771 | ||
| 
						 | 
					5f9fe0f8d0 | ||
| 
						 | 
					7589acc9e8 | ||
| 
						 | 
					94f539bdac | ||
| 
						 | 
					e637fd2386 | ||
| 
						 | 
					6e785bee32 | ||
| 
						 | 
					f883e4f7b8 | ||
| 
						 | 
					5daa7bb7a4 | ||
| 
						 | 
					b0a84d0525 | ||
| 
						 | 
					f1f84ba223 | ||
| 
						 | 
					db830f26cb | ||
| 
						 | 
					61a606dade | ||
| 
						 | 
					2d95575edb | ||
| 
						 | 
					d707483ce3 | ||
| 
						 | 
					e2deb622c2 | ||
| 
						 | 
					6e792a557e | ||
| 
						 | 
					ea2138cf90 | ||
| 
						 | 
					992f3cb78e | ||
| 
						 | 
					828b2ff676 | ||
| 
						 | 
					a231a8272c | ||
| 
						 | 
					f2604b35dc | ||
| 
						 | 
					fc05630f1f | ||
| 
						 | 
					ad960ddbce | ||
| 
						 | 
					239a69680c | ||
| 
						 | 
					f4f1df70f2 | ||
| 
						 | 
					782e9e6554 | ||
| 
						 | 
					64de0113f1 | ||
| 
						 | 
					84db615abc | ||
| 
						 | 
					7c6a56cc63 | ||
| 
						 | 
					a20600b917 | ||
| 
						 | 
					4986fd4111 | ||
| 
						 | 
					96639424e2 | ||
| 
						 | 
					6ac733bf09 | ||
| 
						 | 
					25d82d3311 | ||
| 
						 | 
					f9800fe5a0 | ||
| 
						 | 
					542d991b4c | ||
| 
						 | 
					d1d6963eba | ||
| 
						 | 
					7058b807cd | ||
| 
						 | 
					f49d2561cb | ||
| 
						 | 
					a63e5f1971 | ||
| 
						 | 
					ebbc8a3d8e | ||
| 
						 | 
					08b2d3ba9a | ||
| 
						 | 
					72fbd9f97c | ||
| 
						 | 
					5b6d0419d9 | ||
| 
						 | 
					9df9eeeb18 | ||
| 
						 | 
					5b6321a237 | ||
| 
						 | 
					5e0c455842 | ||
| 
						 | 
					4d687b13cf | ||
| 
						 | 
					d7b8193716 | ||
| 
						 | 
					2e51813417 | ||
| 
						 | 
					90f445e1c9 | ||
| 
						 | 
					143d288cba | ||
| 
						 | 
					13a2ccc46f | ||
| 
						 | 
					ea2b7d7079 | ||
| 
						 | 
					0b52786ce1 | ||
| 
						 | 
					e36469149a | ||
| 
						 | 
					e5fc266be5 | ||
| 
						 | 
					3e4cd634cc | ||
| 
						 | 
					06976f82e7 | ||
| 
						 | 
					fe7c6c90a8 | ||
| 
						 | 
					960a4b537a | ||
| 
						 | 
					c756b1e762 | ||
| 
						 | 
					06921ec84f | ||
| 
						 | 
					8cb1cec656 | ||
| 
						 | 
					a46657d185 | ||
| 
						 | 
					28acf422cb | ||
| 
						 | 
					a7d5da8857 | ||
| 
						 | 
					931a548be3 | ||
| 
						 | 
					bcddbd0f6a | ||
| 
						 | 
					b3dfdb5a3b | ||
| 
						 | 
					6ccc51fd20 | ||
| 
						 | 
					0ea5709a32 | ||
| 
						 | 
					67a2698dac | ||
| 
						 | 
					eea4acfa5c | ||
| 
						 | 
					c99d32efe6 | ||
| 
						 | 
					9fa7591beb | ||
| 
						 | 
					066263f377 | ||
| 
						 | 
					20c1a35211 | ||
| 
						 | 
					ea6112b165 | ||
| 
						 | 
					e222100afe | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -48,4 +48,5 @@ pc-bios/bios-pq/status
 | 
			
		||||
pc-bios/vgabios-pq/status
 | 
			
		||||
pc-bios/optionrom/multiboot.bin
 | 
			
		||||
pc-bios/optionrom/multiboot.raw
 | 
			
		||||
pc-bios/optionrom/extboot.bin
 | 
			
		||||
.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:
 | 
			
		||||
 | 
			
		||||
  - 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))
 | 
			
		||||
 | 
			
		||||
ifeq ($(KVM_KMOD),yes)
 | 
			
		||||
 | 
			
		||||
.PHONEY: kvm-kmod
 | 
			
		||||
 | 
			
		||||
all: kvm-kmod
 | 
			
		||||
 | 
			
		||||
kvm-kmod:
 | 
			
		||||
	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C kvm/kernel V="$(V)" )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
subdir-%: $(GENERATED_HEADERS)
 | 
			
		||||
	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
 | 
			
		||||
 | 
			
		||||
@@ -70,7 +82,7 @@ $(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.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,)
 | 
			
		||||
 | 
			
		||||
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
 | 
			
		||||
@@ -81,6 +93,12 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
 | 
			
		||||
 | 
			
		||||
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
# QObject
 | 
			
		||||
qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
 | 
			
		||||
qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
 | 
			
		||||
qobject-obj-y += qerror.o
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
# block-obj-y is code used by both qemu system emulation and qemu-img
 | 
			
		||||
 | 
			
		||||
@@ -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-$(CONFIG_POSIX) += posix-aio-compat.o
 | 
			
		||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 | 
			
		||||
block-obj-$(CONFIG_POSIX) += compatfd.o
 | 
			
		||||
 | 
			
		||||
block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
 | 
			
		||||
block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
 | 
			
		||||
@@ -120,6 +139,7 @@ net-obj-y += $(addprefix net/, $(net-nested-y))
 | 
			
		||||
 | 
			
		||||
obj-y = $(block-obj-y)
 | 
			
		||||
obj-y += $(net-obj-y)
 | 
			
		||||
obj-y += $(qobject-obj-y)
 | 
			
		||||
obj-y += readline.o console.o
 | 
			
		||||
 | 
			
		||||
obj-y += tcg-runtime.o host-utils.o
 | 
			
		||||
@@ -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 += msmouse.o ps2.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-$(CONFIG_BRLAPI) += baum.o
 | 
			
		||||
@@ -230,18 +248,18 @@ libqemu_common.a: $(obj-y)
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
check-qint: check-qint.o qint.o qemu-malloc.o
 | 
			
		||||
check-qstring: check-qstring.o qstring.o qemu-malloc.o
 | 
			
		||||
check-qdict: check-qdict.o qdict.o 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-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
 | 
			
		||||
@@ -278,6 +296,8 @@ pxe-ne2k_pci.bin pxe-pcnet.bin \
 | 
			
		||||
pxe-rtl8139.bin pxe-virtio.bin \
 | 
			
		||||
bamboo.dtb petalogix-s3adsp1800.dtb \
 | 
			
		||||
multiboot.bin linuxboot.bin
 | 
			
		||||
BLOBS += extboot.bin
 | 
			
		||||
BLOBS += vapic.bin
 | 
			
		||||
else
 | 
			
		||||
BLOBS=
 | 
			
		||||
endif
 | 
			
		||||
@@ -300,7 +320,12 @@ endif
 | 
			
		||||
ifneq ($(BLOBS),)
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
 | 
			
		||||
	set -e; for x in $(BLOBS); do \
 | 
			
		||||
	    if [ -f $(SRC_PATH)/pc-bios/$$x ];then \
 | 
			
		||||
		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
 | 
			
		||||
	    fi \
 | 
			
		||||
	    ; if [ -f pc-bios/optionrom/$$x ];then \
 | 
			
		||||
		$(INSTALL_DATA) pc-bios/optionrom/$$x "$(DESTDIR)$(datadir)"; \
 | 
			
		||||
	    fi \
 | 
			
		||||
	done
 | 
			
		||||
endif
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
 | 
			
		||||
@@ -310,6 +335,9 @@ endif
 | 
			
		||||
	for d in $(TARGET_DIRS); do \
 | 
			
		||||
	$(MAKE) -C $$d $@ || exit 1 ; \
 | 
			
		||||
        done
 | 
			
		||||
ifeq ($(KVM_KMOD),yes)
 | 
			
		||||
	$(MAKE) -C kvm/kernel $@
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# various test targets
 | 
			
		||||
test speed: all
 | 
			
		||||
@@ -430,6 +458,7 @@ tarbin:
 | 
			
		||||
	$(datadir)/pxe-rtl8139.bin \
 | 
			
		||||
	$(datadir)/pxe-pcnet.bin \
 | 
			
		||||
	$(datadir)/pxe-e1000.bin \
 | 
			
		||||
	$(datadir)/extboot.bin \
 | 
			
		||||
	$(docdir)/qemu-doc.html \
 | 
			
		||||
	$(docdir)/qemu-tech.html \
 | 
			
		||||
	$(mandir)/man1/qemu.1 \
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,9 @@ obj-$(CONFIG_ESCC) += escc.o
 | 
			
		||||
# PCI watchdog devices
 | 
			
		||||
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
 | 
			
		||||
obj-y += ne2000.o
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,8 @@ LIBS+=-lm
 | 
			
		||||
 | 
			
		||||
kvm.o kvm-all.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
 | 
			
		||||
 | 
			
		||||
CFLAGS += $(KVM_CFLAGS)
 | 
			
		||||
 | 
			
		||||
config-target.h: config-target.h-timestamp
 | 
			
		||||
config-target.h-timestamp: config-target.mak
 | 
			
		||||
 | 
			
		||||
@@ -40,12 +42,18 @@ all: $(PROGS)
 | 
			
		||||
 | 
			
		||||
#########################################################
 | 
			
		||||
# cpu emulator library
 | 
			
		||||
libobj-y = exec.o translate-all.o cpu-exec.o translate.o
 | 
			
		||||
libobj-y += tcg/tcg.o
 | 
			
		||||
libobj-y = exec.o cpu-exec.o
 | 
			
		||||
libobj-$(CONFIG_NO_CPU_EMULATION) += fake-exec.o
 | 
			
		||||
libobj-$(CONFIG_CPU_EMULATION) += translate-all.o translate.o
 | 
			
		||||
libobj-$(CONFIG_CPU_EMULATION) += tcg/tcg.o
 | 
			
		||||
libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o
 | 
			
		||||
libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o
 | 
			
		||||
libobj-y += op_helper.o helper.o
 | 
			
		||||
libobj-$(CONFIG_NEED_MMU) += mmu.o
 | 
			
		||||
 | 
			
		||||
libobj-$(CONFIG_KVM) += kvm-tpr-opt.o
 | 
			
		||||
libobj-$(CONFIG_KVM) += qemu-kvm-helper.o
 | 
			
		||||
 | 
			
		||||
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
 | 
			
		||||
libobj-$(TARGET_ALPHA) += alpha_palcode.o
 | 
			
		||||
 | 
			
		||||
@@ -82,6 +90,8 @@ op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 | 
			
		||||
# cpu_signal_handler() in cpu-exec.c.
 | 
			
		||||
signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 | 
			
		||||
 | 
			
		||||
qemu-kvm-helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 | 
			
		||||
 | 
			
		||||
#########################################################
 | 
			
		||||
# Linux user emulator target
 | 
			
		||||
 | 
			
		||||
@@ -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
 | 
			
		||||
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
 | 
			
		||||
# MSI-X depends on kvm for interrupt injection,
 | 
			
		||||
# so moved it from Makefile.hw to Makefile.target for now
 | 
			
		||||
obj-y += msix.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
 | 
			
		||||
LIBS+=-lz
 | 
			
		||||
 | 
			
		||||
@@ -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 += 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 += extboot.o
 | 
			
		||||
obj-i386-y += ne2000-isa.o
 | 
			
		||||
obj-i386-y += testdev.o
 | 
			
		||||
 | 
			
		||||
obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
 | 
			
		||||
obj-i386-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
 | 
			
		||||
 | 
			
		||||
# Hardware support
 | 
			
		||||
obj-ia64-y += ide.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
 | 
			
		||||
obj-ia64-y += fdc.o mc146818rtc.o serial.o i8259.o ipf.o
 | 
			
		||||
obj-ia64-y += cirrus_vga.o parallel.o acpi.o piix_pci.o
 | 
			
		||||
obj-ia64-y += usb-uhci.o
 | 
			
		||||
obj-ia64-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
 | 
			
		||||
 | 
			
		||||
# shared objects
 | 
			
		||||
obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o
 | 
			
		||||
obj-ppc-y += ide/cmd646.o
 | 
			
		||||
obj-ppc-y += vga.o vga-pci.o $(sound-obj-y) dma.o openpic.o
 | 
			
		||||
obj-ppc-y += cirrus_vga.o
 | 
			
		||||
# PREP target
 | 
			
		||||
obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.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
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
 | 
			
		||||
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,15 @@
 | 
			
		||||
 | 
			
		||||
include ../config-host.mak
 | 
			
		||||
include $(SRC_PATH)/rules.mak
 | 
			
		||||
-include config.mak
 | 
			
		||||
 | 
			
		||||
.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..
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								QMP/README
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								QMP/README
									
									
									
									
									
								
							@@ -4,45 +4,57 @@
 | 
			
		||||
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 also provides asynchronous events support.
 | 
			
		||||
QMP is JSON[1] based and has the following features:
 | 
			
		||||
 | 
			
		||||
- Lightweight, text-based, easy to parse data format
 | 
			
		||||
- Asynchronous events support 
 | 
			
		||||
- Stability
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
There are also two simple Python scripts available:
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
Usage
 | 
			
		||||
-----
 | 
			
		||||
 | 
			
		||||
To enable QMP, QEMU has to be started in "control mode". This is done
 | 
			
		||||
by passing the flag "control" to the "-monitor" command-line option.
 | 
			
		||||
To enable QMP, QEMU has to be started in "control mode". There are
 | 
			
		||||
two ways of doing this, the simplest one is using the the '-qmp'
 | 
			
		||||
command-line option.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
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
 | 
			
		||||
Trying ::1...
 | 
			
		||||
Trying 127.0.0.1...
 | 
			
		||||
Connected to localhost.
 | 
			
		||||
Escape character is '^]'.
 | 
			
		||||
{"QMP": {"capabilities": []}}
 | 
			
		||||
{ "execute": "query-version" }
 | 
			
		||||
{"return": "0.11.50"}
 | 
			
		||||
{"return": {"qemu": "0.11.50", "package": ""}}
 | 
			
		||||
 | 
			
		||||
Contact
 | 
			
		||||
-------
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
           QEMU Monitor Protocol Draft Specification - Version 0.1
 | 
			
		||||
           QEMU Monitor Protocol Specification - Version 0.1
 | 
			
		||||
 | 
			
		||||
1. Introduction
 | 
			
		||||
===============
 | 
			
		||||
@@ -27,9 +27,9 @@ the JSON standard:
 | 
			
		||||
 | 
			
		||||
http://www.ietf.org/rfc/rfc4627.txt
 | 
			
		||||
 | 
			
		||||
For convenience, json-objects mentioned in this document will have its members
 | 
			
		||||
in a certain order. However, in real protocol usage json-objects members can
 | 
			
		||||
be in ANY order, thus no particular order should be assumed.
 | 
			
		||||
For convenience, json-object members and json-array elements mentioned in
 | 
			
		||||
this document will be in a certain order. However, in real protocol usage
 | 
			
		||||
they can be in ANY order, thus no particular order should be assumed.
 | 
			
		||||
 | 
			
		||||
2.1 General Definitions
 | 
			
		||||
-----------------------
 | 
			
		||||
@@ -85,12 +85,13 @@ without errors.
 | 
			
		||||
 | 
			
		||||
The format is:
 | 
			
		||||
 | 
			
		||||
{ "return": json-value, "id": json-value }
 | 
			
		||||
{ "return": json-object, "id": json-value }
 | 
			
		||||
 | 
			
		||||
 Where,
 | 
			
		||||
 | 
			
		||||
- 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
 | 
			
		||||
  with the command execution (if issued by the Client)
 | 
			
		||||
 | 
			
		||||
@@ -102,13 +103,16 @@ completed because of an error condition.
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
 | 
			
		||||
- The "class" member contains the error class name (eg. "ServiceUnavailable")
 | 
			
		||||
- 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
 | 
			
		||||
- 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 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:
 | 
			
		||||
 | 
			
		||||
{ "event": json-string, "data": json-value,
 | 
			
		||||
{ "event": json-string, "data": json-object,
 | 
			
		||||
  "timestamp": { "seconds": json-number, "microseconds": json-number } }
 | 
			
		||||
 | 
			
		||||
 Where,
 | 
			
		||||
@@ -132,7 +136,7 @@ The format is:
 | 
			
		||||
- The "event" member contains the event's name
 | 
			
		||||
- The "data" member contains event specific data, which is defined in a
 | 
			
		||||
  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
 | 
			
		||||
  microseconds
 | 
			
		||||
 | 
			
		||||
@@ -154,19 +158,20 @@ S: {"QMP": {"capabilities": []}}
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
C: { "execute": "stop" }
 | 
			
		||||
S: {"return": "OK"}
 | 
			
		||||
S: {"return": {}}
 | 
			
		||||
 | 
			
		||||
3.3 KVM information
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
C: {"execute": "query-kvm", "id": "example"}
 | 
			
		||||
S: {"return": "enabled", "id": "example"}
 | 
			
		||||
C: { "execute": "query-kvm", "id": "example" }
 | 
			
		||||
S: {"return": {"enabled": true, "present": true}, "id": "example"}
 | 
			
		||||
 | 
			
		||||
3.4 Parsing error
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
C: { "execute": }
 | 
			
		||||
S: {"error": {"class": "JSONParsing", "data": {}}}
 | 
			
		||||
S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
 | 
			
		||||
{}}}
 | 
			
		||||
 | 
			
		||||
3.5 Powerdown event
 | 
			
		||||
-------------------
 | 
			
		||||
@@ -174,19 +179,25 @@ S: {"error": {"class": "JSONParsing", "data": {}}}
 | 
			
		||||
S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
 | 
			
		||||
"POWERDOWN"}
 | 
			
		||||
 | 
			
		||||
4. Notes to Client implementors
 | 
			
		||||
-------------------------------
 | 
			
		||||
4. Compatibility Considerations
 | 
			
		||||
--------------------------------
 | 
			
		||||
 | 
			
		||||
4.1 It is recommended to always start the Server in pause mode, thus the
 | 
			
		||||
    Client is able to perform any setup procedure without the risk of
 | 
			
		||||
    race conditions and related problems
 | 
			
		||||
In order to achieve maximum compatibility between versions, Clients must not 
 | 
			
		||||
assume any particular:
 | 
			
		||||
 | 
			
		||||
4.2 It is recommended to always check the capabilities json-array, issued
 | 
			
		||||
    with the greeting message, at connection time
 | 
			
		||||
- Size of json-objects or length of json-arrays
 | 
			
		||||
- Order of json-object members or json-array elements
 | 
			
		||||
- Amount of errors generated by a command, that is, new errors can be added
 | 
			
		||||
  to any existing command in newer versions of the Server
 | 
			
		||||
 | 
			
		||||
4.3 Json-objects or json-arrays mentioned in this document are not fixed
 | 
			
		||||
    and no particular size or number of members/elements should be assumed.
 | 
			
		||||
    New members/elements can be added at any time.
 | 
			
		||||
Additionally, Clients should always:
 | 
			
		||||
 | 
			
		||||
4.4 No particular order of json-objects members should be assumed, they
 | 
			
		||||
    can change at any time
 | 
			
		||||
- Check the capabilities json-array at connection 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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								aio.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								aio.c
									
									
									
									
									
								
							@@ -113,8 +113,10 @@ void qemu_aio_flush(void)
 | 
			
		||||
        qemu_aio_wait();
 | 
			
		||||
 | 
			
		||||
        QLIST_FOREACH(node, &aio_handlers, node) {
 | 
			
		||||
            if (node->io_flush) {
 | 
			
		||||
                ret |= node->io_flush(node->opaque);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } while (qemu_bh_poll() || ret > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -213,6 +213,10 @@ static void alsa_poll_handler (void *opaque)
 | 
			
		||||
 | 
			
		||||
    state = snd_pcm_state (hlp->handle);
 | 
			
		||||
    switch (state) {
 | 
			
		||||
    case SND_PCM_STATE_SETUP:
 | 
			
		||||
        alsa_recover (hlp->handle);
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case SND_PCM_STATE_XRUN:
 | 
			
		||||
        alsa_recover (hlp->handle);
 | 
			
		||||
        break;
 | 
			
		||||
@@ -665,7 +669,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
 | 
			
		||||
        (obt->fmt != req->fmt ||
 | 
			
		||||
         obt->nchannels != req->nchannels ||
 | 
			
		||||
         obt->freq != req->freq)) {
 | 
			
		||||
        dolog ("Audio paramters for %s\n", typ);
 | 
			
		||||
        dolog ("Audio parameters for %s\n", typ);
 | 
			
		||||
        alsa_dump_info (req, obt);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,10 @@
 | 
			
		||||
#define AUDIO_CAP "oss"
 | 
			
		||||
#include "audio_int.h"
 | 
			
		||||
 | 
			
		||||
#if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
 | 
			
		||||
#define USE_DSP_POLICY
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct OSSVoiceOut {
 | 
			
		||||
    HWVoiceOut hw;
 | 
			
		||||
    void *pcm_buf;
 | 
			
		||||
@@ -236,14 +240,39 @@ static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
 | 
			
		||||
}
 | 
			
		||||
#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,
 | 
			
		||||
                     struct oss_params *obt, int *pfd)
 | 
			
		||||
{
 | 
			
		||||
    int fd;
 | 
			
		||||
    int version;
 | 
			
		||||
    int oflags = conf.exclusive ? O_EXCL : 0;
 | 
			
		||||
    audio_buf_info abinfo;
 | 
			
		||||
    int fmt, freq, nchannels;
 | 
			
		||||
    int setfragment = 1;
 | 
			
		||||
    const char *dspname = in ? conf.devpath_in : conf.devpath_out;
 | 
			
		||||
    const char *typ = in ? "ADC" : "DAC";
 | 
			
		||||
 | 
			
		||||
@@ -281,27 +310,30 @@ static int oss_open (int in, struct oss_params *req,
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ioctl (fd, OSS_GETVERSION, &version)) {
 | 
			
		||||
        oss_logerr2 (errno, typ, "Failed to get OSS version\n");
 | 
			
		||||
        version = 0;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef USE_DSP_POLICY
 | 
			
		||||
    if (conf.policy >= 0) {
 | 
			
		||||
        int version;
 | 
			
		||||
 | 
			
		||||
        if (!oss_get_version (fd, &version, typ)) {
 | 
			
		||||
            if (conf.debug) {
 | 
			
		||||
                dolog ("OSS version = %#x\n", version);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
#ifdef SNDCTL_DSP_POLICY
 | 
			
		||||
    if (conf.policy >= 0 && version >= 0x040000) {
 | 
			
		||||
            if (version >= 0x040000) {
 | 
			
		||||
                int policy = conf.policy;
 | 
			
		||||
                if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
 | 
			
		||||
            oss_logerr2 (errno, typ, "Failed to set timing policy to %d\n",
 | 
			
		||||
                    oss_logerr2 (errno, typ,
 | 
			
		||||
                                 "Failed to set timing policy to %d\n",
 | 
			
		||||
                                 conf.policy);
 | 
			
		||||
                    goto err;
 | 
			
		||||
                }
 | 
			
		||||
                setfragment = 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
#endif
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    if (setfragment) {
 | 
			
		||||
        int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
 | 
			
		||||
        if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
 | 
			
		||||
            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,
 | 
			
		||||
        .descr = "Open device in exclusive mode (vmix wont work)"
 | 
			
		||||
    },
 | 
			
		||||
#ifdef SNDCTL_DSP_POLICY
 | 
			
		||||
#ifdef USE_DSP_POLICY
 | 
			
		||||
    {
 | 
			
		||||
        .name  = "POLICY",
 | 
			
		||||
        .tag   = AUD_OPT_INT,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										352
									
								
								block.c
									
									
									
									
									
								
							
							
						
						
									
										352
									
								
								block.c
									
									
									
									
									
								
							@@ -26,6 +26,7 @@
 | 
			
		||||
#include "monitor.h"
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
#include "module.h"
 | 
			
		||||
#include "qemu-objects.h"
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_BSD
 | 
			
		||||
#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));
 | 
			
		||||
    else
 | 
			
		||||
        open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
 | 
			
		||||
 | 
			
		||||
    bs->open_flags = open_flags;
 | 
			
		||||
    if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv))
 | 
			
		||||
        ret = -ENOTSUP;
 | 
			
		||||
    else
 | 
			
		||||
@@ -690,6 +693,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
    uint8_t tmp_buf[BDRV_SECTOR_SIZE];
 | 
			
		||||
    int len, nb_sectors, count;
 | 
			
		||||
    int64_t sector_num;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    count = count1;
 | 
			
		||||
    /* first read to align to sector start */
 | 
			
		||||
@@ -698,8 +702,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
        len = count;
 | 
			
		||||
    sector_num = offset >> BDRV_SECTOR_BITS;
 | 
			
		||||
    if (len > 0) {
 | 
			
		||||
        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
 | 
			
		||||
            return ret;
 | 
			
		||||
        memcpy(buf, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), len);
 | 
			
		||||
        count -= len;
 | 
			
		||||
        if (count == 0)
 | 
			
		||||
@@ -711,8 +715,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
    /* read the sectors "in place" */
 | 
			
		||||
    nb_sectors = count >> BDRV_SECTOR_BITS;
 | 
			
		||||
    if (nb_sectors > 0) {
 | 
			
		||||
        if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0)
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        if ((ret = bdrv_read(bs, sector_num, buf, nb_sectors)) < 0)
 | 
			
		||||
            return ret;
 | 
			
		||||
        sector_num += nb_sectors;
 | 
			
		||||
        len = nb_sectors << BDRV_SECTOR_BITS;
 | 
			
		||||
        buf += len;
 | 
			
		||||
@@ -721,8 +725,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
 | 
			
		||||
    /* add data from the last sector */
 | 
			
		||||
    if (count > 0) {
 | 
			
		||||
        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
 | 
			
		||||
            return ret;
 | 
			
		||||
        memcpy(buf, tmp_buf, count);
 | 
			
		||||
    }
 | 
			
		||||
    return count1;
 | 
			
		||||
@@ -734,6 +738,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
    uint8_t tmp_buf[BDRV_SECTOR_SIZE];
 | 
			
		||||
    int len, nb_sectors, count;
 | 
			
		||||
    int64_t sector_num;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    count = count1;
 | 
			
		||||
    /* first write to align to sector start */
 | 
			
		||||
@@ -742,11 +747,11 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
        len = count;
 | 
			
		||||
    sector_num = offset >> BDRV_SECTOR_BITS;
 | 
			
		||||
    if (len > 0) {
 | 
			
		||||
        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
 | 
			
		||||
            return ret;
 | 
			
		||||
        memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len);
 | 
			
		||||
        if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
 | 
			
		||||
            return ret;
 | 
			
		||||
        count -= len;
 | 
			
		||||
        if (count == 0)
 | 
			
		||||
            return count1;
 | 
			
		||||
@@ -757,8 +762,8 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
    /* write the sectors "in place" */
 | 
			
		||||
    nb_sectors = count >> BDRV_SECTOR_BITS;
 | 
			
		||||
    if (nb_sectors > 0) {
 | 
			
		||||
        if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0)
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        if ((ret = bdrv_write(bs, sector_num, buf, nb_sectors)) < 0)
 | 
			
		||||
            return ret;
 | 
			
		||||
        sector_num += nb_sectors;
 | 
			
		||||
        len = nb_sectors << BDRV_SECTOR_BITS;
 | 
			
		||||
        buf += len;
 | 
			
		||||
@@ -767,15 +772,52 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
 | 
			
		||||
    /* add data from the last sector */
 | 
			
		||||
    if (count > 0) {
 | 
			
		||||
        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
 | 
			
		||||
            return ret;
 | 
			
		||||
        memcpy(tmp_buf, buf, count);
 | 
			
		||||
        if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
 | 
			
		||||
            return ret;
 | 
			
		||||
    }
 | 
			
		||||
    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)
 | 
			
		||||
 */
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
        monitor_printf(mon, "%s:", bs->device_name);
 | 
			
		||||
        monitor_printf(mon, " type=");
 | 
			
		||||
        switch(bs->type) {
 | 
			
		||||
        case BDRV_TYPE_HD:
 | 
			
		||||
            monitor_printf(mon, "hd");
 | 
			
		||||
            break;
 | 
			
		||||
        case BDRV_TYPE_CDROM:
 | 
			
		||||
            monitor_printf(mon, "cdrom");
 | 
			
		||||
            break;
 | 
			
		||||
        case BDRV_TYPE_FLOPPY:
 | 
			
		||||
            monitor_printf(mon, "floppy");
 | 
			
		||||
            break;
 | 
			
		||||
    bs_dict = qobject_to_qdict(obj);
 | 
			
		||||
 | 
			
		||||
    monitor_printf(mon, "%s: type=%s removable=%d",
 | 
			
		||||
                        qdict_get_str(bs_dict, "device"),
 | 
			
		||||
                        qdict_get_str(bs_dict, "type"),
 | 
			
		||||
                        qdict_get_bool(bs_dict, "removable"));
 | 
			
		||||
 | 
			
		||||
    if (qdict_get_bool(bs_dict, "removable")) {
 | 
			
		||||
        monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
 | 
			
		||||
    }
 | 
			
		||||
        monitor_printf(mon, " removable=%d", bs->removable);
 | 
			
		||||
        if (bs->removable) {
 | 
			
		||||
            monitor_printf(mon, " locked=%d", bs->locked);
 | 
			
		||||
        }
 | 
			
		||||
        if (bs->drv) {
 | 
			
		||||
 | 
			
		||||
    if (qdict_haskey(bs_dict, "inserted")) {
 | 
			
		||||
        QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
 | 
			
		||||
 | 
			
		||||
        monitor_printf(mon, " file=");
 | 
			
		||||
            monitor_print_filename(mon, bs->filename);
 | 
			
		||||
            if (bs->backing_file[0] != '\0') {
 | 
			
		||||
        monitor_print_filename(mon, qdict_get_str(qdict, "file"));
 | 
			
		||||
        if (qdict_haskey(qdict, "backing_file")) {
 | 
			
		||||
            monitor_printf(mon, " backing_file=");
 | 
			
		||||
                monitor_print_filename(mon, bs->backing_file);
 | 
			
		||||
            monitor_print_filename(mon, qdict_get_str(qdict, "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));
 | 
			
		||||
        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_stats(Monitor *mon)
 | 
			
		||||
void bdrv_info_print(Monitor *mon, const QObject *data)
 | 
			
		||||
{
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    bs_list = qlist_new();
 | 
			
		||||
 | 
			
		||||
    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
 | 
			
		||||
        monitor_printf(mon, "%s:"
 | 
			
		||||
                       " rd_bytes=%" PRIu64
 | 
			
		||||
                       " wr_bytes=%" PRIu64
 | 
			
		||||
                       " rd_operations=%" PRIu64
 | 
			
		||||
                       " wr_operations=%" PRIu64
 | 
			
		||||
        QObject *bs_obj;
 | 
			
		||||
        const char *type = "unknown";
 | 
			
		||||
 | 
			
		||||
        switch(bs->type) {
 | 
			
		||||
        case BDRV_TYPE_HD:
 | 
			
		||||
            type = "hd";
 | 
			
		||||
            break;
 | 
			
		||||
        case BDRV_TYPE_CDROM:
 | 
			
		||||
            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)
 | 
			
		||||
@@ -1463,8 +1647,11 @@ static void multiwrite_user_cb(MultiwriteCB *mcb)
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < mcb->num_callbacks; i++) {
 | 
			
		||||
        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_buf);
 | 
			
		||||
        qemu_vfree(mcb->callbacks[i].free_buf);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1472,23 +1659,32 @@ static void multiwrite_cb(void *opaque, int ret)
 | 
			
		||||
{
 | 
			
		||||
    MultiwriteCB *mcb = opaque;
 | 
			
		||||
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    if (ret < 0 && !mcb->error) {
 | 
			
		||||
        mcb->error = ret;
 | 
			
		||||
        multiwrite_user_cb(mcb);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mcb->num_requests--;
 | 
			
		||||
    if (mcb->num_requests == 0) {
 | 
			
		||||
        if (mcb->error == 0) {
 | 
			
		||||
        multiwrite_user_cb(mcb);
 | 
			
		||||
        }
 | 
			
		||||
        qemu_free(mcb);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1 > IOV_MAX) {
 | 
			
		||||
            merge = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (merge) {
 | 
			
		||||
            size_t size;
 | 
			
		||||
            QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov));
 | 
			
		||||
@@ -1547,7 +1747,7 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
 | 
			
		||||
            // Add the second request
 | 
			
		||||
            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;
 | 
			
		||||
 | 
			
		||||
            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
 | 
			
		||||
    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++) {
 | 
			
		||||
        mcb->num_requests++;
 | 
			
		||||
        acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
 | 
			
		||||
            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
 | 
			
		||||
            // submitted yet. Otherwise we'll wait for the submitted AIOs to
 | 
			
		||||
            // complete and report the error in the callback.
 | 
			
		||||
            if (mcb->num_requests == 0) {
 | 
			
		||||
                reqs[i].error = EIO;
 | 
			
		||||
            if (i == 0) {
 | 
			
		||||
                goto fail;
 | 
			
		||||
            } else {
 | 
			
		||||
                mcb->error = EIO;
 | 
			
		||||
                multiwrite_cb(mcb, -EIO);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            mcb->num_requests++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Complete the dummy request */
 | 
			
		||||
    multiwrite_cb(mcb, 0);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    free(mcb);
 | 
			
		||||
    for (i = 0; i < mcb->num_callbacks; i++) {
 | 
			
		||||
        reqs[i].error = -EIO;
 | 
			
		||||
    }
 | 
			
		||||
    qemu_free(mcb);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								block.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								block.h
									
									
									
									
									
								
							@@ -4,6 +4,7 @@
 | 
			
		||||
#include "qemu-aio.h"
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "qemu-option.h"
 | 
			
		||||
#include "qobject.h"
 | 
			
		||||
 | 
			
		||||
/* block.c */
 | 
			
		||||
typedef struct BlockDriver BlockDriver;
 | 
			
		||||
@@ -45,8 +46,10 @@ typedef struct QEMUSnapshotInfo {
 | 
			
		||||
#define BDRV_SECTOR_SIZE   (1 << BDRV_SECTOR_BITS)
 | 
			
		||||
#define BDRV_SECTOR_MASK   ~(BDRV_SECTOR_SIZE - 1);
 | 
			
		||||
 | 
			
		||||
void bdrv_info(Monitor *mon);
 | 
			
		||||
void bdrv_info_stats(Monitor *mon);
 | 
			
		||||
void bdrv_info_print(Monitor *mon, const QObject *data);
 | 
			
		||||
void bdrv_info(Monitor *mon, QObject **ret_data);
 | 
			
		||||
void bdrv_stats_print(Monitor *mon, const QObject *data);
 | 
			
		||||
void bdrv_info_stats(Monitor *mon, QObject **ret_data);
 | 
			
		||||
 | 
			
		||||
void bdrv_init(void);
 | 
			
		||||
void bdrv_init_with_whitelist(void);
 | 
			
		||||
@@ -74,6 +77,10 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
               void *buf, int count);
 | 
			
		||||
int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
                const void *buf, int count);
 | 
			
		||||
int bdrv_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);
 | 
			
		||||
int64_t bdrv_getlength(BlockDriverState *bs);
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    file = strdup(filename);
 | 
			
		||||
    file = qemu_strdup(filename);
 | 
			
		||||
    s->readahead_size = READ_AHEAD_SIZE;
 | 
			
		||||
 | 
			
		||||
    /* 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 */
 | 
			
		||||
    if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
 | 
			
		||||
dmg_close:
 | 
			
		||||
	close(s->fd);
 | 
			
		||||
	/* open raw instead */
 | 
			
		||||
	bs->drv=bdrv_find_format("raw");
 | 
			
		||||
	return bs->drv->bdrv_open(bs, filename, flags);
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    info_begin=read_off(s->fd);
 | 
			
		||||
    if(info_begin==0)
 | 
			
		||||
	goto dmg_close;
 | 
			
		||||
	goto fail;
 | 
			
		||||
    if(lseek(s->fd,info_begin,SEEK_SET)<0)
 | 
			
		||||
	goto dmg_close;
 | 
			
		||||
	goto fail;
 | 
			
		||||
    if(read_uint32(s->fd)!=0x100)
 | 
			
		||||
	goto dmg_close;
 | 
			
		||||
	goto fail;
 | 
			
		||||
    if((count = read_uint32(s->fd))==0)
 | 
			
		||||
	goto dmg_close;
 | 
			
		||||
	goto fail;
 | 
			
		||||
    info_end = info_begin+count;
 | 
			
		||||
    if(lseek(s->fd,0xf8,SEEK_CUR)<0)
 | 
			
		||||
	goto dmg_close;
 | 
			
		||||
	goto fail;
 | 
			
		||||
 | 
			
		||||
    /* read offsets */
 | 
			
		||||
    last_in_offset = last_out_offset = 0;
 | 
			
		||||
@@ -116,14 +113,14 @@ dmg_close:
 | 
			
		||||
 | 
			
		||||
	count = read_uint32(s->fd);
 | 
			
		||||
	if(count==0)
 | 
			
		||||
	    goto dmg_close;
 | 
			
		||||
	    goto fail;
 | 
			
		||||
	type = read_uint32(s->fd);
 | 
			
		||||
	if(type!=0x6d697368 || count<244)
 | 
			
		||||
	    lseek(s->fd,count-4,SEEK_CUR);
 | 
			
		||||
	else {
 | 
			
		||||
	    int new_size, chunk_count;
 | 
			
		||||
	    if(lseek(s->fd,200,SEEK_CUR)<0)
 | 
			
		||||
	        goto dmg_close;
 | 
			
		||||
	        goto fail;
 | 
			
		||||
	    chunk_count = (count-204)/40;
 | 
			
		||||
	    new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
 | 
			
		||||
	    s->types = qemu_realloc(s->types, new_size/2);
 | 
			
		||||
@@ -142,7 +139,7 @@ dmg_close:
 | 
			
		||||
		    chunk_count--;
 | 
			
		||||
		    i--;
 | 
			
		||||
		    if(lseek(s->fd,36,SEEK_CUR)<0)
 | 
			
		||||
			goto dmg_close;
 | 
			
		||||
			goto fail;
 | 
			
		||||
		    continue;
 | 
			
		||||
		}
 | 
			
		||||
		read_uint32(s->fd);
 | 
			
		||||
@@ -163,11 +160,14 @@ dmg_close:
 | 
			
		||||
    s->compressed_chunk = qemu_malloc(max_compressed_size+1);
 | 
			
		||||
    s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk);
 | 
			
		||||
    if(inflateInit(&s->zstream) != Z_OK)
 | 
			
		||||
	goto dmg_close;
 | 
			
		||||
	goto fail;
 | 
			
		||||
 | 
			
		||||
    s->current_chunk = s->n_chunks;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
fail:
 | 
			
		||||
    close(s->fd);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int is_sector_in_chunk(BDRVDMGState* s,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								block/qcow.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								block/qcow.c
									
									
									
									
									
								
							@@ -277,8 +277,9 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
        /* update the L1 entry */
 | 
			
		||||
        s->l1_table[l1_index] = l2_offset;
 | 
			
		||||
        tmp = cpu_to_be64(l2_offset);
 | 
			
		||||
        if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
 | 
			
		||||
                        &tmp, sizeof(tmp)) != sizeof(tmp))
 | 
			
		||||
        if (bdrv_pwrite_sync(s->hd,
 | 
			
		||||
                s->l1_table_offset + l1_index * sizeof(tmp),
 | 
			
		||||
                &tmp, sizeof(tmp)) < 0)
 | 
			
		||||
            return 0;
 | 
			
		||||
        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);
 | 
			
		||||
    if (new_l2_table) {
 | 
			
		||||
        memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
 | 
			
		||||
        if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
 | 
			
		||||
            s->l2_size * sizeof(uint64_t))
 | 
			
		||||
        if (bdrv_pwrite_sync(s->hd, l2_offset, l2_table,
 | 
			
		||||
                s->l2_size * sizeof(uint64_t)) < 0)
 | 
			
		||||
            return 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        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 */
 | 
			
		||||
        tmp = cpu_to_be64(cluster_offset);
 | 
			
		||||
        l2_table[l2_index] = tmp;
 | 
			
		||||
        if (bdrv_pwrite(s->hd,
 | 
			
		||||
                        l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
 | 
			
		||||
        if (bdrv_pwrite_sync(s->hd, l2_offset + l2_index * sizeof(tmp),
 | 
			
		||||
                &tmp, sizeof(tmp)) < 0)
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return cluster_offset;
 | 
			
		||||
@@ -821,7 +822,8 @@ static int qcow_make_empty(BlockDriverState *bs)
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
            l1_length) < 0)
 | 
			
		||||
        return -1;
 | 
			
		||||
    ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int new_l1_size, new_l1_size2, ret, i;
 | 
			
		||||
    uint64_t *new_l1_table;
 | 
			
		||||
    uint64_t new_l1_table_offset;
 | 
			
		||||
    int64_t new_l1_table_offset;
 | 
			
		||||
    uint8_t data[12];
 | 
			
		||||
 | 
			
		||||
    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) */
 | 
			
		||||
    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++)
 | 
			
		||||
        new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
 | 
			
		||||
    ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
 | 
			
		||||
    if (ret != new_l1_size2)
 | 
			
		||||
    ret = bdrv_pwrite_sync(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    for(i = 0; i < s->l1_size; i++)
 | 
			
		||||
        new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
 | 
			
		||||
@@ -67,9 +71,10 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
 | 
			
		||||
    /* set new table */
 | 
			
		||||
    cpu_to_be32w((uint32_t*)data, new_l1_size);
 | 
			
		||||
    cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
 | 
			
		||||
    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,
 | 
			
		||||
                sizeof(data)) != sizeof(data))
 | 
			
		||||
    ret = bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, l1_size), data,sizeof(data));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
    qemu_free(s->l1_table);
 | 
			
		||||
    qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
 | 
			
		||||
    s->l1_table_offset = new_l1_table_offset;
 | 
			
		||||
@@ -77,8 +82,9 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
 | 
			
		||||
    s->l1_size = new_l1_size;
 | 
			
		||||
    return 0;
 | 
			
		||||
 fail:
 | 
			
		||||
    qemu_free(s->l1_table);
 | 
			
		||||
    return -EIO;
 | 
			
		||||
    qemu_free(new_l1_table);
 | 
			
		||||
    qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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];
 | 
			
		||||
    int l1_start_index;
 | 
			
		||||
    int i;
 | 
			
		||||
    int i, ret;
 | 
			
		||||
 | 
			
		||||
    l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
 | 
			
		||||
    for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) {
 | 
			
		||||
        buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bdrv_pwrite(s->hd, s->l1_table_offset + 8 * l1_start_index,
 | 
			
		||||
        buf, sizeof(buf)) != sizeof(buf))
 | 
			
		||||
    {
 | 
			
		||||
        return -1;
 | 
			
		||||
    ret = bdrv_pwrite_sync(s->hd, s->l1_table_offset + 8 * l1_start_index,
 | 
			
		||||
        buf, sizeof(buf));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
@@ -213,18 +219,16 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int min_index;
 | 
			
		||||
    uint64_t old_l2_offset;
 | 
			
		||||
    uint64_t *l2_table, l2_offset;
 | 
			
		||||
    uint64_t *l2_table;
 | 
			
		||||
    int64_t l2_offset;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    old_l2_offset = s->l1_table[l1_index];
 | 
			
		||||
 | 
			
		||||
    /* allocate a new l2 entry */
 | 
			
		||||
 | 
			
		||||
    l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
 | 
			
		||||
 | 
			
		||||
    /* update the L1 entry */
 | 
			
		||||
 | 
			
		||||
    s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
 | 
			
		||||
    if (write_l1_entry(s, l1_index) < 0) {
 | 
			
		||||
    if (l2_offset < 0) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -241,13 +245,20 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
 | 
			
		||||
        if (bdrv_pread(s->hd, old_l2_offset,
 | 
			
		||||
                       l2_table, s->l2_size * sizeof(uint64_t)) !=
 | 
			
		||||
            s->l2_size * sizeof(uint64_t))
 | 
			
		||||
            return NULL;
 | 
			
		||||
            goto fail;
 | 
			
		||||
    }
 | 
			
		||||
    /* write the l2 table to the file */
 | 
			
		||||
    if (bdrv_pwrite(s->hd, l2_offset,
 | 
			
		||||
                    l2_table, s->l2_size * sizeof(uint64_t)) !=
 | 
			
		||||
        s->l2_size * sizeof(uint64_t))
 | 
			
		||||
        return NULL;
 | 
			
		||||
    ret = bdrv_pwrite_sync(s->hd, l2_offset, l2_table,
 | 
			
		||||
        s->l2_size * sizeof(uint64_t));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        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 */
 | 
			
		||||
 | 
			
		||||
@@ -255,6 +266,11 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
 | 
			
		||||
    s->l2_cache_counts[min_index] = 1;
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
@@ -370,7 +386,7 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
 | 
			
		||||
                        s->cluster_data, n, 1,
 | 
			
		||||
                        &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);
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
        return ret;
 | 
			
		||||
@@ -479,8 +495,8 @@ out:
 | 
			
		||||
 * the l2 table offset in the qcow2 file and the cluster index
 | 
			
		||||
 * 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,
 | 
			
		||||
                             uint64_t **new_l2_table,
 | 
			
		||||
                             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);
 | 
			
		||||
    if (l1_index >= s->l1_size) {
 | 
			
		||||
        ret = qcow2_grow_l1_table(bs, l1_index + 1);
 | 
			
		||||
        if (ret < 0)
 | 
			
		||||
            return 0;
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    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 */
 | 
			
		||||
        l2_offset &= ~QCOW_OFLAG_COPIED;
 | 
			
		||||
        l2_table = l2_load(bs, l2_offset);
 | 
			
		||||
        if (l2_table == NULL)
 | 
			
		||||
            return 0;
 | 
			
		||||
        if (l2_table == NULL) {
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if (l2_offset)
 | 
			
		||||
            qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
 | 
			
		||||
        l2_table = l2_allocate(bs, l1_index);
 | 
			
		||||
        if (l2_table == NULL)
 | 
			
		||||
            return 0;
 | 
			
		||||
        if (l2_table == NULL) {
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        }
 | 
			
		||||
        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_index = l2_index;
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -548,12 +567,14 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
 | 
			
		||||
    if (ret == 0)
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cluster_offset = be64_to_cpu(l2_table[l2_index]);
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
 | 
			
		||||
    if (cluster_offset < 0) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
 | 
			
		||||
                  (cluster_offset >> 9);
 | 
			
		||||
 | 
			
		||||
@@ -574,10 +599,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
    /* compressed clusters never have the copied flag */
 | 
			
		||||
 | 
			
		||||
    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_table + l2_index,
 | 
			
		||||
                    sizeof(uint64_t)) != sizeof(uint64_t))
 | 
			
		||||
                    sizeof(uint64_t)) < 0)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    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 end_offset = (8 * (l2_index + num) + 511) & ~511;
 | 
			
		||||
    size_t len = end_offset - start_offset;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (bdrv_pwrite(s->hd, l2_offset + start_offset, &l2_table[l2_start_index],
 | 
			
		||||
        len) != len)
 | 
			
		||||
    {
 | 
			
		||||
        return -1;
 | 
			
		||||
    ret = bdrv_pwrite_sync(s->hd, l2_offset + start_offset,
 | 
			
		||||
        &l2_table[l2_start_index], len);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
 | 
			
		||||
    QCowL2Meta *m)
 | 
			
		||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int i, j = 0, l2_index, ret;
 | 
			
		||||
    uint64_t *old_cluster, start_sect, l2_offset, *l2_table;
 | 
			
		||||
    uint64_t cluster_offset = m->cluster_offset;
 | 
			
		||||
 | 
			
		||||
    if (m->nb_clusters == 0)
 | 
			
		||||
        return 0;
 | 
			
		||||
@@ -633,10 +659,11 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
 | 
			
		||||
            goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = -EIO;
 | 
			
		||||
    /* 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < m->nb_clusters; i++) {
 | 
			
		||||
        /* 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);
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
    if (write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters) < 0) {
 | 
			
		||||
        ret = -1;
 | 
			
		||||
    ret = write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        qcow2_l2_cache_reset(bs);
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -670,30 +698,36 @@ err:
 | 
			
		||||
/*
 | 
			
		||||
 * alloc_cluster_offset
 | 
			
		||||
 *
 | 
			
		||||
 * For a given offset of the disk image, return cluster offset in
 | 
			
		||||
 * qcow2 file.
 | 
			
		||||
 *
 | 
			
		||||
 * For a given offset of the disk image, return cluster offset in qcow2 file.
 | 
			
		||||
 * If the offset is not found, allocate a new cluster.
 | 
			
		||||
 *
 | 
			
		||||
 * Return the cluster offset if successful,
 | 
			
		||||
 * Return 0, otherwise.
 | 
			
		||||
 * If the cluster was already allocated, m->nb_clusters is set to 0,
 | 
			
		||||
 * 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
                                    uint64_t offset,
 | 
			
		||||
                                    int n_start, int n_end,
 | 
			
		||||
                                    int *num, QCowL2Meta *m)
 | 
			
		||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
 | 
			
		||||
    int n_start, int n_end, int *num, QCowL2Meta *m)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int l2_index, ret;
 | 
			
		||||
    uint64_t l2_offset, *l2_table, cluster_offset;
 | 
			
		||||
    uint64_t l2_offset, *l2_table;
 | 
			
		||||
    int64_t cluster_offset;
 | 
			
		||||
    unsigned int nb_clusters, i = 0;
 | 
			
		||||
    QCowL2Meta *old_alloc;
 | 
			
		||||
 | 
			
		||||
    ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
 | 
			
		||||
    if (ret == 0)
 | 
			
		||||
        return 0;
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
        m->nb_clusters = 0;
 | 
			
		||||
        m->depends_on = NULL;
 | 
			
		||||
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
@@ -723,12 +758,15 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
    while (i < nb_clusters) {
 | 
			
		||||
        i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
 | 
			
		||||
                &l2_table[l2_index], i, 0);
 | 
			
		||||
 | 
			
		||||
        if(be64_to_cpu(l2_table[l2_index + i]))
 | 
			
		||||
        if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        i += count_contiguous_free_clusters(nb_clusters - i,
 | 
			
		||||
                &l2_table[l2_index + i]);
 | 
			
		||||
        if (i >= nb_clusters) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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))
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    assert(i <= nb_clusters);
 | 
			
		||||
    nb_clusters = i;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
@@ -779,6 +818,10 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
    /* allocate a new cluster */
 | 
			
		||||
 | 
			
		||||
    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 */
 | 
			
		||||
    m->offset = offset;
 | 
			
		||||
@@ -787,10 +830,11 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
 | 
			
		||||
    m->cluster_offset = cluster_offset;
 | 
			
		||||
 | 
			
		||||
    *num = m->nb_available - n_start;
 | 
			
		||||
 | 
			
		||||
    return cluster_offset;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
#include "block/qcow2.h"
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
                            int addend);
 | 
			
		||||
 | 
			
		||||
@@ -42,8 +42,8 @@ static int write_refcount_block(BDRVQcowState *s)
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bdrv_pwrite(s->hd, s->refcount_block_cache_offset,
 | 
			
		||||
            s->refcount_block_cache, size) != size)
 | 
			
		||||
    if (bdrv_pwrite_sync(s->hd, s->refcount_block_cache_offset,
 | 
			
		||||
            s->refcount_block_cache, size) < 0)
 | 
			
		||||
    {
 | 
			
		||||
        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]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    int new_table_size, new_table_size2, refcount_table_clusters, i, ret;
 | 
			
		||||
    uint64_t *new_table;
 | 
			
		||||
    int64_t table_offset;
 | 
			
		||||
    uint8_t data[12];
 | 
			
		||||
    int old_table_size;
 | 
			
		||||
    int64_t old_table_offset;
 | 
			
		||||
    unsigned int min_clusters = (min_size >> (s->cluster_bits - 3)) + 1;
 | 
			
		||||
    unsigned int refcount_table_clusters =
 | 
			
		||||
        MAX(1, s->refcount_table_size >> (s->cluster_bits - 3));
 | 
			
		||||
 | 
			
		||||
    if (min_size <= s->refcount_table_size)
 | 
			
		||||
        return 0;
 | 
			
		||||
    /* compute new table size */
 | 
			
		||||
    refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
 | 
			
		||||
    for(;;) {
 | 
			
		||||
        if (refcount_table_clusters == 0) {
 | 
			
		||||
            refcount_table_clusters = 1;
 | 
			
		||||
        } else {
 | 
			
		||||
    while (min_clusters > refcount_table_clusters) {
 | 
			
		||||
        refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
 | 
			
		||||
    }
 | 
			
		||||
        new_table_size = refcount_table_clusters << (s->cluster_bits - 3);
 | 
			
		||||
        if (min_size <= new_table_size)
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef DEBUG_ALLOC2
 | 
			
		||||
    printf("grow_refcount_table from %d to %d\n",
 | 
			
		||||
           s->refcount_table_size,
 | 
			
		||||
           new_table_size);
 | 
			
		||||
#endif
 | 
			
		||||
    new_table_size2 = new_table_size * sizeof(uint64_t);
 | 
			
		||||
    new_table = qemu_mallocz(new_table_size2);
 | 
			
		||||
    memcpy(new_table, s->refcount_table,
 | 
			
		||||
           s->refcount_table_size * sizeof(uint64_t));
 | 
			
		||||
    for(i = 0; i < s->refcount_table_size; i++)
 | 
			
		||||
        cpu_to_be64s(&new_table[i]);
 | 
			
		||||
    /* Note: we cannot update the refcount now to avoid recursion */
 | 
			
		||||
    table_offset = alloc_clusters_noref(bs, new_table_size2);
 | 
			
		||||
    ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2);
 | 
			
		||||
    if (ret != new_table_size2)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    for(i = 0; i < s->refcount_table_size; i++)
 | 
			
		||||
        be64_to_cpus(&new_table[i]);
 | 
			
		||||
 | 
			
		||||
    cpu_to_be64w((uint64_t*)data, table_offset);
 | 
			
		||||
    cpu_to_be32w((uint32_t*)(data + 8), refcount_table_clusters);
 | 
			
		||||
    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
 | 
			
		||||
                    data, sizeof(data)) != sizeof(data))
 | 
			
		||||
        goto fail;
 | 
			
		||||
    qemu_free(s->refcount_table);
 | 
			
		||||
    old_table_offset = s->refcount_table_offset;
 | 
			
		||||
    old_table_size = s->refcount_table_size;
 | 
			
		||||
    s->refcount_table = new_table;
 | 
			
		||||
    s->refcount_table_size = new_table_size;
 | 
			
		||||
    s->refcount_table_offset = table_offset;
 | 
			
		||||
 | 
			
		||||
    update_refcount(bs, table_offset, new_table_size2, 1);
 | 
			
		||||
    qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
 | 
			
		||||
    return 0;
 | 
			
		||||
 fail:
 | 
			
		||||
    qemu_free(new_table);
 | 
			
		||||
    return -EIO;
 | 
			
		||||
    return refcount_table_clusters << (s->cluster_bits - 3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* 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)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int64_t offset, refcount_block_offset;
 | 
			
		||||
    unsigned int refcount_table_index;
 | 
			
		||||
    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);
 | 
			
		||||
    if (refcount_table_index >= s->refcount_table_size) {
 | 
			
		||||
        ret = grow_refcount_table(bs, refcount_table_index + 1);
 | 
			
		||||
        if (ret < 0)
 | 
			
		||||
 | 
			
		||||
    if (refcount_table_index < s->refcount_table_size) {
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
    /* Load or allocate the refcount block */
 | 
			
		||||
    refcount_block_offset = s->refcount_table[refcount_table_index];
 | 
			
		||||
    if (!refcount_block_offset) {
 | 
			
		||||
        if (cache_refcount_updates) {
 | 
			
		||||
            write_refcount_block(s);
 | 
			
		||||
            cache_refcount_updates = 0;
 | 
			
		||||
            }
 | 
			
		||||
        /* create a new refcount block */
 | 
			
		||||
        /* Note: we cannot update the refcount now to avoid recursion */
 | 
			
		||||
        offset = alloc_clusters_noref(bs, s->cluster_size);
 | 
			
		||||
        memset(s->refcount_block_cache, 0, s->cluster_size);
 | 
			
		||||
        ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size);
 | 
			
		||||
        if (ret != s->cluster_size)
 | 
			
		||||
            return -EINVAL;
 | 
			
		||||
        s->refcount_table[refcount_table_index] = offset;
 | 
			
		||||
        data64 = cpu_to_be64(offset);
 | 
			
		||||
        ret = bdrv_pwrite(s->hd, s->refcount_table_offset +
 | 
			
		||||
                          refcount_table_index * sizeof(uint64_t),
 | 
			
		||||
                          &data64, sizeof(data64));
 | 
			
		||||
        if (ret != sizeof(data64))
 | 
			
		||||
            return -EINVAL;
 | 
			
		||||
 | 
			
		||||
        refcount_block_offset = offset;
 | 
			
		||||
        s->refcount_block_cache_offset = offset;
 | 
			
		||||
        update_refcount(bs, offset, s->cluster_size, 1);
 | 
			
		||||
        cache_refcount_updates = cache;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (refcount_block_offset != s->refcount_block_cache_offset) {
 | 
			
		||||
            if (load_refcount_block(bs, refcount_block_offset) < 0)
 | 
			
		||||
                return -EIO;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
            return refcount_block_offset;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * 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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Allocate the refcount block itself and mark it as used */
 | 
			
		||||
    uint64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_ALLOC2
 | 
			
		||||
    fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64
 | 
			
		||||
        " at %" PRIx64 "\n",
 | 
			
		||||
        refcount_table_index, cluster_index << s->cluster_bits, new_block);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
        s->refcount_block_cache_offset = new_block;
 | 
			
		||||
 | 
			
		||||
        /* The block describes itself, need to update the cache */
 | 
			
		||||
        int block_index = (new_block >> s->cluster_bits) &
 | 
			
		||||
            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
 | 
			
		||||
        s->refcount_block_cache[block_index] = cpu_to_be16(1);
 | 
			
		||||
    } else {
 | 
			
		||||
        /* Described somewhere else. This can recurse at most twice before we
 | 
			
		||||
         * arrive at a block that describes itself. */
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* 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)
 | 
			
		||||
@@ -245,43 +397,52 @@ static int write_refcount_block_entries(BDRVQcowState *s,
 | 
			
		||||
    int64_t refcount_block_offset, int first_index, int last_index)
 | 
			
		||||
{
 | 
			
		||||
    size_t size;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (cache_refcount_updates) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (first_index < 0) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    first_index &= ~(REFCOUNTS_PER_SECTOR - 1);
 | 
			
		||||
    last_index = (last_index + REFCOUNTS_PER_SECTOR)
 | 
			
		||||
        & ~(REFCOUNTS_PER_SECTOR - 1);
 | 
			
		||||
 | 
			
		||||
    size = (last_index - first_index) << REFCOUNT_SHIFT;
 | 
			
		||||
    if (bdrv_pwrite(s->hd,
 | 
			
		||||
    ret = bdrv_pwrite_sync(s->hd,
 | 
			
		||||
        refcount_block_offset + (first_index << REFCOUNT_SHIFT),
 | 
			
		||||
        &s->refcount_block_cache[first_index], size) != size)
 | 
			
		||||
    {
 | 
			
		||||
        return -EIO;
 | 
			
		||||
        &s->refcount_block_cache[first_index], size);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* XXX: cache several refcount block clusters ? */
 | 
			
		||||
static int update_refcount(BlockDriverState *bs,
 | 
			
		||||
                            int64_t offset, int64_t length,
 | 
			
		||||
                            int addend)
 | 
			
		||||
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
 | 
			
		||||
    int64_t offset, int64_t length, int addend)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int64_t start, last, cluster_offset;
 | 
			
		||||
    int64_t refcount_block_offset = 0;
 | 
			
		||||
    int64_t table_index = -1, old_table_index;
 | 
			
		||||
    int first_index = -1, last_index = -1;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_ALLOC2
 | 
			
		||||
    printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",
 | 
			
		||||
           offset, length, addend);
 | 
			
		||||
#endif
 | 
			
		||||
    if (length <= 0)
 | 
			
		||||
    if (length < 0) {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    } else if (length == 0) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    start = offset & ~(s->cluster_size - 1);
 | 
			
		||||
    last = (offset + length - 1) & ~(s->cluster_size - 1);
 | 
			
		||||
    for(cluster_offset = start; cluster_offset <= last;
 | 
			
		||||
@@ -289,6 +450,7 @@ static int update_refcount(BlockDriverState *bs,
 | 
			
		||||
    {
 | 
			
		||||
        int block_index, refcount;
 | 
			
		||||
        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 */
 | 
			
		||||
        old_table_index = table_index;
 | 
			
		||||
@@ -306,10 +468,12 @@ static int update_refcount(BlockDriverState *bs,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Load the refcount block and allocate it if needed */
 | 
			
		||||
        refcount_block_offset = alloc_refcount_block(bs, cluster_index);
 | 
			
		||||
        if (refcount_block_offset < 0) {
 | 
			
		||||
            return refcount_block_offset;
 | 
			
		||||
        new_block = alloc_refcount_block(bs, cluster_index);
 | 
			
		||||
        if (new_block < 0) {
 | 
			
		||||
            ret = new_block;
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        refcount_block_offset = new_block;
 | 
			
		||||
 | 
			
		||||
        /* we can update the count and save it */
 | 
			
		||||
        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 += addend;
 | 
			
		||||
        if (refcount < 0 || refcount > 0xffff)
 | 
			
		||||
            return -EINVAL;
 | 
			
		||||
        if (refcount < 0 || refcount > 0xffff) {
 | 
			
		||||
            ret = -EINVAL;
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        if (refcount == 0 && cluster_index < s->free_cluster_index) {
 | 
			
		||||
            s->free_cluster_index = cluster_index;
 | 
			
		||||
        }
 | 
			
		||||
        s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = 0;
 | 
			
		||||
fail:
 | 
			
		||||
 | 
			
		||||
    /* Write last changed block to disk */
 | 
			
		||||
    if (refcount_block_offset != 0) {
 | 
			
		||||
        if (write_refcount_block_entries(s, refcount_block_offset,
 | 
			
		||||
            first_index, last_index) < 0)
 | 
			
		||||
        {
 | 
			
		||||
            return -EIO;
 | 
			
		||||
            return 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 */
 | 
			
		||||
@@ -390,9 +568,13 @@ retry:
 | 
			
		||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
 | 
			
		||||
{
 | 
			
		||||
    int64_t offset;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -407,6 +589,9 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
 | 
			
		||||
    assert(size > 0 && size <= s->cluster_size);
 | 
			
		||||
    if (s->free_byte_offset == 0) {
 | 
			
		||||
        s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size);
 | 
			
		||||
        if (s->free_byte_offset < 0) {
 | 
			
		||||
            return s->free_byte_offset;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 redo:
 | 
			
		||||
    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);
 | 
			
		||||
    } else {
 | 
			
		||||
        offset = qcow2_alloc_clusters(bs, s->cluster_size);
 | 
			
		||||
        if (offset < 0) {
 | 
			
		||||
            return offset;
 | 
			
		||||
        }
 | 
			
		||||
        cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
 | 
			
		||||
        if ((cluster_offset + s->cluster_size) == offset) {
 | 
			
		||||
            /* we are lucky: contiguous data */
 | 
			
		||||
@@ -439,7 +627,13 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
 | 
			
		||||
void qcow2_free_clusters(BlockDriverState *bs,
 | 
			
		||||
                          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) {
 | 
			
		||||
                        nb_csectors = ((offset >> s->csize_shift) &
 | 
			
		||||
                                       s->csize_mask) + 1;
 | 
			
		||||
                        if (addend != 0)
 | 
			
		||||
                            update_refcount(bs, (offset & s->cluster_offset_mask) & ~511,
 | 
			
		||||
                        if (addend != 0) {
 | 
			
		||||
                            int ret;
 | 
			
		||||
                            ret = update_refcount(bs,
 | 
			
		||||
                                (offset & s->cluster_offset_mask) & ~511,
 | 
			
		||||
                                nb_csectors * 512, addend);
 | 
			
		||||
                            if (ret < 0) {
 | 
			
		||||
                                goto fail;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        /* compressed clusters are never modified */
 | 
			
		||||
                        refcount = 2;
 | 
			
		||||
                    } else {
 | 
			
		||||
@@ -572,8 +772,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (l2_modified) {
 | 
			
		||||
                if (bdrv_pwrite(s->hd,
 | 
			
		||||
                                l2_offset, l2_table, l2_size) != l2_size)
 | 
			
		||||
                if (bdrv_pwrite_sync(s->hd,
 | 
			
		||||
                                l2_offset, l2_table, l2_size) < 0)
 | 
			
		||||
                    goto fail;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -594,8 +794,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
 | 
			
		||||
    if (l1_modified) {
 | 
			
		||||
        for(i = 0; i < l1_size; i++)
 | 
			
		||||
            cpu_to_be64s(&l1_table[i]);
 | 
			
		||||
        if (bdrv_pwrite(s->hd, l1_table_offset, l1_table,
 | 
			
		||||
                        l1_size2) != l1_size2)
 | 
			
		||||
        if (bdrv_pwrite_sync(s->hd, l1_table_offset, l1_table,
 | 
			
		||||
                        l1_size2) < 0)
 | 
			
		||||
            goto fail;
 | 
			
		||||
        for(i = 0; i < l1_size; 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);
 | 
			
		||||
    offset = snapshots_offset;
 | 
			
		||||
    if (offset < 0) {
 | 
			
		||||
        return offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < s->nb_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.name_size = cpu_to_be16(name_size);
 | 
			
		||||
        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;
 | 
			
		||||
        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;
 | 
			
		||||
        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;
 | 
			
		||||
        offset += name_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* update the various header fields */
 | 
			
		||||
    data64 = cpu_to_be64(snapshots_offset);
 | 
			
		||||
    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
 | 
			
		||||
                    &data64, sizeof(data64)) != sizeof(data64))
 | 
			
		||||
    if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, snapshots_offset),
 | 
			
		||||
                    &data64, sizeof(data64)) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    data32 = cpu_to_be32(s->nb_snapshots);
 | 
			
		||||
    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
 | 
			
		||||
                    &data32, sizeof(data32)) != sizeof(data32))
 | 
			
		||||
    if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, nb_snapshots),
 | 
			
		||||
                    &data32, sizeof(data32)) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
 | 
			
		||||
    /* free the old snapshot table */
 | 
			
		||||
@@ -235,6 +238,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
 | 
			
		||||
    QCowSnapshot *snapshots1, sn1, *sn = &sn1;
 | 
			
		||||
    int i, ret;
 | 
			
		||||
    uint64_t *l1_table = NULL;
 | 
			
		||||
    int64_t l1_table_offset;
 | 
			
		||||
 | 
			
		||||
    memset(sn, 0, sizeof(*sn));
 | 
			
		||||
 | 
			
		||||
@@ -263,7 +267,12 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
 | 
			
		||||
        goto fail;
 | 
			
		||||
 | 
			
		||||
    /* 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;
 | 
			
		||||
 | 
			
		||||
    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++) {
 | 
			
		||||
        l1_table[i] = cpu_to_be64(s->l1_table[i]);
 | 
			
		||||
    }
 | 
			
		||||
    if (bdrv_pwrite(s->hd, sn->l1_table_offset,
 | 
			
		||||
                    l1_table, s->l1_size * sizeof(uint64_t)) !=
 | 
			
		||||
        (s->l1_size * sizeof(uint64_t)))
 | 
			
		||||
    if (bdrv_pwrite_sync(s->hd, sn->l1_table_offset,
 | 
			
		||||
                    l1_table, s->l1_size * sizeof(uint64_t)) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    qemu_free(l1_table);
 | 
			
		||||
    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,
 | 
			
		||||
                   s->l1_table, l1_size2) != l1_size2)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    if (bdrv_pwrite(s->hd, s->l1_table_offset,
 | 
			
		||||
                    s->l1_table, l1_size2) != l1_size2)
 | 
			
		||||
    if (bdrv_pwrite_sync(s->hd, s->l1_table_offset,
 | 
			
		||||
                    s->l1_table, l1_size2) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    for(i = 0;i < s->l1_size; i++) {
 | 
			
		||||
        be64_to_cpus(&s->l1_table[i]);
 | 
			
		||||
 
 | 
			
		||||
@@ -467,9 +467,11 @@ static void qcow_aio_read_cb(void *opaque, int ret)
 | 
			
		||||
        acb->hd_aiocb = bdrv_aio_readv(s->hd,
 | 
			
		||||
                            (acb->cluster_offset >> 9) + index_in_cluster,
 | 
			
		||||
                            &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
 | 
			
		||||
        if (acb->hd_aiocb == NULL)
 | 
			
		||||
        if (acb->hd_aiocb == NULL) {
 | 
			
		||||
            ret = -EIO;
 | 
			
		||||
            goto done;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
done:
 | 
			
		||||
@@ -561,7 +563,7 @@ static void qcow_aio_write_cb(void *opaque, int ret)
 | 
			
		||||
    acb->hd_aiocb = NULL;
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
    acb->cluster_offset = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
 | 
			
		||||
                                          index_in_cluster,
 | 
			
		||||
                                          n_end, &acb->n, &acb->l2meta);
 | 
			
		||||
    ret = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
 | 
			
		||||
        index_in_cluster, 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. */
 | 
			
		||||
    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,
 | 
			
		||||
            acb, next_depend);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!acb->cluster_offset || (acb->cluster_offset & 511) != 0) {
 | 
			
		||||
        ret = -EIO;
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    assert((acb->cluster_offset & 511) == 0);
 | 
			
		||||
 | 
			
		||||
    if (s->crypt_method) {
 | 
			
		||||
        if (!acb->cluster_data) {
 | 
			
		||||
            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->hd_qiov, acb->n,
 | 
			
		||||
                                    qcow_aio_write_cb, acb);
 | 
			
		||||
    if (acb->hd_aiocb == NULL)
 | 
			
		||||
        goto done;
 | 
			
		||||
    if (acb->hd_aiocb == NULL) {
 | 
			
		||||
        ret = -EIO;
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    if (acb->l2meta.nb_clusters != 0) {
 | 
			
		||||
        QLIST_REMOVE(&acb->l2meta, next_in_flight);
 | 
			
		||||
    }
 | 
			
		||||
done:
 | 
			
		||||
    if (acb->qiov->niov > 1)
 | 
			
		||||
        qemu_vfree(acb->orig_buf);
 | 
			
		||||
@@ -683,27 +693,27 @@ static int get_bits_from_size(size_t size)
 | 
			
		||||
static int preallocate(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    uint64_t cluster_offset = 0;
 | 
			
		||||
    uint64_t nb_sectors;
 | 
			
		||||
    uint64_t offset;
 | 
			
		||||
    int num;
 | 
			
		||||
    int ret;
 | 
			
		||||
    QCowL2Meta meta;
 | 
			
		||||
 | 
			
		||||
    nb_sectors = bdrv_getlength(bs) >> 9;
 | 
			
		||||
    offset = 0;
 | 
			
		||||
    QLIST_INIT(&meta.dependent_requests);
 | 
			
		||||
    meta.cluster_offset = 0;
 | 
			
		||||
 | 
			
		||||
    while (nb_sectors) {
 | 
			
		||||
        num = MIN(nb_sectors, INT_MAX >> 9);
 | 
			
		||||
        cluster_offset = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
 | 
			
		||||
            &meta);
 | 
			
		||||
        ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num, &meta);
 | 
			
		||||
 | 
			
		||||
        if (cluster_offset == 0) {
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (qcow2_alloc_cluster_link_l2(bs, cluster_offset, &meta) < 0) {
 | 
			
		||||
            qcow2_free_any_clusters(bs, cluster_offset, meta.nb_clusters);
 | 
			
		||||
        if (qcow2_alloc_cluster_link_l2(bs, &meta) < 0) {
 | 
			
		||||
            qcow2_free_any_clusters(bs, meta.cluster_offset, meta.nb_clusters);
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -722,10 +732,10 @@ static int preallocate(BlockDriverState *bs)
 | 
			
		||||
     * all of the allocated clusters (otherwise we get failing reads after
 | 
			
		||||
     * EOF). Extend the image to the last allocated sector.
 | 
			
		||||
     */
 | 
			
		||||
    if (cluster_offset != 0) {
 | 
			
		||||
    if (meta.cluster_offset != 0) {
 | 
			
		||||
        uint8_t buf[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;
 | 
			
		||||
@@ -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 ref_clusters, backing_format_len = 0;
 | 
			
		||||
    int ref_clusters, reftable_clusters, backing_format_len = 0;
 | 
			
		||||
    int rounded_ext_bf_len = 0;
 | 
			
		||||
    QCowHeader header;
 | 
			
		||||
    uint64_t tmp, offset;
 | 
			
		||||
    uint64_t old_ref_clusters;
 | 
			
		||||
    QCowCreateState s1, *s = &s1;
 | 
			
		||||
    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);
 | 
			
		||||
    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;
 | 
			
		||||
    header.refcount_table_offset = cpu_to_be64(offset);
 | 
			
		||||
    header.refcount_table_clusters = cpu_to_be32(1);
 | 
			
		||||
    offset += s->cluster_size;
 | 
			
		||||
    header.refcount_table_clusters = cpu_to_be32(reftable_clusters);
 | 
			
		||||
    offset += (reftable_clusters * s->cluster_size);
 | 
			
		||||
    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++) {
 | 
			
		||||
        s->refcount_table[i] = cpu_to_be64(offset);
 | 
			
		||||
        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, s->l1_table_offset,
 | 
			
		||||
        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,
 | 
			
		||||
        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));
 | 
			
		||||
    }
 | 
			
		||||
    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);
 | 
			
		||||
    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;
 | 
			
		||||
    int growable = bs->growable;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    return size;
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qcow_load_vmstate(BlockDriverState *bs, uint8_t *buf,
 | 
			
		||||
 
 | 
			
		||||
@@ -135,6 +135,7 @@ struct QCowAIOCB;
 | 
			
		||||
typedef struct QCowL2Meta
 | 
			
		||||
{
 | 
			
		||||
    uint64_t offset;
 | 
			
		||||
    uint64_t cluster_offset;
 | 
			
		||||
    int n_start;
 | 
			
		||||
    int nb_available;
 | 
			
		||||
    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,
 | 
			
		||||
    int *num);
 | 
			
		||||
uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
                              uint64_t offset,
 | 
			
		||||
                              int n_start, int n_end,
 | 
			
		||||
                              int *num, QCowL2Meta *m);
 | 
			
		||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
 | 
			
		||||
    int n_start, int n_end, int *num, QCowL2Meta *m);
 | 
			
		||||
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
                                         uint64_t offset,
 | 
			
		||||
                                         int compressed_size);
 | 
			
		||||
 | 
			
		||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
 | 
			
		||||
    QCowL2Meta *m);
 | 
			
		||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
 | 
			
		||||
 | 
			
		||||
/* qcow2-snapshot.c functions */
 | 
			
		||||
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,8 @@
 | 
			
		||||
#include "qemu-log.h"
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
#include "module.h"
 | 
			
		||||
#include "compatfd.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include "block/raw-posix-aio.h"
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COCOA
 | 
			
		||||
@@ -595,7 +597,7 @@ static void raw_close(BlockDriverState *bs)
 | 
			
		||||
        close(s->fd);
 | 
			
		||||
        s->fd = -1;
 | 
			
		||||
        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);
 | 
			
		||||
#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) {
 | 
			
		||||
        logout("unsupported version %u.%u\n",
 | 
			
		||||
               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) {
 | 
			
		||||
        logout("unsupported block size %u B\n", header.block_size);
 | 
			
		||||
        goto fail;
 | 
			
		||||
    } else if (header.disk_size !=
 | 
			
		||||
    } else if (header.disk_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;
 | 
			
		||||
    } else if (!uuid_is_null(header.uuid_link)) {
 | 
			
		||||
        logout("link uuid != 0, unsupported\n");
 | 
			
		||||
@@ -831,7 +840,10 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
        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 = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								block/vmdk.c
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								block/vmdk.c
									
									
									
									
									
								
							@@ -87,14 +87,6 @@ typedef struct VmdkMetaData {
 | 
			
		||||
    int valid;
 | 
			
		||||
} VmdkMetaData;
 | 
			
		||||
 | 
			
		||||
typedef struct ActiveBDRVState{
 | 
			
		||||
    BlockDriverState *hd;            // active image handler
 | 
			
		||||
    uint64_t cluster_offset;         // current write offset
 | 
			
		||||
}ActiveBDRVState;
 | 
			
		||||
 | 
			
		||||
static ActiveBDRVState activeBDRV;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t magic;
 | 
			
		||||
@@ -161,7 +153,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
 | 
			
		||||
        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 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -285,7 +277,6 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file)
 | 
			
		||||
        goto fail_rgd;
 | 
			
		||||
    if (write(snp_fd, rgd_buf, gd_size) == -1)
 | 
			
		||||
        goto fail_rgd;
 | 
			
		||||
    qemu_free(rgd_buf);
 | 
			
		||||
 | 
			
		||||
    /* write GD */
 | 
			
		||||
    gd_buf = qemu_malloc(gd_size);
 | 
			
		||||
@@ -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)
 | 
			
		||||
        goto fail_gd;
 | 
			
		||||
    qemu_free(gd_buf);
 | 
			
		||||
    qemu_free(rgd_buf);
 | 
			
		||||
 | 
			
		||||
    close(p_fd);
 | 
			
		||||
    close(snp_fd);
 | 
			
		||||
@@ -458,29 +450,27 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
 | 
			
		||||
static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
 | 
			
		||||
                             uint64_t offset, int allocate)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t parent_cluster_offset;
 | 
			
		||||
    BDRVVmdkState *s = bs->opaque;
 | 
			
		||||
    uint8_t  whole_grain[s->cluster_sectors*512];        // 128 sectors * 512 bytes each = grain size 64KB
 | 
			
		||||
 | 
			
		||||
    // we will be here if it's first write on non-exist grain(cluster).
 | 
			
		||||
    // try to read from parent image, if exist
 | 
			
		||||
    if (bs->backing_hd) {
 | 
			
		||||
        BDRVVmdkState *ps = bs->backing_hd->opaque;
 | 
			
		||||
        int ret;
 | 
			
		||||
 | 
			
		||||
        if (!vmdk_is_cid_valid(bs))
 | 
			
		||||
            return -1;
 | 
			
		||||
 | 
			
		||||
        parent_cluster_offset = get_cluster_offset(bs->backing_hd, NULL,
 | 
			
		||||
            offset, allocate);
 | 
			
		||||
 | 
			
		||||
        if (parent_cluster_offset) {
 | 
			
		||||
            BDRVVmdkState *act_s = activeBDRV.hd->opaque;
 | 
			
		||||
 | 
			
		||||
            if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512)
 | 
			
		||||
        ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
 | 
			
		||||
            s->cluster_sectors);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            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))
 | 
			
		||||
        ret = bdrv_write(s->hd, cluster_offset, whole_grain,
 | 
			
		||||
            s->cluster_sectors);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -492,14 +482,14 @@ static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data)
 | 
			
		||||
    BDRVVmdkState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    /* update L2 table */
 | 
			
		||||
    if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
 | 
			
		||||
                    &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
 | 
			
		||||
    if (bdrv_pwrite_sync(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
 | 
			
		||||
                    &(m_data->offset), sizeof(m_data->offset)) < 0)
 | 
			
		||||
        return -1;
 | 
			
		||||
    /* update backup L2 table */
 | 
			
		||||
    if (s->l1_backup_table_offset != 0) {
 | 
			
		||||
        m_data->l2_offset = s->l1_backup_table[m_data->l1_index];
 | 
			
		||||
        if (bdrv_pwrite(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))
 | 
			
		||||
        if (bdrv_pwrite_sync(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
 | 
			
		||||
                        &(m_data->offset), sizeof(m_data->offset)) < 0)
 | 
			
		||||
            return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -567,9 +557,6 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
 | 
			
		||||
            cluster_offset >>= 9;
 | 
			
		||||
            tmp = cpu_to_le32(cluster_offset);
 | 
			
		||||
            l2_table[l2_index] = tmp;
 | 
			
		||||
            // Save the active image state
 | 
			
		||||
            activeBDRV.cluster_offset = cluster_offset;
 | 
			
		||||
            activeBDRV.hd = bs;
 | 
			
		||||
        }
 | 
			
		||||
        /* First of all we write grain itself, to avoid race condition
 | 
			
		||||
         * that may to corrupt the image.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								block/vpc.c
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								block/vpc.c
									
									
									
									
									
								
							@@ -266,7 +266,7 @@ static inline int64_t get_sector_offset(BlockDriverState *bs,
 | 
			
		||||
 | 
			
		||||
        s->last_bitmap_offset = bitmap_offset;
 | 
			
		||||
        memset(bitmap, 0xff, s->bitmap_size);
 | 
			
		||||
        bdrv_pwrite(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",
 | 
			
		||||
@@ -316,7 +316,7 @@ static int rewrite_footer(BlockDriverState* bs)
 | 
			
		||||
    BDRVVPCState *s = bs->opaque;
 | 
			
		||||
    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)
 | 
			
		||||
        return ret;
 | 
			
		||||
 | 
			
		||||
@@ -351,7 +351,8 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
 | 
			
		||||
 | 
			
		||||
    // Initialize the block's bitmap
 | 
			
		||||
    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)
 | 
			
		||||
    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
 | 
			
		||||
    bat_offset = s->bat_offset + (4 * index);
 | 
			
		||||
    bat_value = be32_to_cpu(s->pagetable[index]);
 | 
			
		||||
    ret = bdrv_pwrite(s->hd, bat_offset, &bat_value, 4);
 | 
			
		||||
    ret = bdrv_pwrite_sync(s->hd, bat_offset, &bat_value, 4);
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
        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
 | 
			
		||||
    // However, we need this to avoid truncating images in qemu-img convert
 | 
			
		||||
    *cyls = (cyls_times_heads + *heads - 1) / *heads;
 | 
			
		||||
    *cyls = cyls_times_heads / *heads;
 | 
			
		||||
 | 
			
		||||
    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*) buf;
 | 
			
		||||
    int fd, i;
 | 
			
		||||
    uint16_t cyls;
 | 
			
		||||
    uint8_t heads;
 | 
			
		||||
    uint8_t secs_per_cyl;
 | 
			
		||||
    uint16_t cyls = 0;
 | 
			
		||||
    uint8_t heads = 0;
 | 
			
		||||
    uint8_t secs_per_cyl = 0;
 | 
			
		||||
    size_t block_size, num_bat_entries;
 | 
			
		||||
    int64_t total_sectors = 0;
 | 
			
		||||
 | 
			
		||||
@@ -503,9 +502,14 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
    if (fd < 0)
 | 
			
		||||
        return -EIO;
 | 
			
		||||
 | 
			
		||||
    // Calculate matching total_size and geometry
 | 
			
		||||
    if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl))
 | 
			
		||||
    /* Calculate matching total_size and geometry. Increase the number of
 | 
			
		||||
       sectors requested until we get enough (or fail). */
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    // Prepare the Hard Disk Footer
 | 
			
		||||
 
 | 
			
		||||
@@ -868,7 +868,8 @@ static int init_directories(BDRVVVFATState* s,
 | 
			
		||||
    {
 | 
			
		||||
	direntry_t* entry=array_get_next(&(s->directory));
 | 
			
		||||
	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 */
 | 
			
		||||
@@ -882,7 +883,7 @@ static int init_directories(BDRVVVFATState* s,
 | 
			
		||||
    mapping->dir_index = 0;
 | 
			
		||||
    mapping->info.dir.parent_mapping_index = -1;
 | 
			
		||||
    mapping->first_mapping_index = -1;
 | 
			
		||||
    mapping->path = strdup(dirname);
 | 
			
		||||
    mapping->path = qemu_strdup(dirname);
 | 
			
		||||
    i = strlen(mapping->path);
 | 
			
		||||
    if (i > 0 && mapping->path[i - 1] == '/')
 | 
			
		||||
	mapping->path[i - 1] = '\0';
 | 
			
		||||
@@ -1632,10 +1633,10 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
 | 
			
		||||
 | 
			
		||||
	    /* rename */
 | 
			
		||||
	    if (strcmp(basename, basename2))
 | 
			
		||||
		schedule_rename(s, cluster_num, strdup(path));
 | 
			
		||||
		schedule_rename(s, cluster_num, qemu_strdup(path));
 | 
			
		||||
	} else if (is_file(direntry))
 | 
			
		||||
	    /* new file */
 | 
			
		||||
	    schedule_new_file(s, strdup(path), cluster_num);
 | 
			
		||||
	    schedule_new_file(s, qemu_strdup(path), cluster_num);
 | 
			
		||||
	else {
 | 
			
		||||
	    assert(0);
 | 
			
		||||
	    return 0;
 | 
			
		||||
@@ -1752,10 +1753,10 @@ static int check_directory_consistency(BDRVVVFATState *s,
 | 
			
		||||
	mapping->mode &= ~MODE_DELETED;
 | 
			
		||||
 | 
			
		||||
	if (strcmp(basename, basename2))
 | 
			
		||||
	    schedule_rename(s, cluster_num, strdup(path));
 | 
			
		||||
	    schedule_rename(s, cluster_num, qemu_strdup(path));
 | 
			
		||||
    } else
 | 
			
		||||
	/* new directory */
 | 
			
		||||
	schedule_mkdir(s, cluster_num, strdup(path));
 | 
			
		||||
	schedule_mkdir(s, cluster_num, qemu_strdup(path));
 | 
			
		||||
 | 
			
		||||
    lfn_init(&lfn);
 | 
			
		||||
    do {
 | 
			
		||||
@@ -2256,7 +2257,11 @@ static int commit_one_file(BDRVVVFATState* s,
 | 
			
		||||
	c = c1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ftruncate(fd, size);
 | 
			
		||||
    if (ftruncate(fd, size)) {
 | 
			
		||||
        perror("ftruncate()");
 | 
			
		||||
        close(fd);
 | 
			
		||||
        return -4;
 | 
			
		||||
    }
 | 
			
		||||
    close(fd);
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
                              size in sectors */
 | 
			
		||||
    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 locked;    /* if true, the media cannot temporarily be ejected */
 | 
			
		||||
    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");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Is this correct for PPC?
 | 
			
		||||
 */
 | 
			
		||||
static inline void dma_flush_range(unsigned long start, unsigned long stop)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif defined(__ia64__)
 | 
			
		||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
 | 
			
		||||
{
 | 
			
		||||
    while (start < stop) {
 | 
			
		||||
	asm volatile ("fc %0" :: "r"(start));
 | 
			
		||||
	start += 32;
 | 
			
		||||
    }
 | 
			
		||||
    asm volatile (";;sync.i;;srlz.i;;");
 | 
			
		||||
}
 | 
			
		||||
#define dma_flush_range(start, end) flush_icache_range(start, end)
 | 
			
		||||
#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
 | 
			
		||||
#else
 | 
			
		||||
static inline void dma_flush_range(unsigned long start, unsigned long stop)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -205,6 +205,8 @@ START_TEST(qdict_put_exists_test)
 | 
			
		||||
 | 
			
		||||
    value = qdict_get_int(tests_dict, key);
 | 
			
		||||
    fail_unless(value == 2);
 | 
			
		||||
 | 
			
		||||
    fail_unless(qdict_size(tests_dict) == 1);
 | 
			
		||||
}
 | 
			
		||||
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`
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
target_list=""
 | 
			
		||||
target_list="x86_64-softmmu"
 | 
			
		||||
case "$cpu" in
 | 
			
		||||
  alpha|cris|ia64|m68k|microblaze|ppc|ppc64|sparc64)
 | 
			
		||||
    cpu="$cpu"
 | 
			
		||||
@@ -197,6 +197,16 @@ case "$cpu" in
 | 
			
		||||
  ;;
 | 
			
		||||
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".
 | 
			
		||||
#  * 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
 | 
			
		||||
@@ -250,12 +260,18 @@ guest_base=""
 | 
			
		||||
uname_release=""
 | 
			
		||||
io_thread="no"
 | 
			
		||||
mixemu="no"
 | 
			
		||||
kvm_trace="no"
 | 
			
		||||
kvm_cap_pit=""
 | 
			
		||||
kvm_cap_device_assignment=""
 | 
			
		||||
kerneldir=""
 | 
			
		||||
aix="no"
 | 
			
		||||
blobs="yes"
 | 
			
		||||
pkgversion=""
 | 
			
		||||
pkgversion=" ($(kvm_version))"
 | 
			
		||||
cpu_emulation="yes"
 | 
			
		||||
kvm_kmod="no"
 | 
			
		||||
check_utests="no"
 | 
			
		||||
user_pie="no"
 | 
			
		||||
zero_malloc=""
 | 
			
		||||
 | 
			
		||||
# OS specific
 | 
			
		||||
if check_define __linux__ ; then
 | 
			
		||||
@@ -388,6 +404,13 @@ AIX)
 | 
			
		||||
  if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
 | 
			
		||||
    audio_possible_drivers="$audio_possible_drivers fmod"
 | 
			
		||||
  fi
 | 
			
		||||
  if [ "$cpu" = "ia64" ] ; then
 | 
			
		||||
     xen="no"
 | 
			
		||||
     target_list="ia64-softmmu"
 | 
			
		||||
     cpu_emulation="no"
 | 
			
		||||
     gdbstub="no"
 | 
			
		||||
     slirp="no"
 | 
			
		||||
  fi
 | 
			
		||||
;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
@@ -517,6 +540,14 @@ for opt do
 | 
			
		||||
  ;;
 | 
			
		||||
  --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-cocoa)
 | 
			
		||||
@@ -594,12 +625,16 @@ for opt do
 | 
			
		||||
  ;;
 | 
			
		||||
  --kerneldir=*) kerneldir="$optarg"
 | 
			
		||||
  ;;
 | 
			
		||||
  --with-kvm-trace) kvm_trace="yes"
 | 
			
		||||
  ;;
 | 
			
		||||
  --with-pkgversion=*) pkgversion=" ($optarg)"
 | 
			
		||||
  ;;
 | 
			
		||||
  --disable-docs) docs="no"
 | 
			
		||||
  ;;
 | 
			
		||||
  --enable-docs) docs="yes"
 | 
			
		||||
  ;;
 | 
			
		||||
  --disable-cpu-emulation) cpu_emulation="no"
 | 
			
		||||
  ;;
 | 
			
		||||
  *) echo "ERROR: unknown option $opt"; show_help="yes"
 | 
			
		||||
  ;;
 | 
			
		||||
  esac
 | 
			
		||||
@@ -721,6 +756,10 @@ echo "  --disable-bluez          disable bluez stack connectivity"
 | 
			
		||||
echo "  --enable-bluez           enable bluez stack connectivity"
 | 
			
		||||
echo "  --disable-kvm            disable 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 "  --enable-nptl            enable usermode NPTL support"
 | 
			
		||||
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 "  --disable-blobs          disable installing provided firmware blobs"
 | 
			
		||||
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 "NOTE: The object files are built at the place where configure is launched"
 | 
			
		||||
exit 1
 | 
			
		||||
@@ -1383,8 +1424,22 @@ EOF
 | 
			
		||||
            kvm_cflags="$kvm_cflags -I$kerneldir/arch/$cpu/include"
 | 
			
		||||
      fi
 | 
			
		||||
  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
 | 
			
		||||
  kvm_cflags="$kvm_cflags -idirafter $source_path/compat"
 | 
			
		||||
  if compile_prog "$kvm_cflags" "" ; then
 | 
			
		||||
    kvm=yes
 | 
			
		||||
  else
 | 
			
		||||
@@ -1406,6 +1461,75 @@ EOF
 | 
			
		||||
  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
 | 
			
		||||
PTHREADLIBS_LIST="-lpthread -lpthreadGC2"
 | 
			
		||||
@@ -1612,6 +1736,21 @@ if compile_prog "" "" ; then
 | 
			
		||||
  splice=yes
 | 
			
		||||
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
 | 
			
		||||
eventfd=no
 | 
			
		||||
cat > $TMPC << EOF
 | 
			
		||||
@@ -1792,8 +1931,9 @@ fi
 | 
			
		||||
 | 
			
		||||
# Consult white-list to determine whether to enable werror
 | 
			
		||||
# by default.  Only enable by default for git builds
 | 
			
		||||
z_version=`cut -f3 -d. $source_path/VERSION`
 | 
			
		||||
 | 
			
		||||
if test -z "$werror" ; then
 | 
			
		||||
    z_version=`cut -f3 -d. $source_path/VERSION`
 | 
			
		||||
    if test "$z_version" = "50" -a \
 | 
			
		||||
        "$linux" = "yes" ; then
 | 
			
		||||
        werror="yes"
 | 
			
		||||
@@ -1802,6 +1942,16 @@ if test -z "$werror" ; then
 | 
			
		||||
    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
 | 
			
		||||
    QEMU_CFLAGS="-Werror $QEMU_CFLAGS"
 | 
			
		||||
fi
 | 
			
		||||
@@ -1830,6 +1980,20 @@ else
 | 
			
		||||
  binsuffix="/bin"
 | 
			
		||||
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 "BIOS directory    $prefix$datasuffix"
 | 
			
		||||
echo "binary directory  $prefix$binsuffix"
 | 
			
		||||
@@ -1873,6 +2037,7 @@ if test -n "$sparc_cpu"; then
 | 
			
		||||
    echo "Target Sparc Arch $sparc_cpu"
 | 
			
		||||
fi
 | 
			
		||||
echo "xen support       $xen"
 | 
			
		||||
echo "CPU emulation     $cpu_emulation"
 | 
			
		||||
echo "brlapi support    $brlapi"
 | 
			
		||||
echo "bluez  support    $bluez"
 | 
			
		||||
echo "Documentation     $docs"
 | 
			
		||||
@@ -1886,6 +2051,9 @@ echo "IO thread         $io_thread"
 | 
			
		||||
echo "Linux AIO support $linux_aio"
 | 
			
		||||
echo "Install blobs     $blobs"
 | 
			
		||||
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 "preadv support    $preadv"
 | 
			
		||||
echo "fdatasync         $fdatasync"
 | 
			
		||||
@@ -2092,6 +2260,9 @@ fi
 | 
			
		||||
if test "$fdt" = "yes" ; then
 | 
			
		||||
  echo "CONFIG_FDT=y" >> $config_host_mak
 | 
			
		||||
fi
 | 
			
		||||
if test "$signalfd" = "yes" ; then
 | 
			
		||||
  echo "CONFIG_SIGNALFD=y" >> $config_host_mak
 | 
			
		||||
fi
 | 
			
		||||
if test "$need_offsetof" = "yes" ; then
 | 
			
		||||
  echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak
 | 
			
		||||
fi
 | 
			
		||||
@@ -2101,6 +2272,11 @@ fi
 | 
			
		||||
if test "$fdatasync" = "yes" ; then
 | 
			
		||||
  echo "CONFIG_FDATASYNC=y" >> $config_host_mak
 | 
			
		||||
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
 | 
			
		||||
if [ "$bsd" = "yes" ] ; then
 | 
			
		||||
@@ -2109,6 +2285,10 @@ fi
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
case "$usb" in
 | 
			
		||||
linux)
 | 
			
		||||
@@ -2122,6 +2302,8 @@ bsd)
 | 
			
		||||
;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
echo "KVM_KMOD=$kvm_kmod" >> $config_host_mak
 | 
			
		||||
 | 
			
		||||
tools=
 | 
			
		||||
if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then
 | 
			
		||||
  tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
 | 
			
		||||
@@ -2272,6 +2454,9 @@ case "$target_arch2" in
 | 
			
		||||
    TARGET_BASE_ARCH=i386
 | 
			
		||||
    target_phys_bits=64
 | 
			
		||||
  ;;
 | 
			
		||||
  ia64)
 | 
			
		||||
    target_phys_bits=64
 | 
			
		||||
  ;;
 | 
			
		||||
  alpha)
 | 
			
		||||
    target_phys_bits=64
 | 
			
		||||
  ;;
 | 
			
		||||
@@ -2402,6 +2587,12 @@ case "$target_arch2" in
 | 
			
		||||
      \( "$target_arch2" = "i386"   -a "$cpu" = "x86_64" \) \) ; then
 | 
			
		||||
      echo "CONFIG_KVM=y" >> $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
 | 
			
		||||
esac
 | 
			
		||||
echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak
 | 
			
		||||
@@ -2610,7 +2801,7 @@ if test "$source_path_used" = "yes" ; then
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# temporary config to build submodules
 | 
			
		||||
for rom in seabios vgabios ; do
 | 
			
		||||
for rom in seabios vgabios; do
 | 
			
		||||
    config_mak=roms/$rom/config.mak
 | 
			
		||||
    echo "# Automatically generated by configure - do not modify" >> $config_mak
 | 
			
		||||
    echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak
 | 
			
		||||
@@ -2636,3 +2827,6 @@ d=libuser
 | 
			
		||||
mkdir -p $d
 | 
			
		||||
rm -f $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;
 | 
			
		||||
    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);
 | 
			
		||||
    if (chr->init)
 | 
			
		||||
        chr->init(chr);
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,8 @@ struct MouseTransformInfo {
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
/* 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);
 | 
			
		||||
int vnc_display_open(DisplayState *ds, const char *display);
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
/* curses.c */
 | 
			
		||||
 
 | 
			
		||||
@@ -849,6 +849,7 @@ extern int phys_ram_fd;
 | 
			
		||||
extern uint8_t *phys_ram_dirty;
 | 
			
		||||
extern ram_addr_t ram_size;
 | 
			
		||||
extern ram_addr_t last_ram_offset;
 | 
			
		||||
extern uint8_t *bios_mem;
 | 
			
		||||
 | 
			
		||||
/* physical memory access */
 | 
			
		||||
 | 
			
		||||
@@ -1017,7 +1018,8 @@ static inline int64_t cpu_get_real_ticks (void)
 | 
			
		||||
#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
 | 
			
		||||
 * 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.  */
 | 
			
		||||
void *qemu_get_ram_ptr(ram_addr_t addr);
 | 
			
		||||
/* This should not be used by devices.  */
 | 
			
		||||
int do_qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
 | 
			
		||||
ram_addr_t qemu_ram_addr_from_host(void *ptr);
 | 
			
		||||
 | 
			
		||||
int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								cpu-defs.h
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								cpu-defs.h
									
									
									
									
									
								
							@@ -27,6 +27,7 @@
 | 
			
		||||
#include <setjmp.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include "osdep.h"
 | 
			
		||||
#include "qemu-queue.h"
 | 
			
		||||
#include "targphys.h"
 | 
			
		||||
@@ -134,6 +135,16 @@ typedef struct CPUWatchpoint {
 | 
			
		||||
    QTAILQ_ENTRY(CPUWatchpoint) entry;
 | 
			
		||||
} CPUWatchpoint;
 | 
			
		||||
 | 
			
		||||
/* forward decleration */
 | 
			
		||||
struct qemu_work_item;
 | 
			
		||||
 | 
			
		||||
struct KVMCPUState {
 | 
			
		||||
    pthread_t thread;
 | 
			
		||||
    int signalled;
 | 
			
		||||
    struct qemu_work_item *queued_work_first, *queued_work_last;
 | 
			
		||||
    int regs_modified;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define CPU_TEMP_BUF_NLONGS 128
 | 
			
		||||
#define CPU_COMMON                                                      \
 | 
			
		||||
    struct TranslationBlock *current_tb; /* currently executing TB  */  \
 | 
			
		||||
@@ -146,8 +157,6 @@ typedef struct CPUWatchpoint {
 | 
			
		||||
    target_ulong mem_io_vaddr; /* target virtual addr at which the      \
 | 
			
		||||
                                     memory was accessed */             \
 | 
			
		||||
    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;                                         \
 | 
			
		||||
    volatile sig_atomic_t exit_request;                                 \
 | 
			
		||||
    /* 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_threads;/* number of threads within this CPU */              \
 | 
			
		||||
    int running; /* Nonzero if cpu is currently running(usermode).  */  \
 | 
			
		||||
    int thread_id;							\
 | 
			
		||||
    /* user data */                                                     \
 | 
			
		||||
    void *opaque;                                                       \
 | 
			
		||||
                                                                        \
 | 
			
		||||
@@ -197,6 +207,9 @@ typedef struct CPUWatchpoint {
 | 
			
		||||
    const char *cpu_model_str;                                          \
 | 
			
		||||
    struct KVMState *kvm_state;                                         \
 | 
			
		||||
    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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								cpu-exec.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								cpu-exec.c
									
									
									
									
									
								
							@@ -19,7 +19,9 @@
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "exec.h"
 | 
			
		||||
#include "disas.h"
 | 
			
		||||
#if !defined(TARGET_IA64)
 | 
			
		||||
#include "tcg.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include "kvm.h"
 | 
			
		||||
 | 
			
		||||
#if !defined(CONFIG_SOFTMMU)
 | 
			
		||||
@@ -38,6 +40,8 @@
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
 | 
			
		||||
// Work around ugly bugs in glibc that mangle global register contents
 | 
			
		||||
#undef env
 | 
			
		||||
@@ -232,11 +236,13 @@ int cpu_exec(CPUState *env1)
 | 
			
		||||
 | 
			
		||||
    env_to_regs();
 | 
			
		||||
#if defined(TARGET_I386)
 | 
			
		||||
    if (!kvm_enabled()) {
 | 
			
		||||
        /* put eflags in CPU temporary format */
 | 
			
		||||
        CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
 | 
			
		||||
        DF = 1 - (2 * ((env->eflags >> 10) & 1));
 | 
			
		||||
        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_M68K)
 | 
			
		||||
    env->cc_op = CC_OP_FLAGS;
 | 
			
		||||
@@ -250,6 +256,7 @@ int cpu_exec(CPUState *env1)
 | 
			
		||||
#elif defined(TARGET_SH4)
 | 
			
		||||
#elif defined(TARGET_CRIS)
 | 
			
		||||
#elif defined(TARGET_S390X)
 | 
			
		||||
#elif defined(TARGET_IA64)
 | 
			
		||||
    /* XXXXX */
 | 
			
		||||
#else
 | 
			
		||||
#error unsupported target CPU
 | 
			
		||||
@@ -317,6 +324,8 @@ int cpu_exec(CPUState *env1)
 | 
			
		||||
                    do_interrupt(env);
 | 
			
		||||
#elif defined(TARGET_M68K)
 | 
			
		||||
                    do_interrupt(0);
 | 
			
		||||
#elif defined(TARGET_IA64)
 | 
			
		||||
		    do_interrupt(env);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
                }
 | 
			
		||||
@@ -672,6 +681,7 @@ int cpu_exec(CPUState *env1)
 | 
			
		||||
#elif defined(TARGET_MICROBLAZE)
 | 
			
		||||
#elif defined(TARGET_MIPS)
 | 
			
		||||
#elif defined(TARGET_SH4)
 | 
			
		||||
#elif defined(TARGET_IA64)
 | 
			
		||||
#elif defined(TARGET_ALPHA)
 | 
			
		||||
#elif defined(TARGET_CRIS)
 | 
			
		||||
#elif defined(TARGET_S390X)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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)
 | 
			
		||||
{
 | 
			
		||||
    const uint8_t *p = (const uint8_t *)buf;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,3 +2,4 @@
 | 
			
		||||
 | 
			
		||||
CONFIG_USB_OHCI=y
 | 
			
		||||
CONFIG_PTIMER=y
 | 
			
		||||
CONFIG_ISA_MMIO=y
 | 
			
		||||
 
 | 
			
		||||
@@ -2,3 +2,4 @@
 | 
			
		||||
 | 
			
		||||
CONFIG_USB_OHCI=y
 | 
			
		||||
CONFIG_PTIMER=y
 | 
			
		||||
CONFIG_ISA_MMIO=y
 | 
			
		||||
 
 | 
			
		||||
@@ -160,6 +160,10 @@ static BlockDriverAIOCB *dma_bdrv_io(
 | 
			
		||||
    dbs->is_write = is_write;
 | 
			
		||||
    dbs->bh = NULL;
 | 
			
		||||
    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);
 | 
			
		||||
    if (!dbs->acb) {
 | 
			
		||||
        qemu_aio_release(dbs);
 | 
			
		||||
 
 | 
			
		||||
@@ -69,9 +69,9 @@ extern int printf(const char *, ...);
 | 
			
		||||
#define AREG1 "r14"
 | 
			
		||||
#define AREG2 "r15"
 | 
			
		||||
#elif defined(__mips__)
 | 
			
		||||
#define AREG0 "fp"
 | 
			
		||||
#define AREG1 "s0"
 | 
			
		||||
#define AREG2 "s1"
 | 
			
		||||
#define AREG0 "s0"
 | 
			
		||||
#define AREG1 "s1"
 | 
			
		||||
#define AREG2 "fp"
 | 
			
		||||
#elif defined(__sparc__)
 | 
			
		||||
#ifdef CONFIG_SOLARIS
 | 
			
		||||
#define AREG0 "g2"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										166
									
								
								exec.c
									
									
									
									
									
								
							
							
						
						
									
										166
									
								
								exec.c
									
									
									
									
									
								
							@@ -34,7 +34,13 @@
 | 
			
		||||
#include "cpu.h"
 | 
			
		||||
#include "exec-all.h"
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "cache-utils.h"
 | 
			
		||||
 | 
			
		||||
#if !defined(TARGET_IA64)
 | 
			
		||||
#include "tcg.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
#include "hw/hw.h"
 | 
			
		||||
#include "osdep.h"
 | 
			
		||||
#include "kvm.h"
 | 
			
		||||
@@ -74,6 +80,8 @@
 | 
			
		||||
#define TARGET_PHYS_ADDR_SPACE_BITS 42
 | 
			
		||||
#elif defined(TARGET_I386)
 | 
			
		||||
#define TARGET_PHYS_ADDR_SPACE_BITS 36
 | 
			
		||||
#elif defined(TARGET_IA64)
 | 
			
		||||
#define TARGET_PHYS_ADDR_SPACE_BITS 36
 | 
			
		||||
#else
 | 
			
		||||
#define TARGET_PHYS_ADDR_SPACE_BITS 32
 | 
			
		||||
#endif
 | 
			
		||||
@@ -111,6 +119,7 @@ uint8_t *code_gen_ptr;
 | 
			
		||||
#if !defined(CONFIG_USER_ONLY)
 | 
			
		||||
int phys_ram_fd;
 | 
			
		||||
uint8_t *phys_ram_dirty;
 | 
			
		||||
uint8_t *bios_mem;
 | 
			
		||||
static int in_migration;
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    if (kvm_enabled())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
#ifdef USE_STATIC_CODE_GEN_BUFFER
 | 
			
		||||
    code_gen_buffer = static_code_gen_buffer;
 | 
			
		||||
    code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
 | 
			
		||||
@@ -588,6 +600,11 @@ void cpu_exec_init(CPUState *env)
 | 
			
		||||
    env->numa_node = 0;
 | 
			
		||||
    QTAILQ_INIT(&env->breakpoints);
 | 
			
		||||
    QTAILQ_INIT(&env->watchpoints);
 | 
			
		||||
#ifdef __WIN32
 | 
			
		||||
    env->thread_id = GetCurrentProcessId();
 | 
			
		||||
#else
 | 
			
		||||
    env->thread_id = getpid();
 | 
			
		||||
#endif
 | 
			
		||||
    *penv = env;
 | 
			
		||||
#if defined(CONFIG_USER_ONLY)
 | 
			
		||||
    cpu_list_unlock();
 | 
			
		||||
@@ -1553,6 +1570,8 @@ void cpu_interrupt(CPUState *env, int mask)
 | 
			
		||||
 | 
			
		||||
    old_mask = env->interrupt_request;
 | 
			
		||||
    env->interrupt_request |= mask;
 | 
			
		||||
    if (kvm_enabled() && !kvm_irqchip_in_kernel())
 | 
			
		||||
	kvm_update_interrupt_request(env);
 | 
			
		||||
 | 
			
		||||
#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)
 | 
			
		||||
{
 | 
			
		||||
    in_migration = enable;
 | 
			
		||||
    if (kvm_enabled()) {
 | 
			
		||||
        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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#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)
 | 
			
		||||
{
 | 
			
		||||
    RAMBlock *new_block;
 | 
			
		||||
@@ -2411,9 +2536,12 @@ ram_addr_t qemu_ram_alloc(ram_addr_t size)
 | 
			
		||||
    size = TARGET_PAGE_ALIGN(size);
 | 
			
		||||
    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)
 | 
			
		||||
    /* 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,
 | 
			
		||||
                               PROT_EXEC|PROT_READ|PROT_WRITE,
 | 
			
		||||
                               MAP_SHARED | MAP_ANONYMOUS, -1, 0);
 | 
			
		||||
#else
 | 
			
		||||
        new_block->host = qemu_vmalloc(size);
 | 
			
		||||
@@ -2421,6 +2549,7 @@ ram_addr_t qemu_ram_alloc(ram_addr_t size)
 | 
			
		||||
#ifdef MADV_MERGEABLE
 | 
			
		||||
        madvise(new_block->host, size, MADV_MERGEABLE);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    new_block->offset = last_ram_offset;
 | 
			
		||||
    new_block->length = size;
 | 
			
		||||
 | 
			
		||||
@@ -2482,9 +2611,7 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
 | 
			
		||||
    return block->host + (addr - block->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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)
 | 
			
		||||
int do_qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
 | 
			
		||||
{
 | 
			
		||||
    RAMBlock *prev;
 | 
			
		||||
    RAMBlock **prevp;
 | 
			
		||||
@@ -2501,11 +2628,23 @@ ram_addr_t qemu_ram_addr_from_host(void *ptr)
 | 
			
		||||
        prev = block;
 | 
			
		||||
        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);
 | 
			
		||||
        abort();
 | 
			
		||||
    }
 | 
			
		||||
    return block->offset + (host - block->host);
 | 
			
		||||
    return ram_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] |=
 | 
			
		||||
                        (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 {
 | 
			
		||||
            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,
 | 
			
		||||
                               int is_write, target_phys_addr_t access_len)
 | 
			
		||||
{
 | 
			
		||||
    unsigned long flush_len = (unsigned long)access_len;
 | 
			
		||||
 | 
			
		||||
    if (buffer != bounce.buffer) {
 | 
			
		||||
        if (is_write) {
 | 
			
		||||
            ram_addr_t addr1 = qemu_ram_addr_from_host(buffer);
 | 
			
		||||
@@ -3301,13 +3447,15 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
 | 
			
		||||
                addr1 += l;
 | 
			
		||||
                access_len -= l;
 | 
			
		||||
	    }
 | 
			
		||||
	    dma_flush_range((unsigned long)buffer,
 | 
			
		||||
			    (unsigned long)buffer + flush_len);
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (is_write) {
 | 
			
		||||
        cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
 | 
			
		||||
    }
 | 
			
		||||
    qemu_free(bounce.buffer);
 | 
			
		||||
    qemu_vfree(bounce.buffer);
 | 
			
		||||
    bounce.buffer = NULL;
 | 
			
		||||
    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 invalidate count %d\n", tb_phys_invalidate_count);
 | 
			
		||||
    cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count);
 | 
			
		||||
#ifdef CONFIG_PROFILER
 | 
			
		||||
    tcg_dump_info(f, cpu_fprintf);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if !defined(CONFIG_USER_ONLY)
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
#if defined(CONFIG_SOLARIS)
 | 
			
		||||
#include <fenv.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include "config-host.h"
 | 
			
		||||
 | 
			
		||||
void set_float_rounding_mode(int val STATUS_PARAM)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@
 | 
			
		||||
#include "sysemu.h"
 | 
			
		||||
#include "gdbstub.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_PACKET_LENGTH 4096
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -164,7 +164,7 @@ static inline int ctz64(uint64_t val)
 | 
			
		||||
{
 | 
			
		||||
#if QEMU_GNUC_PREREQ(3, 4)
 | 
			
		||||
    if (val)
 | 
			
		||||
        return __builtin_ctz(val);
 | 
			
		||||
        return __builtin_ctzll(val);
 | 
			
		||||
    else
 | 
			
		||||
        return 64;
 | 
			
		||||
#else
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								hw/acpi.c
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								hw/acpi.c
									
									
									
									
									
								
							@@ -23,6 +23,8 @@
 | 
			
		||||
#include "i2c.h"
 | 
			
		||||
#include "smbus.h"
 | 
			
		||||
#include "kvm.h"
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
#include "string.h"
 | 
			
		||||
 | 
			
		||||
//#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 */
 | 
			
		||||
 | 
			
		||||
#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_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 PROC_BASE 0xaf00
 | 
			
		||||
#define PCI_BASE 0xae00
 | 
			
		||||
#define PCI_EJ_BASE 0xae08
 | 
			
		||||
 | 
			
		||||
struct gpe_regs {
 | 
			
		||||
    uint16_t sts; /* status */
 | 
			
		||||
    uint16_t en;  /* enabled */
 | 
			
		||||
    uint8_t cpus_sts[32];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct pci_status {
 | 
			
		||||
@@ -587,6 +598,10 @@ static uint32_t gpe_readb(void *opaque, uint32_t addr)
 | 
			
		||||
    uint32_t val = 0;
 | 
			
		||||
    struct gpe_regs *g = opaque;
 | 
			
		||||
    switch (addr) {
 | 
			
		||||
        case PROC_BASE ... PROC_BASE+31:
 | 
			
		||||
            val = g->cpus_sts[addr - PROC_BASE];
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case GPE_BASE:
 | 
			
		||||
        case GPE_BASE + 1:
 | 
			
		||||
            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;
 | 
			
		||||
    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 + 1:
 | 
			
		||||
            gpe_reset_val(&g->sts, addr, val);
 | 
			
		||||
@@ -712,22 +731,72 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *model;
 | 
			
		||||
 | 
			
		||||
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_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_read(PCI_BASE, 8, 4,  pcihotplug_read, &pci0_status);
 | 
			
		||||
 | 
			
		||||
    register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus);
 | 
			
		||||
    register_ioport_read(PCI_EJ_BASE, 4, 4,  pciej_read, bus);
 | 
			
		||||
 | 
			
		||||
    model = cpu_model;
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    g->sts |= 2;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										140
									
								
								hw/apic.c
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								hw/apic.c
									
									
									
									
									
								
							@@ -24,6 +24,8 @@
 | 
			
		||||
#include "host-utils.h"
 | 
			
		||||
#include "kvm.h"
 | 
			
		||||
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
//#define DEBUG_APIC
 | 
			
		||||
 | 
			
		||||
/* APIC Local Vector Table */
 | 
			
		||||
@@ -299,6 +301,9 @@ void cpu_set_apic_base(CPUState *env, uint64_t val)
 | 
			
		||||
#endif
 | 
			
		||||
    if (!s)
 | 
			
		||||
        return;
 | 
			
		||||
    if (kvm_enabled() && kvm_irqchip_in_kernel())
 | 
			
		||||
        s->apicbase = val;
 | 
			
		||||
    else
 | 
			
		||||
        s->apicbase = (val & 0xfffff000) |
 | 
			
		||||
            (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
 | 
			
		||||
    /* if disabled, cannot be enabled again */
 | 
			
		||||
@@ -393,6 +398,11 @@ int apic_get_irq_delivered(void)
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    apic_irq_delivered += !get_bit(s->irr, vector_num);
 | 
			
		||||
@@ -478,6 +488,7 @@ void apic_init_reset(CPUState *env)
 | 
			
		||||
    if (!s)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    cpu_synchronize_state(env);
 | 
			
		||||
    s->tpr = 0;
 | 
			
		||||
    s->spurious_vec = 0xff;
 | 
			
		||||
    s->log_dest = 0;
 | 
			
		||||
@@ -497,6 +508,13 @@ void apic_init_reset(CPUState *env)
 | 
			
		||||
    s->wait_for_sipi = 1;
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
@@ -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 */
 | 
			
		||||
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)
 | 
			
		||||
        qemu_get_timer(f, s->timer);
 | 
			
		||||
 | 
			
		||||
    qemu_kvm_load_lapic(s->cpu_env);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -930,7 +1060,9 @@ static const VMStateDescription vmstate_apic = {
 | 
			
		||||
        VMSTATE_INT64(next_time, APICState),
 | 
			
		||||
        VMSTATE_TIMER(timer, APICState),
 | 
			
		||||
        VMSTATE_END_OF_LIST()
 | 
			
		||||
    }
 | 
			
		||||
    },
 | 
			
		||||
    .pre_save = apic_pre_save,
 | 
			
		||||
    .post_load = apic_post_load,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void apic_reset(void *opaque)
 | 
			
		||||
@@ -955,6 +1087,7 @@ static void apic_reset(void *opaque)
 | 
			
		||||
         */
 | 
			
		||||
        s->lvt[APIC_LVT_LINT0] = 0x700;
 | 
			
		||||
    }
 | 
			
		||||
    qemu_kvm_load_lapic(s->cpu_env);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static CPUReadMemoryFunc * const apic_mem_read[3] = {
 | 
			
		||||
@@ -998,6 +1131,11 @@ int apic_init(CPUState *env)
 | 
			
		||||
    vmstate_register(s->idx, &vmstate_apic, 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;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -71,7 +71,7 @@ static void arm_timer_recalibrate(arm_timer_state *s, int reload)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t limit;
 | 
			
		||||
 | 
			
		||||
    if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
 | 
			
		||||
    if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
 | 
			
		||||
        /* Free running.  */
 | 
			
		||||
        if (s->control & TIMER_CTRL_32BIT)
 | 
			
		||||
            limit = 0xffffffff;
 | 
			
		||||
@@ -113,7 +113,7 @@ static void arm_timer_write(void *opaque, target_phys_addr_t offset,
 | 
			
		||||
        case 1: freq >>= 4; 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);
 | 
			
		||||
        if (s->control & TIMER_CTRL_ENABLE) {
 | 
			
		||||
            /* Restart the timer if still enabled.  */
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,15 @@ typedef struct QEMUMachine {
 | 
			
		||||
    QEMUMachineInitFunc *init;
 | 
			
		||||
    int use_scsi;
 | 
			
		||||
    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;
 | 
			
		||||
    CompatProperty *compat_props;
 | 
			
		||||
    GlobalProperty *compat_props;
 | 
			
		||||
    struct QEMUMachine *next;
 | 
			
		||||
} 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);
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@
 | 
			
		||||
#include "console.h"
 | 
			
		||||
#include "vga_int.h"
 | 
			
		||||
#include "kvm.h"
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
#include "loader.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -2552,6 +2553,7 @@ static CPUWriteMemoryFunc * const cirrus_linear_bitblt_write[3] = {
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
        s->vga.map_addr = s->vga.lfb_addr;
 | 
			
		||||
        s->vga.map_end = s->vga.lfb_end;
 | 
			
		||||
@@ -2561,13 +2563,19 @@ static void map_linear_vram(CirrusVGAState *s)
 | 
			
		||||
    if (!s->vga.map_addr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
#ifndef TARGET_IA64
 | 
			
		||||
    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)
 | 
			
		||||
        && !((s->vga.sr[0x07] & 0x01) == 0)
 | 
			
		||||
        && !((s->vga.gr[0x0B] & 0x14) == 0x14)
 | 
			
		||||
        && !(s->vga.gr[0x0B] & 0x02)) {
 | 
			
		||||
 | 
			
		||||
        vga_dirty_log_stop(&s->vga);
 | 
			
		||||
        cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
 | 
			
		||||
                                    (s->vga.vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM);
 | 
			
		||||
        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,
 | 
			
		||||
                                     s->vga.vga_io_memory);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    vga_dirty_log_start(&s->vga);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
         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,
 | 
			
		||||
                                 s->vga.vga_io_memory);
 | 
			
		||||
 | 
			
		||||
    vga_dirty_log_start(&s->vga);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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;
 | 
			
		||||
 | 
			
		||||
    vga_dirty_log_stop(&s->vga);
 | 
			
		||||
 | 
			
		||||
    /* XXX: add byte swapping apertures */
 | 
			
		||||
    cpu_register_physical_memory(addr, s->vga.vram_size,
 | 
			
		||||
				 s->cirrus_linear_io_addr);
 | 
			
		||||
@@ -3174,10 +3190,14 @@ static void pci_cirrus_write_config(PCIDevice *d,
 | 
			
		||||
    PCICirrusVGAState *pvs = DO_UPCAST(PCICirrusVGAState, dev, d);
 | 
			
		||||
    CirrusVGAState *s = &pvs->cirrus_vga;
 | 
			
		||||
 | 
			
		||||
    vga_dirty_log_stop(&s->vga);
 | 
			
		||||
 | 
			
		||||
    pci_default_write_config(d, address, val, len);
 | 
			
		||||
    if (s->vga.map_addr && d->io_regions[0].addr == PCI_BAR_UNMAPPED)
 | 
			
		||||
        s->vga.map_addr = 0;
 | 
			
		||||
    cirrus_update_memory_access(s);
 | 
			
		||||
 | 
			
		||||
    vga_dirty_log_start(&s->vga);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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_BASE_ADDRESS_SPACE_MEMORY, cirrus_pci_mmio_map);
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
     /* ROM BIOS */
 | 
			
		||||
     rom_add_vga(VGABIOS_CIRRUS_FILENAME);
 | 
			
		||||
     return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 = {
 | 
			
		||||
    .qdev.name    = "Cirrus VGA",
 | 
			
		||||
    .qdev.name    = "cirrus-vga",
 | 
			
		||||
    .qdev.desc    = "Cirrus CLGD 54xx VGA",
 | 
			
		||||
    .qdev.size    = sizeof(PCICirrusVGAState),
 | 
			
		||||
    .qdev.vmsd    = &vmstate_pci_cirrus_vga,
 | 
			
		||||
    .init         = pci_cirrus_vga_initfn,
 | 
			
		||||
    .romfile      = VGABIOS_CIRRUS_FILENAME,
 | 
			
		||||
    .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_device_id(pci_conf, E1000_DEVID);
 | 
			
		||||
    *(uint16_t *)(pci_conf+0x04) = cpu_to_le16(0x0407);
 | 
			
		||||
    *(uint16_t *)(pci_conf+0x06) = cpu_to_le16(0x0010);
 | 
			
		||||
    pci_conf[0x08] = 0x03;
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1146,6 +1137,7 @@ static PCIDeviceInfo e1000_info = {
 | 
			
		||||
    .qdev.vmsd  = &vmstate_e1000,
 | 
			
		||||
    .init       = pci_e1000_init,
 | 
			
		||||
    .exit       = pci_e1000_uninit,
 | 
			
		||||
    .romfile    = "pxe-e1000.bin",
 | 
			
		||||
    .qdev.props = (Property[]) {
 | 
			
		||||
        DEFINE_NIC_PROPERTIES(E1000State, conf),
 | 
			
		||||
        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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										59
									
								
								hw/fdc.c
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								hw/fdc.c
									
									
									
									
									
								
							@@ -370,9 +370,9 @@ enum {
 | 
			
		||||
    FD_CMD_PART_ID = 0x18,
 | 
			
		||||
    FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
 | 
			
		||||
    FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
 | 
			
		||||
    FD_CMD_SAVE = 0x2c,
 | 
			
		||||
    FD_CMD_SAVE = 0x2e,
 | 
			
		||||
    FD_CMD_OPTION = 0x33,
 | 
			
		||||
    FD_CMD_RESTORE = 0x4c,
 | 
			
		||||
    FD_CMD_RESTORE = 0x4e,
 | 
			
		||||
    FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e,
 | 
			
		||||
    FD_CMD_RELATIVE_SEEK_OUT = 0x8f,
 | 
			
		||||
    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 = {
 | 
			
		||||
    .name = "fdctrl",
 | 
			
		||||
    .name = "fdc",
 | 
			
		||||
    .version_id = 2,
 | 
			
		||||
    .minimum_version_id = 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)
 | 
			
		||||
{
 | 
			
		||||
    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->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);
 | 
			
		||||
 | 
			
		||||
    return retval;
 | 
			
		||||
@@ -1879,8 +1860,12 @@ fdctrl_t *fdctrl_init_isa(DriveInfo **fds)
 | 
			
		||||
    ISADevice *dev;
 | 
			
		||||
 | 
			
		||||
    dev = isa_create("isa-fdc");
 | 
			
		||||
    if (fds[0]) {
 | 
			
		||||
        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)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    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);
 | 
			
		||||
    fdctrl = &sys->state;
 | 
			
		||||
    fdctrl->dma_chann = dma_chann; /* FIXME */
 | 
			
		||||
    if (fds[0]) {
 | 
			
		||||
        qdev_prop_set_drive(dev, "driveA", fds[0]);
 | 
			
		||||
    }
 | 
			
		||||
    if (fds[1]) {
 | 
			
		||||
        qdev_prop_set_drive(dev, "driveB", fds[1]);
 | 
			
		||||
    }
 | 
			
		||||
    qdev_init_nofail(dev);
 | 
			
		||||
    sysbus_connect_irq(&sys->busdev, 0, irq);
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    dev = qdev_create(NULL, "SUNW,fdtwo");
 | 
			
		||||
    if (fds[0]) {
 | 
			
		||||
        qdev_prop_set_drive(dev, "drive", fds[0]);
 | 
			
		||||
    }
 | 
			
		||||
    qdev_init_nofail(dev);
 | 
			
		||||
    sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
 | 
			
		||||
    fdctrl = &sys->state;
 | 
			
		||||
@@ -1926,7 +1917,7 @@ fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
 | 
			
		||||
    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;
 | 
			
		||||
    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);
 | 
			
		||||
    fdctrl_connect_drives(fdctrl);
 | 
			
		||||
 | 
			
		||||
    vmstate_register(io_base, &vmstate_fdc, fdctrl);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1980,7 +1972,7 @@ static int isabus_fdc_init1(ISADevice *dev)
 | 
			
		||||
    isa_init_irq(&isa->busdev, &fdctrl->irq, isairq);
 | 
			
		||||
    fdctrl->dma_chann = dma_chann;
 | 
			
		||||
 | 
			
		||||
    ret = fdctrl_init_common(fdctrl);
 | 
			
		||||
    ret = fdctrl_init_common(fdctrl, iobase);
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
@@ -1998,7 +1990,7 @@ static int sysbus_fdc_init1(SysBusDevice *dev)
 | 
			
		||||
    qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
 | 
			
		||||
    fdctrl->dma_chann = -1;
 | 
			
		||||
 | 
			
		||||
    ret = fdctrl_init_common(fdctrl);
 | 
			
		||||
    ret = fdctrl_init_common(fdctrl, io);
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
@@ -2015,7 +2007,7 @@ static int sun4m_fdc_init1(SysBusDevice *dev)
 | 
			
		||||
    qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
 | 
			
		||||
 | 
			
		||||
    fdctrl->sun4m = 1;
 | 
			
		||||
    return fdctrl_init_common(fdctrl);
 | 
			
		||||
    return fdctrl_init_common(fdctrl, io);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ISADeviceInfo isa_fdc_info = {
 | 
			
		||||
@@ -2023,7 +2015,6 @@ static ISADeviceInfo isa_fdc_info = {
 | 
			
		||||
    .qdev.name  = "isa-fdc",
 | 
			
		||||
    .qdev.size  = sizeof(fdctrl_isabus_t),
 | 
			
		||||
    .qdev.no_user = 1,
 | 
			
		||||
    .qdev.vmsd  = &vmstate_fdc_isa,
 | 
			
		||||
    .qdev.reset = fdctrl_external_reset_isa,
 | 
			
		||||
    .qdev.props = (Property[]) {
 | 
			
		||||
        DEFINE_PROP_DRIVE("driveA", fdctrl_isabus_t, state.drives[0].dinfo),
 | 
			
		||||
@@ -2036,7 +2027,6 @@ static SysBusDeviceInfo sysbus_fdc_info = {
 | 
			
		||||
    .init = sysbus_fdc_init1,
 | 
			
		||||
    .qdev.name  = "sysbus-fdc",
 | 
			
		||||
    .qdev.size  = sizeof(fdctrl_sysbus_t),
 | 
			
		||||
    .qdev.vmsd  = &vmstate_fdc_sysbus,
 | 
			
		||||
    .qdev.reset = fdctrl_external_reset_sysbus,
 | 
			
		||||
    .qdev.props = (Property[]) {
 | 
			
		||||
        DEFINE_PROP_DRIVE("driveA", fdctrl_sysbus_t, state.drives[0].dinfo),
 | 
			
		||||
@@ -2049,7 +2039,6 @@ static SysBusDeviceInfo sun4m_fdc_info = {
 | 
			
		||||
    .init = sun4m_fdc_init1,
 | 
			
		||||
    .qdev.name  = "SUNW,fdtwo",
 | 
			
		||||
    .qdev.size  = sizeof(fdctrl_sysbus_t),
 | 
			
		||||
    .qdev.vmsd  = &vmstate_fdc_sysbus,
 | 
			
		||||
    .qdev.reset = fdctrl_external_reset_sysbus,
 | 
			
		||||
    .qdev.props = (Property[]) {
 | 
			
		||||
        DEFINE_PROP_DRIVE("drive", fdctrl_sysbus_t, state.drives[0].dinfo),
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										73
									
								
								hw/fw_cfg.c
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								hw/fw_cfg.c
									
									
									
									
									
								
							@@ -45,11 +45,12 @@ typedef struct _FWCfgEntry {
 | 
			
		||||
    FWCfgCallback callback;
 | 
			
		||||
} FWCfgEntry;
 | 
			
		||||
 | 
			
		||||
typedef struct _FWCfgState {
 | 
			
		||||
struct _FWCfgState {
 | 
			
		||||
    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
 | 
			
		||||
    FWCfgFiles *files;
 | 
			
		||||
    uint16_t cur_entry;
 | 
			
		||||
    uint32_t cur_offset;
 | 
			
		||||
} FWCfgState;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    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");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    copy = qemu_malloc(sizeof(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;
 | 
			
		||||
 | 
			
		||||
    copy = qemu_malloc(sizeof(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;
 | 
			
		||||
 | 
			
		||||
    copy = qemu_malloc(sizeof(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)
 | 
			
		||||
{
 | 
			
		||||
    FWCfgState *s = opaque;
 | 
			
		||||
    int arch = !!(key & FW_CFG_ARCH_LOCAL);
 | 
			
		||||
 | 
			
		||||
    if (!(key & FW_CFG_WRITE_CHANNEL))
 | 
			
		||||
@@ -275,7 +274,53 @@ int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback,
 | 
			
		||||
    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,
 | 
			
		||||
                    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;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								hw/fw_cfg.h
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								hw/fw_cfg.h
									
									
									
									
									
								
							@@ -26,7 +26,11 @@
 | 
			
		||||
#define FW_CFG_SETUP_ADDR       0x16
 | 
			
		||||
#define FW_CFG_SETUP_SIZE       0x17
 | 
			
		||||
#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_ARCH_LOCAL       0x8000
 | 
			
		||||
@@ -35,15 +39,30 @@
 | 
			
		||||
#define FW_CFG_INVALID          0xffff
 | 
			
		||||
 | 
			
		||||
#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);
 | 
			
		||||
 | 
			
		||||
int fw_cfg_add_bytes(void *opaque, uint16_t key, uint8_t *data, uint32_t len);
 | 
			
		||||
int fw_cfg_add_i16(void *opaque, uint16_t key, uint16_t value);
 | 
			
		||||
int fw_cfg_add_i32(void *opaque, uint16_t key, uint32_t value);
 | 
			
		||||
int fw_cfg_add_i64(void *opaque, uint16_t key, uint64_t value);
 | 
			
		||||
int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback,
 | 
			
		||||
typedef struct _FWCfgState FWCfgState;
 | 
			
		||||
int fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len);
 | 
			
		||||
int fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value);
 | 
			
		||||
int fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value);
 | 
			
		||||
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 *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
 | 
			
		||||
int fw_cfg_add_file(FWCfgState *s, const char *dir, const char *filename,
 | 
			
		||||
                    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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -178,7 +178,7 @@ static PCIDeviceInfo grackle_pci_host_info = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static PCIDeviceInfo dec_21154_pci_host_info = {
 | 
			
		||||
    .qdev.name = "DEC 21154",
 | 
			
		||||
    .qdev.name = "dec-21154",
 | 
			
		||||
    .qdev.size = sizeof(PCIDevice),
 | 
			
		||||
    .init      = dec_21154_pci_host_init,
 | 
			
		||||
};
 | 
			
		||||
@@ -188,7 +188,7 @@ static void grackle_register_devices(void)
 | 
			
		||||
    sysbus_register_dev("grackle", sizeof(GrackleState),
 | 
			
		||||
                        pci_grackle_init_device);
 | 
			
		||||
    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_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 */
 | 
			
		||||
    s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock);
 | 
			
		||||
 | 
			
		||||
    if (hpet_in_legacy_mode()) {
 | 
			
		||||
        hpet_disable_pit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 */
 | 
			
		||||
                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)) {
 | 
			
		||||
                    hpet_pit_enable();
 | 
			
		||||
                    hpet_enable_pit();
 | 
			
		||||
                    dprintf("qemu: hpet enabled pit\n");
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            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
 | 
			
		||||
         * be returned to pit until SW reenables hpet.
 | 
			
		||||
         */
 | 
			
		||||
        hpet_pit_enable();
 | 
			
		||||
        hpet_enable_pit();
 | 
			
		||||
    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_uint64;
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
extern const VMStateInfo vmstate_info_u64;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern const VMStateInfo vmstate_info_timer;
 | 
			
		||||
extern const VMStateInfo vmstate_info_ptimer;
 | 
			
		||||
extern const VMStateInfo vmstate_info_buffer;
 | 
			
		||||
@@ -622,6 +626,15 @@ extern const VMStateDescription vmstate_i2c_slave;
 | 
			
		||||
#define VMSTATE_UINT64(_f, _s)                                        \
 | 
			
		||||
    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)                                   \
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										135
									
								
								hw/i8254.c
									
									
									
									
									
								
							
							
						
						
									
										135
									
								
								hw/i8254.c
									
									
									
									
									
								
							@@ -25,38 +25,11 @@
 | 
			
		||||
#include "pc.h"
 | 
			
		||||
#include "isa.h"
 | 
			
		||||
#include "qemu-timer.h"
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
#include "i8254.h"
 | 
			
		||||
 | 
			
		||||
//#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 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
        val = 0x10000;
 | 
			
		||||
    s->count_load_time = qemu_get_clock(vm_clock);
 | 
			
		||||
    s->count = val;
 | 
			
		||||
    pit_irq_timer_update(s, s->count_load_time);
 | 
			
		||||
    s->channels[chan].count_load_time = qemu_get_clock(vm_clock);
 | 
			
		||||
    s->channels[chan].count = val;
 | 
			
		||||
#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 */
 | 
			
		||||
@@ -294,17 +272,17 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 | 
			
		||||
        switch(s->write_state) {
 | 
			
		||||
        default:
 | 
			
		||||
        case RW_STATE_LSB:
 | 
			
		||||
            pit_load_count(s, val);
 | 
			
		||||
            pit_load_count(pit, val, addr);
 | 
			
		||||
            break;
 | 
			
		||||
        case RW_STATE_MSB:
 | 
			
		||||
            pit_load_count(s, val << 8);
 | 
			
		||||
            pit_load_count(pit, val << 8, addr);
 | 
			
		||||
            break;
 | 
			
		||||
        case RW_STATE_WORD0:
 | 
			
		||||
            s->write_latch = val;
 | 
			
		||||
            s->write_state = RW_STATE_WORD1;
 | 
			
		||||
            break;
 | 
			
		||||
        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;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
@@ -364,6 +342,11 @@ static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    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);
 | 
			
		||||
    irq_level = pit_get_out1(s, current_time);
 | 
			
		||||
    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
 | 
			
		||||
    printf("irq_level=%d next_delay=%f\n",
 | 
			
		||||
           irq_level,
 | 
			
		||||
           (double)(expire_time - current_time) / get_ticks_per_sec());
 | 
			
		||||
#endif
 | 
			
		||||
    s->next_transition_time = expire_time;
 | 
			
		||||
    if (expire_time != -1)
 | 
			
		||||
    if (expire_time != -1) {
 | 
			
		||||
        qemu_mod_timer(s->irq_timer, expire_time);
 | 
			
		||||
    else
 | 
			
		||||
    } else {
 | 
			
		||||
        qemu_del_timer(s->irq_timer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    if (version_id != 1)
 | 
			
		||||
    if (version_id != PIT_SAVEVM_VERSION)
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
 | 
			
		||||
    pit->flags = qemu_get_be32(f);
 | 
			
		||||
    for(i = 0; i < 3; i++) {
 | 
			
		||||
        s = &pit->channels[i];
 | 
			
		||||
        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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const VMStateDescription vmstate_pit = {
 | 
			
		||||
VMStateDescription vmstate_pit = {
 | 
			
		||||
    .name = "i8254",
 | 
			
		||||
    .version_id = 2,
 | 
			
		||||
    .minimum_version_id = 2,
 | 
			
		||||
    .minimum_version_id_old = 1,
 | 
			
		||||
    .load_state_old = pit_load_old,
 | 
			
		||||
    .fields      = (VMStateField []) {
 | 
			
		||||
        VMSTATE_UINT32(flags, PITState),
 | 
			
		||||
        VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
 | 
			
		||||
        VMSTATE_TIMER(channels[0].irq_timer, PITState),
 | 
			
		||||
        VMSTATE_END_OF_LIST()
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void pit_reset(void *opaque)
 | 
			
		||||
void pit_reset(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    PITState *pit = opaque;
 | 
			
		||||
    PITChannelState *s;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
#ifdef TARGET_I386
 | 
			
		||||
    pit->flags &= ~PIT_FLAGS_HPET_LEGACY;
 | 
			
		||||
#endif
 | 
			
		||||
    for(i = 0;i < 3; i++) {
 | 
			
		||||
        s = &pit->channels[i];
 | 
			
		||||
        s->mode = 3;
 | 
			
		||||
        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 */
 | 
			
		||||
void hpet_pit_disable(void) {
 | 
			
		||||
    PITChannelState *s;
 | 
			
		||||
    s = &pit_state.channels[0];
 | 
			
		||||
    if (s->irq_timer)
 | 
			
		||||
 | 
			
		||||
void hpet_disable_pit(void)
 | 
			
		||||
{
 | 
			
		||||
    PITChannelState *s = &pit_state.channels[0];
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
 * timer 0
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void hpet_pit_enable(void)
 | 
			
		||||
void hpet_enable_pit(void)
 | 
			
		||||
{
 | 
			
		||||
    PITState *pit = &pit_state;
 | 
			
		||||
    PITChannelState *s;
 | 
			
		||||
    s = &pit->channels[0];
 | 
			
		||||
    s->mode = 3;
 | 
			
		||||
    s->gate = 1;
 | 
			
		||||
    pit_load_count(s, 0);
 | 
			
		||||
    PITChannelState *s = &pit->channels[0];
 | 
			
		||||
 | 
			
		||||
    if (kvm_enabled() && qemu_kvm_pit_in_kernel()) {
 | 
			
		||||
        if (qemu_kvm_has_pit_state2()) {
 | 
			
		||||
            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)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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 "qemu-timer.h"
 | 
			
		||||
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
/* 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)
 | 
			
		||||
{
 | 
			
		||||
    PicState2 *s = opaque;
 | 
			
		||||
 | 
			
		||||
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
 | 
			
		||||
    if (level != irq_level[irq]) {
 | 
			
		||||
#if defined(DEBUG_PIC)
 | 
			
		||||
@@ -212,18 +213,35 @@ static inline void pic_intack(PicState *s, int irq)
 | 
			
		||||
    } else {
 | 
			
		||||
        s->isr |= (1 << irq);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* We don't clear a level sensitive interrupt here */
 | 
			
		||||
    if (!(s->elcr & (1 << irq)))
 | 
			
		||||
        s->irr &= ~(1 << irq);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern int time_drift_fix;
 | 
			
		||||
 | 
			
		||||
int pic_read_irq(PicState2 *s)
 | 
			
		||||
{
 | 
			
		||||
    int irq, irq2, intno;
 | 
			
		||||
 | 
			
		||||
    irq = pic_get_irq(&s->pics[0]);
 | 
			
		||||
    if (irq >= 0) {
 | 
			
		||||
 | 
			
		||||
        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) {
 | 
			
		||||
            irq2 = pic_get_irq(&s->pics[1]);
 | 
			
		||||
            if (irq2 >= 0) {
 | 
			
		||||
@@ -446,9 +464,33 @@ static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
 | 
			
		||||
    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 = {
 | 
			
		||||
    .name = "i8259",
 | 
			
		||||
    .version_id = 1,
 | 
			
		||||
    .pre_save = pic_pre_save,
 | 
			
		||||
    .post_load = pic_post_load,
 | 
			
		||||
    .minimum_version_id = 1,
 | 
			
		||||
    .minimum_version_id_old = 1,
 | 
			
		||||
    .fields      = (VMStateField []) {
 | 
			
		||||
@@ -535,3 +577,103 @@ qemu_irq *i8259_init(qemu_irq parent_irq)
 | 
			
		||||
    isa_pic = s;
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    if (bm->unit == 0) {
 | 
			
		||||
        return container_of(bm, PCIIDEState, bmdma[0]);
 | 
			
		||||
    } else {
 | 
			
		||||
        return container_of(bm, PCIIDEState, bmdma[1]);
 | 
			
		||||
    }
 | 
			
		||||
    return bm->pci_dev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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];
 | 
			
		||||
        d->bus[i].bmdma = bm;
 | 
			
		||||
        bm->bus = d->bus+i;
 | 
			
		||||
        bm->pci_dev = d;
 | 
			
		||||
        qemu_add_vm_change_state_handler(ide_dma_restart_cb, 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;
 | 
			
		||||
 | 
			
		||||
    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_init_nofail(&dev->qdev);
 | 
			
		||||
 | 
			
		||||
@@ -254,7 +251,7 @@ void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
 | 
			
		||||
 | 
			
		||||
static PCIDeviceInfo cmd646_ide_info[] = {
 | 
			
		||||
    {
 | 
			
		||||
        .qdev.name    = "CMD646 IDE",
 | 
			
		||||
        .qdev.name    = "cmd646-ide",
 | 
			
		||||
        .qdev.size    = sizeof(PCIIDEState),
 | 
			
		||||
        .init         = pci_cmd646_ide_initfn,
 | 
			
		||||
        .qdev.props   = (Property[]) {
 | 
			
		||||
 
 | 
			
		||||
@@ -115,7 +115,7 @@ static void ide_identify(IDEState *s)
 | 
			
		||||
    put_le16(p + 20, 3); /* XXX: retired, remove ? */
 | 
			
		||||
    put_le16(p + 21, 512); /* cache size in sectors */
 | 
			
		||||
    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 */
 | 
			
		||||
#if MAX_MULT_SECTORS > 1
 | 
			
		||||
    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 + 21, 512); /* cache size in sectors */
 | 
			
		||||
    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 */
 | 
			
		||||
    put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on 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 */
 | 
			
		||||
    padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
 | 
			
		||||
    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 */
 | 
			
		||||
#if MAX_MULT_SECTORS > 1
 | 
			
		||||
    put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
 | 
			
		||||
@@ -1591,7 +1591,7 @@ static void ide_atapi_cmd(IDEState *s)
 | 
			
		||||
        buf[7] = 0; /* reserved */
 | 
			
		||||
        padstr8(buf + 8, 8, "QEMU");
 | 
			
		||||
        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);
 | 
			
		||||
        break;
 | 
			
		||||
    case GPCMD_GET_CONFIGURATION:
 | 
			
		||||
@@ -2590,7 +2590,7 @@ void ide_bus_reset(IDEBus *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;
 | 
			
		||||
    uint64_t nb_sectors;
 | 
			
		||||
@@ -2619,6 +2619,11 @@ void ide_init_drive(IDEState *s, DriveInfo *dinfo)
 | 
			
		||||
    if (strlen(s->drive_serial_str) == 0)
 | 
			
		||||
        snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
 | 
			
		||||
                 "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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2635,13 +2640,14 @@ void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
 | 
			
		||||
        s->unit = i;
 | 
			
		||||
        s->drive_serial = drive_serial++;
 | 
			
		||||
        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->sector_write_timer = qemu_new_timer(vm_clock,
 | 
			
		||||
                                               ide_sector_write_timer_cb, s);
 | 
			
		||||
        if (i == 0)
 | 
			
		||||
            ide_init_drive(s, hd0);
 | 
			
		||||
            ide_init_drive(s, hd0, NULL);
 | 
			
		||||
        if (i == 1)
 | 
			
		||||
            ide_init_drive(s, hd1);
 | 
			
		||||
            ide_init_drive(s, hd1, NULL);
 | 
			
		||||
    }
 | 
			
		||||
    bus->irq = irq;
 | 
			
		||||
}
 | 
			
		||||
@@ -2669,6 +2675,25 @@ static bool is_identify_set(void *opaque, int version_id)
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    IDEState *s = opaque;
 | 
			
		||||
@@ -2679,14 +2704,42 @@ static int ide_drive_post_load(void *opaque, int version_id)
 | 
			
		||||
            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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 = {
 | 
			
		||||
    .name = "ide_drive",
 | 
			
		||||
    .version_id = 3,
 | 
			
		||||
    .version_id = 4,
 | 
			
		||||
    .minimum_version_id = 0,
 | 
			
		||||
    .minimum_version_id_old = 0,
 | 
			
		||||
    .pre_save = ide_drive_pre_save,
 | 
			
		||||
    .post_load = ide_drive_post_load,
 | 
			
		||||
    .fields      = (VMStateField []) {
 | 
			
		||||
        VMSTATE_INT32(mult_sectors, IDEState),
 | 
			
		||||
@@ -2709,7 +2762,14 @@ const VMStateDescription vmstate_ide_drive = {
 | 
			
		||||
        VMSTATE_UINT8(sense_key, IDEState),
 | 
			
		||||
        VMSTATE_UINT8(asc, IDEState),
 | 
			
		||||
        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()
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@@ -2767,10 +2827,6 @@ static void ide_dma_restart(IDEState *s, int is_read)
 | 
			
		||||
void ide_dma_cancel(BMDMAState *bm)
 | 
			
		||||
{
 | 
			
		||||
    if (bm->status & BM_STATUS_DMAING) {
 | 
			
		||||
        bm->status &= ~BM_STATUS_DMAING;
 | 
			
		||||
        /* cancel DMA request */
 | 
			
		||||
        bm->unit = -1;
 | 
			
		||||
        bm->dma_cb = NULL;
 | 
			
		||||
        if (bm->aiocb) {
 | 
			
		||||
#ifdef DEBUG_AIO
 | 
			
		||||
            printf("aio_cancel\n");
 | 
			
		||||
@@ -2778,6 +2834,10 @@ void ide_dma_cancel(BMDMAState *bm)
 | 
			
		||||
            bdrv_aio_cancel(bm->aiocb);
 | 
			
		||||
            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 */
 | 
			
		||||
    uint8_t lba48;
 | 
			
		||||
    BlockDriverState *bs;
 | 
			
		||||
    char version[9];
 | 
			
		||||
    /* ATAPI specific */
 | 
			
		||||
    uint8_t sense_key;
 | 
			
		||||
    uint8_t asc;
 | 
			
		||||
@@ -416,6 +417,11 @@ struct IDEState {
 | 
			
		||||
    uint8_t *data_ptr;
 | 
			
		||||
    uint8_t *data_end;
 | 
			
		||||
    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 */
 | 
			
		||||
    uint32_t irq_count; /* counts IRQs when using win2k install hack */
 | 
			
		||||
    /* CF-ATA extended error */
 | 
			
		||||
@@ -449,6 +455,7 @@ struct IDEDevice {
 | 
			
		||||
    DeviceState qdev;
 | 
			
		||||
    uint32_t unit;
 | 
			
		||||
    DriveInfo *dinfo;
 | 
			
		||||
    char *version;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef int (*ide_qdev_initfn)(IDEDevice *dev);
 | 
			
		||||
@@ -474,6 +481,7 @@ struct BMDMAState {
 | 
			
		||||
    uint8_t status;
 | 
			
		||||
    uint32_t addr;
 | 
			
		||||
 | 
			
		||||
    struct PCIIDEState *pci_dev;
 | 
			
		||||
    IDEBus *bus;
 | 
			
		||||
    /* current transfer state */
 | 
			
		||||
    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);
 | 
			
		||||
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,
 | 
			
		||||
               qemu_irq irq);
 | 
			
		||||
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];
 | 
			
		||||
        d->bus[i].bmdma = bm;
 | 
			
		||||
        bm->bus = d->bus+i;
 | 
			
		||||
        bm->pci_dev = d;
 | 
			
		||||
        qemu_add_vm_change_state_handler(ide_dma_restart_cb, 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;
 | 
			
		||||
 | 
			
		||||
    dev = pci_create_simple(bus, devfn, "PIIX3 IDE");
 | 
			
		||||
    dev = pci_create_simple(bus, devfn, "piix3-ide");
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    dev = pci_create_simple(bus, devfn, "PIIX4 IDE");
 | 
			
		||||
    dev = pci_create_simple(bus, devfn, "piix4-ide");
 | 
			
		||||
    pci_ide_create_devs(dev, hd_table);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PCIDeviceInfo piix_ide_info[] = {
 | 
			
		||||
    {
 | 
			
		||||
        .qdev.name    = "PIIX3 IDE",
 | 
			
		||||
        .qdev.name    = "piix3-ide",
 | 
			
		||||
        .qdev.size    = sizeof(PCIIDEState),
 | 
			
		||||
        .qdev.no_user = 1,
 | 
			
		||||
        .init         = pci_piix3_ide_initfn,
 | 
			
		||||
    },{
 | 
			
		||||
        .qdev.name    = "PIIX4 IDE",
 | 
			
		||||
        .qdev.name    = "piix4-ide",
 | 
			
		||||
        .qdev.size    = sizeof(PCIIDEState),
 | 
			
		||||
        .qdev.no_user = 1,
 | 
			
		||||
        .init         = pci_piix4_ide_initfn,
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ typedef struct IDEDrive {
 | 
			
		||||
static int ide_drive_initfn(IDEDevice *dev)
 | 
			
		||||
{
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -110,6 +110,7 @@ static IDEDeviceInfo ide_drive_info = {
 | 
			
		||||
    .qdev.props = (Property[]) {
 | 
			
		||||
        DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1),
 | 
			
		||||
        DEFINE_PROP_DRIVE("drive", IDEDrive, dev.dinfo),
 | 
			
		||||
        DEFINE_PROP_STRING("ver",  IDEDrive, dev.version),
 | 
			
		||||
        DEFINE_PROP_END_OF_LIST(),
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										93
									
								
								hw/ioapic.c
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								hw/ioapic.c
									
									
									
									
									
								
							@@ -22,12 +22,16 @@
 | 
			
		||||
 | 
			
		||||
#include "hw.h"
 | 
			
		||||
#include "pc.h"
 | 
			
		||||
#include "sysemu.h"
 | 
			
		||||
#include "qemu-timer.h"
 | 
			
		||||
#include "host-utils.h"
 | 
			
		||||
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
//#define DEBUG_IOAPIC
 | 
			
		||||
 | 
			
		||||
#define IOAPIC_NUM_PINS			0x18
 | 
			
		||||
#define IOAPIC_DEFAULT_BASE_ADDRESS  0xfec00000
 | 
			
		||||
#define IOAPIC_LVT_MASKED 		(1<<16)
 | 
			
		||||
 | 
			
		||||
#define IOAPIC_TRIGGER_EDGE		0
 | 
			
		||||
@@ -45,6 +49,7 @@
 | 
			
		||||
struct IOAPICState {
 | 
			
		||||
    uint8_t id;
 | 
			
		||||
    uint8_t ioregsel;
 | 
			
		||||
    uint64_t base_address;
 | 
			
		||||
 | 
			
		||||
    uint32_t irr;
 | 
			
		||||
    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
 | 
			
		||||
     * the cleanest way of doing it but it should work. */
 | 
			
		||||
 | 
			
		||||
    if (vector == 0)
 | 
			
		||||
    if (vector == 0 && irq0override) {
 | 
			
		||||
        vector = 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
 | 
			
		||||
        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 = {
 | 
			
		||||
    .name = "ioapic",
 | 
			
		||||
    .version_id = 1,
 | 
			
		||||
    .version_id = 2,
 | 
			
		||||
    .minimum_version_id = 1,
 | 
			
		||||
    .minimum_version_id_old = 1,
 | 
			
		||||
    .pre_load = ioapic_pre_load,
 | 
			
		||||
    .post_load = ioapic_post_load,
 | 
			
		||||
    .pre_save = ioapic_pre_save,
 | 
			
		||||
    .fields      = (VMStateField []) {
 | 
			
		||||
        VMSTATE_UINT8(id, 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_END_OF_LIST()
 | 
			
		||||
    }
 | 
			
		||||
@@ -210,8 +293,14 @@ static void ioapic_reset(void *opaque)
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    memset(s, 0, sizeof(*s));
 | 
			
		||||
    s->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
 | 
			
		||||
    for(i = 0; i < IOAPIC_NUM_PINS; i++)
 | 
			
		||||
        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] = {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								hw/loader.c
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								hw/loader.c
									
									
									
									
									
								
							@@ -48,6 +48,7 @@
 | 
			
		||||
#include "sysemu.h"
 | 
			
		||||
#include "uboot_image.h"
 | 
			
		||||
#include "loader.h"
 | 
			
		||||
#include "fw_cfg.h"
 | 
			
		||||
 | 
			
		||||
#include <zlib.h>
 | 
			
		||||
 | 
			
		||||
@@ -526,15 +527,15 @@ struct Rom {
 | 
			
		||||
    char *path;
 | 
			
		||||
    size_t romsize;
 | 
			
		||||
    uint8_t *data;
 | 
			
		||||
    int align;
 | 
			
		||||
    int isrom;
 | 
			
		||||
    char *fw_dir;
 | 
			
		||||
    char *fw_file;
 | 
			
		||||
 | 
			
		||||
    target_phys_addr_t min;
 | 
			
		||||
    target_phys_addr_t max;
 | 
			
		||||
    target_phys_addr_t addr;
 | 
			
		||||
    QTAILQ_ENTRY(Rom) next;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static FWCfgState *fw_cfg;
 | 
			
		||||
static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms);
 | 
			
		||||
int rom_enable_driver_roms;
 | 
			
		||||
 | 
			
		||||
@@ -548,7 +549,7 @@ static void rom_insert(Rom *rom)
 | 
			
		||||
 | 
			
		||||
    /* list is ordered by load address */
 | 
			
		||||
    QTAILQ_FOREACH(item, &roms, next) {
 | 
			
		||||
        if (rom->min >= item->min)
 | 
			
		||||
        if (rom->addr >= item->addr)
 | 
			
		||||
            continue;
 | 
			
		||||
        QTAILQ_INSERT_BEFORE(item, rom, next);
 | 
			
		||||
        return;
 | 
			
		||||
@@ -556,8 +557,8 @@ static void rom_insert(Rom *rom)
 | 
			
		||||
    QTAILQ_INSERT_TAIL(&roms, rom, next);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    Rom *rom;
 | 
			
		||||
    int rc, fd = -1;
 | 
			
		||||
@@ -576,9 +577,11 @@ int rom_add_file(const char *file,
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rom->align   = align;
 | 
			
		||||
    rom->min     = min;
 | 
			
		||||
    rom->max     = max;
 | 
			
		||||
    if (fw_dir) {
 | 
			
		||||
        rom->fw_dir  = qemu_strdup(fw_dir);
 | 
			
		||||
        rom->fw_file = qemu_strdup(file);
 | 
			
		||||
    }
 | 
			
		||||
    rom->addr    = addr;
 | 
			
		||||
    rom->romsize = lseek(fd, 0, SEEK_END);
 | 
			
		||||
    rom->data    = qemu_mallocz(rom->romsize);
 | 
			
		||||
    lseek(fd, 0, SEEK_SET);
 | 
			
		||||
@@ -590,6 +593,8 @@ int rom_add_file(const char *file,
 | 
			
		||||
    }
 | 
			
		||||
    close(fd);
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
@@ -603,15 +608,13 @@ err:
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 = qemu_mallocz(sizeof(*rom));
 | 
			
		||||
    rom->name    = qemu_strdup(name);
 | 
			
		||||
    rom->align   = align;
 | 
			
		||||
    rom->min     = min;
 | 
			
		||||
    rom->max     = max;
 | 
			
		||||
    rom->addr    = addr;
 | 
			
		||||
    rom->romsize = len;
 | 
			
		||||
    rom->data    = qemu_mallocz(rom->romsize);
 | 
			
		||||
    memcpy(rom->data, blob, len);
 | 
			
		||||
@@ -623,14 +626,14 @@ int rom_add_vga(const char *file)
 | 
			
		||||
{
 | 
			
		||||
    if (!rom_enable_driver_roms)
 | 
			
		||||
        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)
 | 
			
		||||
{
 | 
			
		||||
    if (!rom_enable_driver_roms)
 | 
			
		||||
        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)
 | 
			
		||||
@@ -638,8 +641,12 @@ static void rom_reset(void *unused)
 | 
			
		||||
    Rom *rom;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(rom, &roms, next) {
 | 
			
		||||
        if (rom->data == NULL)
 | 
			
		||||
        if (rom->fw_file) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (rom->data == NULL) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize);
 | 
			
		||||
        if (rom->isrom) {
 | 
			
		||||
            /* rom needs to be written only once */
 | 
			
		||||
@@ -656,32 +663,17 @@ int rom_load_all(void)
 | 
			
		||||
    Rom *rom;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(rom, &roms, next) {
 | 
			
		||||
        if (addr < rom->min)
 | 
			
		||||
            addr = rom->min;
 | 
			
		||||
        if (rom->max) {
 | 
			
		||||
            /* load address range */
 | 
			
		||||
            if (rom->align) {
 | 
			
		||||
                addr += (rom->align-1);
 | 
			
		||||
                addr &= ~(rom->align-1);
 | 
			
		||||
        if (rom->fw_file) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
            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) {
 | 
			
		||||
        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->min);
 | 
			
		||||
                    rom->name, addr, rom->addr);
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        }
 | 
			
		||||
        rom->addr = addr;
 | 
			
		||||
        addr  = rom->addr;
 | 
			
		||||
        addr += rom->romsize;
 | 
			
		||||
        memtype = cpu_get_physical_page_desc(rom->addr) & (3 << IO_MEM_SHIFT);
 | 
			
		||||
        if (memtype == IO_MEM_ROM)
 | 
			
		||||
@@ -692,22 +684,35 @@ int rom_load_all(void)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rom_set_fw(void *f)
 | 
			
		||||
{
 | 
			
		||||
    fw_cfg = f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Rom *find_rom(target_phys_addr_t addr)
 | 
			
		||||
{
 | 
			
		||||
    Rom *rom;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(rom, &roms, next) {
 | 
			
		||||
        if (rom->max)
 | 
			
		||||
        if (rom->fw_file) {
 | 
			
		||||
            continue;
 | 
			
		||||
        if (rom->min > addr)
 | 
			
		||||
        }
 | 
			
		||||
        if (rom->addr > addr) {
 | 
			
		||||
            continue;
 | 
			
		||||
        if (rom->min + rom->romsize < addr)
 | 
			
		||||
        }
 | 
			
		||||
        if (rom->addr + rom->romsize < addr) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        return rom;
 | 
			
		||||
    }
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(rom, &roms, next) {
 | 
			
		||||
        if (rom->max)
 | 
			
		||||
        if (rom->fw_file) {
 | 
			
		||||
            continue;
 | 
			
		||||
        if (rom->min > addr)
 | 
			
		||||
        }
 | 
			
		||||
        if (rom->addr + rom->romsize < addr) {
 | 
			
		||||
            continue;
 | 
			
		||||
        if (rom->min + rom->romsize < addr)
 | 
			
		||||
            continue;
 | 
			
		||||
        if (rom->min > end)
 | 
			
		||||
        }
 | 
			
		||||
        if (rom->addr > end) {
 | 
			
		||||
            break;
 | 
			
		||||
        if (!rom->data)
 | 
			
		||||
        }
 | 
			
		||||
        if (!rom->data) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        d = dest + (rom->min - addr);
 | 
			
		||||
        d = dest + (rom->addr - addr);
 | 
			
		||||
        s = rom->data;
 | 
			
		||||
        l = rom->romsize;
 | 
			
		||||
 | 
			
		||||
        if (rom->min < addr) {
 | 
			
		||||
        if (rom->addr < addr) {
 | 
			
		||||
            d = dest;
 | 
			
		||||
            s += (addr - rom->min);
 | 
			
		||||
            l -= (addr - rom->min);
 | 
			
		||||
            s += (addr - rom->addr);
 | 
			
		||||
            l -= (addr - rom->addr);
 | 
			
		||||
        }
 | 
			
		||||
        if ((d + l) > (dest + size)) {
 | 
			
		||||
            l = dest - d;
 | 
			
		||||
@@ -753,7 +760,7 @@ void *rom_ptr(target_phys_addr_t addr)
 | 
			
		||||
    rom = find_rom(addr);
 | 
			
		||||
    if (!rom || !rom->data)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    return rom->data + (addr - rom->min);
 | 
			
		||||
    return rom->data + (addr - rom->addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void do_info_roms(Monitor *mon)
 | 
			
		||||
@@ -761,10 +768,19 @@ void do_info_roms(Monitor *mon)
 | 
			
		||||
    Rom *rom;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(rom, &roms, next) {
 | 
			
		||||
        if (!rom->fw_file) {
 | 
			
		||||
            monitor_printf(mon, "addr=" TARGET_FMT_plx
 | 
			
		||||
                           " size=0x%06zx mem=%s name=\"%s\" \n",
 | 
			
		||||
                           rom->addr, rom->romsize,
 | 
			
		||||
                           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,
 | 
			
		||||
                      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,
 | 
			
		||||
                 target_phys_addr_t min, target_phys_addr_t max, int align);
 | 
			
		||||
                 target_phys_addr_t addr);
 | 
			
		||||
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);
 | 
			
		||||
void *rom_ptr(target_phys_addr_t addr);
 | 
			
		||||
void do_info_roms(Monitor *mon);
 | 
			
		||||
 | 
			
		||||
#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)      \
 | 
			
		||||
    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_OPTION  0xc8000
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										172
									
								
								hw/lsi53c895a.c
									
									
									
									
									
								
							
							
						
						
									
										172
									
								
								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.  */
 | 
			
		||||
#define LSI_TAG_VALID     (1 << 16)
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
typedef struct lsi_request {
 | 
			
		||||
    uint32_t tag;
 | 
			
		||||
    SCSIDevice *dev;
 | 
			
		||||
    uint32_t dma_len;
 | 
			
		||||
    uint8_t *dma_buf;
 | 
			
		||||
    uint32_t pending;
 | 
			
		||||
    int out;
 | 
			
		||||
} lsi_queue;
 | 
			
		||||
    QTAILQ_ENTRY(lsi_request) next;
 | 
			
		||||
} lsi_request;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    PCIDevice dev;
 | 
			
		||||
@@ -198,16 +202,13 @@ typedef struct {
 | 
			
		||||
     * 3 if a DMA operation is in progress.  */
 | 
			
		||||
    int waiting;
 | 
			
		||||
    SCSIBus bus;
 | 
			
		||||
    SCSIDevice *current_dev;
 | 
			
		||||
    SCSIDevice *select_dev;
 | 
			
		||||
    int current_lun;
 | 
			
		||||
    /* The tag is a combination of the device ID and the SCSI tag.  */
 | 
			
		||||
    uint32_t current_tag;
 | 
			
		||||
    uint32_t current_dma_len;
 | 
			
		||||
    uint32_t select_tag;
 | 
			
		||||
    int command_complete;
 | 
			
		||||
    uint8_t *dma_buf;
 | 
			
		||||
    lsi_queue *queue;
 | 
			
		||||
    int queue_len;
 | 
			
		||||
    int active_commands;
 | 
			
		||||
    QTAILQ_HEAD(, lsi_request) queue;
 | 
			
		||||
    lsi_request *current;
 | 
			
		||||
 | 
			
		||||
    uint32_t dsa;
 | 
			
		||||
    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 void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
@@ -391,9 +392,9 @@ static void lsi_stop_script(LSIState *s)
 | 
			
		||||
 | 
			
		||||
static void lsi_update_irq(LSIState *s)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    int level;
 | 
			
		||||
    static int last_level;
 | 
			
		||||
    lsi_request *p;
 | 
			
		||||
 | 
			
		||||
    /* It's unclear whether the DIP/SIP bits should be cleared when the
 | 
			
		||||
       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)) {
 | 
			
		||||
        DPRINTF("Handled IRQs & disconnected, looking for pending "
 | 
			
		||||
                "processes\n");
 | 
			
		||||
        for (i = 0; i < s->active_commands; i++) {
 | 
			
		||||
            if (s->queue[i].pending) {
 | 
			
		||||
                lsi_reselect(s, s->queue[i].tag);
 | 
			
		||||
        QTAILQ_FOREACH(p, &s->queue, next) {
 | 
			
		||||
            if (p->pending) {
 | 
			
		||||
                lsi_reselect(s, p);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -508,15 +509,16 @@ static void lsi_do_dma(LSIState *s, int out)
 | 
			
		||||
    uint32_t count;
 | 
			
		||||
    target_phys_addr_t addr;
 | 
			
		||||
 | 
			
		||||
    if (!s->current_dma_len) {
 | 
			
		||||
    assert(s->current);
 | 
			
		||||
    if (!s->current->dma_len) {
 | 
			
		||||
        /* Wait until data is available.  */
 | 
			
		||||
        DPRINTF("DMA no data available\n");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    count = s->dbc;
 | 
			
		||||
    if (count > s->current_dma_len)
 | 
			
		||||
        count = s->current_dma_len;
 | 
			
		||||
    if (count > s->current->dma_len)
 | 
			
		||||
        count = s->current->dma_len;
 | 
			
		||||
 | 
			
		||||
    addr = s->dnad;
 | 
			
		||||
    /* 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->dbc -= count;
 | 
			
		||||
 | 
			
		||||
    if (s->dma_buf == NULL) {
 | 
			
		||||
        s->dma_buf = s->current_dev->info->get_buf(s->current_dev,
 | 
			
		||||
                                                   s->current_tag);
 | 
			
		||||
    if (s->current->dma_buf == NULL) {
 | 
			
		||||
        s->current->dma_buf = s->current->dev->info->get_buf(s->current->dev,
 | 
			
		||||
                                                             s->current->tag);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* ??? Set SFBR to first data byte.  */
 | 
			
		||||
    if (out) {
 | 
			
		||||
        cpu_physical_memory_read(addr, s->dma_buf, count);
 | 
			
		||||
        cpu_physical_memory_read(addr, s->current->dma_buf, count);
 | 
			
		||||
    } 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;
 | 
			
		||||
    if (s->current_dma_len == 0) {
 | 
			
		||||
        s->dma_buf = NULL;
 | 
			
		||||
    s->current->dma_len -= count;
 | 
			
		||||
    if (s->current->dma_len == 0) {
 | 
			
		||||
        s->current->dma_buf = NULL;
 | 
			
		||||
        if (out) {
 | 
			
		||||
            /* 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 {
 | 
			
		||||
            /* 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 {
 | 
			
		||||
        s->dma_buf += count;
 | 
			
		||||
        s->current->dma_buf += count;
 | 
			
		||||
        lsi_resume_script(s);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -563,15 +565,14 @@ static void lsi_do_dma(LSIState *s, int out)
 | 
			
		||||
/* Add a command to the queue.  */
 | 
			
		||||
static void lsi_queue_command(LSIState *s)
 | 
			
		||||
{
 | 
			
		||||
    lsi_queue *p;
 | 
			
		||||
    lsi_request *p = s->current;
 | 
			
		||||
 | 
			
		||||
    DPRINTF("Queueing tag=0x%x\n", s->current_tag);
 | 
			
		||||
    if (s->queue_len == s->active_commands) {
 | 
			
		||||
        s->queue_len++;
 | 
			
		||||
        s->queue = qemu_realloc(s->queue, s->queue_len * sizeof(lsi_queue));
 | 
			
		||||
    }
 | 
			
		||||
    p = &s->queue[s->active_commands++];
 | 
			
		||||
    p->tag = s->current_tag;
 | 
			
		||||
    assert(s->current != NULL);
 | 
			
		||||
    assert(s->current->dma_len == 0);
 | 
			
		||||
    QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
 | 
			
		||||
    s->current = NULL;
 | 
			
		||||
 | 
			
		||||
    p->pending = 0;
 | 
			
		||||
    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.  */
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    p = NULL;
 | 
			
		||||
    for (n = 0; n < s->active_commands; n++) {
 | 
			
		||||
        p = &s->queue[n];
 | 
			
		||||
        if (p->tag == tag)
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    if (n == s->active_commands) {
 | 
			
		||||
        BADF("Reselected non-existant command tag=0x%x\n", tag);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    id = (tag >> 8) & 0xf;
 | 
			
		||||
    assert(s->current == NULL);
 | 
			
		||||
    QTAILQ_REMOVE(&s->queue, p, next);
 | 
			
		||||
    s->current = p;
 | 
			
		||||
 | 
			
		||||
    id = (p->tag >> 8) & 0xf;
 | 
			
		||||
    s->ssid = id | 0x80;
 | 
			
		||||
    /* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
 | 
			
		||||
    if (!s->dcntl & LSI_DCNTL_COM) {
 | 
			
		||||
        s->sfbr = 1 << (id & 0x7);
 | 
			
		||||
    }
 | 
			
		||||
    DPRINTF("Reselected target %d\n", id);
 | 
			
		||||
    s->current_dev = s->bus.devs[id];
 | 
			
		||||
    s->current_tag = tag;
 | 
			
		||||
    s->scntl1 |= LSI_SCNTL1_CON;
 | 
			
		||||
    lsi_set_phase(s, PHASE_MI);
 | 
			
		||||
    s->msg_action = p->out ? 2 : 3;
 | 
			
		||||
    s->current_dma_len = p->pending;
 | 
			
		||||
    s->dma_buf = NULL;
 | 
			
		||||
    s->current->dma_len = p->pending;
 | 
			
		||||
    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, tag & 0xff);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s->active_commands--;
 | 
			
		||||
    if (n != s->active_commands) {
 | 
			
		||||
        s->queue[n] = s->queue[s->active_commands];
 | 
			
		||||
        lsi_add_msg_byte(s, p->tag & 0xff);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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.  */
 | 
			
		||||
static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
 | 
			
		||||
{
 | 
			
		||||
    lsi_queue *p;
 | 
			
		||||
    int i;
 | 
			
		||||
    for (i = 0; i < s->active_commands; i++) {
 | 
			
		||||
        p = &s->queue[i];
 | 
			
		||||
    lsi_request *p;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(p, &s->queue, next) {
 | 
			
		||||
        if (p->tag == tag) {
 | 
			
		||||
            if (p->pending) {
 | 
			
		||||
                BADF("Multiple IO pending for tag %d\n", tag);
 | 
			
		||||
@@ -656,7 +640,7 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
 | 
			
		||||
                (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
 | 
			
		||||
                 !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
 | 
			
		||||
                /* Reselect device.  */
 | 
			
		||||
                lsi_reselect(s, tag);
 | 
			
		||||
                lsi_reselect(s, p);
 | 
			
		||||
                return 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                DPRINTF("Queueing IO tag=0x%x\n", tag);
 | 
			
		||||
@@ -687,11 +671,15 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
 | 
			
		||||
        } else {
 | 
			
		||||
            lsi_set_phase(s, PHASE_ST);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        qemu_free(s->current);
 | 
			
		||||
        s->current = NULL;
 | 
			
		||||
 | 
			
		||||
        lsi_resume_script(s);
 | 
			
		||||
        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))) {
 | 
			
		||||
        if (lsi_queue_tag(s, tag, arg))
 | 
			
		||||
            return;
 | 
			
		||||
@@ -699,7 +687,7 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
 | 
			
		||||
 | 
			
		||||
    /* host adapter (re)connected */
 | 
			
		||||
    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;
 | 
			
		||||
    if (!s->waiting)
 | 
			
		||||
        return;
 | 
			
		||||
@@ -721,14 +709,20 @@ static void lsi_do_command(LSIState *s)
 | 
			
		||||
    cpu_physical_memory_read(s->dnad, buf, s->dbc);
 | 
			
		||||
    s->sfbr = buf[0];
 | 
			
		||||
    s->command_complete = 0;
 | 
			
		||||
    n = s->current_dev->info->send_command(s->current_dev, s->current_tag, buf,
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        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) {
 | 
			
		||||
        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) {
 | 
			
		||||
@@ -851,16 +845,16 @@ static void lsi_do_msgout(LSIState *s)
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        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);
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x21: /* HEAD of queue */
 | 
			
		||||
            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;
 | 
			
		||||
        case 0x22: /* ORDERED queue */
 | 
			
		||||
            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;
 | 
			
		||||
        default:
 | 
			
		||||
            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)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    lsi_request *p;
 | 
			
		||||
 | 
			
		||||
    DPRINTF("Wait Reselect\n");
 | 
			
		||||
    if (s->current_dma_len)
 | 
			
		||||
        BADF("Reselect with pending DMA\n");
 | 
			
		||||
    for (i = 0; i < s->active_commands; i++) {
 | 
			
		||||
        if (s->queue[i].pending) {
 | 
			
		||||
            lsi_reselect(s, s->queue[i].tag);
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(p, &s->queue, next) {
 | 
			
		||||
        if (p->pending) {
 | 
			
		||||
            lsi_reselect(s, p);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (s->current_dma_len == 0) {
 | 
			
		||||
    if (s->current == NULL) {
 | 
			
		||||
        s->waiting = 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1093,8 +1087,8 @@ again:
 | 
			
		||||
                /* ??? Linux drivers compain when this is set.  Maybe
 | 
			
		||||
                   it only applies in low-level mode (unimplemented).
 | 
			
		||||
                lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
 | 
			
		||||
                s->current_dev = s->bus.devs[id];
 | 
			
		||||
                s->current_tag = id << 8;
 | 
			
		||||
                s->select_dev = s->bus.devs[id];
 | 
			
		||||
                s->select_tag = id << 8;
 | 
			
		||||
                s->scntl1 |= LSI_SCNTL1_CON;
 | 
			
		||||
                if (insn & (1 << 3)) {
 | 
			
		||||
                    s->socl |= LSI_SOCL_ATN;
 | 
			
		||||
@@ -2006,9 +2000,11 @@ static void lsi_pre_save(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    LSIState *s = opaque;
 | 
			
		||||
 | 
			
		||||
    assert(s->dma_buf == NULL);
 | 
			
		||||
    assert(s->current_dma_len == 0);
 | 
			
		||||
    assert(s->active_commands == 0);
 | 
			
		||||
    if (s->current) {
 | 
			
		||||
        assert(s->current->dma_buf == NULL);
 | 
			
		||||
        assert(s->current->dma_len == 0);
 | 
			
		||||
    }
 | 
			
		||||
    assert(QTAILQ_EMPTY(&s->queue));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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->ram_io_addr);
 | 
			
		||||
 | 
			
		||||
    qemu_free(s->queue);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2138,9 +2132,7 @@ static int lsi_scsi_init(PCIDevice *dev)
 | 
			
		||||
                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc);
 | 
			
		||||
    pci_register_bar((struct PCIDevice *)s, 2, 0x2000,
 | 
			
		||||
                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
 | 
			
		||||
    s->queue = qemu_malloc(sizeof(lsi_queue));
 | 
			
		||||
    s->queue_len = 1;
 | 
			
		||||
    s->active_commands = 0;
 | 
			
		||||
    QTAILQ_INIT(&s->queue);
 | 
			
		||||
 | 
			
		||||
    lsi_soft_reset(s);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,8 @@
 | 
			
		||||
 | 
			
		||||
//#define DEBUG_CMOS
 | 
			
		||||
 | 
			
		||||
#define RTC_REINJECT_ON_ACK_COUNT 20
 | 
			
		||||
 | 
			
		||||
#define RTC_SECONDS             0
 | 
			
		||||
#define RTC_SECONDS_ALARM       1
 | 
			
		||||
#define RTC_MINUTES             2
 | 
			
		||||
@@ -76,6 +78,7 @@ struct RTCState {
 | 
			
		||||
    int64_t next_periodic_time;
 | 
			
		||||
    /* second update */
 | 
			
		||||
    int64_t next_second_time;
 | 
			
		||||
    uint16_t irq_reinject_on_ack_count;
 | 
			
		||||
    uint32_t irq_coalesced;
 | 
			
		||||
    uint32_t period;
 | 
			
		||||
    QEMUTimer *coalesced_timer;
 | 
			
		||||
@@ -180,6 +183,8 @@ static void rtc_periodic_timer(void *opaque)
 | 
			
		||||
        s->cmos_data[RTC_REG_C] |= 0xc0;
 | 
			
		||||
#ifdef TARGET_I386
 | 
			
		||||
        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();
 | 
			
		||||
            rtc_irq_raise(s->irq);
 | 
			
		||||
            if (!apic_get_irq_delivered()) {
 | 
			
		||||
@@ -458,6 +463,18 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
 | 
			
		||||
        case RTC_REG_C:
 | 
			
		||||
            ret = s->cmos_data[s->cmos_index];
 | 
			
		||||
            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;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										231
									
								
								hw/msix.c
									
									
									
									
									
								
							
							
						
						
									
										231
									
								
								hw/msix.c
									
									
									
									
									
								
							@@ -14,12 +14,15 @@
 | 
			
		||||
#include "hw.h"
 | 
			
		||||
#include "msix.h"
 | 
			
		||||
#include "pci.h"
 | 
			
		||||
#define QEMU_KVM_NO_CPU
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
/* Declaration from linux/pci_regs.h */
 | 
			
		||||
#define  PCI_CAP_ID_MSIX 0x11 /* MSI-X */
 | 
			
		||||
#define  PCI_MSIX_FLAGS 2     /* Table at lower 11 bits */
 | 
			
		||||
#define  PCI_MSIX_FLAGS_QSIZE	0x7FF
 | 
			
		||||
#define  PCI_MSIX_FLAGS_ENABLE	(1 << 15)
 | 
			
		||||
#define  PCI_MSIX_FLAGS_MASKALL	(1 << 14)
 | 
			
		||||
#define  PCI_MSIX_FLAGS_BIRMASK	(7 << 0)
 | 
			
		||||
 | 
			
		||||
/* MSI-X capability structure */
 | 
			
		||||
@@ -27,9 +30,10 @@
 | 
			
		||||
#define MSIX_PBA_OFFSET 8
 | 
			
		||||
#define MSIX_CAP_LENGTH 12
 | 
			
		||||
 | 
			
		||||
/* MSI enable bit is in byte 1 in FLAGS register */
 | 
			
		||||
#define MSIX_ENABLE_OFFSET (PCI_MSIX_FLAGS + 1)
 | 
			
		||||
/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */
 | 
			
		||||
#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1)
 | 
			
		||||
#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
 | 
			
		||||
#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8)
 | 
			
		||||
 | 
			
		||||
/* MSI-X table format */
 | 
			
		||||
#define MSIX_MSG_ADDR 0
 | 
			
		||||
@@ -60,6 +64,117 @@
 | 
			
		||||
/* Flag for interrupt controller to declare MSI-X support */
 | 
			
		||||
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. */
 | 
			
		||||
/* Given a bar and its size, add MSI-X table on top of it
 | 
			
		||||
 * 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);
 | 
			
		||||
    pdev->msix_cap = config_offset;
 | 
			
		||||
    /* 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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)
 | 
			
		||||
{
 | 
			
		||||
    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    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,
 | 
			
		||||
@@ -169,11 +313,12 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
 | 
			
		||||
    PCIDevice *dev = opaque;
 | 
			
		||||
    unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
 | 
			
		||||
    int vector = offset / MSIX_ENTRY_SIZE;
 | 
			
		||||
    int was_masked = msix_is_masked(dev, vector);
 | 
			
		||||
    pci_set_long(dev->msix_table_page + offset, val);
 | 
			
		||||
    if (!msix_is_masked(dev, vector) && msix_is_pending(dev, vector)) {
 | 
			
		||||
        msix_clr_pending(dev, vector);
 | 
			
		||||
        msix_notify(dev, vector);
 | 
			
		||||
    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
 | 
			
		||||
        kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector));
 | 
			
		||||
    }
 | 
			
		||||
    msix_handle_mask_update(dev, vector);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
        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 *
 | 
			
		||||
                                        sizeof *dev->msix_entry_used);
 | 
			
		||||
 | 
			
		||||
@@ -267,6 +418,10 @@ static void msix_free_irq_entries(PCIDevice *dev)
 | 
			
		||||
{
 | 
			
		||||
    int vector;
 | 
			
		||||
 | 
			
		||||
    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
 | 
			
		||||
        kvm_msix_free(dev);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
 | 
			
		||||
        dev->msix_entry_used[vector] = 0;
 | 
			
		||||
        msix_clr_pending(dev, vector);
 | 
			
		||||
@@ -287,6 +442,8 @@ int msix_uninit(PCIDevice *dev)
 | 
			
		||||
    dev->msix_table_page = NULL;
 | 
			
		||||
    qemu_free(dev->msix_entry_used);
 | 
			
		||||
    dev->msix_entry_used = NULL;
 | 
			
		||||
    qemu_free(dev->msix_irq_entries);
 | 
			
		||||
    dev->msix_irq_entries = NULL;
 | 
			
		||||
    dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -295,10 +452,13 @@ void msix_save(PCIDevice *dev, QEMUFile *f)
 | 
			
		||||
{
 | 
			
		||||
    unsigned n = dev->msix_entries_nr;
 | 
			
		||||
 | 
			
		||||
    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
 | 
			
		||||
    if (!msix_supported) {
 | 
			
		||||
        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 + MSIX_PAGE_PENDING, (n + 7) / 8);
 | 
			
		||||
}
 | 
			
		||||
@@ -308,6 +468,9 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
 | 
			
		||||
{
 | 
			
		||||
    unsigned n = dev->msix_entries_nr;
 | 
			
		||||
 | 
			
		||||
    if (!msix_supported)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
@@ -327,7 +490,7 @@ int msix_present(PCIDevice *dev)
 | 
			
		||||
int msix_enabled(PCIDevice *dev)
 | 
			
		||||
{
 | 
			
		||||
    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -352,6 +515,13 @@ void msix_notify(PCIDevice *dev, unsigned vector)
 | 
			
		||||
        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 = (address << 32) | pci_get_long(table_entry + MSIX_MSG_ADDR);
 | 
			
		||||
    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))
 | 
			
		||||
        return;
 | 
			
		||||
    msix_free_irq_entries(dev);
 | 
			
		||||
    dev->config[dev->msix_cap + MSIX_ENABLE_OFFSET] &=
 | 
			
		||||
	    ~dev->wmask[dev->msix_cap + MSIX_ENABLE_OFFSET];
 | 
			
		||||
    dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
 | 
			
		||||
	    ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
 | 
			
		||||
    memset(dev->msix_table_page, 0, MSIX_PAGE_SIZE);
 | 
			
		||||
    msix_mask_all(dev, dev->msix_entries_nr);
 | 
			
		||||
}
 | 
			
		||||
@@ -380,9 +550,19 @@ void msix_reset(PCIDevice *dev)
 | 
			
		||||
/* Mark vector as used. */
 | 
			
		||||
int msix_vector_use(PCIDevice *dev, unsigned vector)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    if (vector >= dev->msix_entries_nr)
 | 
			
		||||
        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -395,6 +575,9 @@ void msix_vector_unuse(PCIDevice *dev, unsigned vector)
 | 
			
		||||
    if (--dev->msix_entry_used[vector]) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
 | 
			
		||||
        kvm_msix_del(dev, vector);
 | 
			
		||||
    }
 | 
			
		||||
    msix_clr_pending(dev, vector);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -67,7 +67,7 @@
 | 
			
		||||
#define MP_AUDIO_IRQ            30
 | 
			
		||||
 | 
			
		||||
/* Wolfson 8750 I2C address */
 | 
			
		||||
#define MP_WM_ADDR              0x34
 | 
			
		||||
#define MP_WM_ADDR              0x1A
 | 
			
		||||
 | 
			
		||||
/* Ethernet register offsets */
 | 
			
		||||
#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];
 | 
			
		||||
    mv88w8618_tx_desc desc;
 | 
			
		||||
    uint32_t next_desc;
 | 
			
		||||
    uint8_t buf[2048];
 | 
			
		||||
    int len;
 | 
			
		||||
 | 
			
		||||
    if (!desc_addr) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    do {
 | 
			
		||||
        eth_tx_desc_get(desc_addr, &desc);
 | 
			
		||||
        next_desc = desc.next;
 | 
			
		||||
        if (desc.cmdstat & MP_ETH_TX_OWN) {
 | 
			
		||||
            len = desc.bytes;
 | 
			
		||||
            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);
 | 
			
		||||
            eth_tx_desc_put(desc_addr, &desc);
 | 
			
		||||
        }
 | 
			
		||||
        desc_addr = desc.next;
 | 
			
		||||
        desc_addr = next_desc;
 | 
			
		||||
    } while (desc_addr != s->tx_queue[queue_index]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										130
									
								
								hw/pc.c
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								hw/pc.c
									
									
									
									
									
								
							@@ -44,6 +44,9 @@
 | 
			
		||||
#include "ide.h"
 | 
			
		||||
#include "loader.h"
 | 
			
		||||
#include "elf.h"
 | 
			
		||||
#include "device-assignment.h"
 | 
			
		||||
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
/* output Bochs bios info messages */
 | 
			
		||||
//#define DEBUG_BIOS
 | 
			
		||||
@@ -52,6 +55,8 @@
 | 
			
		||||
//#define DEBUG_MULTIBOOT
 | 
			
		||||
 | 
			
		||||
#define BIOS_FILENAME "bios.bin"
 | 
			
		||||
#define EXTBOOT_FILENAME "extboot.bin"
 | 
			
		||||
#define VAPIC_FILENAME "vapic.bin"
 | 
			
		||||
 | 
			
		||||
#define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
 | 
			
		||||
 | 
			
		||||
@@ -69,6 +74,8 @@ static RTCState *rtc_state;
 | 
			
		||||
static PITState *pit;
 | 
			
		||||
static PCII440FXState *i440fx_state;
 | 
			
		||||
 | 
			
		||||
qemu_irq *ioapic_irq_hack;
 | 
			
		||||
 | 
			
		||||
typedef struct isa_irq_state {
 | 
			
		||||
    qemu_irq *i8259;
 | 
			
		||||
    qemu_irq *ioapic;
 | 
			
		||||
@@ -560,19 +567,21 @@ static int load_multiboot(void *fw_cfg,
 | 
			
		||||
    }
 | 
			
		||||
    if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
 | 
			
		||||
        uint64_t elf_entry;
 | 
			
		||||
        uint64_t elf_low, elf_high;
 | 
			
		||||
        int kernel_size;
 | 
			
		||||
        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);
 | 
			
		||||
        if (kernel_size < 0) {
 | 
			
		||||
            fprintf(stderr, "Error while loading elf kernel\n");
 | 
			
		||||
            exit(1);
 | 
			
		||||
        }
 | 
			
		||||
        mh_load_addr = mh_entry_addr = elf_entry;
 | 
			
		||||
        mb_kernel_size = kernel_size;
 | 
			
		||||
        mh_load_addr = elf_low;
 | 
			
		||||
        mb_kernel_size = elf_high - elf_low;
 | 
			
		||||
        mh_entry_addr = elf_entry;
 | 
			
		||||
 | 
			
		||||
        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");
 | 
			
		||||
            exit(1);
 | 
			
		||||
        }
 | 
			
		||||
@@ -950,7 +959,7 @@ int cpu_is_bsp(CPUState *env)
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
@@ -959,6 +968,7 @@ static CPUState *pc_new_cpu(const char *cpu_model)
 | 
			
		||||
        fprintf(stderr, "Unable to find x86 CPU definition\n");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
    env->kvm_cpu_state.regs_modified = 1;
 | 
			
		||||
    if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
 | 
			
		||||
        env->cpuid_apic_id = env->cpu_index;
 | 
			
		||||
        /* APIC reset callback resets cpu */
 | 
			
		||||
@@ -966,6 +976,11 @@ static CPUState *pc_new_cpu(const char *cpu_model)
 | 
			
		||||
    } else {
 | 
			
		||||
        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1013,6 +1028,9 @@ static void pc_init1(ram_addr_t ram_size,
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (kvm_enabled()) {
 | 
			
		||||
        kvm_set_boot_cpu_id(0);
 | 
			
		||||
    }
 | 
			
		||||
    for (i = 0; i < smp_cpus; i++) {
 | 
			
		||||
        env = pc_new_cpu(cpu_model);
 | 
			
		||||
    }
 | 
			
		||||
@@ -1020,18 +1038,11 @@ static void pc_init1(ram_addr_t ram_size,
 | 
			
		||||
    vmport_init();
 | 
			
		||||
 | 
			
		||||
    /* 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);
 | 
			
		||||
 | 
			
		||||
    /* 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,
 | 
			
		||||
                 below_4g_mem_size - 0x100000,
 | 
			
		||||
                 ram_addr);
 | 
			
		||||
                 ram_addr + 0x100000);
 | 
			
		||||
 | 
			
		||||
    /* above 4giga memory allocation */
 | 
			
		||||
    if (above_4g_mem_size > 0) {
 | 
			
		||||
@@ -1073,11 +1084,17 @@ static void pc_init1(ram_addr_t ram_size,
 | 
			
		||||
    isa_bios_size = bios_size;
 | 
			
		||||
    if (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,
 | 
			
		||||
                                 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;
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    fw_cfg = bochs_bios_init();
 | 
			
		||||
    rom_set_fw(fw_cfg);
 | 
			
		||||
 | 
			
		||||
    if (linux_boot) {
 | 
			
		||||
        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);
 | 
			
		||||
#ifdef KVM_CAP_IRQCHIP
 | 
			
		||||
    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
 | 
			
		||||
        isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
 | 
			
		||||
        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) {
 | 
			
		||||
        pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq);
 | 
			
		||||
@@ -1146,7 +1172,13 @@ static void pc_init1(ram_addr_t ram_size,
 | 
			
		||||
 | 
			
		||||
    if (pci_enabled) {
 | 
			
		||||
        isa_irq_state->ioapic = ioapic_init();
 | 
			
		||||
        ioapic_irq_hack = isa_irq;
 | 
			
		||||
    }
 | 
			
		||||
#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);
 | 
			
		||||
    if (!no_hpet) {
 | 
			
		||||
@@ -1171,7 +1203,7 @@ static void pc_init1(ram_addr_t ram_size,
 | 
			
		||||
        if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
 | 
			
		||||
            pc_init_ne2k_isa(nd);
 | 
			
		||||
        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) {
 | 
			
		||||
@@ -1223,7 +1255,7 @@ static void pc_init1(ram_addr_t ram_size,
 | 
			
		||||
            qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
 | 
			
		||||
            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) {
 | 
			
		||||
@@ -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 */
 | 
			
		||||
    if (pci_enabled) {
 | 
			
		||||
        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,
 | 
			
		||||
@@ -1285,7 +1335,7 @@ void cmos_set_s3_resume(void)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QEMUMachine pc_machine = {
 | 
			
		||||
    .name = "pc-0.11",
 | 
			
		||||
    .name = "pc-0.12",
 | 
			
		||||
    .alias = "pc",
 | 
			
		||||
    .desc = "Standard PC",
 | 
			
		||||
    .init = pc_init_pci,
 | 
			
		||||
@@ -1293,12 +1343,39 @@ static QEMUMachine pc_machine = {
 | 
			
		||||
    .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 = {
 | 
			
		||||
    .name = "pc-0.10",
 | 
			
		||||
    .desc = "Standard PC, qemu 0.10",
 | 
			
		||||
    .init = pc_init_pci,
 | 
			
		||||
    .max_cpus = 255,
 | 
			
		||||
    .compat_props = (CompatProperty[]) {
 | 
			
		||||
    .compat_props = (GlobalProperty[]) {
 | 
			
		||||
        {
 | 
			
		||||
            .driver   = "virtio-blk-pci",
 | 
			
		||||
            .property = "class",
 | 
			
		||||
@@ -1315,6 +1392,18 @@ static QEMUMachine pc_machine_v0_10 = {
 | 
			
		||||
            .driver   = "virtio-blk-pci",
 | 
			
		||||
            .property = "vectors",
 | 
			
		||||
            .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 */ }
 | 
			
		||||
    },
 | 
			
		||||
@@ -1330,6 +1419,7 @@ static QEMUMachine isapc_machine = {
 | 
			
		||||
static void pc_machine_init(void)
 | 
			
		||||
{
 | 
			
		||||
    qemu_register_machine(&pc_machine);
 | 
			
		||||
    qemu_register_machine(&pc_machine_v0_11);
 | 
			
		||||
    qemu_register_machine(&pc_machine_v0_10);
 | 
			
		||||
    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_new(void *opaque, int irq, int level);
 | 
			
		||||
qemu_irq *i8259_init(qemu_irq parent_irq);
 | 
			
		||||
qemu_irq *kvm_i8259_init(qemu_irq parent_irq);
 | 
			
		||||
int pic_read_irq(PicState2 *s);
 | 
			
		||||
void pic_update_irq(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 apic_reset_irq_delivered(void);
 | 
			
		||||
int apic_get_irq_delivered(void);
 | 
			
		||||
void apic_set_irq_delivered(void);
 | 
			
		||||
 | 
			
		||||
/* 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_out(PITState *pit, int channel, int64_t current_time);
 | 
			
		||||
 | 
			
		||||
void hpet_pit_disable(void);
 | 
			
		||||
void hpet_pit_enable(void);
 | 
			
		||||
/* i8254-kvm.c */
 | 
			
		||||
 | 
			
		||||
PITState *kvm_pit_init(int base, qemu_irq irq);
 | 
			
		||||
 | 
			
		||||
void hpet_disable_pit(void);
 | 
			
		||||
void hpet_enable_pit(void);
 | 
			
		||||
 | 
			
		||||
/* vmport.c */
 | 
			
		||||
void vmport_init(void);
 | 
			
		||||
@@ -93,6 +99,7 @@ extern int fd_bootchk;
 | 
			
		||||
 | 
			
		||||
void ioport_set_a20(int enable);
 | 
			
		||||
int ioport_get_a20(void);
 | 
			
		||||
CPUState *pc_new_cpu(const char *cpu_model);
 | 
			
		||||
 | 
			
		||||
/* acpi.c */
 | 
			
		||||
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,
 | 
			
		||||
                       qemu_irq sci_irq);
 | 
			
		||||
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 */
 | 
			
		||||
extern int no_hpet;
 | 
			
		||||
@@ -116,6 +123,9 @@ void pcspk_init(PITState *);
 | 
			
		||||
int pcspk_audio_init(qemu_irq *pic);
 | 
			
		||||
 | 
			
		||||
/* piix_pci.c */
 | 
			
		||||
/* config space register for IRQ routing */
 | 
			
		||||
#define PIIX_CONFIG_IRQ_ROUTE 0x60
 | 
			
		||||
 | 
			
		||||
struct PCII440FXState;
 | 
			
		||||
typedef struct PCII440FXState PCII440FXState;
 | 
			
		||||
 | 
			
		||||
@@ -127,6 +137,10 @@ void i440fx_init_memory_mappings(PCII440FXState *d);
 | 
			
		||||
extern PCIDevice *piix4_dev;
 | 
			
		||||
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 */
 | 
			
		||||
enum vga_retrace_method {
 | 
			
		||||
    VGA_RETRACE_DUMB,
 | 
			
		||||
@@ -149,5 +163,10 @@ void isa_cirrus_vga_init(void);
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,8 @@
 | 
			
		||||
#include "scsi.h"
 | 
			
		||||
#include "virtio-blk.h"
 | 
			
		||||
#include "qemu-config.h"
 | 
			
		||||
#include "qemu-objects.h"
 | 
			
		||||
#include "device-assignment.h"
 | 
			
		||||
 | 
			
		||||
#if defined(TARGET_I386)
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    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);
 | 
			
		||||
    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);
 | 
			
		||||
    scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo, dinfo->unit);
 | 
			
		||||
    dinfo->unit = scsidev->id;
 | 
			
		||||
 | 
			
		||||
    if (printinfo)
 | 
			
		||||
        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);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (!((BusState*)bus)->allow_hotplug) {
 | 
			
		||||
        monitor_printf(mon, "PCI bus doesn't support hotplug\n");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (type) {
 | 
			
		||||
    case IF_SCSI:
 | 
			
		||||
        if (!dinfo) {
 | 
			
		||||
            monitor_printf(mon, "scsi requires a backing file/device.\n");
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        dev = pci_create(bus, devfn, "lsi53c895a");
 | 
			
		||||
        if (qdev_init(&dev->qdev) < 0)
 | 
			
		||||
            dev = NULL;
 | 
			
		||||
        if (dev) {
 | 
			
		||||
        if (dev && dinfo) {
 | 
			
		||||
            if (scsi_hot_add(&dev->qdev, dinfo, 0) != 0) {
 | 
			
		||||
                qdev_unplug(&dev->qdev);
 | 
			
		||||
                dev = NULL;
 | 
			
		||||
@@ -212,7 +226,54 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
 | 
			
		||||
    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;
 | 
			
		||||
    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);
 | 
			
		||||
    else if (strcmp(type, "storage") == 0)
 | 
			
		||||
        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
 | 
			
		||||
        monitor_printf(mon, "invalid type: %s\n", type);
 | 
			
		||||
 | 
			
		||||
    if (dev) {
 | 
			
		||||
        monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n",
 | 
			
		||||
                       0, pci_bus_num(dev->bus), PCI_SLOT(dev->devfn),
 | 
			
		||||
                       PCI_FUNC(dev->devfn));
 | 
			
		||||
        *ret_data =
 | 
			
		||||
        qobject_from_jsonf("{ 'domain': 0, 'bus': %d, 'slot': %d, "
 | 
			
		||||
                           "'function': %d }", pci_bus_num(dev->bus),
 | 
			
		||||
                           PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
 | 
			
		||||
        assert(*ret_data != NULL);
 | 
			
		||||
    } else
 | 
			
		||||
        monitor_printf(mon, "failed to add %s\n", opts);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										346
									
								
								hw/pci.c
									
									
									
									
									
								
							
							
						
						
									
										346
									
								
								hw/pci.c
									
									
									
									
									
								
							@@ -26,6 +26,10 @@
 | 
			
		||||
#include "monitor.h"
 | 
			
		||||
#include "net.h"
 | 
			
		||||
#include "sysemu.h"
 | 
			
		||||
#include "loader.h"
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
#include "hw/pc.h"
 | 
			
		||||
#include "device-assignment.h"
 | 
			
		||||
 | 
			
		||||
//#define DEBUG_PCI
 | 
			
		||||
#ifdef DEBUG_PCI
 | 
			
		||||
@@ -62,12 +66,15 @@ static struct BusInfo pci_bus_info = {
 | 
			
		||||
    .print_dev  = pcibus_dev_print,
 | 
			
		||||
    .props      = (Property[]) {
 | 
			
		||||
        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()
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void pci_update_mappings(PCIDevice *d);
 | 
			
		||||
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;
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    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 |
 | 
			
		||||
                                  PCI_COMMAND_MASTER);
 | 
			
		||||
    dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
 | 
			
		||||
@@ -274,6 +318,43 @@ static VMStateInfo vmstate_info_pci_config = {
 | 
			
		||||
    .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 = {
 | 
			
		||||
    .name = "PCIDevice",
 | 
			
		||||
    .version_id = 2,
 | 
			
		||||
@@ -284,7 +365,9 @@ const VMStateDescription vmstate_pci_device = {
 | 
			
		||||
        VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
 | 
			
		||||
                                   vmstate_info_pci_config,
 | 
			
		||||
                                   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()
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@@ -299,7 +382,9 @@ const VMStateDescription vmstate_pcie_device = {
 | 
			
		||||
        VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
 | 
			
		||||
                                   vmstate_info_pci_config,
 | 
			
		||||
                                   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()
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@@ -311,12 +396,23 @@ static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s)
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
    /* Restore the interrupt status bit. */
 | 
			
		||||
    pci_update_irq_status(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
@@ -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
 | 
			
		||||
 */
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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,
 | 
			
		||||
                     unsigned *slotp)
 | 
			
		||||
{
 | 
			
		||||
@@ -490,16 +636,18 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
 | 
			
		||||
            if (!bus->devices[devfn])
 | 
			
		||||
                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: ;
 | 
			
		||||
    } 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);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    pci_dev->bus = bus;
 | 
			
		||||
    pci_dev->devfn = devfn;
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
                                     config_read, config_write,
 | 
			
		||||
                                     PCI_HEADER_TYPE_NORMAL);
 | 
			
		||||
    if (pci_dev == NULL) {
 | 
			
		||||
        hw_error("PCI: can't register device\n");
 | 
			
		||||
    }
 | 
			
		||||
    return pci_dev;
 | 
			
		||||
}
 | 
			
		||||
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 val = 0;
 | 
			
		||||
    assert(len == 1 || len == 2 || len == 4);
 | 
			
		||||
 | 
			
		||||
    len = MIN(len, pci_config_size(d) - address);
 | 
			
		||||
    memcpy(&val, d->config + address, len);
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    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) {
 | 
			
		||||
        uint8_t wmask = d->wmask[addr + i];
 | 
			
		||||
        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) ||
 | 
			
		||||
        ranges_overlap(addr, l, PCI_ROM_ADDRESS, 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)
 | 
			
		||||
{
 | 
			
		||||
    PCIDevice *pci_dev = opaque;
 | 
			
		||||
    PCIBus *bus;
 | 
			
		||||
    int change;
 | 
			
		||||
 | 
			
		||||
    change = level - pci_dev->irq_state[irq_num];
 | 
			
		||||
    change = level - pci_irq_state(pci_dev, irq_num);
 | 
			
		||||
    if (!change)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    pci_dev->irq_state[irq_num] = level;
 | 
			
		||||
    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);
 | 
			
		||||
#if defined(TARGET_IA64)
 | 
			
		||||
    ioapic_set_irq(pci_dev, irq_num, level);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    pci_set_irq_state(pci_dev, irq_num, level);
 | 
			
		||||
    pci_update_irq_status(pci_dev);
 | 
			
		||||
    pci_change_irq_level(pci_dev, irq_num, change);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
                                     info->config_read, info->config_write,
 | 
			
		||||
                                     info->header_type);
 | 
			
		||||
    if (pci_dev == NULL)
 | 
			
		||||
        return -1;
 | 
			
		||||
    rc = info->init(pci_dev);
 | 
			
		||||
    if (rc != 0)
 | 
			
		||||
        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)
 | 
			
		||||
        bus->hotplug(pci_dev, 1);
 | 
			
		||||
    return 0;
 | 
			
		||||
@@ -1319,6 +1534,37 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 */
 | 
			
		||||
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"
 | 
			
		||||
 | 
			
		||||
struct kvm_irq_routing_entry;
 | 
			
		||||
 | 
			
		||||
/* PCI includes legacy ISA access.  */
 | 
			
		||||
#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;
 | 
			
		||||
 | 
			
		||||
#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);
 | 
			
		||||
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 {
 | 
			
		||||
    pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
 | 
			
		||||
#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_MASTER	0x4	/* Enable bus master */
 | 
			
		||||
#define PCI_STATUS              0x06    /* 16 bits */
 | 
			
		||||
#define  PCI_STATUS_INTERRUPT   0x08
 | 
			
		||||
#define PCI_REVISION_ID         0x08    /* 8 bits  */
 | 
			
		||||
#define PCI_CLASS_PROG		0x09	/* Reg. Level Programming Interface */
 | 
			
		||||
#define PCI_CLASS_DEVICE        0x0a    /* Device class */
 | 
			
		||||
@@ -159,10 +171,19 @@ typedef struct PCIIORegion {
 | 
			
		||||
/* Bits in the PCI Status Register (PCI 2.3 spec) */
 | 
			
		||||
#define PCI_STATUS_RESERVED1	0x007
 | 
			
		||||
#define PCI_STATUS_INT_STATUS	0x008
 | 
			
		||||
#ifndef PCI_STATUS_CAP_LIST
 | 
			
		||||
#define PCI_STATUS_CAP_LIST	0x010
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef PCI_STATUS_66MHZ
 | 
			
		||||
#define PCI_STATUS_66MHZ	0x020
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define PCI_STATUS_RESERVED2	0x040
 | 
			
		||||
 | 
			
		||||
#ifndef PCI_STATUS_FAST_BACK
 | 
			
		||||
#define PCI_STATUS_FAST_BACK	0x080
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define PCI_STATUS_DEVSEL	0x600
 | 
			
		||||
 | 
			
		||||
#define PCI_STATUS_RESERVED_MASK_LO (PCI_STATUS_RESERVED1 | \
 | 
			
		||||
@@ -191,6 +212,11 @@ enum {
 | 
			
		||||
    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 {
 | 
			
		||||
    DeviceState qdev;
 | 
			
		||||
    /* PCI config space */
 | 
			
		||||
@@ -220,7 +246,7 @@ struct PCIDevice {
 | 
			
		||||
    qemu_irq *irq;
 | 
			
		||||
 | 
			
		||||
    /* Current IRQ levels.  Used internally by the generic PCI code.  */
 | 
			
		||||
    int irq_state[PCI_NUM_PINS];
 | 
			
		||||
    uint8_t irq_state;
 | 
			
		||||
 | 
			
		||||
    /* Capability bits */
 | 
			
		||||
    uint32_t cap_present;
 | 
			
		||||
@@ -241,6 +267,28 @@ struct PCIDevice {
 | 
			
		||||
    uint32_t msix_bar_size;
 | 
			
		||||
    /* Version id needed for VMState */
 | 
			
		||||
    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,
 | 
			
		||||
@@ -252,6 +300,14 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
 | 
			
		||||
                            pcibus_t size, int type,
 | 
			
		||||
                            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);
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
uint32_t pci_default_read_config(PCIDevice *d,
 | 
			
		||||
                                 uint32_t address, int len);
 | 
			
		||||
void pci_default_write_config(PCIDevice *d,
 | 
			
		||||
                              uint32_t address, uint32_t val, int len);
 | 
			
		||||
void pci_device_save(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 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,
 | 
			
		||||
                     unsigned *slotp);
 | 
			
		||||
 | 
			
		||||
int pci_parse_host_devaddr(const char *addr, int *busp,
 | 
			
		||||
                           int *slotp, int *funcp);
 | 
			
		||||
 | 
			
		||||
void pci_info(Monitor *mon);
 | 
			
		||||
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
 | 
			
		||||
                        pci_map_irq_fn map_irq, const char *name);
 | 
			
		||||
@@ -379,6 +442,9 @@ typedef struct {
 | 
			
		||||
 | 
			
		||||
    /* pcie stuff */
 | 
			
		||||
    int is_express;   /* is this device pci express? */
 | 
			
		||||
 | 
			
		||||
    /* rom bar */
 | 
			
		||||
    const char *romfile;
 | 
			
		||||
} PCIDeviceInfo;
 | 
			
		||||
 | 
			
		||||
void pci_qdev_register(PCIDeviceInfo *info);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								hw/pcspk.c
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								hw/pcspk.c
									
									
									
									
									
								
							@@ -27,6 +27,8 @@
 | 
			
		||||
#include "isa.h"
 | 
			
		||||
#include "audio/audio.h"
 | 
			
		||||
#include "qemu-timer.h"
 | 
			
		||||
#include "i8254.h"
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
#define PCSPK_BUF_LEN 1792
 | 
			
		||||
#define PCSPK_SAMPLE_RATE 32000
 | 
			
		||||
@@ -48,6 +50,43 @@ typedef struct {
 | 
			
		||||
static const char *s_spk = "pcspk";
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    unsigned int i;
 | 
			
		||||
@@ -72,6 +111,8 @@ static void pcspk_callback(void *opaque, int free)
 | 
			
		||||
    PCSpkState *s = opaque;
 | 
			
		||||
    unsigned int n;
 | 
			
		||||
 | 
			
		||||
    kvm_get_pit_ch2(s->pit, NULL);
 | 
			
		||||
 | 
			
		||||
    if (pit_get_mode(s->pit, 2) != 3)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
@@ -117,6 +158,8 @@ static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
 | 
			
		||||
    PCSpkState *s = opaque;
 | 
			
		||||
    int out;
 | 
			
		||||
 | 
			
		||||
    kvm_get_pit_ch2(s->pit, NULL);
 | 
			
		||||
 | 
			
		||||
    s->dummy_refresh_clock ^= (1 << 4);
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    struct kvm_pit_state inkernel_state;
 | 
			
		||||
    PCSpkState *s = opaque;
 | 
			
		||||
    const int gate = val & 1;
 | 
			
		||||
 | 
			
		||||
    kvm_get_pit_ch2(s->pit, &inkernel_state);
 | 
			
		||||
 | 
			
		||||
    s->data_on = (val >> 1) & 1;
 | 
			
		||||
    pit_set_gate(s->pit, 2, gate);
 | 
			
		||||
    if (s->voice) {
 | 
			
		||||
@@ -135,6 +181,8 @@ static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 | 
			
		||||
            s->play_pos = 0;
 | 
			
		||||
        AUD_set_active_out(s->voice, gate & s->data_on);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    kvm_set_pit_ch2(s->pit, &inkernel_state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pcspk_init(PITState *pit)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,8 @@
 | 
			
		||||
#include "isa.h"
 | 
			
		||||
#include "sysbus.h"
 | 
			
		||||
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
typedef PCIHostState I440FXState;
 | 
			
		||||
 | 
			
		||||
typedef struct PIIX3State {
 | 
			
		||||
@@ -88,6 +90,10 @@ static void i440fx_update_memory_mappings(PCII440FXState *d)
 | 
			
		||||
    int i, r;
 | 
			
		||||
    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);
 | 
			
		||||
    for(i = 0; i < 12; i++) {
 | 
			
		||||
        r = (d->dev.config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3;
 | 
			
		||||
@@ -201,6 +207,8 @@ static int i440fx_initfn(PCIDevice *dev)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PIIX3State *piix3_dev;
 | 
			
		||||
 | 
			
		||||
PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *pic)
 | 
			
		||||
{
 | 
			
		||||
    DeviceState *dev;
 | 
			
		||||
@@ -226,6 +234,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *
 | 
			
		||||
 | 
			
		||||
    *piix3_devfn = piix3->dev.devfn;
 | 
			
		||||
 | 
			
		||||
    piix3_dev = piix3;
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    PIIX3State *d = opaque;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@
 | 
			
		||||
#include "ppc405.h"
 | 
			
		||||
#include "sysemu.h"
 | 
			
		||||
#include "kvm.h"
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
#define PPC440EP_PCI_CONFIG     0xeec00000
 | 
			
		||||
#define PPC440EP_PCI_INTACK     0xeed00000
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include "device_tree.h"
 | 
			
		||||
#include "loader.h"
 | 
			
		||||
#include "elf.h"
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@
 | 
			
		||||
#include "ppce500.h"
 | 
			
		||||
#include "loader.h"
 | 
			
		||||
#include "elf.h"
 | 
			
		||||
#include "qemu-kvm.h"
 | 
			
		||||
 | 
			
		||||
#define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
 | 
			
		||||
#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);
 | 
			
		||||
        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)
 | 
			
		||||
@@ -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) {
 | 
			
		||||
        return;
 | 
			
		||||
    for (i = 0; props[i].driver != NULL; i++) {
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
        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;
 | 
			
		||||
    qdev_prop_set_defaults(dev, dev->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);
 | 
			
		||||
    if (qdev_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);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct CompatProperty {
 | 
			
		||||
typedef struct GlobalProperty {
 | 
			
		||||
    const char *driver;
 | 
			
		||||
    const char *property;
 | 
			
		||||
    const char *value;
 | 
			
		||||
};
 | 
			
		||||
    QTAILQ_ENTRY(GlobalProperty) next;
 | 
			
		||||
} GlobalProperty;
 | 
			
		||||
 | 
			
		||||
/*** 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_defaults(DeviceState *dev, Property *props);
 | 
			
		||||
 | 
			
		||||
void qdev_prop_register_compat(CompatProperty *props);
 | 
			
		||||
void qdev_prop_set_compat(DeviceState *dev);
 | 
			
		||||
void qdev_prop_register_global(GlobalProperty *prop);
 | 
			
		||||
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.  */
 | 
			
		||||
extern struct BusInfo system_bus_info;
 | 
			
		||||
 
 | 
			
		||||
@@ -3353,14 +3353,6 @@ static int pci_rtl8139_init(PCIDevice *dev)
 | 
			
		||||
    qemu_mod_timer(s->timer,
 | 
			
		||||
        rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock)));
 | 
			
		||||
#endif /* RTL8139_ONBOARD_TIMER */
 | 
			
		||||
 | 
			
		||||
    if (!dev->qdev.hotplugged) {
 | 
			
		||||
        static int loaded = 0;
 | 
			
		||||
        if (!loaded) {
 | 
			
		||||
            rom_add_option("pxe-rtl8139.bin");
 | 
			
		||||
            loaded = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -3371,6 +3363,7 @@ static PCIDeviceInfo rtl8139_info = {
 | 
			
		||||
    .qdev.vmsd  = &vmstate_rtl8139,
 | 
			
		||||
    .init       = pci_rtl8139_init,
 | 
			
		||||
    .exit       = pci_rtl8139_uninit,
 | 
			
		||||
    .romfile    = "pxe-rtl8139.bin",
 | 
			
		||||
    .qdev.props = (Property[]) {
 | 
			
		||||
        DEFINE_NIC_PROPERTIES(RTL8139State, conf),
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
    /* 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 *******************/
 | 
			
		||||
 
 | 
			
		||||
@@ -142,6 +142,13 @@ static void s390_init(ram_addr_t ram_size,
 | 
			
		||||
    ram_addr_t initrd_size = 0;
 | 
			
		||||
    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 */
 | 
			
		||||
    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);
 | 
			
		||||
        env->psw.addr = KERN_IMAGE_START;
 | 
			
		||||
        env->psw.mask = 0x0000000180000000UL;
 | 
			
		||||
        env->psw.mask = 0x0000000180000000ULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (initrd_filename) {
 | 
			
		||||
@@ -201,7 +208,11 @@ static void s390_init(ram_addr_t ram_size,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Create VirtIO console */
 | 
			
		||||
    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 */
 | 
			
		||||
    for(i = 0; i < nb_nics; i++) {
 | 
			
		||||
@@ -209,7 +220,7 @@ static void s390_init(ram_addr_t ram_size,
 | 
			
		||||
        DeviceState *dev;
 | 
			
		||||
 | 
			
		||||
        if (!nd->model) {
 | 
			
		||||
            nd->model = (char*)"virtio";
 | 
			
		||||
            nd->model = qemu_strdup("virtio");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (strcmp(nd->model, "virtio")) {
 | 
			
		||||
@@ -243,6 +254,10 @@ static QEMUMachine s390_machine = {
 | 
			
		||||
    .alias = "s390",
 | 
			
		||||
    .desc = "VirtIO based S390 machine",
 | 
			
		||||
    .init = s390_init,
 | 
			
		||||
    .no_serial = 1,
 | 
			
		||||
    .no_parallel = 1,
 | 
			
		||||
    .use_virtcon = 1,
 | 
			
		||||
    .no_vga = 1,
 | 
			
		||||
    .max_cpus = 255,
 | 
			
		||||
    .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