Compare commits
	
		
			240 Commits
		
	
	
		
			pull-input
			...
			pull-chard
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | ac1b84dd1e | ||
|  | 2396187076 | ||
|  | 01207d0b78 | ||
|  | 0ca540dbae | ||
|  | ed9b103d3e | ||
|  | c57ec3249e | ||
|  | fe6c53b4bb | ||
|  | b0f15a5d56 | ||
|  | 118760dfc9 | ||
|  | b304bf0021 | ||
|  | 3f1506704e | ||
|  | 0c126db27c | ||
|  | 72c1d3af6e | ||
|  | 2b194951c5 | ||
|  | c8f8f9fb2b | ||
|  | d2f41a1169 | ||
|  | 43a32ed68f | ||
|  | b29c8f115d | ||
|  | 0624976f61 | ||
|  | 7c2cb42b50 | ||
|  | af5199347a | ||
|  | c9dd4074df | ||
|  | 9b74d0d598 | ||
|  | 4b87dc4c97 | ||
|  | dbb2a1326a | ||
|  | c3aa84b68f | ||
|  | e9d818b8b1 | ||
|  | cbc14e6f28 | ||
|  | 16513b1b45 | ||
|  | e22492d332 | ||
|  | 919372251c | ||
|  | 863d7c9105 | ||
|  | 12b316d4c1 | ||
|  | 6cd859aa8a | ||
|  | b4c85ddcec | ||
|  | 38ee14f4f3 | ||
|  | e3c1adf16e | ||
|  | 2e7bcdb99a | ||
|  | 5264917bcf | ||
|  | 220c8ed536 | ||
|  | f1b7e0e498 | ||
|  | 175f099b30 | ||
|  | 15d914b18d | ||
|  | 262f6f5140 | ||
|  | 4a4fcdf6df | ||
|  | 4900116e6f | ||
|  | 8f480de0c9 | ||
|  | 5d12f961c6 | ||
|  | 6e1f0a55a1 | ||
|  | 8e46bbf362 | ||
|  | ddfa83ea06 | ||
|  | 6cb46e1e90 | ||
|  | 8dcf525abc | ||
|  | f8e2484389 | ||
|  | 523fdc08cc | ||
|  | 017a86f7ad | ||
|  | 2e796c7621 | ||
|  | 8d8db193f2 | ||
|  | a51a6b6ad5 | ||
|  | f029341494 | ||
|  | 7763ffa017 | ||
|  | 3353d0dcc3 | ||
|  | 82295d8a2d | ||
|  | 464400f6a5 | ||
|  | 4fed9421e9 | ||
|  | ac4df4e608 | ||
|  | fd8cec932c | ||
|  | f53f3d0a00 | ||
|  | d7c698af8a | ||
|  | 6570025e53 | ||
|  | 80aaa0741f | ||
|  | 6fc0303b95 | ||
|  | bb2b045034 | ||
|  | c3f8d28e45 | ||
|  | 4089f7c6a0 | ||
|  | 2c02f88780 | ||
|  | 4c288acbd6 | ||
|  | 9c83ffd859 | ||
|  | eb909c7f72 | ||
|  | c75203c8d3 | ||
|  | c6e0bd9b70 | ||
|  | 8ae8e904fc | ||
|  | d5546c5e77 | ||
|  | 7dc74db88b | ||
|  | 464d9f641d | ||
|  | 078896a9ee | ||
|  | cd5d031e75 | ||
|  | 50c75136be | ||
|  | 90ce8a061b | ||
|  | 47ea2de2d6 | ||
|  | f47c3f5a80 | ||
|  | 2fa4c042bc | ||
|  | 64bb01aa35 | ||
|  | b1f7d84fd2 | ||
|  | 85c09bc016 | ||
|  | 7e7494627f | ||
|  | 0f20ba62c3 | ||
|  | 0ce470cd4c | ||
|  | a0fcac9c21 | ||
|  | c138593380 | ||
|  | 3f94170be3 | ||
|  | 7c43bca004 | ||
|  | f3c75d42ad | ||
|  | 3707cd62db | ||
|  | 7dff9abe63 | ||
|  | 3c3b0ddefa | ||
|  | e5d7d2b0f5 | ||
|  | 0a61f3b478 | ||
|  | ac174549b7 | ||
|  | 57354f8f12 | ||
|  | 557d52fa69 | ||
|  | e8f7b27b99 | ||
|  | b8476fc7c6 | ||
|  | f1064f612c | ||
|  | 6f3dab41fb | ||
|  | 4d82038e41 | ||
|  | b41da4ebb2 | ||
|  | 2fdf78e649 | ||
|  | 818692ff95 | ||
|  | e0ffe77f27 | ||
|  | 4430e07663 | ||
|  | 024215b242 | ||
|  | 8203e31b54 | ||
|  | e13500b3c3 | ||
|  | f293f04ab5 | ||
|  | 953f0f5842 | ||
|  | 63be09365a | ||
|  | aa9e930c88 | ||
|  | 56eabc7508 | ||
|  | 111c5f54a1 | ||
|  | a737d3ebc8 | ||
|  | 50f5fc0cf2 | ||
|  | 5dffff5a47 | ||
|  | 9b47bb490c | ||
|  | bb5275338d | ||
|  | 32ea54ab5f | ||
|  | 27b95bfe62 | ||
|  | 9c294d5ab3 | ||
|  | 84cab1e2f5 | ||
|  | e0498daab5 | ||
|  | 71a8c019c4 | ||
|  | 38a853375e | ||
|  | 52a4984d97 | ||
|  | 60511041d6 | ||
|  | 94840e0700 | ||
|  | f5bc1bfa35 | ||
|  | 3f34cf910c | ||
|  | 61de36761b | ||
|  | 5736245c80 | ||
|  | 3b66da82ce | ||
|  | 18674b2678 | ||
|  | 6a2331d12e | ||
|  | 133e70ee88 | ||
|  | eb1e7c3e51 | ||
|  | b36f100e17 | ||
|  | 0658aa9cba | ||
|  | 69b31b907b | ||
|  | 66c3e32841 | ||
|  | ce8ca30b39 | ||
|  | 6d41d146c9 | ||
|  | da29cb7bc7 | ||
|  | 29a0e4e9a1 | ||
|  | c73860803f | ||
|  | 28288b48a8 | ||
|  | fab7fe426f | ||
|  | 1b0bd0029f | ||
|  | 587c51f74b | ||
|  | 5c77a786e2 | ||
|  | 1fa6c53304 | ||
|  | a98eb9e99d | ||
|  | 6a4fda3358 | ||
|  | e44259b6d4 | ||
|  | 98d1eb2748 | ||
|  | a824bc191a | ||
|  | 86ba37edcb | ||
|  | 7ee19fb9d6 | ||
|  | 3d1140bf3e | ||
|  | 097ec5d850 | ||
|  | f5c0f7f981 | ||
|  | 67a33f3727 | ||
|  | 74698350ca | ||
|  | f53f81e08b | ||
|  | 968e76bcab | ||
|  | cea4e57473 | ||
|  | 2c0c52ae62 | ||
|  | b24d0b472b | ||
|  | ab9408a2d1 | ||
|  | 3fd0aadfc1 | ||
|  | e16a626b82 | ||
|  | f026da7830 | ||
|  | cac7f0ba4a | ||
|  | e072fe796e | ||
|  | dbcc48fa8f | ||
|  | 88e33d08c9 | ||
|  | 5177d2ca93 | ||
|  | ed8ac5686a | ||
|  | 354a6decf1 | ||
|  | 959e9c9d1e | ||
|  | 4f17e9c738 | ||
|  | 595c6eefb7 | ||
|  | 5cb151acb1 | ||
|  | bc80838f86 | ||
|  | d3f9df8fb8 | ||
|  | d32404fe42 | ||
|  | 2009227fbe | ||
|  | 4b98eeef50 | ||
|  | 5e591d8812 | ||
|  | ee6e02c0ac | ||
|  | 3c3cbbdc84 | ||
|  | 59800ec8e5 | ||
|  | 4e38181979 | ||
|  | 3052f0d594 | ||
|  | 09aa9a526a | ||
|  | 6cd8712c5f | ||
|  | 7a7c05d77d | ||
|  | 363248e8c9 | ||
|  | 0dc083fe10 | ||
|  | ca480de664 | ||
|  | 135a129a1c | ||
|  | 9c06a1f79f | ||
|  | 88ccd23a0c | ||
|  | 401949176c | ||
|  | 0bfe9299da | ||
|  | 81d2fb4dfd | ||
|  | 6475c9f05c | ||
|  | a5100e752b | ||
|  | 993c91a0e9 | ||
|  | b51910baf2 | ||
|  | 974a196d7f | ||
|  | f19e00d776 | ||
|  | 76ca310a19 | ||
| cd98d390ae | |||
|  | 8a3ae9109e | ||
|  | 4cf2348026 | ||
|  | 4fa4ce7107 | ||
|  | fae0864573 | ||
|  | 75b7931ec6 | ||
|  | f9a49dfa02 | ||
|  | 9ba3cf540f | ||
|  | d77f7779b4 | 
| @@ -158,7 +158,6 @@ Guest CPU Cores (KVM): | ||||
| ---------------------- | ||||
|  | ||||
| Overall | ||||
| M: Gleb Natapov <gleb@redhat.com> | ||||
| M: Paolo Bonzini <pbonzini@redhat.com> | ||||
| L: kvm@vger.kernel.org | ||||
| S: Supported | ||||
| @@ -176,12 +175,14 @@ S: Maintained | ||||
| F: target-ppc/kvm.c | ||||
|  | ||||
| S390 | ||||
| M: Christian Borntraeger <borntraeger@de.ibm.com> | ||||
| M: Cornelia Huck <cornelia.huck@de.ibm.com> | ||||
| M: Alexander Graf <agraf@suse.de> | ||||
| S: Maintained | ||||
| F: target-s390x/kvm.c | ||||
| F: hw/intc/s390_flic.[hc] | ||||
|  | ||||
| X86 | ||||
| M: Gleb Natapov <gleb@redhat.com> | ||||
| M: Marcelo Tosatti <mtosatti@redhat.com> | ||||
| L: kvm@vger.kernel.org | ||||
| S: Supported | ||||
| @@ -495,10 +496,13 @@ F: hw/s390x/s390-*.c | ||||
|  | ||||
| S390 Virtio-ccw | ||||
| M: Cornelia Huck <cornelia.huck@de.ibm.com> | ||||
| M: Christian Borntraeger <borntraeger@de.ibm.com> | ||||
| M: Alexander Graf <agraf@suse.de> | ||||
| S: Supported | ||||
| F: hw/s390x/s390-virtio-ccw.c | ||||
| F: hw/s390x/css.[hc] | ||||
| F: hw/s390x/sclp*.[hc] | ||||
| F: hw/s390x/ipl*.[hc] | ||||
| T: git git://github.com/cohuck/qemu virtio-ccw-upstr | ||||
|  | ||||
| UniCore32 Machines | ||||
| @@ -629,6 +633,7 @@ F: hw/block/virtio-blk.c | ||||
|  | ||||
| virtio-ccw | ||||
| M: Cornelia Huck <cornelia.huck@de.ibm.com> | ||||
| M: Christian Borntraeger <borntraeger@de.ibm.com> | ||||
| S: Supported | ||||
| F: hw/s390x/virtio-ccw.[hc] | ||||
| T: git git://github.com/cohuck/qemu virtio-ccw-upstr | ||||
|   | ||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -399,7 +399,7 @@ endif | ||||
| 		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \ | ||||
| 	done | ||||
| 	for d in $(TARGET_DIRS); do \ | ||||
| 	$(MAKE) -C $$d $@ || exit 1 ; \ | ||||
| 	$(MAKE) $(SUBDIR_MAKEFLAGS) TARGET_DIR=$$d/ -C $$d $@ || exit 1 ; \ | ||||
|         done | ||||
|  | ||||
| # various test targets | ||||
|   | ||||
| @@ -21,11 +21,6 @@ block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o | ||||
|  | ||||
| block-obj-m = block/ | ||||
|  | ||||
| ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) | ||||
| # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add. | ||||
| # only pull in the actual virtio-9p device if we also enabled virtio. | ||||
| CONFIG_REALLY_VIRTFS=y | ||||
| endif | ||||
|  | ||||
| ###################################################################### | ||||
| # smartcard | ||||
|   | ||||
							
								
								
									
										52
									
								
								arch_init.c
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								arch_init.c
									
									
									
									
									
								
							| @@ -164,8 +164,9 @@ static struct { | ||||
|     uint8_t *encoded_buf; | ||||
|     /* buffer for storing page content */ | ||||
|     uint8_t *current_buf; | ||||
|     /* Cache for XBZRLE */ | ||||
|     /* Cache for XBZRLE, Protected by lock. */ | ||||
|     PageCache *cache; | ||||
|     QemuMutex lock; | ||||
| } XBZRLE = { | ||||
|     .encoded_buf = NULL, | ||||
|     .current_buf = NULL, | ||||
| @@ -174,16 +175,52 @@ static struct { | ||||
| /* buffer used for XBZRLE decoding */ | ||||
| static uint8_t *xbzrle_decoded_buf; | ||||
|  | ||||
| static void XBZRLE_cache_lock(void) | ||||
| { | ||||
|     if (migrate_use_xbzrle()) | ||||
|         qemu_mutex_lock(&XBZRLE.lock); | ||||
| } | ||||
|  | ||||
| static void XBZRLE_cache_unlock(void) | ||||
| { | ||||
|     if (migrate_use_xbzrle()) | ||||
|         qemu_mutex_unlock(&XBZRLE.lock); | ||||
| } | ||||
|  | ||||
| int64_t xbzrle_cache_resize(int64_t new_size) | ||||
| { | ||||
|     PageCache *new_cache, *cache_to_free; | ||||
|  | ||||
|     if (new_size < TARGET_PAGE_SIZE) { | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     /* no need to lock, the current thread holds qemu big lock */ | ||||
|     if (XBZRLE.cache != NULL) { | ||||
|         return cache_resize(XBZRLE.cache, new_size / TARGET_PAGE_SIZE) * | ||||
|             TARGET_PAGE_SIZE; | ||||
|         /* check XBZRLE.cache again later */ | ||||
|         if (pow2floor(new_size) == migrate_xbzrle_cache_size()) { | ||||
|             return pow2floor(new_size); | ||||
|         } | ||||
|         new_cache = cache_init(new_size / TARGET_PAGE_SIZE, | ||||
|                                         TARGET_PAGE_SIZE); | ||||
|         if (!new_cache) { | ||||
|             DPRINTF("Error creating cache\n"); | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         XBZRLE_cache_lock(); | ||||
|         /* the XBZRLE.cache may have be destroyed, check it again */ | ||||
|         if (XBZRLE.cache != NULL) { | ||||
|             cache_to_free = XBZRLE.cache; | ||||
|             XBZRLE.cache = new_cache; | ||||
|         } else { | ||||
|             cache_to_free = new_cache; | ||||
|         } | ||||
|         XBZRLE_cache_unlock(); | ||||
|  | ||||
|         cache_fini(cache_to_free); | ||||
|     } | ||||
|  | ||||
|     return pow2floor(new_size); | ||||
| } | ||||
|  | ||||
| @@ -539,6 +576,8 @@ static int ram_save_block(QEMUFile *f, bool last_stage) | ||||
|             ret = ram_control_save_page(f, block->offset, | ||||
|                                offset, TARGET_PAGE_SIZE, &bytes_sent); | ||||
|  | ||||
|             XBZRLE_cache_lock(); | ||||
|  | ||||
|             current_addr = block->offset + offset; | ||||
|             if (ret != RAM_SAVE_CONTROL_NOT_SUPP) { | ||||
|                 if (ret != RAM_SAVE_CONTROL_DELAYED) { | ||||
| @@ -587,6 +626,7 @@ static int ram_save_block(QEMUFile *f, bool last_stage) | ||||
|                 acct_info.norm_pages++; | ||||
|             } | ||||
|  | ||||
|             XBZRLE_cache_unlock(); | ||||
|             /* if page is unmodified, continue to the next */ | ||||
|             if (bytes_sent > 0) { | ||||
|                 last_sent_block = block; | ||||
| @@ -654,6 +694,7 @@ static void migration_end(void) | ||||
|         migration_bitmap = NULL; | ||||
|     } | ||||
|  | ||||
|     XBZRLE_cache_lock(); | ||||
|     if (XBZRLE.cache) { | ||||
|         cache_fini(XBZRLE.cache); | ||||
|         g_free(XBZRLE.cache); | ||||
| @@ -663,6 +704,7 @@ static void migration_end(void) | ||||
|         XBZRLE.encoded_buf = NULL; | ||||
|         XBZRLE.current_buf = NULL; | ||||
|     } | ||||
|     XBZRLE_cache_unlock(); | ||||
| } | ||||
|  | ||||
| static void ram_migration_cancel(void *opaque) | ||||
| @@ -693,13 +735,17 @@ static int ram_save_setup(QEMUFile *f, void *opaque) | ||||
|     dirty_rate_high_cnt = 0; | ||||
|  | ||||
|     if (migrate_use_xbzrle()) { | ||||
|         qemu_mutex_lock_iothread(); | ||||
|         XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() / | ||||
|                                   TARGET_PAGE_SIZE, | ||||
|                                   TARGET_PAGE_SIZE); | ||||
|         if (!XBZRLE.cache) { | ||||
|             qemu_mutex_unlock_iothread(); | ||||
|             DPRINTF("Error creating cache\n"); | ||||
|             return -1; | ||||
|         } | ||||
|         qemu_mutex_init(&XBZRLE.lock); | ||||
|         qemu_mutex_unlock_iothread(); | ||||
|  | ||||
|         /* We prefer not to abort if there is no memory */ | ||||
|         XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE); | ||||
|   | ||||
							
								
								
									
										34
									
								
								block.c
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								block.c
									
									
									
									
									
								
							| @@ -935,7 +935,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, | ||||
|  | ||||
|     bdrv_refresh_limits(bs); | ||||
|     assert(bdrv_opt_mem_align(bs) != 0); | ||||
|     assert(bs->request_alignment != 0); | ||||
|     assert((bs->request_alignment != 0) || bs->sg); | ||||
|  | ||||
| #ifndef _WIN32 | ||||
|     if (bs->is_temporary) { | ||||
| @@ -1017,7 +1017,12 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename, | ||||
|             ret = -EINVAL; | ||||
|             goto fail; | ||||
|         } | ||||
|         qdict_del(*options, "filename"); | ||||
|  | ||||
|         if (!drv->bdrv_needs_filename) { | ||||
|             qdict_del(*options, "filename"); | ||||
|         } else { | ||||
|             filename = qdict_get_str(*options, "filename"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (!drv->bdrv_file_open) { | ||||
| @@ -1229,6 +1234,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, | ||||
|         ret = bdrv_file_open(bs, filename, &options, flags & ~BDRV_O_PROTOCOL, | ||||
|                              &local_err); | ||||
|         if (!ret) { | ||||
|             drv = bs->drv; | ||||
|             goto done; | ||||
|         } else if (bs->drv) { | ||||
|             goto close_and_fail; | ||||
| @@ -1847,11 +1853,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest, | ||||
|     pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name), | ||||
|             bs_src->device_name); | ||||
|     bs_dest->device_list = bs_src->device_list; | ||||
|  | ||||
|     /* keep the same entry in graph_bdrv_states | ||||
|      * We do want to swap name but don't want to swap linked list entries | ||||
|      */ | ||||
|     bs_dest->node_list   = bs_src->node_list; | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -1870,6 +1871,17 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old) | ||||
| { | ||||
|     BlockDriverState tmp; | ||||
|  | ||||
|     /* The code needs to swap the node_name but simply swapping node_list won't | ||||
|      * work so first remove the nodes from the graph list, do the swap then | ||||
|      * insert them back if needed. | ||||
|      */ | ||||
|     if (bs_new->node_name[0] != '\0') { | ||||
|         QTAILQ_REMOVE(&graph_bdrv_states, bs_new, node_list); | ||||
|     } | ||||
|     if (bs_old->node_name[0] != '\0') { | ||||
|         QTAILQ_REMOVE(&graph_bdrv_states, bs_old, node_list); | ||||
|     } | ||||
|  | ||||
|     /* bs_new must be anonymous and shouldn't have anything fancy enabled */ | ||||
|     assert(bs_new->device_name[0] == '\0'); | ||||
|     assert(QLIST_EMPTY(&bs_new->dirty_bitmaps)); | ||||
| @@ -1898,6 +1910,14 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old) | ||||
|     assert(bs_new->io_limits_enabled == false); | ||||
|     assert(!throttle_have_timer(&bs_new->throttle_state)); | ||||
|  | ||||
|     /* insert the nodes back into the graph node list if needed */ | ||||
|     if (bs_new->node_name[0] != '\0') { | ||||
|         QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_new, node_list); | ||||
|     } | ||||
|     if (bs_old->node_name[0] != '\0') { | ||||
|         QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_old, node_list); | ||||
|     } | ||||
|  | ||||
|     bdrv_rebind(bs_new); | ||||
|     bdrv_rebind(bs_old); | ||||
| } | ||||
|   | ||||
| @@ -3,21 +3,12 @@ | ||||
|  * | ||||
|  * Copyright (C) 2012 Bharata B Rao <bharata@linux.vnet.ibm.com> | ||||
|  * | ||||
|  * Pipe handling mechanism in AIO implementation is derived from | ||||
|  * block/rbd.c. Hence, | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||||
|  * See the COPYING file in the top-level directory. | ||||
|  * | ||||
|  * Copyright (C) 2010-2011 Christian Brunner <chb@muc.de>, | ||||
|  *                         Josh Durgin <josh.durgin@dreamhost.com> | ||||
|  * | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2.  See | ||||
|  * the COPYING file in the top-level directory. | ||||
|  * | ||||
|  * Contributions after 2012-01-13 are licensed under the terms of the | ||||
|  * GNU GPL, version 2 or (at your option) any later version. | ||||
|  */ | ||||
| #include <glusterfs/api/glfs.h> | ||||
| #include "block/block_int.h" | ||||
| #include "qemu/sockets.h" | ||||
| #include "qemu/uri.h" | ||||
|  | ||||
| typedef struct GlusterAIOCB { | ||||
| @@ -32,9 +23,6 @@ typedef struct BDRVGlusterState { | ||||
|     struct glfs_fd *fd; | ||||
| } BDRVGlusterState; | ||||
|  | ||||
| #define GLUSTER_FD_READ  0 | ||||
| #define GLUSTER_FD_WRITE 1 | ||||
|  | ||||
| typedef struct GlusterConf { | ||||
|     char *server; | ||||
|     int port; | ||||
|   | ||||
| @@ -1231,12 +1231,11 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun); | ||||
|     bs->request_alignment = iscsilun->block_size; | ||||
|  | ||||
|     /* Medium changer or tape. We dont have any emulation for this so this must | ||||
|      * be sg ioctl compatible. We force it to be sg, otherwise qemu will try | ||||
|      * to read from the device to guess the image format. | ||||
|     /* We don't have any emulation for devices other than disks and CD-ROMs, so | ||||
|      * this must be sg ioctl compatible. We force it to be sg, otherwise qemu | ||||
|      * will try to read from the device to guess the image format. | ||||
|      */ | ||||
|     if (iscsilun->type == TYPE_MEDIUM_CHANGER || | ||||
|         iscsilun->type == TYPE_TAPE) { | ||||
|     if (iscsilun->type != TYPE_DISK && iscsilun->type != TYPE_ROM) { | ||||
|         bs->sg = 1; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -520,9 +520,6 @@ static void mirror_complete(BlockJob *job, Error **errp) | ||||
|  | ||||
|     ret = bdrv_open_backing_file(s->target, NULL, &local_err); | ||||
|     if (ret < 0) { | ||||
|         char backing_filename[PATH_MAX]; | ||||
|         bdrv_get_full_backing_filename(s->target, backing_filename, | ||||
|                                        sizeof(backing_filename)); | ||||
|         error_propagate(errp, local_err); | ||||
|         return; | ||||
|     } | ||||
|   | ||||
| @@ -336,6 +336,17 @@ error: | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static void raw_parse_filename(const char *filename, QDict *options, | ||||
|                                Error **errp) | ||||
| { | ||||
|     /* The filename does not have to be prefixed by the protocol name, since | ||||
|      * "file" is the default protocol; therefore, the return value of this | ||||
|      * function call can be ignored. */ | ||||
|     strstart(filename, "file:", &filename); | ||||
|  | ||||
|     qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename))); | ||||
| } | ||||
|  | ||||
| static QemuOptsList raw_runtime_opts = { | ||||
|     .name = "raw", | ||||
|     .head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head), | ||||
| @@ -1230,6 +1241,8 @@ static int raw_create(const char *filename, QEMUOptionParameter *options, | ||||
|     int result = 0; | ||||
|     int64_t total_size = 0; | ||||
|  | ||||
|     strstart(filename, "file:", &filename); | ||||
|  | ||||
|     /* Read out options */ | ||||
|     while (options && options->name) { | ||||
|         if (!strcmp(options->name, BLOCK_OPT_SIZE)) { | ||||
| @@ -1412,6 +1425,7 @@ static BlockDriver bdrv_file = { | ||||
|     .instance_size = sizeof(BDRVRawState), | ||||
|     .bdrv_needs_filename = true, | ||||
|     .bdrv_probe = NULL, /* no probe for protocols */ | ||||
|     .bdrv_parse_filename = raw_parse_filename, | ||||
|     .bdrv_file_open = raw_open, | ||||
|     .bdrv_reopen_prepare = raw_reopen_prepare, | ||||
|     .bdrv_reopen_commit = raw_reopen_commit, | ||||
|   | ||||
| @@ -251,6 +251,17 @@ static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped) | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void raw_parse_filename(const char *filename, QDict *options, | ||||
|                                Error **errp) | ||||
| { | ||||
|     /* The filename does not have to be prefixed by the protocol name, since | ||||
|      * "file" is the default protocol; therefore, the return value of this | ||||
|      * function call can be ignored. */ | ||||
|     strstart(filename, "file:", &filename); | ||||
|  | ||||
|     qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename))); | ||||
| } | ||||
|  | ||||
| static QemuOptsList raw_runtime_opts = { | ||||
|     .name = "raw", | ||||
|     .head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head), | ||||
| @@ -470,6 +481,8 @@ static int raw_create(const char *filename, QEMUOptionParameter *options, | ||||
|     int fd; | ||||
|     int64_t total_size = 0; | ||||
|  | ||||
|     strstart(filename, "file:", &filename); | ||||
|  | ||||
|     /* Read out options */ | ||||
|     while (options && options->name) { | ||||
|         if (!strcmp(options->name, BLOCK_OPT_SIZE)) { | ||||
| @@ -504,6 +517,7 @@ static BlockDriver bdrv_file = { | ||||
|     .protocol_name	= "file", | ||||
|     .instance_size	= sizeof(BDRVRawState), | ||||
|     .bdrv_needs_filename = true, | ||||
|     .bdrv_parse_filename = raw_parse_filename, | ||||
|     .bdrv_file_open	= raw_open, | ||||
|     .bdrv_close		= raw_close, | ||||
|     .bdrv_create	= raw_create, | ||||
|   | ||||
							
								
								
									
										15
									
								
								blockdev.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								blockdev.c
									
									
									
									
									
								
							| @@ -2266,6 +2266,7 @@ void qmp_block_job_complete(const char *device, Error **errp) | ||||
| void qmp_blockdev_add(BlockdevOptions *options, Error **errp) | ||||
| { | ||||
|     QmpOutputVisitor *ov = qmp_output_visitor_new(); | ||||
|     DriveInfo *dinfo; | ||||
|     QObject *obj; | ||||
|     QDict *qdict; | ||||
|     Error *local_err = NULL; | ||||
| @@ -2282,8 +2283,10 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) | ||||
|      * | ||||
|      * For now, simply forbidding the combination for all drivers will do. */ | ||||
|     if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) { | ||||
|         bool direct = options->cache->has_direct && options->cache->direct; | ||||
|         if (!options->has_cache && !direct) { | ||||
|         bool direct = options->has_cache && | ||||
|                       options->cache->has_direct && | ||||
|                       options->cache->direct; | ||||
|         if (!direct) { | ||||
|             error_setg(errp, "aio=native requires cache.direct=true"); | ||||
|             goto fail; | ||||
|         } | ||||
| @@ -2301,12 +2304,18 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) | ||||
|  | ||||
|     qdict_flatten(qdict); | ||||
|  | ||||
|     blockdev_init(NULL, qdict, &local_err); | ||||
|     dinfo = blockdev_init(NULL, qdict, &local_err); | ||||
|     if (local_err) { | ||||
|         error_propagate(errp, local_err); | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
|     if (bdrv_key_required(dinfo->bdrv)) { | ||||
|         drive_uninit(dinfo); | ||||
|         error_setg(errp, "blockdev-add doesn't support encrypted devices"); | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
| fail: | ||||
|     qmp_output_visitor_cleanup(ov); | ||||
| } | ||||
|   | ||||
							
								
								
									
										87
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										87
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -14,13 +14,14 @@ fi | ||||
| TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c" | ||||
| TMPB="qemu-conf-${RANDOM}-$$-${RANDOM}" | ||||
| TMPO="${TMPDIR1}/${TMPB}.o" | ||||
| TMPCXX="${TMPDIR1}/${TMPB}.cxx" | ||||
| TMPL="${TMPDIR1}/${TMPB}.lo" | ||||
| TMPA="${TMPDIR1}/lib${TMPB}.la" | ||||
| TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe" | ||||
|  | ||||
| # NB: do not call "exit" in the trap handler; this is buggy with some shells; | ||||
| # see <1285349658-3122-1-git-send-email-loic.minier@linaro.org> | ||||
| trap "rm -f $TMPC $TMPO $TMPE" EXIT INT QUIT TERM | ||||
| trap "rm -f $TMPC $TMPO $TMPCXX $TMPE" EXIT INT QUIT TERM | ||||
| rm -f config.log | ||||
|  | ||||
| # Print a helpful header at the top of config.log | ||||
| @@ -54,10 +55,13 @@ error_exit() { | ||||
|     exit 1 | ||||
| } | ||||
|  | ||||
| do_cc() { | ||||
|     # Run the compiler, capturing its output to the log. | ||||
|     echo $cc "$@" >> config.log | ||||
|     $cc "$@" >> config.log 2>&1 || return $? | ||||
| do_compiler() { | ||||
|     # Run the compiler, capturing its output to the log. First argument | ||||
|     # is compiler binary to execute. | ||||
|     local compiler="$1" | ||||
|     shift | ||||
|     echo $compiler "$@" >> config.log | ||||
|     $compiler "$@" >> config.log 2>&1 || return $? | ||||
|     # Test passed. If this is an --enable-werror build, rerun | ||||
|     # the test with -Werror and bail out if it fails. This | ||||
|     # makes warning-generating-errors in configure test code | ||||
| @@ -71,14 +75,39 @@ do_cc() { | ||||
|            return 0 | ||||
|         ;; | ||||
|     esac | ||||
|     echo $cc -Werror "$@" >> config.log | ||||
|     $cc -Werror "$@" >> config.log 2>&1 && return $? | ||||
|     echo $compiler -Werror "$@" >> config.log | ||||
|     $compiler -Werror "$@" >> config.log 2>&1 && return $? | ||||
|     error_exit "configure test passed without -Werror but failed with -Werror." \ | ||||
|         "This is probably a bug in the configure script. The failing command" \ | ||||
|         "will be at the bottom of config.log." \ | ||||
|         "You can run configure with --disable-werror to bypass this check." | ||||
| } | ||||
|  | ||||
| do_cc() { | ||||
|     do_compiler "$cc" "$@" | ||||
| } | ||||
|  | ||||
| do_cxx() { | ||||
|     do_compiler "$cxx" "$@" | ||||
| } | ||||
|  | ||||
| update_cxxflags() { | ||||
|     # Set QEMU_CXXFLAGS from QEMU_CFLAGS by filtering out those | ||||
|     # options which some versions of GCC's C++ compiler complain about | ||||
|     # because they only make sense for C programs. | ||||
|     QEMU_CXXFLAGS= | ||||
|     for arg in $QEMU_CFLAGS; do | ||||
|         case $arg in | ||||
|             -Wstrict-prototypes|-Wmissing-prototypes|-Wnested-externs|\ | ||||
|             -Wold-style-declaration|-Wold-style-definition|-Wredundant-decls) | ||||
|                 ;; | ||||
|             *) | ||||
|                 QEMU_CXXFLAGS=${QEMU_CXXFLAGS:+$QEMU_CXXFLAGS }$arg | ||||
|                 ;; | ||||
|         esac | ||||
|     done | ||||
| } | ||||
|  | ||||
| compile_object() { | ||||
|   do_cc $QEMU_CFLAGS -c -o $TMPO $TMPC | ||||
| } | ||||
| @@ -373,7 +402,7 @@ sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}" | ||||
| ARFLAGS="${ARFLAGS-rv}" | ||||
|  | ||||
| # default flags for all hosts | ||||
| QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS" | ||||
| QEMU_CFLAGS="-fno-strict-aliasing -fno-common $QEMU_CFLAGS" | ||||
| QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS" | ||||
| QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS" | ||||
| QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS" | ||||
| @@ -1340,6 +1369,19 @@ if test "$ARCH" = "unknown"; then | ||||
|     fi | ||||
| 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 | ||||
|     if test -d "$source_path/.git" -a \ | ||||
|         "$linux" = "yes" ; then | ||||
|         werror="yes" | ||||
|     else | ||||
|         werror="no" | ||||
|     fi | ||||
| fi | ||||
|  | ||||
| # check that the C compiler works. | ||||
| cat > $TMPC <<EOF | ||||
| int main(void) { return 0; } | ||||
| @@ -1360,14 +1402,16 @@ EOF | ||||
|  | ||||
|     compile_object | ||||
|  | ||||
|     cat > $TMPC <<EOF | ||||
|     cat > $TMPCXX <<EOF | ||||
| extern "C" { | ||||
|    int c_function(void); | ||||
| } | ||||
| int c_function(void) { return 42; } | ||||
| EOF | ||||
|  | ||||
|     if (cc=$cxx do_cc $QEMU_CFLAGS -o $TMPE $TMPC $TMPO $LDFLAGS); then | ||||
|     update_cxxflags | ||||
|  | ||||
|     if do_cxx $QEMU_CXXFLAGS -o $TMPE $TMPCXX $TMPO $LDFLAGS; then | ||||
|         # C++ compiler $cxx works ok with C compiler $cc | ||||
|         : | ||||
|     else | ||||
| @@ -1380,19 +1424,6 @@ else | ||||
|     cxx= | ||||
| 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 | ||||
|     if test -d "$source_path/.git" -a \ | ||||
|         "$linux" = "yes" ; then | ||||
|         werror="yes" | ||||
|     else | ||||
|         werror="no" | ||||
|     fi | ||||
| fi | ||||
|  | ||||
| gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits" | ||||
| gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags" | ||||
| gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" | ||||
| @@ -4076,7 +4107,11 @@ echo "vhost-net support $vhost_net" | ||||
| echo "vhost-scsi support $vhost_scsi" | ||||
| echo "Trace backend     $trace_backend" | ||||
| echo "Trace output file $trace_file-<pid>" | ||||
| if test "$spice" = "yes"; then | ||||
| echo "spice support     $spice ($spice_protocol_version/$spice_server_version)" | ||||
| else | ||||
| echo "spice support     $spice" | ||||
| fi | ||||
| echo "rbd support       $rbd" | ||||
| echo "xfsctl support    $xfs" | ||||
| echo "nss used          $smartcard_nss" | ||||
| @@ -4937,6 +4972,12 @@ for i in $ARCH $TARGET_BASE_ARCH ; do | ||||
|     echo "CONFIG_ALPHA_DIS=y"  >> $config_target_mak | ||||
|     echo "CONFIG_ALPHA_DIS=y"  >> config-all-disas.mak | ||||
|   ;; | ||||
|   aarch64) | ||||
|     if test -n "${cxx}"; then | ||||
|       echo "CONFIG_ARM_A64_DIS=y"  >> $config_target_mak | ||||
|       echo "CONFIG_ARM_A64_DIS=y"  >> config-all-disas.mak | ||||
|     fi | ||||
|   ;; | ||||
|   arm) | ||||
|     echo "CONFIG_ARM_DIS=y"  >> $config_target_mak | ||||
|     echo "CONFIG_ARM_DIS=y"  >> config-all-disas.mak | ||||
|   | ||||
							
								
								
									
										25
									
								
								cpus.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								cpus.c
									
									
									
									
									
								
							| @@ -1117,8 +1117,13 @@ void resume_all_vcpus(void) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* For temporary buffers for forming a name */ | ||||
| #define VCPU_THREAD_NAME_SIZE 16 | ||||
|  | ||||
| static void qemu_tcg_init_vcpu(CPUState *cpu) | ||||
| { | ||||
|     char thread_name[VCPU_THREAD_NAME_SIZE]; | ||||
|  | ||||
|     tcg_cpu_address_space_init(cpu, cpu->as); | ||||
|  | ||||
|     /* share a single thread for all cpus with TCG */ | ||||
| @@ -1127,8 +1132,10 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) | ||||
|         cpu->halt_cond = g_malloc0(sizeof(QemuCond)); | ||||
|         qemu_cond_init(cpu->halt_cond); | ||||
|         tcg_halt_cond = cpu->halt_cond; | ||||
|         qemu_thread_create(cpu->thread, qemu_tcg_cpu_thread_fn, cpu, | ||||
|                            QEMU_THREAD_JOINABLE); | ||||
|         snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG", | ||||
|                  cpu->cpu_index); | ||||
|         qemu_thread_create(cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, | ||||
|                            cpu, QEMU_THREAD_JOINABLE); | ||||
| #ifdef _WIN32 | ||||
|         cpu->hThread = qemu_thread_get_handle(cpu->thread); | ||||
| #endif | ||||
| @@ -1144,11 +1151,15 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) | ||||
|  | ||||
| static void qemu_kvm_start_vcpu(CPUState *cpu) | ||||
| { | ||||
|     char thread_name[VCPU_THREAD_NAME_SIZE]; | ||||
|  | ||||
|     cpu->thread = g_malloc0(sizeof(QemuThread)); | ||||
|     cpu->halt_cond = g_malloc0(sizeof(QemuCond)); | ||||
|     qemu_cond_init(cpu->halt_cond); | ||||
|     qemu_thread_create(cpu->thread, qemu_kvm_cpu_thread_fn, cpu, | ||||
|                        QEMU_THREAD_JOINABLE); | ||||
|     snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/KVM", | ||||
|              cpu->cpu_index); | ||||
|     qemu_thread_create(cpu->thread, thread_name, qemu_kvm_cpu_thread_fn, | ||||
|                        cpu, QEMU_THREAD_JOINABLE); | ||||
|     while (!cpu->created) { | ||||
|         qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); | ||||
|     } | ||||
| @@ -1156,10 +1167,14 @@ static void qemu_kvm_start_vcpu(CPUState *cpu) | ||||
|  | ||||
| static void qemu_dummy_start_vcpu(CPUState *cpu) | ||||
| { | ||||
|     char thread_name[VCPU_THREAD_NAME_SIZE]; | ||||
|  | ||||
|     cpu->thread = g_malloc0(sizeof(QemuThread)); | ||||
|     cpu->halt_cond = g_malloc0(sizeof(QemuCond)); | ||||
|     qemu_cond_init(cpu->halt_cond); | ||||
|     qemu_thread_create(cpu->thread, qemu_dummy_cpu_thread_fn, cpu, | ||||
|     snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/DUMMY", | ||||
|              cpu->cpu_index); | ||||
|     qemu_thread_create(cpu->thread, thread_name, qemu_dummy_cpu_thread_fn, cpu, | ||||
|                        QEMU_THREAD_JOINABLE); | ||||
|     while (!cpu->created) { | ||||
|         qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); | ||||
|   | ||||
| @@ -47,4 +47,5 @@ CONFIG_E500=y | ||||
| CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) | ||||
| # For PReP | ||||
| CONFIG_MC146818RTC=y | ||||
| CONFIG_ETSEC=y | ||||
| CONFIG_ISA_TESTDEV=y | ||||
|   | ||||
| @@ -1342,7 +1342,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr, | ||||
|         ASSERT(format[5] == 'L'); | ||||
|         AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide()); | ||||
|         if (instr->ShiftMoveWide() > 0) { | ||||
|           AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide()); | ||||
|           AppendToOutput(", lsl #%" PRId64, 16 * instr->ShiftMoveWide()); | ||||
|         } | ||||
|       } | ||||
|       return 8; | ||||
| @@ -1391,7 +1391,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr, | ||||
|     } | ||||
|     case 'F': {  // IFPSingle, IFPDouble or IFPFBits. | ||||
|       if (format[3] == 'F') {  // IFPFbits. | ||||
|         AppendToOutput("#%d", 64 - instr->FPScale()); | ||||
|         AppendToOutput("#%" PRId64, 64 - instr->FPScale()); | ||||
|         return 8; | ||||
|       } else { | ||||
|         AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(), | ||||
| @@ -1412,23 +1412,23 @@ int Disassembler::SubstituteImmediateField(Instruction* instr, | ||||
|       return 5; | ||||
|     } | ||||
|     case 'P': {  // IP - Conditional compare. | ||||
|       AppendToOutput("#%d", instr->ImmCondCmp()); | ||||
|       AppendToOutput("#%" PRId64, instr->ImmCondCmp()); | ||||
|       return 2; | ||||
|     } | ||||
|     case 'B': {  // Bitfields. | ||||
|       return SubstituteBitfieldImmediateField(instr, format); | ||||
|     } | ||||
|     case 'E': {  // IExtract. | ||||
|       AppendToOutput("#%d", instr->ImmS()); | ||||
|       AppendToOutput("#%" PRId64, instr->ImmS()); | ||||
|       return 8; | ||||
|     } | ||||
|     case 'S': {  // IS - Test and branch bit. | ||||
|       AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) | | ||||
|                             instr->ImmTestBranchBit40()); | ||||
|       AppendToOutput("#%" PRId64, (instr->ImmTestBranchBit5() << 5) | | ||||
|                                   instr->ImmTestBranchBit40()); | ||||
|       return 2; | ||||
|     } | ||||
|     case 'D': {  // IDebug - HLT and BRK instructions. | ||||
|       AppendToOutput("#0x%x", instr->ImmException()); | ||||
|       AppendToOutput("#0x%" PRIx64, instr->ImmException()); | ||||
|       return 6; | ||||
|     } | ||||
|     default: { | ||||
| @@ -1598,12 +1598,12 @@ int Disassembler::SubstituteExtendField(Instruction* instr, | ||||
|       (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) || | ||||
|        (instr->ExtendMode() == UXTX))) { | ||||
|     if (instr->ImmExtendShift() > 0) { | ||||
|       AppendToOutput(", lsl #%d", instr->ImmExtendShift()); | ||||
|       AppendToOutput(", lsl #%" PRId64, instr->ImmExtendShift()); | ||||
|     } | ||||
|   } else { | ||||
|     AppendToOutput(", %s", extend_mode[instr->ExtendMode()]); | ||||
|     if (instr->ImmExtendShift() > 0) { | ||||
|       AppendToOutput(" #%d", instr->ImmExtendShift()); | ||||
|       AppendToOutput(" #%" PRId64, instr->ImmExtendShift()); | ||||
|     } | ||||
|   } | ||||
|   return 3; | ||||
| @@ -1632,7 +1632,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr, | ||||
|   if (!((ext == UXTX) && (shift == 0))) { | ||||
|     AppendToOutput(", %s", extend_mode[ext]); | ||||
|     if (shift != 0) { | ||||
|       AppendToOutput(" #%d", instr->SizeLS()); | ||||
|       AppendToOutput(" #%" PRId64, instr->SizeLS()); | ||||
|     } | ||||
|   } | ||||
|   return 9; | ||||
|   | ||||
							
								
								
									
										14
									
								
								exec.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								exec.c
									
									
									
									
									
								
							| @@ -1029,7 +1029,7 @@ static void *file_ram_alloc(RAMBlock *block, | ||||
|  | ||||
|     hpagesize = gethugepagesize(path); | ||||
|     if (!hpagesize) { | ||||
|         return NULL; | ||||
|         goto error; | ||||
|     } | ||||
|  | ||||
|     if (memory < hpagesize) { | ||||
| @@ -1038,7 +1038,7 @@ static void *file_ram_alloc(RAMBlock *block, | ||||
|  | ||||
|     if (kvm_enabled() && !kvm_has_sync_mmu()) { | ||||
|         fprintf(stderr, "host lacks kvm mmu notifiers, -mem-path unsupported\n"); | ||||
|         return NULL; | ||||
|         goto error; | ||||
|     } | ||||
|  | ||||
|     /* Make name safe to use with mkstemp by replacing '/' with '_'. */ | ||||
| @@ -1056,7 +1056,7 @@ static void *file_ram_alloc(RAMBlock *block, | ||||
|     if (fd < 0) { | ||||
|         perror("unable to create backing store for hugepages"); | ||||
|         g_free(filename); | ||||
|         return NULL; | ||||
|         goto error; | ||||
|     } | ||||
|     unlink(filename); | ||||
|     g_free(filename); | ||||
| @@ -1076,7 +1076,7 @@ static void *file_ram_alloc(RAMBlock *block, | ||||
|     if (area == MAP_FAILED) { | ||||
|         perror("file_ram_alloc: can't mmap RAM pages"); | ||||
|         close(fd); | ||||
|         return (NULL); | ||||
|         goto error; | ||||
|     } | ||||
|  | ||||
|     if (mem_prealloc) { | ||||
| @@ -1120,6 +1120,12 @@ static void *file_ram_alloc(RAMBlock *block, | ||||
|  | ||||
|     block->fd = fd; | ||||
|     return area; | ||||
|  | ||||
| error: | ||||
|     if (mem_prealloc) { | ||||
|         exit(1); | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
| #else | ||||
| static void *file_ram_alloc(RAMBlock *block, | ||||
|   | ||||
| @@ -1,4 +1,6 @@ | ||||
| ifeq ($(CONFIG_REALLY_VIRTFS),y) | ||||
| ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) | ||||
| # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add. | ||||
| # only pull in the actual virtio-9p device if we also enabled virtio. | ||||
| common-obj-y = qemu-fsdev.o virtio-9p-marshal.o | ||||
| else | ||||
| common-obj-y = qemu-fsdev-dummy.o | ||||
|   | ||||
| @@ -595,7 +595,7 @@ static int do_readlink(struct iovec *iovec, struct iovec *out_iovec) | ||||
|     } | ||||
|     buffer = g_malloc(size); | ||||
|     v9fs_string_init(&target); | ||||
|     retval = readlink(path.data, buffer, size); | ||||
|     retval = readlink(path.data, buffer, size - 1); | ||||
|     if (retval > 0) { | ||||
|         buffer[retval] = '\0'; | ||||
|         v9fs_string_sprintf(&target, "%s", buffer); | ||||
|   | ||||
| @@ -17,35 +17,55 @@ | ||||
| #include "block/coroutine.h" | ||||
| #include "virtio-9p-coth.h" | ||||
|  | ||||
| static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf) | ||||
| { | ||||
|     ssize_t len, maxlen = PATH_MAX; | ||||
|  | ||||
|     buf->data = g_malloc(PATH_MAX); | ||||
|     for(;;) { | ||||
|         len = s->ops->readlink(&s->ctx, path, buf->data, maxlen); | ||||
|         if (len < 0) { | ||||
|             g_free(buf->data); | ||||
|             buf->data = NULL; | ||||
|             buf->size = 0; | ||||
|             break; | ||||
|         } else if (len == maxlen) { | ||||
|             /* | ||||
|              * We dodn't have space to put the NULL or we have more | ||||
|              * to read. Increase the size and try again | ||||
|              */ | ||||
|             maxlen *= 2; | ||||
|             g_free(buf->data); | ||||
|             buf->data = g_malloc(maxlen); | ||||
|             continue; | ||||
|         } | ||||
|         /* | ||||
|          * Null terminate the readlink output | ||||
|          */ | ||||
|         buf->data[len] = '\0'; | ||||
|         buf->size = len; | ||||
|         break; | ||||
|     } | ||||
|     return len; | ||||
| } | ||||
|  | ||||
| int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf) | ||||
| { | ||||
|     int err; | ||||
|     ssize_t len; | ||||
|     V9fsState *s = pdu->s; | ||||
|  | ||||
|     if (v9fs_request_cancelled(pdu)) { | ||||
|         return -EINTR; | ||||
|     } | ||||
|     buf->data = g_malloc(PATH_MAX); | ||||
|     v9fs_path_read_lock(s); | ||||
|     v9fs_co_run_in_worker( | ||||
|         { | ||||
|             len = s->ops->readlink(&s->ctx, path, | ||||
|                                    buf->data, PATH_MAX - 1); | ||||
|             if (len > -1) { | ||||
|                 buf->size = len; | ||||
|                 buf->data[len] = 0; | ||||
|                 err = 0; | ||||
|             } else { | ||||
|             err = __readlink(s, path, buf); | ||||
|             if (err < 0) { | ||||
|                 err = -errno; | ||||
|             } | ||||
|         }); | ||||
|     v9fs_path_unlock(s); | ||||
|     if (err) { | ||||
|         g_free(buf->data); | ||||
|         buf->data = NULL; | ||||
|         buf->size = 0; | ||||
|     } | ||||
|     return err; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -498,7 +498,7 @@ static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path, | ||||
| static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path, | ||||
|                               const char *name, V9fsPath *target) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     struct file_handle *fh; | ||||
|     int dirfd, ret, mnt_id; | ||||
|     struct handle_data *data = (struct handle_data *)ctx->private; | ||||
| @@ -513,7 +513,9 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path, | ||||
|         dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); | ||||
|     } else { | ||||
|         /* relative to export root */ | ||||
|         dirfd = open(rpath(ctx, ".", buffer), O_DIRECTORY); | ||||
|         buffer = rpath(ctx, "."); | ||||
|         dirfd = open(buffer, O_DIRECTORY); | ||||
|         g_free(buffer); | ||||
|     } | ||||
|     if (dirfd < 0) { | ||||
|         return dirfd; | ||||
| @@ -521,7 +523,7 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path, | ||||
|     fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes); | ||||
|     fh->handle_bytes = data->handle_bytes; | ||||
|     /* add a "./" at the beginning of the path */ | ||||
|     snprintf(buffer, PATH_MAX, "./%s", name); | ||||
|     buffer = g_strdup_printf("./%s", name); | ||||
|     /* flag = 0 imply don't follow symlink */ | ||||
|     ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0); | ||||
|     if (!ret) { | ||||
| @@ -531,6 +533,7 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path, | ||||
|         g_free(fh); | ||||
|     } | ||||
|     close(dirfd); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -42,18 +42,18 @@ | ||||
|  | ||||
| #define VIRTFS_META_DIR ".virtfs_metadata" | ||||
|  | ||||
| static const char *local_mapped_attr_path(FsContext *ctx, | ||||
|                                           const char *path, char *buffer) | ||||
| static char *local_mapped_attr_path(FsContext *ctx, const char *path) | ||||
| { | ||||
|     char *dir_name; | ||||
|     char *tmp_path = g_strdup(path); | ||||
|     char *base_name = basename(tmp_path); | ||||
|     char *buffer; | ||||
|  | ||||
|     /* NULL terminate the directory */ | ||||
|     dir_name = tmp_path; | ||||
|     *(base_name - 1) = '\0'; | ||||
|  | ||||
|     snprintf(buffer, PATH_MAX, "%s/%s/%s/%s", | ||||
|     buffer = g_strdup_printf("%s/%s/%s/%s", | ||||
|              ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name); | ||||
|     g_free(tmp_path); | ||||
|     return buffer; | ||||
| @@ -92,10 +92,11 @@ static void local_mapped_file_attr(FsContext *ctx, const char *path, | ||||
| { | ||||
|     FILE *fp; | ||||
|     char buf[ATTR_MAX]; | ||||
|     char attr_path[PATH_MAX]; | ||||
|     char *attr_path; | ||||
|  | ||||
|     local_mapped_attr_path(ctx, path, attr_path); | ||||
|     attr_path = local_mapped_attr_path(ctx, path); | ||||
|     fp = local_fopen(attr_path, "r"); | ||||
|     g_free(attr_path); | ||||
|     if (!fp) { | ||||
|         return; | ||||
|     } | ||||
| @@ -118,12 +119,13 @@ static void local_mapped_file_attr(FsContext *ctx, const char *path, | ||||
| static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) | ||||
| { | ||||
|     int err; | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     char *path = fs_path->data; | ||||
|  | ||||
|     err =  lstat(rpath(fs_ctx, path, buffer), stbuf); | ||||
|     buffer = rpath(fs_ctx, path); | ||||
|     err =  lstat(buffer, stbuf); | ||||
|     if (err) { | ||||
|         return err; | ||||
|         goto err_out; | ||||
|     } | ||||
|     if (fs_ctx->export_flags & V9FS_SM_MAPPED) { | ||||
|         /* Actual credentials are part of extended attrs */ | ||||
| @@ -131,41 +133,42 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) | ||||
|         gid_t tmp_gid; | ||||
|         mode_t tmp_mode; | ||||
|         dev_t tmp_dev; | ||||
|         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid, | ||||
|                     sizeof(uid_t)) > 0) { | ||||
|         if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { | ||||
|             stbuf->st_uid = tmp_uid; | ||||
|         } | ||||
|         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid, | ||||
|                     sizeof(gid_t)) > 0) { | ||||
|         if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { | ||||
|             stbuf->st_gid = tmp_gid; | ||||
|         } | ||||
|         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode", | ||||
|         if (getxattr(buffer, "user.virtfs.mode", | ||||
|                     &tmp_mode, sizeof(mode_t)) > 0) { | ||||
|             stbuf->st_mode = tmp_mode; | ||||
|         } | ||||
|         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev, | ||||
|                         sizeof(dev_t)) > 0) { | ||||
|         if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { | ||||
|                 stbuf->st_rdev = tmp_dev; | ||||
|         } | ||||
|     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { | ||||
|         local_mapped_file_attr(fs_ctx, path, stbuf); | ||||
|     } | ||||
|  | ||||
| err_out: | ||||
|     g_free(buffer); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| static int local_create_mapped_attr_dir(FsContext *ctx, const char *path) | ||||
| { | ||||
|     int err; | ||||
|     char attr_dir[PATH_MAX]; | ||||
|     char *attr_dir; | ||||
|     char *tmp_path = g_strdup(path); | ||||
|  | ||||
|     snprintf(attr_dir, PATH_MAX, "%s/%s/%s", | ||||
|     attr_dir = g_strdup_printf("%s/%s/%s", | ||||
|              ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR); | ||||
|  | ||||
|     err = mkdir(attr_dir, 0700); | ||||
|     if (err < 0 && errno == EEXIST) { | ||||
|         err = 0; | ||||
|     } | ||||
|     g_free(attr_dir); | ||||
|     g_free(tmp_path); | ||||
|     return err; | ||||
| } | ||||
| @@ -176,10 +179,11 @@ static int local_set_mapped_file_attr(FsContext *ctx, | ||||
|     FILE *fp; | ||||
|     int ret = 0; | ||||
|     char buf[ATTR_MAX]; | ||||
|     char attr_path[PATH_MAX]; | ||||
|     char *attr_path; | ||||
|     int uid = -1, gid = -1, mode = -1, rdev = -1; | ||||
|  | ||||
|     fp = local_fopen(local_mapped_attr_path(ctx, path, attr_path), "r"); | ||||
|     attr_path = local_mapped_attr_path(ctx, path); | ||||
|     fp = local_fopen(attr_path, "r"); | ||||
|     if (!fp) { | ||||
|         goto create_map_file; | ||||
|     } | ||||
| @@ -241,6 +245,7 @@ update_map_file: | ||||
|     fclose(fp); | ||||
|  | ||||
| err_out: | ||||
|     g_free(attr_path); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| @@ -282,36 +287,43 @@ static int local_set_xattr(const char *path, FsCred *credp) | ||||
| static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, | ||||
|                                          FsCred *credp) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|  | ||||
|     if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, | ||||
|                 credp->fc_gid) < 0) { | ||||
|     buffer = rpath(fs_ctx, path); | ||||
|     if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) { | ||||
|         /* | ||||
|          * If we fail to change ownership and if we are | ||||
|          * using security model none. Ignore the error | ||||
|          */ | ||||
|         if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { | ||||
|             return -1; | ||||
|             goto err; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) { | ||||
|         return -1; | ||||
|     if (chmod(buffer, credp->fc_mode & 07777) < 0) { | ||||
|         goto err; | ||||
|     } | ||||
|  | ||||
|     g_free(buffer); | ||||
|     return 0; | ||||
| err: | ||||
|     g_free(buffer); | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, | ||||
|                               char *buf, size_t bufsz) | ||||
| { | ||||
|     ssize_t tsize = -1; | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     char *path = fs_path->data; | ||||
|  | ||||
|     if ((fs_ctx->export_flags & V9FS_SM_MAPPED) || | ||||
|         (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) { | ||||
|         int fd; | ||||
|         fd = open(rpath(fs_ctx, path, buffer), O_RDONLY | O_NOFOLLOW); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         fd = open(buffer, O_RDONLY | O_NOFOLLOW); | ||||
|         g_free(buffer); | ||||
|         if (fd == -1) { | ||||
|             return -1; | ||||
|         } | ||||
| @@ -322,7 +334,9 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, | ||||
|         return tsize; | ||||
|     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || | ||||
|                (fs_ctx->export_flags & V9FS_SM_NONE)) { | ||||
|         tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         tsize = readlink(buffer, buf, bufsz); | ||||
|         g_free(buffer); | ||||
|     } | ||||
|     return tsize; | ||||
| } | ||||
| @@ -340,20 +354,24 @@ static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs) | ||||
| static int local_open(FsContext *ctx, V9fsPath *fs_path, | ||||
|                       int flags, V9fsFidOpenState *fs) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     char *path = fs_path->data; | ||||
|  | ||||
|     fs->fd = open(rpath(ctx, path, buffer), flags | O_NOFOLLOW); | ||||
|     buffer = rpath(ctx, path); | ||||
|     fs->fd = open(buffer, flags | O_NOFOLLOW); | ||||
|     g_free(buffer); | ||||
|     return fs->fd; | ||||
| } | ||||
|  | ||||
| static int local_opendir(FsContext *ctx, | ||||
|                          V9fsPath *fs_path, V9fsFidOpenState *fs) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     char *path = fs_path->data; | ||||
|  | ||||
|     fs->dir = opendir(rpath(ctx, path, buffer)); | ||||
|     buffer = rpath(ctx, path); | ||||
|     fs->dir = opendir(buffer); | ||||
|     g_free(buffer); | ||||
|     if (!fs->dir) { | ||||
|         return -1; | ||||
|     } | ||||
| @@ -441,18 +459,23 @@ static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs, | ||||
|  | ||||
| static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     int ret = -1; | ||||
|     char *path = fs_path->data; | ||||
|  | ||||
|     if (fs_ctx->export_flags & V9FS_SM_MAPPED) { | ||||
|         return local_set_xattr(rpath(fs_ctx, path, buffer), credp); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         ret = local_set_xattr(buffer, credp); | ||||
|         g_free(buffer); | ||||
|     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { | ||||
|         return local_set_mapped_file_attr(fs_ctx, path, credp); | ||||
|     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || | ||||
|                (fs_ctx->export_flags & V9FS_SM_NONE)) { | ||||
|         return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         ret = chmod(buffer, credp->fc_mode); | ||||
|         g_free(buffer); | ||||
|     } | ||||
|     return -1; | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, | ||||
| @@ -462,7 +485,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, | ||||
|     int err = -1; | ||||
|     int serrno = 0; | ||||
|     V9fsString fullname; | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|  | ||||
|     v9fs_string_init(&fullname); | ||||
|     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); | ||||
| @@ -470,21 +493,23 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, | ||||
|  | ||||
|     /* Determine the security model */ | ||||
|     if (fs_ctx->export_flags & V9FS_SM_MAPPED) { | ||||
|         err = mknod(rpath(fs_ctx, path, buffer), | ||||
|                 SM_LOCAL_MODE_BITS|S_IFREG, 0); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); | ||||
|         if (err == -1) { | ||||
|             g_free(buffer); | ||||
|             goto out; | ||||
|         } | ||||
|         err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); | ||||
|         err = local_set_xattr(buffer, credp); | ||||
|         if (err == -1) { | ||||
|             serrno = errno; | ||||
|             goto err_end; | ||||
|         } | ||||
|     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { | ||||
|  | ||||
|         err = mknod(rpath(fs_ctx, path, buffer), | ||||
|                     SM_LOCAL_MODE_BITS|S_IFREG, 0); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); | ||||
|         if (err == -1) { | ||||
|             g_free(buffer); | ||||
|             goto out; | ||||
|         } | ||||
|         err = local_set_mapped_file_attr(fs_ctx, path, credp); | ||||
| @@ -494,9 +519,10 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, | ||||
|         } | ||||
|     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || | ||||
|                (fs_ctx->export_flags & V9FS_SM_NONE)) { | ||||
|         err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode, | ||||
|                 credp->fc_rdev); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         err = mknod(buffer, credp->fc_mode, credp->fc_rdev); | ||||
|         if (err == -1) { | ||||
|             g_free(buffer); | ||||
|             goto out; | ||||
|         } | ||||
|         err = local_post_create_passthrough(fs_ctx, path, credp); | ||||
| @@ -508,8 +534,9 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, | ||||
|     goto out; | ||||
|  | ||||
| err_end: | ||||
|     remove(rpath(fs_ctx, path, buffer)); | ||||
|     remove(buffer); | ||||
|     errno = serrno; | ||||
|     g_free(buffer); | ||||
| out: | ||||
|     v9fs_string_free(&fullname); | ||||
|     return err; | ||||
| @@ -522,7 +549,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, | ||||
|     int err = -1; | ||||
|     int serrno = 0; | ||||
|     V9fsString fullname; | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|  | ||||
|     v9fs_string_init(&fullname); | ||||
|     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); | ||||
| @@ -530,19 +557,23 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, | ||||
|  | ||||
|     /* Determine the security model */ | ||||
|     if (fs_ctx->export_flags & V9FS_SM_MAPPED) { | ||||
|         err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); | ||||
|         if (err == -1) { | ||||
|             g_free(buffer); | ||||
|             goto out; | ||||
|         } | ||||
|         credp->fc_mode = credp->fc_mode|S_IFDIR; | ||||
|         err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); | ||||
|         err = local_set_xattr(buffer, credp); | ||||
|         if (err == -1) { | ||||
|             serrno = errno; | ||||
|             goto err_end; | ||||
|         } | ||||
|     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { | ||||
|         err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); | ||||
|         if (err == -1) { | ||||
|             g_free(buffer); | ||||
|             goto out; | ||||
|         } | ||||
|         credp->fc_mode = credp->fc_mode|S_IFDIR; | ||||
| @@ -553,8 +584,10 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, | ||||
|         } | ||||
|     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || | ||||
|                (fs_ctx->export_flags & V9FS_SM_NONE)) { | ||||
|         err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         err = mkdir(buffer, credp->fc_mode); | ||||
|         if (err == -1) { | ||||
|             g_free(buffer); | ||||
|             goto out; | ||||
|         } | ||||
|         err = local_post_create_passthrough(fs_ctx, path, credp); | ||||
| @@ -566,8 +599,9 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, | ||||
|     goto out; | ||||
|  | ||||
| err_end: | ||||
|     remove(rpath(fs_ctx, path, buffer)); | ||||
|     remove(buffer); | ||||
|     errno = serrno; | ||||
|     g_free(buffer); | ||||
| out: | ||||
|     v9fs_string_free(&fullname); | ||||
|     return err; | ||||
| @@ -626,7 +660,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, | ||||
|     int err = -1; | ||||
|     int serrno = 0; | ||||
|     V9fsString fullname; | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|  | ||||
|     /* | ||||
|      * Mark all the open to not follow symlinks | ||||
| @@ -639,21 +673,25 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, | ||||
|  | ||||
|     /* Determine the security model */ | ||||
|     if (fs_ctx->export_flags & V9FS_SM_MAPPED) { | ||||
|         fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         fd = open(buffer, flags, SM_LOCAL_MODE_BITS); | ||||
|         if (fd == -1) { | ||||
|             g_free(buffer); | ||||
|             err = fd; | ||||
|             goto out; | ||||
|         } | ||||
|         credp->fc_mode = credp->fc_mode|S_IFREG; | ||||
|         /* Set cleint credentials in xattr */ | ||||
|         err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); | ||||
|         err = local_set_xattr(buffer, credp); | ||||
|         if (err == -1) { | ||||
|             serrno = errno; | ||||
|             goto err_end; | ||||
|         } | ||||
|     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { | ||||
|         fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         fd = open(buffer, flags, SM_LOCAL_MODE_BITS); | ||||
|         if (fd == -1) { | ||||
|             g_free(buffer); | ||||
|             err = fd; | ||||
|             goto out; | ||||
|         } | ||||
| @@ -666,8 +704,10 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, | ||||
|         } | ||||
|     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || | ||||
|                (fs_ctx->export_flags & V9FS_SM_NONE)) { | ||||
|         fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         fd = open(buffer, flags, credp->fc_mode); | ||||
|         if (fd == -1) { | ||||
|             g_free(buffer); | ||||
|             err = fd; | ||||
|             goto out; | ||||
|         } | ||||
| @@ -683,8 +723,9 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, | ||||
|  | ||||
| err_end: | ||||
|     close(fd); | ||||
|     remove(rpath(fs_ctx, path, buffer)); | ||||
|     remove(buffer); | ||||
|     errno = serrno; | ||||
|     g_free(buffer); | ||||
| out: | ||||
|     v9fs_string_free(&fullname); | ||||
|     return err; | ||||
| @@ -698,7 +739,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, | ||||
|     int serrno = 0; | ||||
|     char *newpath; | ||||
|     V9fsString fullname; | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|  | ||||
|     v9fs_string_init(&fullname); | ||||
|     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); | ||||
| @@ -708,10 +749,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, | ||||
|     if (fs_ctx->export_flags & V9FS_SM_MAPPED) { | ||||
|         int fd; | ||||
|         ssize_t oldpath_size, write_size; | ||||
|         fd = open(rpath(fs_ctx, newpath, buffer), | ||||
|                   O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, | ||||
|                   SM_LOCAL_MODE_BITS); | ||||
|         buffer = rpath(fs_ctx, newpath); | ||||
|         fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); | ||||
|         if (fd == -1) { | ||||
|             g_free(buffer); | ||||
|             err = fd; | ||||
|             goto out; | ||||
|         } | ||||
| @@ -730,7 +771,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, | ||||
|         close(fd); | ||||
|         /* Set cleint credentials in symlink's xattr */ | ||||
|         credp->fc_mode = credp->fc_mode|S_IFLNK; | ||||
|         err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp); | ||||
|         err = local_set_xattr(buffer, credp); | ||||
|         if (err == -1) { | ||||
|             serrno = errno; | ||||
|             goto err_end; | ||||
| @@ -738,10 +779,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, | ||||
|     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { | ||||
|         int fd; | ||||
|         ssize_t oldpath_size, write_size; | ||||
|         fd = open(rpath(fs_ctx, newpath, buffer), | ||||
|                   O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, | ||||
|                   SM_LOCAL_MODE_BITS); | ||||
|         buffer = rpath(fs_ctx, newpath); | ||||
|         fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); | ||||
|         if (fd == -1) { | ||||
|             g_free(buffer); | ||||
|             err = fd; | ||||
|             goto out; | ||||
|         } | ||||
| @@ -767,12 +808,13 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, | ||||
|         } | ||||
|     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || | ||||
|                (fs_ctx->export_flags & V9FS_SM_NONE)) { | ||||
|         err = symlink(oldpath, rpath(fs_ctx, newpath, buffer)); | ||||
|         buffer = rpath(fs_ctx, newpath); | ||||
|         err = symlink(oldpath, buffer); | ||||
|         if (err) { | ||||
|             g_free(buffer); | ||||
|             goto out; | ||||
|         } | ||||
|         err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid, | ||||
|                      credp->fc_gid); | ||||
|         err = lchown(buffer, credp->fc_uid, credp->fc_gid); | ||||
|         if (err == -1) { | ||||
|             /* | ||||
|              * If we fail to change ownership and if we are | ||||
| @@ -788,8 +830,9 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, | ||||
|     goto out; | ||||
|  | ||||
| err_end: | ||||
|     remove(rpath(fs_ctx, newpath, buffer)); | ||||
|     remove(buffer); | ||||
|     errno = serrno; | ||||
|     g_free(buffer); | ||||
| out: | ||||
|     v9fs_string_free(&fullname); | ||||
|     return err; | ||||
| @@ -800,13 +843,16 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath, | ||||
| { | ||||
|     int ret; | ||||
|     V9fsString newpath; | ||||
|     char buffer[PATH_MAX], buffer1[PATH_MAX]; | ||||
|     char *buffer, *buffer1; | ||||
|  | ||||
|     v9fs_string_init(&newpath); | ||||
|     v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); | ||||
|  | ||||
|     ret = link(rpath(ctx, oldpath->data, buffer), | ||||
|                rpath(ctx, newpath.data, buffer1)); | ||||
|     buffer = rpath(ctx, oldpath->data); | ||||
|     buffer1 = rpath(ctx, newpath.data); | ||||
|     ret = link(buffer, buffer1); | ||||
|     g_free(buffer); | ||||
|     g_free(buffer1); | ||||
|  | ||||
|     /* now link the virtfs_metadata files */ | ||||
|     if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) { | ||||
| @@ -815,8 +861,11 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath, | ||||
|         if (ret < 0) { | ||||
|             goto err_out; | ||||
|         } | ||||
|         ret = link(local_mapped_attr_path(ctx, oldpath->data, buffer), | ||||
|                    local_mapped_attr_path(ctx, newpath.data, buffer1)); | ||||
|         buffer = local_mapped_attr_path(ctx, oldpath->data); | ||||
|         buffer1 = local_mapped_attr_path(ctx, newpath.data); | ||||
|         ret = link(buffer, buffer1); | ||||
|         g_free(buffer); | ||||
|         g_free(buffer1); | ||||
|         if (ret < 0 && errno != ENOENT) { | ||||
|             goto err_out; | ||||
|         } | ||||
| @@ -828,17 +877,21 @@ err_out: | ||||
|  | ||||
| static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     int ret; | ||||
|     char *path = fs_path->data; | ||||
|  | ||||
|     return truncate(rpath(ctx, path, buffer), size); | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret = truncate(buffer, size); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int local_rename(FsContext *ctx, const char *oldpath, | ||||
|                         const char *newpath) | ||||
| { | ||||
|     int err; | ||||
|     char buffer[PATH_MAX], buffer1[PATH_MAX]; | ||||
|     char *buffer, *buffer1; | ||||
|  | ||||
|     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { | ||||
|         err = local_create_mapped_attr_dir(ctx, newpath); | ||||
| @@ -846,50 +899,69 @@ static int local_rename(FsContext *ctx, const char *oldpath, | ||||
|             return err; | ||||
|         } | ||||
|         /* rename the .virtfs_metadata files */ | ||||
|         err = rename(local_mapped_attr_path(ctx, oldpath, buffer), | ||||
|                      local_mapped_attr_path(ctx, newpath, buffer1)); | ||||
|         buffer = local_mapped_attr_path(ctx, oldpath); | ||||
|         buffer1 = local_mapped_attr_path(ctx, newpath); | ||||
|         err = rename(buffer, buffer1); | ||||
|         g_free(buffer); | ||||
|         g_free(buffer1); | ||||
|         if (err < 0 && errno != ENOENT) { | ||||
|             return err; | ||||
|         } | ||||
|     } | ||||
|     return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1)); | ||||
|  | ||||
|     buffer = rpath(ctx, oldpath); | ||||
|     buffer1 = rpath(ctx, newpath); | ||||
|     err = rename(buffer, buffer1); | ||||
|     g_free(buffer); | ||||
|     g_free(buffer1); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     int ret = -1; | ||||
|     char *path = fs_path->data; | ||||
|  | ||||
|     if ((credp->fc_uid == -1 && credp->fc_gid == -1) || | ||||
|         (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || | ||||
|         (fs_ctx->export_flags & V9FS_SM_NONE)) { | ||||
|         return lchown(rpath(fs_ctx, path, buffer), | ||||
|                       credp->fc_uid, credp->fc_gid); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         ret = lchown(buffer, credp->fc_uid, credp->fc_gid); | ||||
|         g_free(buffer); | ||||
|     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) { | ||||
|         return local_set_xattr(rpath(fs_ctx, path, buffer), credp); | ||||
|         buffer = rpath(fs_ctx, path); | ||||
|         ret = local_set_xattr(buffer, credp); | ||||
|         g_free(buffer); | ||||
|     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { | ||||
|         return local_set_mapped_file_attr(fs_ctx, path, credp); | ||||
|     } | ||||
|     return -1; | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int local_utimensat(FsContext *s, V9fsPath *fs_path, | ||||
|                            const struct timespec *buf) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     int ret; | ||||
|     char *path = fs_path->data; | ||||
|  | ||||
|     return qemu_utimens(rpath(s, path, buffer), buf); | ||||
|     buffer = rpath(s, path); | ||||
|     ret = qemu_utimens(buffer, buf); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int local_remove(FsContext *ctx, const char *path) | ||||
| { | ||||
|     int err; | ||||
|     struct stat stbuf; | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|  | ||||
|     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { | ||||
|         err =  lstat(rpath(ctx, path, buffer), &stbuf); | ||||
|         buffer = rpath(ctx, path); | ||||
|         err =  lstat(buffer, &stbuf); | ||||
|         g_free(buffer); | ||||
|         if (err) { | ||||
|             goto err_out; | ||||
|         } | ||||
| @@ -898,8 +970,10 @@ static int local_remove(FsContext *ctx, const char *path) | ||||
|          * directory | ||||
|          */ | ||||
|         if (S_ISDIR(stbuf.st_mode)) { | ||||
|             sprintf(buffer, "%s/%s/%s", ctx->fs_root, path, VIRTFS_META_DIR); | ||||
|             buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root, | ||||
|                                      path, VIRTFS_META_DIR); | ||||
|             err = remove(buffer); | ||||
|             g_free(buffer); | ||||
|             if (err < 0 && errno != ENOENT) { | ||||
|                 /* | ||||
|                  * We didn't had the .virtfs_metadata file. May be file created | ||||
| @@ -912,7 +986,9 @@ static int local_remove(FsContext *ctx, const char *path) | ||||
|          * Now remove the name from parent directory | ||||
|          * .virtfs_metadata directory | ||||
|          */ | ||||
|         err = remove(local_mapped_attr_path(ctx, path, buffer)); | ||||
|         buffer = local_mapped_attr_path(ctx, path); | ||||
|         err = remove(buffer); | ||||
|         g_free(buffer); | ||||
|         if (err < 0 && errno != ENOENT) { | ||||
|             /* | ||||
|              * We didn't had the .virtfs_metadata file. May be file created | ||||
| @@ -921,7 +997,10 @@ static int local_remove(FsContext *ctx, const char *path) | ||||
|             goto err_out; | ||||
|         } | ||||
|     } | ||||
|     return remove(rpath(ctx, path, buffer)); | ||||
|  | ||||
|     buffer = rpath(ctx, path); | ||||
|     err = remove(buffer); | ||||
|     g_free(buffer); | ||||
| err_out: | ||||
|     return err; | ||||
| } | ||||
| @@ -946,10 +1025,14 @@ static int local_fsync(FsContext *ctx, int fid_type, | ||||
|  | ||||
| static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     int ret; | ||||
|     char *path = fs_path->data; | ||||
|  | ||||
|     return statfs(rpath(s, path, buffer), stbuf); | ||||
|     buffer = rpath(s, path); | ||||
|     ret = statfs(buffer, stbuf); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path, | ||||
| @@ -1022,7 +1105,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir, | ||||
| { | ||||
|     int ret; | ||||
|     V9fsString fullname; | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|  | ||||
|     v9fs_string_init(&fullname); | ||||
|  | ||||
| @@ -1033,9 +1116,10 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir, | ||||
|              * If directory remove .virtfs_metadata contained in the | ||||
|              * directory | ||||
|              */ | ||||
|             sprintf(buffer, "%s/%s/%s", ctx->fs_root, | ||||
|                     fullname.data, VIRTFS_META_DIR); | ||||
|             buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root, | ||||
|                                      fullname.data, VIRTFS_META_DIR); | ||||
|             ret = remove(buffer); | ||||
|             g_free(buffer); | ||||
|             if (ret < 0 && errno != ENOENT) { | ||||
|                 /* | ||||
|                  * We didn't had the .virtfs_metadata file. May be file created | ||||
| @@ -1048,7 +1132,9 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir, | ||||
|          * Now remove the name from parent directory | ||||
|          * .virtfs_metadata directory. | ||||
|          */ | ||||
|         ret = remove(local_mapped_attr_path(ctx, fullname.data, buffer)); | ||||
|         buffer = local_mapped_attr_path(ctx, fullname.data); | ||||
|         ret = remove(buffer); | ||||
|         g_free(buffer); | ||||
|         if (ret < 0 && errno != ENOENT) { | ||||
|             /* | ||||
|              * We didn't had the .virtfs_metadata file. May be file created | ||||
| @@ -1058,10 +1144,12 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir, | ||||
|         } | ||||
|     } | ||||
|     /* Remove the name finally */ | ||||
|     ret = remove(rpath(ctx, fullname.data, buffer)); | ||||
|     v9fs_string_free(&fullname); | ||||
|     buffer = rpath(ctx, fullname.data); | ||||
|     ret = remove(buffer); | ||||
|     g_free(buffer); | ||||
|  | ||||
| err_out: | ||||
|     v9fs_string_free(&fullname); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -26,8 +26,13 @@ | ||||
| static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path, | ||||
|                                 const char *name, void *value, size_t size) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value, size); | ||||
|     char *buffer; | ||||
|     ssize_t ret; | ||||
|  | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret = lgetxattr(buffer, MAP_ACL_ACCESS, value, size); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path, | ||||
| @@ -52,17 +57,23 @@ static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path, | ||||
| static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name, | ||||
|                             void *value, size_t size, int flags) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value, | ||||
|             size, flags); | ||||
|     char *buffer; | ||||
|     int ret; | ||||
|  | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret = lsetxattr(buffer, MAP_ACL_ACCESS, value, size, flags); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int mp_pacl_removexattr(FsContext *ctx, | ||||
|                                const char *path, const char *name) | ||||
| { | ||||
|     int ret; | ||||
|     char buffer[PATH_MAX]; | ||||
|     ret  = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS); | ||||
|     char *buffer; | ||||
|  | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret  = lremovexattr(buffer, MAP_ACL_ACCESS); | ||||
|     if (ret == -1 && errno == ENODATA) { | ||||
|         /* | ||||
|          * We don't get ENODATA error when trying to remove a | ||||
| @@ -72,14 +83,20 @@ static int mp_pacl_removexattr(FsContext *ctx, | ||||
|         errno = 0; | ||||
|         ret = 0; | ||||
|     } | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path, | ||||
|                                 const char *name, void *value, size_t size) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value, size); | ||||
|     char *buffer; | ||||
|     ssize_t ret; | ||||
|  | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret = lgetxattr(buffer, MAP_ACL_DEFAULT, value, size); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path, | ||||
| @@ -104,17 +121,23 @@ static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path, | ||||
| static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name, | ||||
|                             void *value, size_t size, int flags) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value, | ||||
|             size, flags); | ||||
|     char *buffer; | ||||
|     int ret; | ||||
|  | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret = lsetxattr(buffer, MAP_ACL_DEFAULT, value, size, flags); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int mp_dacl_removexattr(FsContext *ctx, | ||||
|                                const char *path, const char *name) | ||||
| { | ||||
|     int ret; | ||||
|     char buffer[PATH_MAX]; | ||||
|     ret  = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT); | ||||
|     char *buffer; | ||||
|  | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret  = lremovexattr(buffer, MAP_ACL_DEFAULT); | ||||
|     if (ret == -1 && errno == ENODATA) { | ||||
|         /* | ||||
|          * We don't get ENODATA error when trying to remove a | ||||
| @@ -124,6 +147,7 @@ static int mp_dacl_removexattr(FsContext *ctx, | ||||
|         errno = 0; | ||||
|         ret = 0; | ||||
|     } | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,9 @@ | ||||
| static ssize_t mp_user_getxattr(FsContext *ctx, const char *path, | ||||
|                                 const char *name, void *value, size_t size) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     ssize_t ret; | ||||
|  | ||||
|     if (strncmp(name, "user.virtfs.", 12) == 0) { | ||||
|         /* | ||||
|          * Don't allow fetch of user.virtfs namesapce | ||||
| @@ -30,7 +32,10 @@ static ssize_t mp_user_getxattr(FsContext *ctx, const char *path, | ||||
|         errno = ENOATTR; | ||||
|         return -1; | ||||
|     } | ||||
|     return lgetxattr(rpath(ctx, path, buffer), name, value, size); | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret = lgetxattr(buffer, name, value, size); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static ssize_t mp_user_listxattr(FsContext *ctx, const char *path, | ||||
| @@ -69,7 +74,9 @@ static ssize_t mp_user_listxattr(FsContext *ctx, const char *path, | ||||
| static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name, | ||||
|                             void *value, size_t size, int flags) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     int ret; | ||||
|  | ||||
|     if (strncmp(name, "user.virtfs.", 12) == 0) { | ||||
|         /* | ||||
|          * Don't allow fetch of user.virtfs namesapce | ||||
| @@ -78,13 +85,18 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name, | ||||
|         errno = EACCES; | ||||
|         return -1; | ||||
|     } | ||||
|     return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags); | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret = lsetxattr(buffer, name, value, size, flags); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int mp_user_removexattr(FsContext *ctx, | ||||
|                                const char *path, const char *name) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     int ret; | ||||
|  | ||||
|     if (strncmp(name, "user.virtfs.", 12) == 0) { | ||||
|         /* | ||||
|          * Don't allow fetch of user.virtfs namesapce | ||||
| @@ -93,7 +105,10 @@ static int mp_user_removexattr(FsContext *ctx, | ||||
|         errno = EACCES; | ||||
|         return -1; | ||||
|     } | ||||
|     return lremovexattr(rpath(ctx, path, buffer), name); | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret = lremovexattr(buffer, name); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| XattrOperations mapped_user_xattr = { | ||||
|   | ||||
| @@ -67,21 +67,24 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, | ||||
|                         void *value, size_t vsize) | ||||
| { | ||||
|     ssize_t size = 0; | ||||
|     char buffer[PATH_MAX]; | ||||
|     char *buffer; | ||||
|     void *ovalue = value; | ||||
|     XattrOperations *xops; | ||||
|     char *orig_value, *orig_value_start; | ||||
|     ssize_t xattr_len, parsed_len = 0, attr_len; | ||||
|  | ||||
|     /* Get the actual len */ | ||||
|     xattr_len = llistxattr(rpath(ctx, path, buffer), value, 0); | ||||
|     buffer = rpath(ctx, path); | ||||
|     xattr_len = llistxattr(buffer, value, 0); | ||||
|     if (xattr_len <= 0) { | ||||
|         g_free(buffer); | ||||
|         return xattr_len; | ||||
|     } | ||||
|  | ||||
|     /* Now fetch the xattr and find the actual size */ | ||||
|     orig_value = g_malloc(xattr_len); | ||||
|     xattr_len = llistxattr(rpath(ctx, path, buffer), orig_value, xattr_len); | ||||
|     xattr_len = llistxattr(buffer, orig_value, xattr_len); | ||||
|     g_free(buffer); | ||||
|  | ||||
|     /* store the orig pointer */ | ||||
|     orig_value_start = orig_value; | ||||
|   | ||||
| @@ -54,23 +54,38 @@ ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value, | ||||
| static inline ssize_t pt_getxattr(FsContext *ctx, const char *path, | ||||
|                                   const char *name, void *value, size_t size) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     return lgetxattr(rpath(ctx, path, buffer), name, value, size); | ||||
|     char *buffer; | ||||
|     ssize_t ret; | ||||
|  | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret = lgetxattr(buffer, name, value, size); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static inline int pt_setxattr(FsContext *ctx, const char *path, | ||||
|                               const char *name, void *value, | ||||
|                               size_t size, int flags) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags); | ||||
|     char *buffer; | ||||
|     int ret; | ||||
|  | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret = lsetxattr(buffer, name, value, size, flags); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static inline int pt_removexattr(FsContext *ctx, | ||||
|                                  const char *path, const char *name) | ||||
| { | ||||
|     char buffer[PATH_MAX]; | ||||
|     return lremovexattr(rpath(ctx, path, buffer), name); | ||||
|     char *buffer; | ||||
|     int ret; | ||||
|  | ||||
|     buffer = rpath(ctx, path); | ||||
|     ret = lremovexattr(path, name); | ||||
|     g_free(buffer); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path, | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| #include <sys/time.h> | ||||
| #include <utime.h> | ||||
| #include <sys/resource.h> | ||||
| #include <glib.h> | ||||
| #include "hw/virtio/virtio.h" | ||||
| #include "fsdev/file-op-9p.h" | ||||
| #include "fsdev/virtio-9p-marshal.h" | ||||
| @@ -112,10 +113,9 @@ enum p9_proto_version { | ||||
|  | ||||
| #define FID_REFERENCED          0x1 | ||||
| #define FID_NON_RECLAIMABLE     0x2 | ||||
| static inline const char *rpath(FsContext *ctx, const char *path, char *buffer) | ||||
| static inline char *rpath(FsContext *ctx, const char *path) | ||||
| { | ||||
|     snprintf(buffer, PATH_MAX, "%s/%s", ctx->fs_root, path); | ||||
|     return buffer; | ||||
|     return g_strdup_printf("%s/%s", ctx->fs_root, path); | ||||
| } | ||||
|  | ||||
| /* | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| devices-dirs-$(CONFIG_REALLY_VIRTFS) += 9pfs/ | ||||
| devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/ | ||||
| devices-dirs-$(CONFIG_ACPI) += acpi/ | ||||
| devices-dirs-$(CONFIG_SOFTMMU) += audio/ | ||||
| devices-dirs-$(CONFIG_SOFTMMU) += block/ | ||||
|   | ||||
| @@ -110,10 +110,10 @@ | ||||
| #define MP_PHY_88E3015          0x01410E20 | ||||
|  | ||||
| /* TX descriptor status */ | ||||
| #define MP_ETH_TX_OWN           (1 << 31) | ||||
| #define MP_ETH_TX_OWN           (1U << 31) | ||||
|  | ||||
| /* RX descriptor status */ | ||||
| #define MP_ETH_RX_OWN           (1 << 31) | ||||
| #define MP_ETH_RX_OWN           (1U << 31) | ||||
|  | ||||
| /* Interrupt cause/mask bits */ | ||||
| #define MP_ETH_IRQ_RX_BIT       0 | ||||
|   | ||||
| @@ -809,22 +809,26 @@ static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s, | ||||
|                 uint32_t diff, uint32_t value) | ||||
| { | ||||
|     if (s->compat1509) { | ||||
|         if (diff & (1 << 31))			/* MCBSP3_CLK_HIZ_DI */ | ||||
|             omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"), | ||||
|                             (value >> 31) & 1); | ||||
|         if (diff & (1 << 1))			/* CLK32K */ | ||||
|             omap_clk_onoff(omap_findclk(s, "clk32k_out"), | ||||
|                             (~value >> 1) & 1); | ||||
|         if (diff & (1U << 31)) { | ||||
|             /* MCBSP3_CLK_HIZ_DI */ | ||||
|             omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"), (value >> 31) & 1); | ||||
|         } | ||||
|         if (diff & (1 << 1)) { | ||||
|             /* CLK32K */ | ||||
|             omap_clk_onoff(omap_findclk(s, "clk32k_out"), (~value >> 1) & 1); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s, | ||||
|                 uint32_t diff, uint32_t value) | ||||
| { | ||||
|     if (diff & (1 << 31))			/* CONF_MOD_UART3_CLK_MODE_R */ | ||||
|          omap_clk_reparent(omap_findclk(s, "uart3_ck"), | ||||
|                          omap_findclk(s, ((value >> 31) & 1) ? | ||||
|                                  "ck_48m" : "armper_ck")); | ||||
|     if (diff & (1U << 31)) { | ||||
|         /* CONF_MOD_UART3_CLK_MODE_R */ | ||||
|         omap_clk_reparent(omap_findclk(s, "uart3_ck"), | ||||
|                           omap_findclk(s, ((value >> 31) & 1) ? | ||||
|                                        "ck_48m" : "armper_ck")); | ||||
|     } | ||||
|     if (diff & (1 << 30))			/* CONF_MOD_UART2_CLK_MODE_R */ | ||||
|          omap_clk_reparent(omap_findclk(s, "uart2_ck"), | ||||
|                          omap_findclk(s, ((value >> 30) & 1) ? | ||||
|   | ||||
| @@ -259,7 +259,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri, | ||||
|  | ||||
|     case 1: | ||||
|         /* Idle */ | ||||
|         if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */ | ||||
|         if (!(s->cm_regs[CCCR >> 2] & (1U << 31))) { /* CPDIS */ | ||||
|             cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT); | ||||
|             break; | ||||
|         } | ||||
| @@ -496,7 +496,7 @@ typedef struct { | ||||
| #define SSCR0_SSE	(1 << 7) | ||||
| #define SSCR0_RIM	(1 << 22) | ||||
| #define SSCR0_TIM	(1 << 23) | ||||
| #define SSCR0_MOD	(1 << 31) | ||||
| #define SSCR0_MOD       (1U << 31) | ||||
| #define SSCR0_DSS(x)	(((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1) | ||||
| #define SSCR1_RIE	(1 << 0) | ||||
| #define SSCR1_TIE	(1 << 1) | ||||
| @@ -1006,7 +1006,7 @@ static void pxa2xx_rtc_write(void *opaque, hwaddr addr, | ||||
|  | ||||
|     switch (addr) { | ||||
|     case RTTR: | ||||
|         if (!(s->rttr & (1 << 31))) { | ||||
|         if (!(s->rttr & (1U << 31))) { | ||||
|             pxa2xx_rtc_hzupdate(s); | ||||
|             s->rttr = value; | ||||
|             pxa2xx_rtc_alarm_update(s, s->rtsr); | ||||
|   | ||||
| @@ -110,7 +110,7 @@ static void pxa2xx_gpio_set(void *opaque, int line, int level) | ||||
|     } | ||||
|  | ||||
|     bank = line >> 5; | ||||
|     mask = 1 << (line & 31); | ||||
|     mask = 1U << (line & 31); | ||||
|  | ||||
|     if (level) { | ||||
|         s->status[bank] |= s->rising[bank] & mask & | ||||
|   | ||||
| @@ -105,7 +105,7 @@ static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) { | ||||
|  | ||||
|     for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) { | ||||
|         irq = s->priority[i] & 0x3f; | ||||
|         if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) { | ||||
|         if ((s->priority[i] & (1U << 31)) && irq < PXA2XX_PIC_SRCS) { | ||||
|             /* Source peripheral ID is valid.  */ | ||||
|             bit = 1 << (irq & 31); | ||||
|             int_set = (irq >= 32); | ||||
| @@ -119,7 +119,7 @@ static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) { | ||||
|             if (mask[int_set] & bit & ~s->is_fiq[int_set]) { | ||||
|                 /* IRQ asserted */ | ||||
|                 ichp &= 0x0000ffff; | ||||
|                 ichp |= (1 << 31) | (irq << 16); | ||||
|                 ichp |= (1U << 31) | (irq << 16); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -358,7 +358,7 @@ static void start_data_plane_bh(void *opaque) | ||||
|  | ||||
|     qemu_bh_delete(s->start_bh); | ||||
|     s->start_bh = NULL; | ||||
|     qemu_thread_create(&s->thread, data_plane_thread, | ||||
|     qemu_thread_create(&s->thread, "data_plane", data_plane_thread, | ||||
|                        s, QEMU_THREAD_JOINABLE); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -284,12 +284,30 @@ static void *load_at(int fd, int offset, int size) | ||||
| #define SZ		64 | ||||
| #include "hw/elf_ops.h" | ||||
|  | ||||
| const char *load_elf_strerror(int error) | ||||
| { | ||||
|     switch (error) { | ||||
|     case 0: | ||||
|         return "No error"; | ||||
|     case ELF_LOAD_FAILED: | ||||
|         return "Failed to load ELF"; | ||||
|     case ELF_LOAD_NOT_ELF: | ||||
|         return "The image is not ELF"; | ||||
|     case ELF_LOAD_WRONG_ARCH: | ||||
|         return "The image is from incompatible architecture"; | ||||
|     case ELF_LOAD_WRONG_ENDIAN: | ||||
|         return "The image has incorrect endianness"; | ||||
|     default: | ||||
|         return "Unknown error"; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* return < 0 if error, otherwise the number of bytes loaded in memory */ | ||||
| int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), | ||||
|              void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, | ||||
|              uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb) | ||||
| { | ||||
|     int fd, data_order, target_data_order, must_swab, ret; | ||||
|     int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED; | ||||
|     uint8_t e_ident[EI_NIDENT]; | ||||
|  | ||||
|     fd = open(filename, O_RDONLY | O_BINARY); | ||||
| @@ -302,8 +320,10 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), | ||||
|     if (e_ident[0] != ELFMAG0 || | ||||
|         e_ident[1] != ELFMAG1 || | ||||
|         e_ident[2] != ELFMAG2 || | ||||
|         e_ident[3] != ELFMAG3) | ||||
|         e_ident[3] != ELFMAG3) { | ||||
|         ret = ELF_LOAD_NOT_ELF; | ||||
|         goto fail; | ||||
|     } | ||||
| #ifdef HOST_WORDS_BIGENDIAN | ||||
|     data_order = ELFDATA2MSB; | ||||
| #else | ||||
| @@ -317,6 +337,7 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), | ||||
|     } | ||||
|  | ||||
|     if (target_data_order != e_ident[EI_DATA]) { | ||||
|         ret = ELF_LOAD_WRONG_ENDIAN; | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
| @@ -329,12 +350,9 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), | ||||
|                          pentry, lowaddr, highaddr, elf_machine, clear_lsb); | ||||
|     } | ||||
|  | ||||
|     close(fd); | ||||
|     return ret; | ||||
|  | ||||
|  fail: | ||||
|     close(fd); | ||||
|     return -1; | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static void bswap_uboot_header(uboot_image_header_t *hdr) | ||||
|   | ||||
| @@ -440,27 +440,33 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id) | ||||
| static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) | ||||
| { | ||||
|     const char *typename = object_get_typename(OBJECT(bus)); | ||||
|     BusClass *bc; | ||||
|     char *buf; | ||||
|     int i,len; | ||||
|     int i, len, bus_id; | ||||
|  | ||||
|     bus->parent = parent; | ||||
|  | ||||
|     if (name) { | ||||
|         bus->name = g_strdup(name); | ||||
|     } else if (bus->parent && bus->parent->id) { | ||||
|         /* parent device has id -> use it for bus name */ | ||||
|         /* parent device has id -> use it plus parent-bus-id for bus name */ | ||||
|         bus_id = bus->parent->num_child_bus; | ||||
|  | ||||
|         len = strlen(bus->parent->id) + 16; | ||||
|         buf = g_malloc(len); | ||||
|         snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus); | ||||
|         snprintf(buf, len, "%s.%d", bus->parent->id, bus_id); | ||||
|         bus->name = buf; | ||||
|     } else { | ||||
|         /* no id -> use lowercase bus type for bus name */ | ||||
|         /* no id -> use lowercase bus type plus global bus-id for bus name */ | ||||
|         bc = BUS_GET_CLASS(bus); | ||||
|         bus_id = bc->automatic_ids++; | ||||
|  | ||||
|         len = strlen(typename) + 16; | ||||
|         buf = g_malloc(len); | ||||
|         len = snprintf(buf, len, "%s.%d", typename, | ||||
|                        bus->parent ? bus->parent->num_child_bus : 0); | ||||
|         for (i = 0; i < len; i++) | ||||
|         len = snprintf(buf, len, "%s.%d", typename, bus_id); | ||||
|         for (i = 0; i < len; i++) { | ||||
|             buf[i] = qemu_tolower(buf[i]); | ||||
|         } | ||||
|         bus->name = buf; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -992,7 +992,7 @@ wait_more: | ||||
|  | ||||
|     /* vfb */ | ||||
|     fb = container_of(xfb, struct XenFB, c.xendev); | ||||
|     fb->c.con = graphic_console_init(NULL, &xenfb_ops, fb); | ||||
|     fb->c.con = graphic_console_init(NULL, 0, &xenfb_ops, fb); | ||||
|     fb->have_console = 1; | ||||
|  | ||||
|     /* vkbd */ | ||||
|   | ||||
| @@ -643,6 +643,21 @@ static inline char acpi_get_hex(uint32_t val) | ||||
| #define ACPI_PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start) | ||||
| #define ACPI_PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start) | ||||
|  | ||||
| #define ACPI_PCINOHP_OFFSET_HEX (*ssdt_pcinohp_name - *ssdt_pcinohp_start + 1) | ||||
| #define ACPI_PCINOHP_OFFSET_ADR (*ssdt_pcinohp_adr - *ssdt_pcinohp_start) | ||||
| #define ACPI_PCINOHP_SIZEOF (*ssdt_pcinohp_end - *ssdt_pcinohp_start) | ||||
| #define ACPI_PCINOHP_AML (ssdp_pcihp_aml + *ssdt_pcinohp_start) | ||||
|  | ||||
| #define ACPI_PCIVGA_OFFSET_HEX (*ssdt_pcivga_name - *ssdt_pcivga_start + 1) | ||||
| #define ACPI_PCIVGA_OFFSET_ADR (*ssdt_pcivga_adr - *ssdt_pcivga_start) | ||||
| #define ACPI_PCIVGA_SIZEOF (*ssdt_pcivga_end - *ssdt_pcivga_start) | ||||
| #define ACPI_PCIVGA_AML (ssdp_pcihp_aml + *ssdt_pcivga_start) | ||||
|  | ||||
| #define ACPI_PCIQXL_OFFSET_HEX (*ssdt_pciqxl_name - *ssdt_pciqxl_start + 1) | ||||
| #define ACPI_PCIQXL_OFFSET_ADR (*ssdt_pciqxl_adr - *ssdt_pciqxl_start) | ||||
| #define ACPI_PCIQXL_SIZEOF (*ssdt_pciqxl_end - *ssdt_pciqxl_start) | ||||
| #define ACPI_PCIQXL_AML (ssdp_pcihp_aml + *ssdt_pciqxl_start) | ||||
|  | ||||
| #define ACPI_SSDT_SIGNATURE 0x54445353 /* SSDT */ | ||||
| #define ACPI_SSDT_HEADER_LENGTH 36 | ||||
|  | ||||
| @@ -677,6 +692,33 @@ static void patch_pcihp(int slot, uint8_t *ssdt_ptr) | ||||
|     ssdt_ptr[ACPI_PCIHP_OFFSET_ADR + 2] = slot; | ||||
| } | ||||
|  | ||||
| static void patch_pcinohp(int slot, uint8_t *ssdt_ptr) | ||||
| { | ||||
|     unsigned devfn = PCI_DEVFN(slot, 0); | ||||
|  | ||||
|     ssdt_ptr[ACPI_PCINOHP_OFFSET_HEX] = acpi_get_hex(devfn >> 4); | ||||
|     ssdt_ptr[ACPI_PCINOHP_OFFSET_HEX + 1] = acpi_get_hex(devfn); | ||||
|     ssdt_ptr[ACPI_PCINOHP_OFFSET_ADR + 2] = slot; | ||||
| } | ||||
|  | ||||
| static void patch_pcivga(int slot, uint8_t *ssdt_ptr) | ||||
| { | ||||
|     unsigned devfn = PCI_DEVFN(slot, 0); | ||||
|  | ||||
|     ssdt_ptr[ACPI_PCIVGA_OFFSET_HEX] = acpi_get_hex(devfn >> 4); | ||||
|     ssdt_ptr[ACPI_PCIVGA_OFFSET_HEX + 1] = acpi_get_hex(devfn); | ||||
|     ssdt_ptr[ACPI_PCIVGA_OFFSET_ADR + 2] = slot; | ||||
| } | ||||
|  | ||||
| static void patch_pciqxl(int slot, uint8_t *ssdt_ptr) | ||||
| { | ||||
|     unsigned devfn = PCI_DEVFN(slot, 0); | ||||
|  | ||||
|     ssdt_ptr[ACPI_PCIQXL_OFFSET_HEX] = acpi_get_hex(devfn >> 4); | ||||
|     ssdt_ptr[ACPI_PCIQXL_OFFSET_HEX + 1] = acpi_get_hex(devfn); | ||||
|     ssdt_ptr[ACPI_PCIQXL_OFFSET_ADR + 2] = slot; | ||||
| } | ||||
|  | ||||
| /* Assign BSEL property to all buses.  In the future, this can be changed | ||||
|  * to only assign to buses that support hotplug. | ||||
|  */ | ||||
| @@ -737,6 +779,10 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state) | ||||
|     AcpiBuildPciBusHotplugState *parent = child->parent; | ||||
|     GArray *bus_table = build_alloc_array(); | ||||
|     DECLARE_BITMAP(slot_hotplug_enable, PCI_SLOT_MAX); | ||||
|     DECLARE_BITMAP(slot_device_present, PCI_SLOT_MAX); | ||||
|     DECLARE_BITMAP(slot_device_system, PCI_SLOT_MAX); | ||||
|     DECLARE_BITMAP(slot_device_vga, PCI_SLOT_MAX); | ||||
|     DECLARE_BITMAP(slot_device_qxl, PCI_SLOT_MAX); | ||||
|     uint8_t op; | ||||
|     int i; | ||||
|     QObject *bsel; | ||||
| @@ -764,40 +810,82 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state) | ||||
|         build_append_byte(bus_table, 0x08); /* NameOp */ | ||||
|         build_append_nameseg(bus_table, "BSEL"); | ||||
|         build_append_int(bus_table, qint_get_int(qobject_to_qint(bsel))); | ||||
|  | ||||
|         memset(slot_hotplug_enable, 0xff, sizeof slot_hotplug_enable); | ||||
|     } else { | ||||
|         /* No bsel - no slots are hot-pluggable */ | ||||
|         memset(slot_hotplug_enable, 0x00, sizeof slot_hotplug_enable); | ||||
|     } | ||||
|  | ||||
|         for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { | ||||
|             DeviceClass *dc; | ||||
|             PCIDeviceClass *pc; | ||||
|             PCIDevice *pdev = bus->devices[i]; | ||||
|     memset(slot_device_present, 0x00, sizeof slot_device_present); | ||||
|     memset(slot_device_system, 0x00, sizeof slot_device_present); | ||||
|     memset(slot_device_vga, 0x00, sizeof slot_device_vga); | ||||
|     memset(slot_device_qxl, 0x00, sizeof slot_device_qxl); | ||||
|  | ||||
|             if (!pdev) { | ||||
|                 continue; | ||||
|             } | ||||
|     for (i = 0; i < ARRAY_SIZE(bus->devices); i += PCI_FUNC_MAX) { | ||||
|         DeviceClass *dc; | ||||
|         PCIDeviceClass *pc; | ||||
|         PCIDevice *pdev = bus->devices[i]; | ||||
|         int slot = PCI_SLOT(i); | ||||
|  | ||||
|             pc = PCI_DEVICE_GET_CLASS(pdev); | ||||
|             dc = DEVICE_GET_CLASS(pdev); | ||||
|         if (!pdev) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|             if (!dc->hotpluggable || pc->is_bridge) { | ||||
|                 int slot = PCI_SLOT(i); | ||||
|         set_bit(slot, slot_device_present); | ||||
|         pc = PCI_DEVICE_GET_CLASS(pdev); | ||||
|         dc = DEVICE_GET_CLASS(pdev); | ||||
|  | ||||
|                 clear_bit(slot, slot_hotplug_enable); | ||||
|         if (pc->class_id == PCI_CLASS_BRIDGE_ISA) { | ||||
|             set_bit(slot, slot_device_system); | ||||
|         } | ||||
|  | ||||
|         if (pc->class_id == PCI_CLASS_DISPLAY_VGA) { | ||||
|             set_bit(slot, slot_device_vga); | ||||
|  | ||||
|             if (object_dynamic_cast(OBJECT(pdev), "qxl-vga")) { | ||||
|                 set_bit(slot, slot_device_qxl); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /* Append Device object for each slot which supports eject */ | ||||
|         for (i = 0; i < PCI_SLOT_MAX; i++) { | ||||
|             bool can_eject = test_bit(i, slot_hotplug_enable); | ||||
|             if (can_eject) { | ||||
|                 void *pcihp = acpi_data_push(bus_table, | ||||
|                                              ACPI_PCIHP_SIZEOF); | ||||
|                 memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF); | ||||
|                 patch_pcihp(i, pcihp); | ||||
|                 bus_hotplug_support = true; | ||||
|             } | ||||
|         if (!dc->hotpluggable || pc->is_bridge) { | ||||
|             clear_bit(slot, slot_hotplug_enable); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* Append Device object for each slot */ | ||||
|     for (i = 0; i < PCI_SLOT_MAX; i++) { | ||||
|         bool can_eject = test_bit(i, slot_hotplug_enable); | ||||
|         bool present = test_bit(i, slot_device_present); | ||||
|         bool vga = test_bit(i, slot_device_vga); | ||||
|         bool qxl = test_bit(i, slot_device_qxl); | ||||
|         bool system = test_bit(i, slot_device_system); | ||||
|         if (can_eject) { | ||||
|             void *pcihp = acpi_data_push(bus_table, | ||||
|                                          ACPI_PCIHP_SIZEOF); | ||||
|             memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF); | ||||
|             patch_pcihp(i, pcihp); | ||||
|             bus_hotplug_support = true; | ||||
|         } else if (qxl) { | ||||
|             void *pcihp = acpi_data_push(bus_table, | ||||
|                                          ACPI_PCIQXL_SIZEOF); | ||||
|             memcpy(pcihp, ACPI_PCIQXL_AML, ACPI_PCIQXL_SIZEOF); | ||||
|             patch_pciqxl(i, pcihp); | ||||
|         } else if (vga) { | ||||
|             void *pcihp = acpi_data_push(bus_table, | ||||
|                                          ACPI_PCIVGA_SIZEOF); | ||||
|             memcpy(pcihp, ACPI_PCIVGA_AML, ACPI_PCIVGA_SIZEOF); | ||||
|             patch_pcivga(i, pcihp); | ||||
|         } else if (system) { | ||||
|             /* Nothing to do: system devices are in DSDT. */ | ||||
|         } else if (present) { | ||||
|             void *pcihp = acpi_data_push(bus_table, | ||||
|                                          ACPI_PCINOHP_SIZEOF); | ||||
|             memcpy(pcihp, ACPI_PCINOHP_AML, ACPI_PCINOHP_SIZEOF); | ||||
|             patch_pcinohp(i, pcihp); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (bsel) { | ||||
|         method = build_alloc_method("DVNT", 2); | ||||
|  | ||||
|         for (i = 0; i < PCI_SLOT_MAX; i++) { | ||||
| @@ -976,7 +1064,14 @@ build_ssdt(GArray *table_data, GArray *linker, | ||||
|  | ||||
|         { | ||||
|             AcpiBuildPciBusHotplugState hotplug_state; | ||||
|             PCIBus *bus = find_i440fx(); /* TODO: Q35 support */ | ||||
|             Object *pci_host; | ||||
|             PCIBus *bus = NULL; | ||||
|             bool ambiguous; | ||||
|  | ||||
|             pci_host = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous); | ||||
|             if (!ambiguous && pci_host) { | ||||
|                 bus = PCI_HOST_BRIDGE(pci_host)->bus; | ||||
|             } | ||||
|  | ||||
|             build_pci_bus_state_init(&hotplug_state, NULL); | ||||
|  | ||||
|   | ||||
| @@ -80,6 +80,8 @@ DefinitionBlock ( | ||||
|             Name(_HID, EisaId("PNP0A03")) | ||||
|             Name(_ADR, 0x00) | ||||
|             Name(_UID, 1) | ||||
| //#define PX13 S0B_ | ||||
| //            External(PX13, DeviceObj) | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -87,34 +89,6 @@ DefinitionBlock ( | ||||
| #include "acpi-dsdt-hpet.dsl" | ||||
|  | ||||
|  | ||||
| /**************************************************************** | ||||
|  * VGA | ||||
|  ****************************************************************/ | ||||
|  | ||||
|     Scope(\_SB.PCI0) { | ||||
|         Device(VGA) { | ||||
|             Name(_ADR, 0x00020000) | ||||
|             OperationRegion(PCIC, PCI_Config, Zero, 0x4) | ||||
|             Field(PCIC, DWordAcc, NoLock, Preserve) { | ||||
|                 VEND, 32 | ||||
|             } | ||||
|             Method(_S1D, 0, NotSerialized) { | ||||
|                 Return (0x00) | ||||
|             } | ||||
|             Method(_S2D, 0, NotSerialized) { | ||||
|                 Return (0x00) | ||||
|             } | ||||
|             Method(_S3D, 0, NotSerialized) { | ||||
|                 If (LEqual(VEND, 0x1001b36)) { | ||||
|                     Return (0x03)           // QXL | ||||
|                 } Else { | ||||
|                     Return (0x00) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
| /**************************************************************** | ||||
|  * PIIX4 PM | ||||
|  ****************************************************************/ | ||||
| @@ -132,6 +106,9 @@ DefinitionBlock ( | ||||
|  ****************************************************************/ | ||||
|  | ||||
|     Scope(\_SB.PCI0) { | ||||
|  | ||||
|         External(ISA, DeviceObj) | ||||
|  | ||||
|         Device(ISA) { | ||||
|             Name(_ADR, 0x00010000) | ||||
|  | ||||
|   | ||||
| @@ -3,12 +3,12 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x53, | ||||
| 0x44, | ||||
| 0x54, | ||||
| 0x87, | ||||
| 0x85, | ||||
| 0x11, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0x1, | ||||
| 0xb8, | ||||
| 0x8b, | ||||
| 0x42, | ||||
| 0x58, | ||||
| 0x50, | ||||
| @@ -146,7 +146,7 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x1, | ||||
| 0x10, | ||||
| 0x4e, | ||||
| 0x15, | ||||
| 0x18, | ||||
| 0x2e, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| @@ -163,9 +163,9 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x53, | ||||
| 0x11, | ||||
| 0x42, | ||||
| 0x7, | ||||
| 0xa, | ||||
| 0x6e, | ||||
| 0xa, | ||||
| 0x9e, | ||||
| 0x88, | ||||
| 0xd, | ||||
| 0x0, | ||||
| @@ -217,11 +217,59 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x0, | ||||
| 0xd, | ||||
| 0xff, | ||||
| 0xad, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0xa1, | ||||
| 0x88, | ||||
| 0xd, | ||||
| 0x0, | ||||
| 0x1, | ||||
| 0xc, | ||||
| 0x3, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0xf, | ||||
| 0xae, | ||||
| 0xff, | ||||
| 0xae, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0xf1, | ||||
| 0x0, | ||||
| 0x88, | ||||
| 0xd, | ||||
| 0x0, | ||||
| 0x1, | ||||
| 0xc, | ||||
| 0x3, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0x20, | ||||
| 0xaf, | ||||
| 0xdf, | ||||
| 0xaf, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0xc0, | ||||
| 0x0, | ||||
| 0x88, | ||||
| 0xd, | ||||
| 0x0, | ||||
| 0x1, | ||||
| 0xc, | ||||
| 0x3, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0xe4, | ||||
| 0xaf, | ||||
| 0xff, | ||||
| 0xff, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0xf3, | ||||
| 0x1c, | ||||
| 0x50, | ||||
| 0x87, | ||||
| 0x17, | ||||
| 0x0, | ||||
| @@ -347,7 +395,7 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x45, | ||||
| 0x53, | ||||
| 0xa, | ||||
| 0x5c, | ||||
| 0x8c, | ||||
| 0x50, | ||||
| 0x53, | ||||
| 0x33, | ||||
| @@ -358,7 +406,7 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x45, | ||||
| 0x53, | ||||
| 0xa, | ||||
| 0x60, | ||||
| 0x90, | ||||
| 0x50, | ||||
| 0x45, | ||||
| 0x33, | ||||
| @@ -369,7 +417,7 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x45, | ||||
| 0x53, | ||||
| 0xa, | ||||
| 0x68, | ||||
| 0x98, | ||||
| 0x50, | ||||
| 0x4c, | ||||
| 0x33, | ||||
| @@ -638,103 +686,6 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x79, | ||||
| 0x0, | ||||
| 0x10, | ||||
| 0x40, | ||||
| 0x6, | ||||
| 0x2e, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x42, | ||||
| 0x5f, | ||||
| 0x50, | ||||
| 0x43, | ||||
| 0x49, | ||||
| 0x30, | ||||
| 0x5b, | ||||
| 0x82, | ||||
| 0x43, | ||||
| 0x5, | ||||
| 0x56, | ||||
| 0x47, | ||||
| 0x41, | ||||
| 0x5f, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x41, | ||||
| 0x44, | ||||
| 0x52, | ||||
| 0xc, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0x2, | ||||
| 0x0, | ||||
| 0x5b, | ||||
| 0x80, | ||||
| 0x50, | ||||
| 0x43, | ||||
| 0x49, | ||||
| 0x43, | ||||
| 0x2, | ||||
| 0x0, | ||||
| 0xa, | ||||
| 0x4, | ||||
| 0x5b, | ||||
| 0x81, | ||||
| 0xb, | ||||
| 0x50, | ||||
| 0x43, | ||||
| 0x49, | ||||
| 0x43, | ||||
| 0x3, | ||||
| 0x56, | ||||
| 0x45, | ||||
| 0x4e, | ||||
| 0x44, | ||||
| 0x20, | ||||
| 0x14, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x31, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa4, | ||||
| 0x0, | ||||
| 0x14, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x32, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa4, | ||||
| 0x0, | ||||
| 0x14, | ||||
| 0x19, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x33, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa0, | ||||
| 0xe, | ||||
| 0x93, | ||||
| 0x56, | ||||
| 0x45, | ||||
| 0x4e, | ||||
| 0x44, | ||||
| 0xc, | ||||
| 0x36, | ||||
| 0x1b, | ||||
| 0x0, | ||||
| 0x1, | ||||
| 0xa4, | ||||
| 0xa, | ||||
| 0x3, | ||||
| 0xa1, | ||||
| 0x3, | ||||
| 0xa4, | ||||
| 0x0, | ||||
| 0x10, | ||||
| 0x25, | ||||
| 0x2e, | ||||
| 0x5f, | ||||
| @@ -860,7 +811,7 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x4e, | ||||
| 0x1, | ||||
| 0x10, | ||||
| 0x4b, | ||||
| 0x4a, | ||||
| 0x1e, | ||||
| 0x2f, | ||||
| 0x3, | ||||
| @@ -878,7 +829,7 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x5f, | ||||
| 0x5b, | ||||
| 0x82, | ||||
| 0x2d, | ||||
| 0x2c, | ||||
| 0x53, | ||||
| 0x4d, | ||||
| 0x43, | ||||
| @@ -898,9 +849,8 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x53, | ||||
| 0x54, | ||||
| 0x41, | ||||
| 0xb, | ||||
| 0x0, | ||||
| 0xff, | ||||
| 0xa, | ||||
| 0xf0, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x43, | ||||
| @@ -4061,7 +4011,7 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x1, | ||||
| 0x10, | ||||
| 0x47, | ||||
| 0xe, | ||||
| 0x11, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x42, | ||||
| @@ -4291,6 +4241,54 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x3, | ||||
| 0x75, | ||||
| 0x60, | ||||
| 0x5b, | ||||
| 0x82, | ||||
| 0x2e, | ||||
| 0x50, | ||||
| 0x52, | ||||
| 0x45, | ||||
| 0x53, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x48, | ||||
| 0x49, | ||||
| 0x44, | ||||
| 0xd, | ||||
| 0x41, | ||||
| 0x43, | ||||
| 0x50, | ||||
| 0x49, | ||||
| 0x30, | ||||
| 0x30, | ||||
| 0x30, | ||||
| 0x34, | ||||
| 0x0, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x43, | ||||
| 0x52, | ||||
| 0x53, | ||||
| 0x11, | ||||
| 0xd, | ||||
| 0xa, | ||||
| 0xa, | ||||
| 0x47, | ||||
| 0x1, | ||||
| 0x0, | ||||
| 0xaf, | ||||
| 0x0, | ||||
| 0xaf, | ||||
| 0x0, | ||||
| 0x20, | ||||
| 0x79, | ||||
| 0x0, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x54, | ||||
| 0x41, | ||||
| 0xa, | ||||
| 0xb, | ||||
| 0x10, | ||||
| 0x42, | ||||
| 0xc, | ||||
| @@ -4488,5 +4486,5 @@ static unsigned char AcpiDsdtAmlCode[] = { | ||||
| 0x0 | ||||
| }; | ||||
| static unsigned short piix_dsdt_applesmc_sta[] = { | ||||
| 0x384 | ||||
| 0x353 | ||||
| }; | ||||
|   | ||||
| @@ -221,10 +221,16 @@ static void pc_init1(QEMUMachineInitArgs *args, | ||||
|     } else { | ||||
|         for(i = 0; i < MAX_IDE_BUS; i++) { | ||||
|             ISADevice *dev; | ||||
|             char busname[] = "ide.0"; | ||||
|             dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], | ||||
|                                ide_irq[i], | ||||
|                                hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); | ||||
|             idebus[i] = qdev_get_child_bus(DEVICE(dev), "ide.0"); | ||||
|             /* | ||||
|              * The ide bus name is ide.0 for the first bus and ide.1 for the | ||||
|              * second one. | ||||
|              */ | ||||
|             busname[4] = '0' + i; | ||||
|             idebus[i] = qdev_get_child_bus(DEVICE(dev), busname); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -72,6 +72,8 @@ DefinitionBlock ( | ||||
|             Name(_ADR, 0x00) | ||||
|             Name(_UID, 1) | ||||
|  | ||||
|             External(ISA, DeviceObj) | ||||
|  | ||||
|             // _OSC: based on sample of ACPI3.0b spec | ||||
|             Name(SUPP, 0) // PCI _OSC Support Field value | ||||
|             Name(CTRL, 0) // PCI _OSC Control Field value | ||||
| @@ -133,26 +135,6 @@ DefinitionBlock ( | ||||
| #include "acpi-dsdt-hpet.dsl" | ||||
|  | ||||
|  | ||||
| /**************************************************************** | ||||
|  * VGA | ||||
|  ****************************************************************/ | ||||
|  | ||||
|     Scope(\_SB.PCI0) { | ||||
|         Device(VGA) { | ||||
|             Name(_ADR, 0x00010000) | ||||
|             Method(_S1D, 0, NotSerialized) { | ||||
|                 Return (0x00) | ||||
|             } | ||||
|             Method(_S2D, 0, NotSerialized) { | ||||
|                 Return (0x00) | ||||
|             } | ||||
|             Method(_S3D, 0, NotSerialized) { | ||||
|                 Return (0x00) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
| /**************************************************************** | ||||
|  * LPC ISA bridge | ||||
|  ****************************************************************/ | ||||
| @@ -160,8 +142,7 @@ DefinitionBlock ( | ||||
|     Scope(\_SB.PCI0) { | ||||
|         /* PCI D31:f0 LPC ISA bridge */ | ||||
|         Device(ISA) { | ||||
|             /* PCI D31:f0 */ | ||||
|             Name(_ADR, 0x001f0000) | ||||
|             Name (_ADR, 0x001F0000)  // _ADR: Address | ||||
|  | ||||
|             /* ICH9 PCI to ISA irq remapping */ | ||||
|             OperationRegion(PIRQ, PCI_Config, 0x60, 0x0C) | ||||
|   | ||||
| @@ -3,12 +3,12 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { | ||||
| 0x53, | ||||
| 0x44, | ||||
| 0x54, | ||||
| 0xdf, | ||||
| 0xd7, | ||||
| 0x1c, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0x1, | ||||
| 0xff, | ||||
| 0x3e, | ||||
| 0x42, | ||||
| 0x58, | ||||
| 0x50, | ||||
| @@ -415,11 +415,11 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0xf7, | ||||
| 0xd7, | ||||
| 0xc, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0xf8, | ||||
| 0xd8, | ||||
| 0xc, | ||||
| 0x88, | ||||
| 0xd, | ||||
| @@ -853,61 +853,6 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { | ||||
| 0x79, | ||||
| 0x0, | ||||
| 0x10, | ||||
| 0x36, | ||||
| 0x2e, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x42, | ||||
| 0x5f, | ||||
| 0x50, | ||||
| 0x43, | ||||
| 0x49, | ||||
| 0x30, | ||||
| 0x5b, | ||||
| 0x82, | ||||
| 0x2a, | ||||
| 0x56, | ||||
| 0x47, | ||||
| 0x41, | ||||
| 0x5f, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x41, | ||||
| 0x44, | ||||
| 0x52, | ||||
| 0xc, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0x1, | ||||
| 0x0, | ||||
| 0x14, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x31, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa4, | ||||
| 0x0, | ||||
| 0x14, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x32, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa4, | ||||
| 0x0, | ||||
| 0x14, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x33, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa4, | ||||
| 0x0, | ||||
| 0x10, | ||||
| 0x4c, | ||||
| 0x7, | ||||
| 0x2e, | ||||
| @@ -1033,7 +978,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { | ||||
| 0x4e, | ||||
| 0x1, | ||||
| 0x10, | ||||
| 0x4b, | ||||
| 0x4a, | ||||
| 0x1e, | ||||
| 0x2f, | ||||
| 0x3, | ||||
| @@ -1051,7 +996,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { | ||||
| 0x5f, | ||||
| 0x5b, | ||||
| 0x82, | ||||
| 0x2d, | ||||
| 0x2c, | ||||
| 0x53, | ||||
| 0x4d, | ||||
| 0x43, | ||||
| @@ -1071,9 +1016,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { | ||||
| 0x53, | ||||
| 0x54, | ||||
| 0x41, | ||||
| 0xb, | ||||
| 0x0, | ||||
| 0xff, | ||||
| 0xa, | ||||
| 0xf0, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x43, | ||||
| @@ -7016,7 +6960,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { | ||||
| 0x1, | ||||
| 0x10, | ||||
| 0x47, | ||||
| 0xe, | ||||
| 0x11, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x42, | ||||
| @@ -7121,8 +7065,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { | ||||
| 0x54, | ||||
| 0x1, | ||||
| 0xb, | ||||
| 0x0, | ||||
| 0xaf, | ||||
| 0xd8, | ||||
| 0xc, | ||||
| 0xa, | ||||
| 0x20, | ||||
| 0x5b, | ||||
| @@ -7246,6 +7190,54 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { | ||||
| 0x3, | ||||
| 0x75, | ||||
| 0x60, | ||||
| 0x5b, | ||||
| 0x82, | ||||
| 0x2e, | ||||
| 0x50, | ||||
| 0x52, | ||||
| 0x45, | ||||
| 0x53, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x48, | ||||
| 0x49, | ||||
| 0x44, | ||||
| 0xd, | ||||
| 0x41, | ||||
| 0x43, | ||||
| 0x50, | ||||
| 0x49, | ||||
| 0x30, | ||||
| 0x30, | ||||
| 0x30, | ||||
| 0x34, | ||||
| 0x0, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x43, | ||||
| 0x52, | ||||
| 0x53, | ||||
| 0x11, | ||||
| 0xd, | ||||
| 0xa, | ||||
| 0xa, | ||||
| 0x47, | ||||
| 0x1, | ||||
| 0xd8, | ||||
| 0xc, | ||||
| 0xd8, | ||||
| 0xc, | ||||
| 0x0, | ||||
| 0x20, | ||||
| 0x79, | ||||
| 0x0, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x54, | ||||
| 0x41, | ||||
| 0xa, | ||||
| 0xb, | ||||
| 0x10, | ||||
| 0x4f, | ||||
| 0x8, | ||||
| @@ -7392,5 +7384,5 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { | ||||
| 0x0 | ||||
| }; | ||||
| static unsigned short q35_dsdt_applesmc_sta[] = { | ||||
| 0x431 | ||||
| 0x3fa | ||||
| }; | ||||
|   | ||||
| @@ -46,5 +46,55 @@ DefinitionBlock ("ssdt-pcihp.aml", "SSDT", 0x01, "BXPC", "BXSSDTPCIHP", 0x1) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ACPI_EXTRACT_DEVICE_START ssdt_pcinohp_start | ||||
|         ACPI_EXTRACT_DEVICE_END ssdt_pcinohp_end | ||||
|         ACPI_EXTRACT_DEVICE_STRING ssdt_pcinohp_name | ||||
|  | ||||
|         // Extract the offsets of the device name, address dword and the slot | ||||
|         // name byte - we fill them in for each device. | ||||
|         Device(SBB) { | ||||
|             ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pcinohp_adr | ||||
|             Name(_ADR, 0xAA0000) | ||||
|         } | ||||
|  | ||||
|         ACPI_EXTRACT_DEVICE_START ssdt_pcivga_start | ||||
|         ACPI_EXTRACT_DEVICE_END ssdt_pcivga_end | ||||
|         ACPI_EXTRACT_DEVICE_STRING ssdt_pcivga_name | ||||
|  | ||||
|         // Extract the offsets of the device name, address dword and the slot | ||||
|         // name byte - we fill them in for each device. | ||||
|         Device(SCC) { | ||||
|             ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pcivga_adr | ||||
|             Name(_ADR, 0xAA0000) | ||||
|             Method(_S1D, 0, NotSerialized) { | ||||
|                 Return (0x00) | ||||
|             } | ||||
|             Method(_S2D, 0, NotSerialized) { | ||||
|                 Return (0x00) | ||||
|             } | ||||
|             Method(_S3D, 0, NotSerialized) { | ||||
|                 Return (0x00) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ACPI_EXTRACT_DEVICE_START ssdt_pciqxl_start | ||||
|         ACPI_EXTRACT_DEVICE_END ssdt_pciqxl_end | ||||
|         ACPI_EXTRACT_DEVICE_STRING ssdt_pciqxl_name | ||||
|  | ||||
|         // Extract the offsets of the device name, address dword and the slot | ||||
|         // name byte - we fill them in for each device. | ||||
|         Device(SDD) { | ||||
|             ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pciqxl_adr | ||||
|             Name(_ADR, 0xAA0000) | ||||
|             Method(_S1D, 0, NotSerialized) { | ||||
|                 Return (0x00) | ||||
|             } | ||||
|             Method(_S2D, 0, NotSerialized) { | ||||
|                 Return (0x00) | ||||
|             } | ||||
|             Method(_S3D, 0, NotSerialized) { | ||||
|                 Return (0x03)           // QXL | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,23 +1,38 @@ | ||||
| static unsigned char ssdt_pcihp_name[] = { | ||||
| 0x33 | ||||
| 0x34 | ||||
| }; | ||||
| static unsigned char ssdt_pcivga_end[] = { | ||||
| 0x99 | ||||
| }; | ||||
| static unsigned char ssdt_pcivga_name[] = { | ||||
| 0x70 | ||||
| }; | ||||
| static unsigned char ssdt_pcihp_adr[] = { | ||||
| 0x44 | ||||
| 0x45 | ||||
| }; | ||||
| static unsigned char ssdt_pcinohp_end[] = { | ||||
| 0x6d | ||||
| }; | ||||
| static unsigned char ssdt_pcihp_end[] = { | ||||
| 0x5b | ||||
| 0x5c | ||||
| }; | ||||
| static unsigned char ssdt_pciqxl_start[] = { | ||||
| 0x99 | ||||
| }; | ||||
| static unsigned char ssdt_pcinohp_name[] = { | ||||
| 0x5f | ||||
| }; | ||||
| static unsigned char ssdp_pcihp_aml[] = { | ||||
| 0x53, | ||||
| 0x53, | ||||
| 0x44, | ||||
| 0x54, | ||||
| 0x5b, | ||||
| 0xc6, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0x1, | ||||
| 0xe8, | ||||
| 0x6b, | ||||
| 0x42, | ||||
| 0x58, | ||||
| 0x50, | ||||
| @@ -45,7 +60,8 @@ static unsigned char ssdp_pcihp_aml[] = { | ||||
| 0x13, | ||||
| 0x20, | ||||
| 0x10, | ||||
| 0x36, | ||||
| 0x41, | ||||
| 0xa, | ||||
| 0x5c, | ||||
| 0x2e, | ||||
| 0x5f, | ||||
| @@ -98,11 +114,138 @@ static unsigned char ssdp_pcihp_aml[] = { | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x55, | ||||
| 0x4e | ||||
| 0x4e, | ||||
| 0x5b, | ||||
| 0x82, | ||||
| 0xf, | ||||
| 0x53, | ||||
| 0x42, | ||||
| 0x42, | ||||
| 0x5f, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x41, | ||||
| 0x44, | ||||
| 0x52, | ||||
| 0xc, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0xaa, | ||||
| 0x0, | ||||
| 0x5b, | ||||
| 0x82, | ||||
| 0x2a, | ||||
| 0x53, | ||||
| 0x43, | ||||
| 0x43, | ||||
| 0x5f, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x41, | ||||
| 0x44, | ||||
| 0x52, | ||||
| 0xc, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0xaa, | ||||
| 0x0, | ||||
| 0x14, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x31, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa4, | ||||
| 0x0, | ||||
| 0x14, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x32, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa4, | ||||
| 0x0, | ||||
| 0x14, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x33, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa4, | ||||
| 0x0, | ||||
| 0x5b, | ||||
| 0x82, | ||||
| 0x2b, | ||||
| 0x53, | ||||
| 0x44, | ||||
| 0x44, | ||||
| 0x5f, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x41, | ||||
| 0x44, | ||||
| 0x52, | ||||
| 0xc, | ||||
| 0x0, | ||||
| 0x0, | ||||
| 0xaa, | ||||
| 0x0, | ||||
| 0x14, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x31, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa4, | ||||
| 0x0, | ||||
| 0x14, | ||||
| 0x8, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x32, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa4, | ||||
| 0x0, | ||||
| 0x14, | ||||
| 0x9, | ||||
| 0x5f, | ||||
| 0x53, | ||||
| 0x33, | ||||
| 0x44, | ||||
| 0x0, | ||||
| 0xa4, | ||||
| 0xa, | ||||
| 0x3 | ||||
| }; | ||||
| static unsigned char ssdt_pciqxl_adr[] = { | ||||
| 0xa6 | ||||
| }; | ||||
| static unsigned char ssdt_pcinohp_adr[] = { | ||||
| 0x69 | ||||
| }; | ||||
| static unsigned char ssdt_pcivga_adr[] = { | ||||
| 0x7a | ||||
| }; | ||||
| static unsigned char ssdt_pciqxl_name[] = { | ||||
| 0x9c | ||||
| }; | ||||
| static unsigned char ssdt_pcivga_start[] = { | ||||
| 0x6d | ||||
| }; | ||||
| static unsigned char ssdt_pciqxl_end[] = { | ||||
| 0xc6 | ||||
| }; | ||||
| static unsigned char ssdt_pcihp_start[] = { | ||||
| 0x30 | ||||
| 0x31 | ||||
| }; | ||||
| static unsigned char ssdt_pcihp_id[] = { | ||||
| 0x3d | ||||
| 0x3e | ||||
| }; | ||||
| static unsigned char ssdt_pcinohp_start[] = { | ||||
| 0x5c | ||||
| }; | ||||
|   | ||||
| @@ -40,7 +40,7 @@ | ||||
| #define AHCI_PORT_PRIV_DMA_SZ     (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \ | ||||
|                                    AHCI_RX_FIS_SZ) | ||||
|  | ||||
| #define AHCI_IRQ_ON_SG            (1 << 31) | ||||
| #define AHCI_IRQ_ON_SG            (1U << 31) | ||||
| #define AHCI_CMD_ATAPI            (1 << 5) | ||||
| #define AHCI_CMD_WRITE            (1 << 6) | ||||
| #define AHCI_CMD_PREFETCH         (1 << 7) | ||||
| @@ -61,7 +61,7 @@ | ||||
| /* HOST_CTL bits */ | ||||
| #define HOST_CTL_RESET            (1 << 0)  /* reset controller; self-clear */ | ||||
| #define HOST_CTL_IRQ_EN           (1 << 1)  /* global IRQ enable */ | ||||
| #define HOST_CTL_AHCI_EN          (1 << 31) /* AHCI enabled */ | ||||
| #define HOST_CTL_AHCI_EN          (1U << 31) /* AHCI enabled */ | ||||
|  | ||||
| /* HOST_CAP bits */ | ||||
| #define HOST_CAP_SSC              (1 << 14) /* Slumber capable */ | ||||
| @@ -69,7 +69,7 @@ | ||||
| #define HOST_CAP_CLO              (1 << 24) /* Command List Override support */ | ||||
| #define HOST_CAP_SSS              (1 << 27) /* Staggered Spin-up */ | ||||
| #define HOST_CAP_NCQ              (1 << 30) /* Native Command Queueing */ | ||||
| #define HOST_CAP_64               (1 << 31) /* PCI DAC (64-bit DMA) support */ | ||||
| #define HOST_CAP_64               (1U << 31) /* PCI DAC (64-bit DMA) support */ | ||||
|  | ||||
| /* registers for each SATA port */ | ||||
| #define PORT_LST_ADDR             0x00 /* command list DMA addr */ | ||||
| @@ -89,7 +89,7 @@ | ||||
| #define PORT_RESERVED             0x3c /* reserved */ | ||||
|  | ||||
| /* PORT_IRQ_{STAT,MASK} bits */ | ||||
| #define PORT_IRQ_COLD_PRES        (1 << 31) /* cold presence detect */ | ||||
| #define PORT_IRQ_COLD_PRES        (1U << 31) /* cold presence detect */ | ||||
| #define PORT_IRQ_TF_ERR           (1 << 30) /* task file error */ | ||||
| #define PORT_IRQ_HBUS_ERR         (1 << 29) /* host bus fatal error */ | ||||
| #define PORT_IRQ_HBUS_DATA_ERR    (1 << 28) /* host bus data error */ | ||||
| @@ -151,7 +151,7 @@ | ||||
| #define PORT_IRQ_STAT_HBDS        (1 << 28) /* Host Bus Data Error Status */ | ||||
| #define PORT_IRQ_STAT_HBFS        (1 << 29) /* Host Bus Fatal Error Status */ | ||||
| #define PORT_IRQ_STAT_TFES        (1 << 30) /* Task File Error Status */ | ||||
| #define PORT_IRQ_STAT_CPDS        (1 << 31) /* Code Port Detect Status */ | ||||
| #define PORT_IRQ_STAT_CPDS        (1U << 31) /* Code Port Detect Status */ | ||||
|  | ||||
| /* ap->flags bits */ | ||||
| #define AHCI_FLAG_NO_NCQ                  (1 << 24) | ||||
|   | ||||
| @@ -281,7 +281,7 @@ static void kbd_write_command(void *opaque, hwaddr addr, | ||||
|         kbd_update_irq(s); | ||||
|         break; | ||||
|     case KBD_CCMD_READ_INPORT: | ||||
|         kbd_queue(s, 0x00, 0); | ||||
|         kbd_queue(s, 0x80, 0); | ||||
|         break; | ||||
|     case KBD_CCMD_READ_OUTPORT: | ||||
|         kbd_queue(s, s->outport, 0); | ||||
|   | ||||
| @@ -93,9 +93,6 @@ static void ioapic_set_irq(void *opaque, int vector, int level) | ||||
|         uint32_t mask = 1 << vector; | ||||
|         uint64_t entry = s->ioredtbl[vector]; | ||||
|  | ||||
|         if (entry & (1 << IOAPIC_LVT_POLARITY_SHIFT)) { | ||||
|             level = !level; | ||||
|         } | ||||
|         if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) == | ||||
|             IOAPIC_TRIGGER_LEVEL) { | ||||
|             /* level triggered */ | ||||
|   | ||||
| @@ -228,7 +228,7 @@ int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs) | ||||
|  | ||||
|     encap.cap = KVM_CAP_IRQ_MPIC; | ||||
|     encap.args[0] = opp->fd; | ||||
|     encap.args[1] = cs->cpu_index; | ||||
|     encap.args[1] = kvm_arch_vcpu_id(cs); | ||||
|  | ||||
|     return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap); | ||||
| } | ||||
|   | ||||
| @@ -33,6 +33,17 @@ | ||||
| #include "qemu/error-report.h" | ||||
| #include "qapi/visitor.h" | ||||
|  | ||||
| static int get_cpu_index_by_dt_id(int cpu_dt_id) | ||||
| { | ||||
|     PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id); | ||||
|  | ||||
|     if (cpu) { | ||||
|         return cpu->parent_obj.cpu_index; | ||||
|     } | ||||
|  | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu) | ||||
| { | ||||
|     CPUState *cs = CPU(cpu); | ||||
| @@ -659,7 +670,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
| static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
|                           target_ulong opcode, target_ulong *args) | ||||
| { | ||||
|     target_ulong server = args[0]; | ||||
|     target_ulong server = get_cpu_index_by_dt_id(args[0]); | ||||
|     target_ulong mfrr = args[1]; | ||||
|  | ||||
|     if (server >= spapr->icp->nr_servers) { | ||||
| @@ -728,7 +739,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
|     } | ||||
|  | ||||
|     nr = rtas_ld(args, 0); | ||||
|     server = rtas_ld(args, 1); | ||||
|     server = get_cpu_index_by_dt_id(rtas_ld(args, 1)); | ||||
|     priority = rtas_ld(args, 2); | ||||
|  | ||||
|     if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers) | ||||
|   | ||||
| @@ -65,7 +65,7 @@ static void icp_get_kvm_state(ICPState *ss) | ||||
|     ret = kvm_vcpu_ioctl(ss->cs, KVM_GET_ONE_REG, ®); | ||||
|     if (ret != 0) { | ||||
|         error_report("Unable to retrieve KVM interrupt controller state" | ||||
|                 " for CPU %d: %s", ss->cs->cpu_index, strerror(errno)); | ||||
|                 " for CPU %ld: %s", kvm_arch_vcpu_id(ss->cs), strerror(errno)); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
| @@ -97,7 +97,7 @@ static int icp_set_kvm_state(ICPState *ss, int version_id) | ||||
|     ret = kvm_vcpu_ioctl(ss->cs, KVM_SET_ONE_REG, ®); | ||||
|     if (ret != 0) { | ||||
|         error_report("Unable to restore KVM interrupt controller state (0x%" | ||||
|                 PRIx64 ") for CPU %d: %s", state, ss->cs->cpu_index, | ||||
|                 PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(ss->cs), | ||||
|                 strerror(errno)); | ||||
|         return ret; | ||||
|     } | ||||
| @@ -325,15 +325,15 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu) | ||||
|         struct kvm_enable_cap xics_enable_cap = { | ||||
|             .cap = KVM_CAP_IRQ_XICS, | ||||
|             .flags = 0, | ||||
|             .args = {icpkvm->kernel_xics_fd, cs->cpu_index, 0, 0}, | ||||
|             .args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0}, | ||||
|         }; | ||||
|  | ||||
|         ss->cs = cs; | ||||
|  | ||||
|         ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap); | ||||
|         if (ret < 0) { | ||||
|             error_report("Unable to connect CPU%d to kernel XICS: %s", | ||||
|                     cs->cpu_index, strerror(errno)); | ||||
|             error_report("Unable to connect CPU%ld to kernel XICS: %s", | ||||
|                     kvm_arch_vcpu_id(cs), strerror(errno)); | ||||
|             exit(1); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -55,7 +55,7 @@ static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params) | ||||
|                            &entry, &kernel_low, &kernel_high, 1, | ||||
|                            ELF_MACHINE, 0); | ||||
|  | ||||
|     if (!kernel_size) { | ||||
|     if (kernel_size <= 0) { | ||||
|         fprintf(stderr, "qemu: could not load kernel '%s'\n", | ||||
|                 loader_params->kernel_filename); | ||||
|         exit(1); | ||||
|   | ||||
| @@ -32,3 +32,6 @@ obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o | ||||
|  | ||||
| obj-$(CONFIG_VIRTIO) += virtio-net.o | ||||
| obj-y += vhost_net.o | ||||
|  | ||||
| obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \ | ||||
| 			fsl_etsec/rings.o fsl_etsec/miim.o | ||||
|   | ||||
							
								
								
									
										465
									
								
								hw/net/fsl_etsec/etsec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										465
									
								
								hw/net/fsl_etsec/etsec.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,465 @@ | ||||
| /* | ||||
|  * QEMU Freescale eTSEC Emulator | ||||
|  * | ||||
|  * Copyright (c) 2011-2013 AdaCore | ||||
|  * | ||||
|  * 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. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * This implementation doesn't include ring priority, TCP/IP Off-Load, QoS. | ||||
|  */ | ||||
|  | ||||
| #include "sysemu/sysemu.h" | ||||
| #include "hw/sysbus.h" | ||||
| #include "trace.h" | ||||
| #include "hw/ptimer.h" | ||||
| #include "etsec.h" | ||||
| #include "registers.h" | ||||
|  | ||||
| /* #define HEX_DUMP */ | ||||
| /* #define DEBUG_REGISTER */ | ||||
|  | ||||
| #ifdef DEBUG_REGISTER | ||||
| static const int debug_etsec = 1; | ||||
| #else | ||||
| static const int debug_etsec; | ||||
| #endif | ||||
|  | ||||
| #define DPRINTF(fmt, ...) do {                 \ | ||||
|     if (debug_etsec) {                         \ | ||||
|         qemu_log(fmt , ## __VA_ARGS__);        \ | ||||
|     }                                          \ | ||||
|     } while (0) | ||||
|  | ||||
| static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size) | ||||
| { | ||||
|     eTSEC          *etsec     = opaque; | ||||
|     uint32_t        reg_index = addr / 4; | ||||
|     eTSEC_Register *reg       = NULL; | ||||
|     uint32_t        ret       = 0x0; | ||||
|  | ||||
|     assert(reg_index < ETSEC_REG_NUMBER); | ||||
|  | ||||
|     reg = &etsec->regs[reg_index]; | ||||
|  | ||||
|  | ||||
|     switch (reg->access) { | ||||
|     case ACC_WO: | ||||
|         ret = 0x00000000; | ||||
|         break; | ||||
|  | ||||
|     case ACC_RW: | ||||
|     case ACC_W1C: | ||||
|     case ACC_RO: | ||||
|     default: | ||||
|         ret = reg->value; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     DPRINTF("Read  0x%08x @ 0x" TARGET_FMT_plx | ||||
|             "                            : %s (%s)\n", | ||||
|             ret, addr, reg->name, reg->desc); | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static void write_tstat(eTSEC          *etsec, | ||||
|                         eTSEC_Register *reg, | ||||
|                         uint32_t        reg_index, | ||||
|                         uint32_t        value) | ||||
| { | ||||
|     int i = 0; | ||||
|  | ||||
|     for (i = 0; i < 8; i++) { | ||||
|         /* Check THLTi flag in TSTAT */ | ||||
|         if (value & (1 << (31 - i))) { | ||||
|             etsec_walk_tx_ring(etsec, i); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* Write 1 to clear */ | ||||
|     reg->value &= ~value; | ||||
| } | ||||
|  | ||||
| static void write_rstat(eTSEC          *etsec, | ||||
|                         eTSEC_Register *reg, | ||||
|                         uint32_t        reg_index, | ||||
|                         uint32_t        value) | ||||
| { | ||||
|     int i = 0; | ||||
|  | ||||
|     for (i = 0; i < 8; i++) { | ||||
|         /* Check QHLTi flag in RSTAT */ | ||||
|         if (value & (1 << (23 - i)) && !(reg->value & (1 << (23 - i)))) { | ||||
|             etsec_walk_rx_ring(etsec, i); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* Write 1 to clear */ | ||||
|     reg->value &= ~value; | ||||
| } | ||||
|  | ||||
| static void write_tbasex(eTSEC          *etsec, | ||||
|                          eTSEC_Register *reg, | ||||
|                          uint32_t        reg_index, | ||||
|                          uint32_t        value) | ||||
| { | ||||
|     reg->value = value & ~0x7; | ||||
|  | ||||
|     /* Copy this value in the ring's TxBD pointer */ | ||||
|     etsec->regs[TBPTR0 + (reg_index - TBASE0)].value = value & ~0x7; | ||||
| } | ||||
|  | ||||
| static void write_rbasex(eTSEC          *etsec, | ||||
|                          eTSEC_Register *reg, | ||||
|                          uint32_t        reg_index, | ||||
|                          uint32_t        value) | ||||
| { | ||||
|     reg->value = value & ~0x7; | ||||
|  | ||||
|     /* Copy this value in the ring's RxBD pointer */ | ||||
|     etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7; | ||||
| } | ||||
|  | ||||
| static void write_ievent(eTSEC          *etsec, | ||||
|                          eTSEC_Register *reg, | ||||
|                          uint32_t        reg_index, | ||||
|                          uint32_t        value) | ||||
| { | ||||
|     /* Write 1 to clear */ | ||||
|     reg->value &= ~value; | ||||
|  | ||||
|     if (!(reg->value & (IEVENT_TXF | IEVENT_TXF))) { | ||||
|         qemu_irq_lower(etsec->tx_irq); | ||||
|     } | ||||
|     if (!(reg->value & (IEVENT_RXF | IEVENT_RXF))) { | ||||
|         qemu_irq_lower(etsec->rx_irq); | ||||
|     } | ||||
|  | ||||
|     if (!(reg->value & (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC | | ||||
|                         IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC | | ||||
|                         IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ | | ||||
|                         IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE | | ||||
|                         IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD | | ||||
|                         IEVENT_MMRW))) { | ||||
|         qemu_irq_lower(etsec->err_irq); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void write_dmactrl(eTSEC          *etsec, | ||||
|                           eTSEC_Register *reg, | ||||
|                           uint32_t        reg_index, | ||||
|                           uint32_t        value) | ||||
| { | ||||
|     reg->value = value; | ||||
|  | ||||
|     if (value & DMACTRL_GRS) { | ||||
|  | ||||
|         if (etsec->rx_buffer_len != 0) { | ||||
|             /* Graceful receive stop delayed until end of frame */ | ||||
|         } else { | ||||
|             /* Graceful receive stop now */ | ||||
|             etsec->regs[IEVENT].value |= IEVENT_GRSC; | ||||
|             if (etsec->regs[IMASK].value & IMASK_GRSCEN) { | ||||
|                 qemu_irq_raise(etsec->err_irq); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (value & DMACTRL_GTS) { | ||||
|  | ||||
|         if (etsec->tx_buffer_len != 0) { | ||||
|             /* Graceful transmit stop delayed until end of frame */ | ||||
|         } else { | ||||
|             /* Graceful transmit stop now */ | ||||
|             etsec->regs[IEVENT].value |= IEVENT_GTSC; | ||||
|             if (etsec->regs[IMASK].value & IMASK_GTSCEN) { | ||||
|                 qemu_irq_raise(etsec->err_irq); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (!(value & DMACTRL_WOP)) { | ||||
|         /* Start polling */ | ||||
|         ptimer_stop(etsec->ptimer); | ||||
|         ptimer_set_count(etsec->ptimer, 1); | ||||
|         ptimer_run(etsec->ptimer, 1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void etsec_write(void     *opaque, | ||||
|                         hwaddr    addr, | ||||
|                         uint64_t  value, | ||||
|                         unsigned  size) | ||||
| { | ||||
|     eTSEC          *etsec     = opaque; | ||||
|     uint32_t        reg_index = addr / 4; | ||||
|     eTSEC_Register *reg       = NULL; | ||||
|     uint32_t        before    = 0x0; | ||||
|  | ||||
|     assert(reg_index < ETSEC_REG_NUMBER); | ||||
|  | ||||
|     reg = &etsec->regs[reg_index]; | ||||
|     before = reg->value; | ||||
|  | ||||
|     switch (reg_index) { | ||||
|     case IEVENT: | ||||
|         write_ievent(etsec, reg, reg_index, value); | ||||
|         break; | ||||
|  | ||||
|     case DMACTRL: | ||||
|         write_dmactrl(etsec, reg, reg_index, value); | ||||
|         break; | ||||
|  | ||||
|     case TSTAT: | ||||
|         write_tstat(etsec, reg, reg_index, value); | ||||
|         break; | ||||
|  | ||||
|     case RSTAT: | ||||
|         write_rstat(etsec, reg, reg_index, value); | ||||
|         break; | ||||
|  | ||||
|     case TBASE0 ... TBASE7: | ||||
|         write_tbasex(etsec, reg, reg_index, value); | ||||
|         break; | ||||
|  | ||||
|     case RBASE0 ... RBASE7: | ||||
|         write_rbasex(etsec, reg, reg_index, value); | ||||
|         break; | ||||
|  | ||||
|     case MIIMCFG ... MIIMIND: | ||||
|         etsec_write_miim(etsec, reg, reg_index, value); | ||||
|         break; | ||||
|  | ||||
|     default: | ||||
|         /* Default handling */ | ||||
|         switch (reg->access) { | ||||
|  | ||||
|         case ACC_RW: | ||||
|         case ACC_WO: | ||||
|             reg->value = value; | ||||
|             break; | ||||
|  | ||||
|         case ACC_W1C: | ||||
|             reg->value &= ~value; | ||||
|             break; | ||||
|  | ||||
|         case ACC_RO: | ||||
|         default: | ||||
|             /* Read Only or Unknown register */ | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     DPRINTF("Write 0x%08x @ 0x" TARGET_FMT_plx | ||||
|             " val:0x%08x->0x%08x : %s (%s)\n", | ||||
|             (unsigned int)value, addr, before, reg->value, | ||||
|             reg->name, reg->desc); | ||||
| } | ||||
|  | ||||
| static const MemoryRegionOps etsec_ops = { | ||||
|     .read = etsec_read, | ||||
|     .write = etsec_write, | ||||
|     .endianness = DEVICE_NATIVE_ENDIAN, | ||||
|     .impl = { | ||||
|         .min_access_size = 4, | ||||
|         .max_access_size = 4, | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| static void etsec_timer_hit(void *opaque) | ||||
| { | ||||
|     eTSEC *etsec = opaque; | ||||
|  | ||||
|     ptimer_stop(etsec->ptimer); | ||||
|  | ||||
|     if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) { | ||||
|  | ||||
|         if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) { | ||||
|             etsec_walk_tx_ring(etsec, 0); | ||||
|         } | ||||
|         ptimer_set_count(etsec->ptimer, 1); | ||||
|         ptimer_run(etsec->ptimer, 1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void etsec_reset(DeviceState *d) | ||||
| { | ||||
|     eTSEC *etsec = ETSEC_COMMON(d); | ||||
|     int i = 0; | ||||
|     int reg_index = 0; | ||||
|  | ||||
|     /* Default value for all registers */ | ||||
|     for (i = 0; i < ETSEC_REG_NUMBER; i++) { | ||||
|         etsec->regs[i].name   = "Reserved"; | ||||
|         etsec->regs[i].desc   = ""; | ||||
|         etsec->regs[i].access = ACC_UNKNOWN; | ||||
|         etsec->regs[i].value  = 0x00000000; | ||||
|     } | ||||
|  | ||||
|     /* Set-up known registers */ | ||||
|     for (i = 0; eTSEC_registers_def[i].name != NULL; i++) { | ||||
|  | ||||
|         reg_index = eTSEC_registers_def[i].offset / 4; | ||||
|  | ||||
|         etsec->regs[reg_index].name   = eTSEC_registers_def[i].name; | ||||
|         etsec->regs[reg_index].desc   = eTSEC_registers_def[i].desc; | ||||
|         etsec->regs[reg_index].access = eTSEC_registers_def[i].access; | ||||
|         etsec->regs[reg_index].value  = eTSEC_registers_def[i].reset; | ||||
|     } | ||||
|  | ||||
|     etsec->tx_buffer     = NULL; | ||||
|     etsec->tx_buffer_len = 0; | ||||
|     etsec->rx_buffer     = NULL; | ||||
|     etsec->rx_buffer_len = 0; | ||||
|  | ||||
|     etsec->phy_status = | ||||
|         MII_SR_EXTENDED_CAPS    | MII_SR_LINK_STATUS   | MII_SR_AUTONEG_CAPS  | | ||||
|         MII_SR_AUTONEG_COMPLETE | MII_SR_PREAMBLE_SUPPRESS | | ||||
|         MII_SR_EXTENDED_STATUS  | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS | | ||||
|         MII_SR_10T_HD_CAPS      | MII_SR_10T_FD_CAPS   | MII_SR_100X_HD_CAPS  | | ||||
|         MII_SR_100X_FD_CAPS     | MII_SR_100T4_CAPS; | ||||
| } | ||||
|  | ||||
| static void etsec_cleanup(NetClientState *nc) | ||||
| { | ||||
|     /* qemu_log("eTSEC cleanup\n"); */ | ||||
| } | ||||
|  | ||||
| static int etsec_can_receive(NetClientState *nc) | ||||
| { | ||||
|     eTSEC *etsec = qemu_get_nic_opaque(nc); | ||||
|  | ||||
|     return etsec->rx_buffer_len == 0; | ||||
| } | ||||
|  | ||||
| static ssize_t etsec_receive(NetClientState *nc, | ||||
|                              const uint8_t  *buf, | ||||
|                              size_t          size) | ||||
| { | ||||
|     eTSEC *etsec = qemu_get_nic_opaque(nc); | ||||
|  | ||||
| #if defined(HEX_DUMP) | ||||
|     fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size); | ||||
|     qemu_hexdump(buf, stderr, "", size); | ||||
| #endif | ||||
|     etsec_rx_ring_write(etsec, buf, size); | ||||
|     return size; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void etsec_set_link_status(NetClientState *nc) | ||||
| { | ||||
|     eTSEC *etsec = qemu_get_nic_opaque(nc); | ||||
|  | ||||
|     etsec_miim_link_status(etsec, nc); | ||||
| } | ||||
|  | ||||
| static NetClientInfo net_etsec_info = { | ||||
|     .type = NET_CLIENT_OPTIONS_KIND_NIC, | ||||
|     .size = sizeof(NICState), | ||||
|     .can_receive = etsec_can_receive, | ||||
|     .receive = etsec_receive, | ||||
|     .cleanup = etsec_cleanup, | ||||
|     .link_status_changed = etsec_set_link_status, | ||||
| }; | ||||
|  | ||||
| static void etsec_realize(DeviceState *dev, Error **errp) | ||||
| { | ||||
|     eTSEC        *etsec = ETSEC_COMMON(dev); | ||||
|  | ||||
|     etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf, | ||||
|                               object_get_typename(OBJECT(dev)), dev->id, etsec); | ||||
|     qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a); | ||||
|  | ||||
|  | ||||
|     etsec->bh     = qemu_bh_new(etsec_timer_hit, etsec); | ||||
|     etsec->ptimer = ptimer_init(etsec->bh); | ||||
|     ptimer_set_freq(etsec->ptimer, 100); | ||||
| } | ||||
|  | ||||
| static void etsec_instance_init(Object *obj) | ||||
| { | ||||
|     eTSEC        *etsec = ETSEC_COMMON(obj); | ||||
|     SysBusDevice *sbd   = SYS_BUS_DEVICE(obj); | ||||
|  | ||||
|     memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec, | ||||
|                           "eTSEC", 0x1000); | ||||
|     sysbus_init_mmio(sbd, &etsec->io_area); | ||||
|  | ||||
|     sysbus_init_irq(sbd, &etsec->tx_irq); | ||||
|     sysbus_init_irq(sbd, &etsec->rx_irq); | ||||
|     sysbus_init_irq(sbd, &etsec->err_irq); | ||||
| } | ||||
|  | ||||
| static Property etsec_properties[] = { | ||||
|     DEFINE_NIC_PROPERTIES(eTSEC, conf), | ||||
|     DEFINE_PROP_END_OF_LIST(), | ||||
| }; | ||||
|  | ||||
| static void etsec_class_init(ObjectClass *klass, void *data) | ||||
| { | ||||
|     DeviceClass *dc = DEVICE_CLASS(klass); | ||||
|  | ||||
|     dc->realize = etsec_realize; | ||||
|     dc->reset = etsec_reset; | ||||
|     dc->props = etsec_properties; | ||||
| } | ||||
|  | ||||
| static TypeInfo etsec_info = { | ||||
|     .name                  = "eTSEC", | ||||
|     .parent                = TYPE_SYS_BUS_DEVICE, | ||||
|     .instance_size         = sizeof(eTSEC), | ||||
|     .class_init            = etsec_class_init, | ||||
|     .instance_init         = etsec_instance_init, | ||||
| }; | ||||
|  | ||||
| static void etsec_register_types(void) | ||||
| { | ||||
|     type_register_static(&etsec_info); | ||||
| } | ||||
|  | ||||
| type_init(etsec_register_types) | ||||
|  | ||||
| DeviceState *etsec_create(hwaddr         base, | ||||
|                           MemoryRegion * mr, | ||||
|                           NICInfo      * nd, | ||||
|                           qemu_irq       tx_irq, | ||||
|                           qemu_irq       rx_irq, | ||||
|                           qemu_irq       err_irq) | ||||
| { | ||||
|     DeviceState *dev; | ||||
|  | ||||
|     dev = qdev_create(NULL, "eTSEC"); | ||||
|     qdev_set_nic_properties(dev, nd); | ||||
|  | ||||
|     if (qdev_init(dev)) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq); | ||||
|     sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq); | ||||
|     sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, err_irq); | ||||
|  | ||||
|     memory_region_add_subregion(mr, base, | ||||
|                                 SYS_BUS_DEVICE(dev)->mmio[0].memory); | ||||
|  | ||||
|     return dev; | ||||
| } | ||||
							
								
								
									
										174
									
								
								hw/net/fsl_etsec/etsec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								hw/net/fsl_etsec/etsec.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | ||||
| /* | ||||
|  * QEMU Freescale eTSEC Emulator | ||||
|  * | ||||
|  * Copyright (c) 2011-2013 AdaCore | ||||
|  * | ||||
|  * 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 _ETSEC_H_ | ||||
| #define _ETSEC_H_ | ||||
|  | ||||
| #include "hw/qdev.h" | ||||
| #include "hw/sysbus.h" | ||||
| #include "net/net.h" | ||||
| #include "hw/ptimer.h" | ||||
|  | ||||
| /* Buffer Descriptors */ | ||||
|  | ||||
| typedef struct eTSEC_rxtx_bd { | ||||
|     uint16_t flags; | ||||
|     uint16_t length; | ||||
|     uint32_t bufptr; | ||||
| } eTSEC_rxtx_bd; | ||||
|  | ||||
| #define BD_WRAP       (1 << 13) | ||||
| #define BD_INTERRUPT  (1 << 12) | ||||
| #define BD_LAST       (1 << 11) | ||||
|  | ||||
| #define BD_TX_READY     (1 << 15) | ||||
| #define BD_TX_PADCRC    (1 << 14) | ||||
| #define BD_TX_TC        (1 << 10) | ||||
| #define BD_TX_PREDEF    (1 << 9) | ||||
| #define BD_TX_HFELC     (1 << 7) | ||||
| #define BD_TX_CFRL      (1 << 6) | ||||
| #define BD_TX_RC_MASK   0xF | ||||
| #define BD_TX_RC_OFFSET 0x2 | ||||
| #define BD_TX_TOEUN     (1 << 1) | ||||
| #define BD_TX_TR        (1 << 0) | ||||
|  | ||||
| #define BD_RX_EMPTY     (1 << 15) | ||||
| #define BD_RX_RO1       (1 << 14) | ||||
| #define BD_RX_FIRST     (1 << 10) | ||||
| #define BD_RX_MISS      (1 << 8) | ||||
| #define BD_RX_BROADCAST (1 << 7) | ||||
| #define BD_RX_MULTICAST (1 << 6) | ||||
| #define BD_RX_LG        (1 << 5) | ||||
| #define BD_RX_NO        (1 << 4) | ||||
| #define BD_RX_SH        (1 << 3) | ||||
| #define BD_RX_CR        (1 << 2) | ||||
| #define BD_RX_OV        (1 << 1) | ||||
| #define BD_RX_TR        (1 << 0) | ||||
|  | ||||
| /* Tx FCB flags */ | ||||
| #define FCB_TX_VLN     (1 << 7) | ||||
| #define FCB_TX_IP      (1 << 6) | ||||
| #define FCB_TX_IP6     (1 << 5) | ||||
| #define FCB_TX_TUP     (1 << 4) | ||||
| #define FCB_TX_UDP     (1 << 3) | ||||
| #define FCB_TX_CIP     (1 << 2) | ||||
| #define FCB_TX_CTU     (1 << 1) | ||||
| #define FCB_TX_NPH     (1 << 0) | ||||
|  | ||||
| /* PHY Status Register */ | ||||
| #define MII_SR_EXTENDED_CAPS     0x0001    /* Extended register capabilities */ | ||||
| #define MII_SR_JABBER_DETECT     0x0002    /* Jabber Detected */ | ||||
| #define MII_SR_LINK_STATUS       0x0004    /* Link Status 1 = link */ | ||||
| #define MII_SR_AUTONEG_CAPS      0x0008    /* Auto Neg Capable */ | ||||
| #define MII_SR_REMOTE_FAULT      0x0010    /* Remote Fault Detect */ | ||||
| #define MII_SR_AUTONEG_COMPLETE  0x0020    /* Auto Neg Complete */ | ||||
| #define MII_SR_PREAMBLE_SUPPRESS 0x0040    /* Preamble may be suppressed */ | ||||
| #define MII_SR_EXTENDED_STATUS   0x0100    /* Ext. status info in Reg 0x0F */ | ||||
| #define MII_SR_100T2_HD_CAPS     0x0200    /* 100T2 Half Duplex Capable */ | ||||
| #define MII_SR_100T2_FD_CAPS     0x0400    /* 100T2 Full Duplex Capable */ | ||||
| #define MII_SR_10T_HD_CAPS       0x0800    /* 10T   Half Duplex Capable */ | ||||
| #define MII_SR_10T_FD_CAPS       0x1000    /* 10T   Full Duplex Capable */ | ||||
| #define MII_SR_100X_HD_CAPS      0x2000    /* 100X  Half Duplex Capable */ | ||||
| #define MII_SR_100X_FD_CAPS      0x4000    /* 100X  Full Duplex Capable */ | ||||
| #define MII_SR_100T4_CAPS        0x8000    /* 100T4 Capable */ | ||||
|  | ||||
| /* eTSEC */ | ||||
|  | ||||
| /* Number of register in the device */ | ||||
| #define ETSEC_REG_NUMBER 1024 | ||||
|  | ||||
| typedef struct eTSEC_Register { | ||||
|     const char *name; | ||||
|     const char *desc; | ||||
|     uint32_t    access; | ||||
|     uint32_t    value; | ||||
| } eTSEC_Register; | ||||
|  | ||||
| typedef struct eTSEC { | ||||
|     SysBusDevice  busdev; | ||||
|  | ||||
|     MemoryRegion  io_area; | ||||
|  | ||||
|     eTSEC_Register regs[ETSEC_REG_NUMBER]; | ||||
|  | ||||
|     NICState *nic; | ||||
|     NICConf   conf; | ||||
|  | ||||
|     /* Tx */ | ||||
|  | ||||
|     uint8_t       *tx_buffer; | ||||
|     uint32_t       tx_buffer_len; | ||||
|     eTSEC_rxtx_bd  first_bd; | ||||
|  | ||||
|     /* Rx */ | ||||
|  | ||||
|     uint8_t       *rx_buffer; | ||||
|     uint32_t       rx_buffer_len; | ||||
|     uint32_t       rx_remaining_data; | ||||
|     uint8_t        rx_first_in_frame; | ||||
|     uint8_t        rx_fcb_size; | ||||
|     eTSEC_rxtx_bd  rx_first_bd; | ||||
|     uint8_t        rx_fcb[10]; | ||||
|     uint32_t       rx_padding; | ||||
|  | ||||
|     /* IRQs */ | ||||
|     qemu_irq     tx_irq; | ||||
|     qemu_irq     rx_irq; | ||||
|     qemu_irq     err_irq; | ||||
|  | ||||
|  | ||||
|     uint16_t phy_status; | ||||
|     uint16_t phy_control; | ||||
|  | ||||
|     /* Polling */ | ||||
|     QEMUBH *bh; | ||||
|     struct ptimer_state *ptimer; | ||||
|  | ||||
| } eTSEC; | ||||
|  | ||||
| #define TYPE_ETSEC_COMMON "eTSEC" | ||||
| #define ETSEC_COMMON(obj) \ | ||||
|      OBJECT_CHECK(eTSEC, (obj), TYPE_ETSEC_COMMON) | ||||
|  | ||||
| #define eTSEC_TRANSMIT 1 | ||||
| #define eTSEC_RECEIVE  2 | ||||
|  | ||||
| DeviceState *etsec_create(hwaddr        base, | ||||
|                           MemoryRegion *mr, | ||||
|                           NICInfo      *nd, | ||||
|                           qemu_irq      tx_irq, | ||||
|                           qemu_irq      rx_irq, | ||||
|                           qemu_irq      err_irq); | ||||
|  | ||||
| void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr); | ||||
| void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr); | ||||
| void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size); | ||||
|  | ||||
| void etsec_write_miim(eTSEC          *etsec, | ||||
|                       eTSEC_Register *reg, | ||||
|                       uint32_t        reg_index, | ||||
|                       uint32_t        value); | ||||
|  | ||||
| void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc); | ||||
|  | ||||
| #endif /* ! _ETSEC_H_ */ | ||||
							
								
								
									
										146
									
								
								hw/net/fsl_etsec/miim.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								hw/net/fsl_etsec/miim.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| /* | ||||
|  * QEMU Freescale eTSEC Emulator | ||||
|  * | ||||
|  * Copyright (c) 2011-2013 AdaCore | ||||
|  * | ||||
|  * 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 "etsec.h" | ||||
| #include "registers.h" | ||||
|  | ||||
| /* #define DEBUG_MIIM */ | ||||
|  | ||||
| #define MIIM_CONTROL    0 | ||||
| #define MIIM_STATUS     1 | ||||
| #define MIIM_PHY_ID_1   2 | ||||
| #define MIIM_PHY_ID_2   3 | ||||
| #define MIIM_T2_STATUS  10 | ||||
| #define MIIM_EXT_STATUS 15 | ||||
|  | ||||
| static void miim_read_cycle(eTSEC *etsec) | ||||
| { | ||||
|     uint8_t  phy; | ||||
|     uint8_t  addr; | ||||
|     uint16_t value; | ||||
|  | ||||
|     phy  = (etsec->regs[MIIMADD].value >> 8) & 0x1F; | ||||
|     (void)phy; /* Unreferenced */ | ||||
|     addr = etsec->regs[MIIMADD].value & 0x1F; | ||||
|  | ||||
|     switch (addr) { | ||||
|     case MIIM_CONTROL: | ||||
|         value = etsec->phy_control; | ||||
|         break; | ||||
|     case MIIM_STATUS: | ||||
|         value = etsec->phy_status; | ||||
|         break; | ||||
|     case MIIM_T2_STATUS: | ||||
|         value = 0x1800;           /* Local and remote receivers OK */ | ||||
|         break; | ||||
|     default: | ||||
|         value = 0x0; | ||||
|         break; | ||||
|     }; | ||||
|  | ||||
| #ifdef DEBUG_MIIM | ||||
|     qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value); | ||||
| #endif | ||||
|  | ||||
|     etsec->regs[MIIMSTAT].value = value; | ||||
| } | ||||
|  | ||||
| static void miim_write_cycle(eTSEC *etsec) | ||||
| { | ||||
|     uint8_t  phy; | ||||
|     uint8_t  addr; | ||||
|     uint16_t value; | ||||
|  | ||||
|     phy   = (etsec->regs[MIIMADD].value >> 8) & 0x1F; | ||||
|     (void)phy; /* Unreferenced */ | ||||
|     addr  = etsec->regs[MIIMADD].value & 0x1F; | ||||
|     value = etsec->regs[MIIMCON].value & 0xffff; | ||||
|  | ||||
| #ifdef DEBUG_MIIM | ||||
|     qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value); | ||||
| #endif | ||||
|  | ||||
|     switch (addr) { | ||||
|     case MIIM_CONTROL: | ||||
|         etsec->phy_control = value & ~(0x8100); | ||||
|         break; | ||||
|     default: | ||||
|         break; | ||||
|     }; | ||||
| } | ||||
|  | ||||
| void etsec_write_miim(eTSEC          *etsec, | ||||
|                       eTSEC_Register *reg, | ||||
|                       uint32_t        reg_index, | ||||
|                       uint32_t        value) | ||||
| { | ||||
|  | ||||
|     switch (reg_index) { | ||||
|  | ||||
|     case MIIMCOM: | ||||
|         /* Read and scan cycle */ | ||||
|  | ||||
|         if ((!(reg->value & MIIMCOM_READ)) && (value & MIIMCOM_READ)) { | ||||
|             /* Read */ | ||||
|             miim_read_cycle(etsec); | ||||
|         } | ||||
|         reg->value = value; | ||||
|         break; | ||||
|  | ||||
|     case MIIMCON: | ||||
|         reg->value = value & 0xffff; | ||||
|         miim_write_cycle(etsec); | ||||
|         break; | ||||
|  | ||||
|     default: | ||||
|         /* Default handling */ | ||||
|         switch (reg->access) { | ||||
|  | ||||
|         case ACC_RW: | ||||
|         case ACC_WO: | ||||
|             reg->value = value; | ||||
|             break; | ||||
|  | ||||
|         case ACC_W1C: | ||||
|             reg->value &= ~value; | ||||
|             break; | ||||
|  | ||||
|         case ACC_RO: | ||||
|         default: | ||||
|             /* Read Only or Unknown register */ | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc) | ||||
| { | ||||
|     /* Set link status */ | ||||
|     if (nc->link_down) { | ||||
|         etsec->phy_status &= ~MII_SR_LINK_STATUS; | ||||
|     } else { | ||||
|         etsec->phy_status |= MII_SR_LINK_STATUS; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										295
									
								
								hw/net/fsl_etsec/registers.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								hw/net/fsl_etsec/registers.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,295 @@ | ||||
| /* | ||||
|  * QEMU Freescale eTSEC Emulator | ||||
|  * | ||||
|  * Copyright (c) 2011-2013 AdaCore | ||||
|  * | ||||
|  * 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 "registers.h" | ||||
|  | ||||
| const eTSEC_Register_Definition eTSEC_registers_def[] = { | ||||
| {0x000, "TSEC_ID",  "Controller ID register",    ACC_RO,  0x01240000}, | ||||
| {0x004, "TSEC_ID2", "Controller ID register 2",  ACC_RO,  0x003000F0}, | ||||
| {0x010, "IEVENT",   "Interrupt event register",  ACC_W1C, 0x00000000}, | ||||
| {0x014, "IMASK",    "Interrupt mask register",   ACC_RW,  0x00000000}, | ||||
| {0x018, "EDIS",     "Error disabled register",   ACC_RW,  0x00000000}, | ||||
| {0x020, "ECNTRL",   "Ethernet control register", ACC_RW,  0x00000040}, | ||||
| {0x028, "PTV",      "Pause time value register", ACC_RW,  0x00000000}, | ||||
| {0x02C, "DMACTRL",  "DMA control register",      ACC_RW,  0x00000000}, | ||||
| {0x030, "TBIPA",    "TBI PHY address register",  ACC_RW,  0x00000000}, | ||||
|  | ||||
| /* eTSEC FIFO Control and Status Registers */ | ||||
|  | ||||
| {0x058, "FIFO_RX_ALARM",          "FIFO receive alarm start threshold register",    ACC_RW, 0x00000040}, | ||||
| {0x05C, "FIFO_RX_ALARM_SHUTOFF",  "FIFO receive alarm shut-off threshold register", ACC_RW, 0x00000080}, | ||||
| {0x08C, "FIFO_TX_THR",            "FIFO transmit threshold register",               ACC_RW, 0x00000080}, | ||||
| {0x098, "FIFO_TX_STARVE",         "FIFO transmit starve register",                  ACC_RW, 0x00000040}, | ||||
| {0x09C, "FIFO_TX_STARVE_SHUTOFF", "FIFO transmit starve shut-off register",         ACC_RW, 0x00000080}, | ||||
|  | ||||
| /* eTSEC Transmit Control and Status Registers */ | ||||
|  | ||||
| {0x100, "TCTRL",        "Transmit control register",                ACC_RW,  0x00000000}, | ||||
| {0x104, "TSTAT",        "Transmit status register",                 ACC_W1C, 0x00000000}, | ||||
| {0x108, "DFVLAN",       "Default VLAN control word",                ACC_RW,  0x81000000}, | ||||
| {0x110, "TXIC",         "Transmit interrupt coalescing register",   ACC_RW,  0x00000000}, | ||||
| {0x114, "TQUEUE",       "Transmit queue control register",          ACC_RW,  0x00008000}, | ||||
| {0x140, "TR03WT",       "TxBD Rings 0-3 round-robin weightings",    ACC_RW,  0x00000000}, | ||||
| {0x144, "TR47WT",       "TxBD Rings 4-7 round-robin weightings",    ACC_RW,  0x00000000}, | ||||
| {0x180, "TBDBPH",       "Tx data buffer pointer high bits",         ACC_RW,  0x00000000}, | ||||
| {0x184, "TBPTR0",       "TxBD pointer for ring 0",                  ACC_RW,  0x00000000}, | ||||
| {0x18C, "TBPTR1",       "TxBD pointer for ring 1",                  ACC_RW,  0x00000000}, | ||||
| {0x194, "TBPTR2",       "TxBD pointer for ring 2",                  ACC_RW,  0x00000000}, | ||||
| {0x19C, "TBPTR3",       "TxBD pointer for ring 3",                  ACC_RW,  0x00000000}, | ||||
| {0x1A4, "TBPTR4",       "TxBD pointer for ring 4",                  ACC_RW,  0x00000000}, | ||||
| {0x1AC, "TBPTR5",       "TxBD pointer for ring 5",                  ACC_RW,  0x00000000}, | ||||
| {0x1B4, "TBPTR6",       "TxBD pointer for ring 6",                  ACC_RW,  0x00000000}, | ||||
| {0x1BC, "TBPTR7",       "TxBD pointer for ring 7",                  ACC_RW,  0x00000000}, | ||||
| {0x200, "TBASEH",       "TxBD base address high bits",              ACC_RW,  0x00000000}, | ||||
| {0x204, "TBASE0",       "TxBD base address of ring 0",              ACC_RW,  0x00000000}, | ||||
| {0x20C, "TBASE1",       "TxBD base address of ring 1",              ACC_RW,  0x00000000}, | ||||
| {0x214, "TBASE2",       "TxBD base address of ring 2",              ACC_RW,  0x00000000}, | ||||
| {0x21C, "TBASE3",       "TxBD base address of ring 3",              ACC_RW,  0x00000000}, | ||||
| {0x224, "TBASE4",       "TxBD base address of ring 4",              ACC_RW,  0x00000000}, | ||||
| {0x22C, "TBASE5",       "TxBD base address of ring 5",              ACC_RW,  0x00000000}, | ||||
| {0x234, "TBASE6",       "TxBD base address of ring 6",              ACC_RW,  0x00000000}, | ||||
| {0x23C, "TBASE7",       "TxBD base address of ring 7",              ACC_RW,  0x00000000}, | ||||
| {0x280, "TMR_TXTS1_ID", "Tx time stamp identification tag (set 1)", ACC_RO,  0x00000000}, | ||||
| {0x284, "TMR_TXTS2_ID", "Tx time stamp identification tag (set 2)", ACC_RO,  0x00000000}, | ||||
| {0x2C0, "TMR_TXTS1_H",  "Tx time stamp high (set 1)",               ACC_RO,  0x00000000}, | ||||
| {0x2C4, "TMR_TXTS1_L",  "Tx time stamp high (set 1)",               ACC_RO,  0x00000000}, | ||||
| {0x2C8, "TMR_TXTS2_H",  "Tx time stamp high (set 2)",               ACC_RO,  0x00000000}, | ||||
| {0x2CC, "TMR_TXTS2_L",  "Tx time stamp high (set 2)",               ACC_RO,  0x00000000}, | ||||
|  | ||||
| /* eTSEC Receive Control and Status Registers */ | ||||
|  | ||||
| {0x300, "RCTRL",      "Receive control register",                     ACC_RW,  0x00000000}, | ||||
| {0x304, "RSTAT",      "Receive status register",                      ACC_W1C, 0x00000000}, | ||||
| {0x310, "RXIC",       "Receive interrupt coalescing register",        ACC_RW,  0x00000000}, | ||||
| {0x314, "RQUEUE",     "Receive queue control register.",              ACC_RW,  0x00800080}, | ||||
| {0x330, "RBIFX",      "Receive bit field extract control register",   ACC_RW,  0x00000000}, | ||||
| {0x334, "RQFAR",      "Receive queue filing table address register",  ACC_RW,  0x00000000}, | ||||
| {0x338, "RQFCR",      "Receive queue filing table control register",  ACC_RW,  0x00000000}, | ||||
| {0x33C, "RQFPR",      "Receive queue filing table property register", ACC_RW,  0x00000000}, | ||||
| {0x340, "MRBLR",      "Maximum receive buffer length register",       ACC_RW,  0x00000000}, | ||||
| {0x380, "RBDBPH",     "Rx data buffer pointer high bits",             ACC_RW,  0x00000000}, | ||||
| {0x384, "RBPTR0",     "RxBD pointer for ring 0",                      ACC_RW,  0x00000000}, | ||||
| {0x38C, "RBPTR1",     "RxBD pointer for ring 1",                      ACC_RW,  0x00000000}, | ||||
| {0x394, "RBPTR2",     "RxBD pointer for ring 2",                      ACC_RW,  0x00000000}, | ||||
| {0x39C, "RBPTR3",     "RxBD pointer for ring 3",                      ACC_RW,  0x00000000}, | ||||
| {0x3A4, "RBPTR4",     "RxBD pointer for ring 4",                      ACC_RW,  0x00000000}, | ||||
| {0x3AC, "RBPTR5",     "RxBD pointer for ring 5",                      ACC_RW,  0x00000000}, | ||||
| {0x3B4, "RBPTR6",     "RxBD pointer for ring 6",                      ACC_RW,  0x00000000}, | ||||
| {0x3BC, "RBPTR7",     "RxBD pointer for ring 7",                      ACC_RW,  0x00000000}, | ||||
| {0x400, "RBASEH",     "RxBD base address high bits",                  ACC_RW,  0x00000000}, | ||||
| {0x404, "RBASE0",     "RxBD base address of ring 0",                  ACC_RW,  0x00000000}, | ||||
| {0x40C, "RBASE1",     "RxBD base address of ring 1",                  ACC_RW,  0x00000000}, | ||||
| {0x414, "RBASE2",     "RxBD base address of ring 2",                  ACC_RW,  0x00000000}, | ||||
| {0x41C, "RBASE3",     "RxBD base address of ring 3",                  ACC_RW,  0x00000000}, | ||||
| {0x424, "RBASE4",     "RxBD base address of ring 4",                  ACC_RW,  0x00000000}, | ||||
| {0x42C, "RBASE5",     "RxBD base address of ring 5",                  ACC_RW,  0x00000000}, | ||||
| {0x434, "RBASE6",     "RxBD base address of ring 6",                  ACC_RW,  0x00000000}, | ||||
| {0x43C, "RBASE7",     "RxBD base address of ring 7",                  ACC_RW,  0x00000000}, | ||||
| {0x4C0, "TMR_RXTS_H", "Rx timer time stamp register high",            ACC_RW,  0x00000000}, | ||||
| {0x4C4, "TMR_RXTS_L", "Rx timer time stamp register low",             ACC_RW,  0x00000000}, | ||||
|  | ||||
| /* eTSEC MAC Registers */ | ||||
|  | ||||
| {0x500, "MACCFG1",     "MAC configuration register 1",          ACC_RW, 0x00000000}, | ||||
| {0x504, "MACCFG2",     "MAC configuration register 2",          ACC_RW, 0x00007000}, | ||||
| {0x508, "IPGIFG",      "Inter-packet/inter-frame gap register", ACC_RW, 0x40605060}, | ||||
| {0x50C, "HAFDUP",      "Half-duplex control",                   ACC_RW, 0x00A1F037}, | ||||
| {0x510, "MAXFRM",      "Maximum frame length",                  ACC_RW, 0x00000600}, | ||||
| {0x520, "MIIMCFG",     "MII management configuration",          ACC_RW, 0x00000007}, | ||||
| {0x524, "MIIMCOM",     "MII management command",                ACC_RW, 0x00000000}, | ||||
| {0x528, "MIIMADD",     "MII management address",                ACC_RW, 0x00000000}, | ||||
| {0x52C, "MIIMCON",     "MII management control",                ACC_WO, 0x00000000}, | ||||
| {0x530, "MIIMSTAT",    "MII management status",                 ACC_RO, 0x00000000}, | ||||
| {0x534, "MIIMIND",     "MII management indicator",              ACC_RO, 0x00000000}, | ||||
| {0x53C, "IFSTAT",      "Interface status",                      ACC_RO, 0x00000000}, | ||||
| {0x540, "MACSTNADDR1", "MAC station address register 1",        ACC_RW, 0x00000000}, | ||||
| {0x544, "MACSTNADDR2", "MAC station address register 2",        ACC_RW, 0x00000000}, | ||||
| {0x548, "MAC01ADDR1",  "MAC exact match address 1, part 1",     ACC_RW, 0x00000000}, | ||||
| {0x54C, "MAC01ADDR2",  "MAC exact match address 1, part 2",     ACC_RW, 0x00000000}, | ||||
| {0x550, "MAC02ADDR1",  "MAC exact match address 2, part 1",     ACC_RW, 0x00000000}, | ||||
| {0x554, "MAC02ADDR2",  "MAC exact match address 2, part 2",     ACC_RW, 0x00000000}, | ||||
| {0x558, "MAC03ADDR1",  "MAC exact match address 3, part 1",     ACC_RW, 0x00000000}, | ||||
| {0x55C, "MAC03ADDR2",  "MAC exact match address 3, part 2",     ACC_RW, 0x00000000}, | ||||
| {0x560, "MAC04ADDR1",  "MAC exact match address 4, part 1",     ACC_RW, 0x00000000}, | ||||
| {0x564, "MAC04ADDR2",  "MAC exact match address 4, part 2",     ACC_RW, 0x00000000}, | ||||
| {0x568, "MAC05ADDR1",  "MAC exact match address 5, part 1",     ACC_RW, 0x00000000}, | ||||
| {0x56C, "MAC05ADDR2",  "MAC exact match address 5, part 2",     ACC_RW, 0x00000000}, | ||||
| {0x570, "MAC06ADDR1",  "MAC exact match address 6, part 1",     ACC_RW, 0x00000000}, | ||||
| {0x574, "MAC06ADDR2",  "MAC exact match address 6, part 2",     ACC_RW, 0x00000000}, | ||||
| {0x578, "MAC07ADDR1",  "MAC exact match address 7, part 1",     ACC_RW, 0x00000000}, | ||||
| {0x57C, "MAC07ADDR2",  "MAC exact match address 7, part 2",     ACC_RW, 0x00000000}, | ||||
| {0x580, "MAC08ADDR1",  "MAC exact match address 8, part 1",     ACC_RW, 0x00000000}, | ||||
| {0x584, "MAC08ADDR2",  "MAC exact match address 8, part 2",     ACC_RW, 0x00000000}, | ||||
| {0x588, "MAC09ADDR1",  "MAC exact match address 9, part 1",     ACC_RW, 0x00000000}, | ||||
| {0x58C, "MAC09ADDR2",  "MAC exact match address 9, part 2",     ACC_RW, 0x00000000}, | ||||
| {0x590, "MAC10ADDR1",  "MAC exact match address 10, part 1",    ACC_RW, 0x00000000}, | ||||
| {0x594, "MAC10ADDR2",  "MAC exact match address 10, part 2",    ACC_RW, 0x00000000}, | ||||
| {0x598, "MAC11ADDR1",  "MAC exact match address 11, part 1",    ACC_RW, 0x00000000}, | ||||
| {0x59C, "MAC11ADDR2",  "MAC exact match address 11, part 2",    ACC_RW, 0x00000000}, | ||||
| {0x5A0, "MAC12ADDR1",  "MAC exact match address 12, part 1",    ACC_RW, 0x00000000}, | ||||
| {0x5A4, "MAC12ADDR2",  "MAC exact match address 12, part 2",    ACC_RW, 0x00000000}, | ||||
| {0x5A8, "MAC13ADDR1",  "MAC exact match address 13, part 1",    ACC_RW, 0x00000000}, | ||||
| {0x5AC, "MAC13ADDR2",  "MAC exact match address 13, part 2",    ACC_RW, 0x00000000}, | ||||
| {0x5B0, "MAC14ADDR1",  "MAC exact match address 14, part 1",    ACC_RW, 0x00000000}, | ||||
| {0x5B4, "MAC14ADDR2",  "MAC exact match address 14, part 2",    ACC_RW, 0x00000000}, | ||||
| {0x5B8, "MAC15ADDR1",  "MAC exact match address 15, part 1",    ACC_RW, 0x00000000}, | ||||
| {0x5BC, "MAC15ADDR2",  "MAC exact match address 15, part 2",    ACC_RW, 0x00000000}, | ||||
|  | ||||
| /* eTSEC, "Transmit", "and", Receive, Counters */ | ||||
|  | ||||
| {0x680, "TR64",  "Transmit and receive 64-byte frame counter ",                   ACC_RW, 0x00000000}, | ||||
| {0x684, "TR127", "Transmit and receive 65- to 127-byte frame counter",            ACC_RW, 0x00000000}, | ||||
| {0x688, "TR255", "Transmit and receive 128- to 255-byte frame counter",           ACC_RW, 0x00000000}, | ||||
| {0x68C, "TR511", "Transmit and receive 256- to 511-byte frame counter",           ACC_RW, 0x00000000}, | ||||
| {0x690, "TR1K",  "Transmit and receive 512- to 1023-byte frame counter",          ACC_RW, 0x00000000}, | ||||
| {0x694, "TRMAX", "Transmit and receive 1024- to 1518-byte frame counter",         ACC_RW, 0x00000000}, | ||||
| {0x698, "TRMGV", "Transmit and receive 1519- to 1522-byte good VLAN frame count", ACC_RW, 0x00000000}, | ||||
|  | ||||
| /* eTSEC Receive Counters */ | ||||
|  | ||||
| {0x69C, "RBYT", "Receive byte counter",                  ACC_RW, 0x00000000}, | ||||
| {0x6A0, "RPKT", "Receive packet counter",                ACC_RW, 0x00000000}, | ||||
| {0x6A4, "RFCS", "Receive FCS error counter",             ACC_RW, 0x00000000}, | ||||
| {0x6A8, "RMCA", "Receive multicast packet counter",      ACC_RW, 0x00000000}, | ||||
| {0x6AC, "RBCA", "Receive broadcast packet counter",      ACC_RW, 0x00000000}, | ||||
| {0x6B0, "RXCF", "Receive control frame packet counter ", ACC_RW, 0x00000000}, | ||||
| {0x6B4, "RXPF", "Receive PAUSE frame packet counter",    ACC_RW, 0x00000000}, | ||||
| {0x6B8, "RXUO", "Receive unknown OP code counter ",      ACC_RW, 0x00000000}, | ||||
| {0x6BC, "RALN", "Receive alignment error counter ",      ACC_RW, 0x00000000}, | ||||
| {0x6C0, "RFLR", "Receive frame length error counter ",   ACC_RW, 0x00000000}, | ||||
| {0x6C4, "RCDE", "Receive code error counter ",           ACC_RW, 0x00000000}, | ||||
| {0x6C8, "RCSE", "Receive carrier sense error counter",   ACC_RW, 0x00000000}, | ||||
| {0x6CC, "RUND", "Receive undersize packet counter",      ACC_RW, 0x00000000}, | ||||
| {0x6D0, "ROVR", "Receive oversize packet counter ",      ACC_RW, 0x00000000}, | ||||
| {0x6D4, "RFRG", "Receive fragments counter",             ACC_RW, 0x00000000}, | ||||
| {0x6D8, "RJBR", "Receive jabber counter ",               ACC_RW, 0x00000000}, | ||||
| {0x6DC, "RDRP", "Receive drop counter",                  ACC_RW, 0x00000000}, | ||||
|  | ||||
| /* eTSEC Transmit Counters */ | ||||
|  | ||||
| {0x6E0, "TBYT", "Transmit byte counter",                       ACC_RW, 0x00000000}, | ||||
| {0x6E4, "TPKT", "Transmit packet counter",                     ACC_RW, 0x00000000}, | ||||
| {0x6E8, "TMCA", "Transmit multicast packet counter ",          ACC_RW, 0x00000000}, | ||||
| {0x6EC, "TBCA", "Transmit broadcast packet counter ",          ACC_RW, 0x00000000}, | ||||
| {0x6F0, "TXPF", "Transmit PAUSE control frame counter ",       ACC_RW, 0x00000000}, | ||||
| {0x6F4, "TDFR", "Transmit deferral packet counter ",           ACC_RW, 0x00000000}, | ||||
| {0x6F8, "TEDF", "Transmit excessive deferral packet counter ", ACC_RW, 0x00000000}, | ||||
| {0x6FC, "TSCL", "Transmit single collision packet counter",    ACC_RW, 0x00000000}, | ||||
| {0x700, "TMCL", "Transmit multiple collision packet counter",  ACC_RW, 0x00000000}, | ||||
| {0x704, "TLCL", "Transmit late collision packet counter",      ACC_RW, 0x00000000}, | ||||
| {0x708, "TXCL", "Transmit excessive collision packet counter", ACC_RW, 0x00000000}, | ||||
| {0x70C, "TNCL", "Transmit total collision counter ",           ACC_RW, 0x00000000}, | ||||
| {0x714, "TDRP", "Transmit drop frame counter",                 ACC_RW, 0x00000000}, | ||||
| {0x718, "TJBR", "Transmit jabber frame counter ",              ACC_RW, 0x00000000}, | ||||
| {0x71C, "TFCS", "Transmit FCS error counter",                  ACC_RW, 0x00000000}, | ||||
| {0x720, "TXCF", "Transmit control frame counter ",             ACC_RW, 0x00000000}, | ||||
| {0x724, "TOVR", "Transmit oversize frame counter",             ACC_RW, 0x00000000}, | ||||
| {0x728, "TUND", "Transmit undersize frame counter ",           ACC_RW, 0x00000000}, | ||||
| {0x72C, "TFRG", "Transmit fragments frame counter ",           ACC_RW, 0x00000000}, | ||||
|  | ||||
| /* eTSEC Counter Control and TOE Statistics Registers */ | ||||
|  | ||||
| {0x730, "CAR1", "Carry register one register",           ACC_W1C, 0x00000000}, | ||||
| {0x734, "CAR2", "Carry register two register ",          ACC_W1C, 0x00000000}, | ||||
| {0x738, "CAM1", "Carry register one mask register ",     ACC_RW,  0xFE03FFFF}, | ||||
| {0x73C, "CAM2", "Carry register two mask register ",     ACC_RW,  0x000FFFFD}, | ||||
| {0x740, "RREJ", "Receive filer rejected packet counter", ACC_RW,  0x00000000}, | ||||
|  | ||||
| /* Hash Function Registers */ | ||||
|  | ||||
| {0x800, "IGADDR0", "Individual/group address register 0", ACC_RW, 0x00000000}, | ||||
| {0x804, "IGADDR1", "Individual/group address register 1", ACC_RW, 0x00000000}, | ||||
| {0x808, "IGADDR2", "Individual/group address register 2", ACC_RW, 0x00000000}, | ||||
| {0x80C, "IGADDR3", "Individual/group address register 3", ACC_RW, 0x00000000}, | ||||
| {0x810, "IGADDR4", "Individual/group address register 4", ACC_RW, 0x00000000}, | ||||
| {0x814, "IGADDR5", "Individual/group address register 5", ACC_RW, 0x00000000}, | ||||
| {0x818, "IGADDR6", "Individual/group address register 6", ACC_RW, 0x00000000}, | ||||
| {0x81C, "IGADDR7", "Individual/group address register 7", ACC_RW, 0x00000000}, | ||||
| {0x880, "GADDR0",  "Group address register 0",            ACC_RW, 0x00000000}, | ||||
| {0x884, "GADDR1",  "Group address register 1",            ACC_RW, 0x00000000}, | ||||
| {0x888, "GADDR2",  "Group address register 2",            ACC_RW, 0x00000000}, | ||||
| {0x88C, "GADDR3",  "Group address register 3",            ACC_RW, 0x00000000}, | ||||
| {0x890, "GADDR4",  "Group address register 4",            ACC_RW, 0x00000000}, | ||||
| {0x894, "GADDR5",  "Group address register 5",            ACC_RW, 0x00000000}, | ||||
| {0x898, "GADDR6",  "Group address register 6",            ACC_RW, 0x00000000}, | ||||
| {0x89C, "GADDR7",  "Group address register 7",            ACC_RW, 0x00000000}, | ||||
|  | ||||
| /* eTSEC DMA Attribute Registers */ | ||||
|  | ||||
| {0xBF8, "ATTR",    "Attribute register",                                  ACC_RW, 0x00000000}, | ||||
| {0xBFC, "ATTRELI", "Attribute extract length and extract index register", ACC_RW, 0x00000000}, | ||||
|  | ||||
|  | ||||
| /* eTSEC Lossless Flow Control Registers */ | ||||
|  | ||||
| {0xC00, "RQPRM0",  "Receive Queue Parameters register 0 ", ACC_RW, 0x00000000}, | ||||
| {0xC04, "RQPRM1",  "Receive Queue Parameters register 1 ", ACC_RW, 0x00000000}, | ||||
| {0xC08, "RQPRM2",  "Receive Queue Parameters register 2 ", ACC_RW, 0x00000000}, | ||||
| {0xC0C, "RQPRM3",  "Receive Queue Parameters register 3 ", ACC_RW, 0x00000000}, | ||||
| {0xC10, "RQPRM4",  "Receive Queue Parameters register 4 ", ACC_RW, 0x00000000}, | ||||
| {0xC14, "RQPRM5",  "Receive Queue Parameters register 5 ", ACC_RW, 0x00000000}, | ||||
| {0xC18, "RQPRM6",  "Receive Queue Parameters register 6 ", ACC_RW, 0x00000000}, | ||||
| {0xC1C, "RQPRM7",  "Receive Queue Parameters register 7 ", ACC_RW, 0x00000000}, | ||||
| {0xC44, "RFBPTR0", "Last Free RxBD pointer for ring 0",    ACC_RW, 0x00000000}, | ||||
| {0xC4C, "RFBPTR1", "Last Free RxBD pointer for ring 1",    ACC_RW, 0x00000000}, | ||||
| {0xC54, "RFBPTR2", "Last Free RxBD pointer for ring 2",    ACC_RW, 0x00000000}, | ||||
| {0xC5C, "RFBPTR3", "Last Free RxBD pointer for ring 3",    ACC_RW, 0x00000000}, | ||||
| {0xC64, "RFBPTR4", "Last Free RxBD pointer for ring 4",    ACC_RW, 0x00000000}, | ||||
| {0xC6C, "RFBPTR5", "Last Free RxBD pointer for ring 5",    ACC_RW, 0x00000000}, | ||||
| {0xC74, "RFBPTR6", "Last Free RxBD pointer for ring 6",    ACC_RW, 0x00000000}, | ||||
| {0xC7C, "RFBPTR7", "Last Free RxBD pointer for ring 7",    ACC_RW, 0x00000000}, | ||||
|  | ||||
| /* eTSEC Future Expansion Space */ | ||||
|  | ||||
| /* Reserved*/ | ||||
|  | ||||
| /* eTSEC IEEE 1588 Registers */ | ||||
|  | ||||
| {0xE00, "TMR_CTRL",     "Timer control register",                          ACC_RW,  0x00010001}, | ||||
| {0xE04, "TMR_TEVENT",   "time stamp event register",                       ACC_W1C, 0x00000000}, | ||||
| {0xE08, "TMR_TEMASK",   "Timer event mask register",                       ACC_RW,  0x00000000}, | ||||
| {0xE0C, "TMR_PEVENT",   "time stamp event register",                       ACC_RW,  0x00000000}, | ||||
| {0xE10, "TMR_PEMASK",   "Timer event mask register",                       ACC_RW,  0x00000000}, | ||||
| {0xE14, "TMR_STAT",     "time stamp status register",                      ACC_RW,  0x00000000}, | ||||
| {0xE18, "TMR_CNT_H",    "timer counter high register",                     ACC_RW,  0x00000000}, | ||||
| {0xE1C, "TMR_CNT_L",    "timer counter low register",                      ACC_RW,  0x00000000}, | ||||
| {0xE20, "TMR_ADD",      "Timer drift compensation addend register",        ACC_RW,  0x00000000}, | ||||
| {0xE24, "TMR_ACC",      "Timer accumulator register",                      ACC_RW,  0x00000000}, | ||||
| {0xE28, "TMR_PRSC",     "Timer prescale",                                  ACC_RW,  0x00000002}, | ||||
| {0xE30, "TMROFF_H",     "Timer offset high",                               ACC_RW,  0x00000000}, | ||||
| {0xE34, "TMROFF_L",     "Timer offset low",                                ACC_RW,  0x00000000}, | ||||
| {0xE40, "TMR_ALARM1_H", "Timer alarm 1 high register",                     ACC_RW,  0xFFFFFFFF}, | ||||
| {0xE44, "TMR_ALARM1_L", "Timer alarm 1 high register",                     ACC_RW,  0xFFFFFFFF}, | ||||
| {0xE48, "TMR_ALARM2_H", "Timer alarm 2 high register",                     ACC_RW,  0xFFFFFFFF}, | ||||
| {0xE4C, "TMR_ALARM2_L", "Timer alarm 2 high register",                     ACC_RW,  0xFFFFFFFF}, | ||||
| {0xE80, "TMR_FIPER1",   "Timer fixed period interval",                     ACC_RW,  0xFFFFFFFF}, | ||||
| {0xE84, "TMR_FIPER2",   "Timer fixed period interval",                     ACC_RW,  0xFFFFFFFF}, | ||||
| {0xE88, "TMR_FIPER3",   "Timer fixed period interval",                     ACC_RW,  0xFFFFFFFF}, | ||||
| {0xEA0, "TMR_ETTS1_H",  "Time stamp of general purpose external trigger ", ACC_RW,  0x00000000}, | ||||
| {0xEA4, "TMR_ETTS1_L",  "Time stamp of general purpose external trigger",  ACC_RW,  0x00000000}, | ||||
| {0xEA8, "TMR_ETTS2_H",  "Time stamp of general purpose external trigger ", ACC_RW,  0x00000000}, | ||||
| {0xEAC, "TMR_ETTS2_L",  "Time stamp of general purpose external trigger",  ACC_RW,  0x00000000}, | ||||
|  | ||||
| /* End Of Table */ | ||||
| {0x0, 0x0, 0x0, 0x0, 0x0} | ||||
| }; | ||||
							
								
								
									
										320
									
								
								hw/net/fsl_etsec/registers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										320
									
								
								hw/net/fsl_etsec/registers.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,320 @@ | ||||
| /* | ||||
|  * QEMU Freescale eTSEC Emulator | ||||
|  * | ||||
|  * Copyright (c) 2011-2013 AdaCore | ||||
|  * | ||||
|  * 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 _ETSEC_REGISTERS_H_ | ||||
| #define _ETSEC_REGISTERS_H_ | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| enum eTSEC_Register_Access_Type { | ||||
|     ACC_RW      = 1,            /* Read/Write */ | ||||
|     ACC_RO      = 2,            /* Read Only */ | ||||
|     ACC_WO      = 3,            /* Write Only */ | ||||
|     ACC_W1C     = 4,            /* Write 1 to clear */ | ||||
|     ACC_UNKNOWN = 5             /* Unknown register*/ | ||||
| }; | ||||
|  | ||||
| typedef struct eTSEC_Register_Definition { | ||||
|     uint32_t                         offset; | ||||
|     const char                      *name; | ||||
|     const char                      *desc; | ||||
|     enum eTSEC_Register_Access_Type  access; | ||||
|     uint32_t                         reset; | ||||
| } eTSEC_Register_Definition; | ||||
|  | ||||
| extern const eTSEC_Register_Definition eTSEC_registers_def[]; | ||||
|  | ||||
| #define DMACTRL_LE  (1 << 15) | ||||
| #define DMACTRL_GRS (1 <<  4) | ||||
| #define DMACTRL_GTS (1 <<  3) | ||||
| #define DMACTRL_WOP (1 <<  0) | ||||
|  | ||||
| #define IEVENT_PERR  (1 <<  0) | ||||
| #define IEVENT_DPE   (1 <<  1) | ||||
| #define IEVENT_FIQ   (1 <<  2) | ||||
| #define IEVENT_FIR   (1 <<  3) | ||||
| #define IEVENT_FGPI  (1 <<  4) | ||||
| #define IEVENT_RXF   (1 <<  7) | ||||
| #define IEVENT_GRSC  (1 <<  8) | ||||
| #define IEVENT_MMRW  (1 <<  9) | ||||
| #define IEVENT_MMRD  (1 << 10) | ||||
| #define IEVENT_MAG   (1 << 11) | ||||
| #define IEVENT_RXB   (1 << 15) | ||||
| #define IEVENT_XFUN  (1 << 16) | ||||
| #define IEVENT_CRL   (1 << 17) | ||||
| #define IEVENT_LC    (1 << 18) | ||||
| #define IEVENT_TXF   (1 << 20) | ||||
| #define IEVENT_TXB   (1 << 21) | ||||
| #define IEVENT_TXE   (1 << 22) | ||||
| #define IEVENT_TXC   (1 << 23) | ||||
| #define IEVENT_BABT  (1 << 24) | ||||
| #define IEVENT_GTSC  (1 << 25) | ||||
| #define IEVENT_MSRO  (1 << 26) | ||||
| #define IEVENT_EBERR (1 << 28) | ||||
| #define IEVENT_BSY   (1 << 29) | ||||
| #define IEVENT_RXC   (1 << 30) | ||||
| #define IEVENT_BABR  (1 << 31) | ||||
|  | ||||
| #define IMASK_RXFEN  (1 <<  7) | ||||
| #define IMASK_GRSCEN (1 <<  8) | ||||
| #define IMASK_RXBEN  (1 << 15) | ||||
| #define IMASK_TXFEN  (1 << 20) | ||||
| #define IMASK_TXBEN  (1 << 21) | ||||
| #define IMASK_GTSCEN (1 << 25) | ||||
|  | ||||
| #define MACCFG1_TX_EN  (1 << 0) | ||||
| #define MACCFG1_RX_EN  (1 << 2) | ||||
|  | ||||
| #define MACCFG2_CRC_EN  (1 << 1) | ||||
| #define MACCFG2_PADCRC  (1 << 2) | ||||
|  | ||||
| #define MIIMCOM_READ (1 << 0) | ||||
| #define MIIMCOM_SCAN (1 << 1) | ||||
|  | ||||
| #define RCTRL_PRSDEP_MASK   (0x3) | ||||
| #define RCTRL_PRSDEP_OFFSET (6) | ||||
| #define RCTRL_RSF           (1 << 2) | ||||
|  | ||||
| /* Index of each register */ | ||||
|  | ||||
| #define TSEC_ID      (0x000 / 4) | ||||
| #define TSEC_ID2     (0x004 / 4) | ||||
| #define IEVENT       (0x010 / 4) | ||||
| #define IMASK        (0x014 / 4) | ||||
| #define EDIS         (0x018 / 4) | ||||
| #define ECNTRL       (0x020 / 4) | ||||
| #define PTV          (0x028 / 4) | ||||
| #define DMACTRL      (0x02C / 4) | ||||
| #define TBIPA        (0x030 / 4) | ||||
| #define TCTRL        (0x100 / 4) | ||||
| #define TSTAT        (0x104 / 4) | ||||
| #define DFVLAN       (0x108 / 4) | ||||
| #define TXIC         (0x110 / 4) | ||||
| #define TQUEUE       (0x114 / 4) | ||||
| #define TR03WT       (0x140 / 4) | ||||
| #define TR47WT       (0x144 / 4) | ||||
| #define TBDBPH       (0x180 / 4) | ||||
| #define TBPTR0       (0x184 / 4) | ||||
| #define TBPTR1       (0x18C / 4) | ||||
| #define TBPTR2       (0x194 / 4) | ||||
| #define TBPTR3       (0x19C / 4) | ||||
| #define TBPTR4       (0x1A4 / 4) | ||||
| #define TBPTR5       (0x1AC / 4) | ||||
| #define TBPTR6       (0x1B4 / 4) | ||||
| #define TBPTR7       (0x1BC / 4) | ||||
| #define TBASEH       (0x200 / 4) | ||||
| #define TBASE0       (0x204 / 4) | ||||
| #define TBASE1       (0x20C / 4) | ||||
| #define TBASE2       (0x214 / 4) | ||||
| #define TBASE3       (0x21C / 4) | ||||
| #define TBASE4       (0x224 / 4) | ||||
| #define TBASE5       (0x22C / 4) | ||||
| #define TBASE6       (0x234 / 4) | ||||
| #define TBASE7       (0x23C / 4) | ||||
| #define TMR_TXTS1_ID (0x280 / 4) | ||||
| #define TMR_TXTS2_ID (0x284 / 4) | ||||
| #define TMR_TXTS1_H  (0x2C0 / 4) | ||||
| #define TMR_TXTS1_L  (0x2C4 / 4) | ||||
| #define TMR_TXTS2_H  (0x2C8 / 4) | ||||
| #define TMR_TXTS2_L  (0x2CC / 4) | ||||
| #define RCTRL        (0x300 / 4) | ||||
| #define RSTAT        (0x304 / 4) | ||||
| #define RXIC         (0x310 / 4) | ||||
| #define RQUEUE       (0x314 / 4) | ||||
| #define RBIFX        (0x330 / 4) | ||||
| #define RQFAR        (0x334 / 4) | ||||
| #define RQFCR        (0x338 / 4) | ||||
| #define RQFPR        (0x33C / 4) | ||||
| #define MRBLR        (0x340 / 4) | ||||
| #define RBDBPH       (0x380 / 4) | ||||
| #define RBPTR0       (0x384 / 4) | ||||
| #define RBPTR1       (0x38C / 4) | ||||
| #define RBPTR2       (0x394 / 4) | ||||
| #define RBPTR3       (0x39C / 4) | ||||
| #define RBPTR4       (0x3A4 / 4) | ||||
| #define RBPTR5       (0x3AC / 4) | ||||
| #define RBPTR6       (0x3B4 / 4) | ||||
| #define RBPTR7       (0x3BC / 4) | ||||
| #define RBASEH       (0x400 / 4) | ||||
| #define RBASE0       (0x404 / 4) | ||||
| #define RBASE1       (0x40C / 4) | ||||
| #define RBASE2       (0x414 / 4) | ||||
| #define RBASE3       (0x41C / 4) | ||||
| #define RBASE4       (0x424 / 4) | ||||
| #define RBASE5       (0x42C / 4) | ||||
| #define RBASE6       (0x434 / 4) | ||||
| #define RBASE7       (0x43C / 4) | ||||
| #define TMR_RXTS_H   (0x4C0 / 4) | ||||
| #define TMR_RXTS_L   (0x4C4 / 4) | ||||
| #define MACCFG1      (0x500 / 4) | ||||
| #define MACCFG2      (0x504 / 4) | ||||
| #define IPGIFG       (0x508 / 4) | ||||
| #define HAFDUP       (0x50C / 4) | ||||
| #define MAXFRM       (0x510 / 4) | ||||
| #define MIIMCFG      (0x520 / 4) | ||||
| #define MIIMCOM      (0x524 / 4) | ||||
| #define MIIMADD      (0x528 / 4) | ||||
| #define MIIMCON      (0x52C / 4) | ||||
| #define MIIMSTAT     (0x530 / 4) | ||||
| #define MIIMIND      (0x534 / 4) | ||||
| #define IFSTAT       (0x53C / 4) | ||||
| #define MACSTNADDR1  (0x540 / 4) | ||||
| #define MACSTNADDR2  (0x544 / 4) | ||||
| #define MAC01ADDR1   (0x548 / 4) | ||||
| #define MAC01ADDR2   (0x54C / 4) | ||||
| #define MAC02ADDR1   (0x550 / 4) | ||||
| #define MAC02ADDR2   (0x554 / 4) | ||||
| #define MAC03ADDR1   (0x558 / 4) | ||||
| #define MAC03ADDR2   (0x55C / 4) | ||||
| #define MAC04ADDR1   (0x560 / 4) | ||||
| #define MAC04ADDR2   (0x564 / 4) | ||||
| #define MAC05ADDR1   (0x568 / 4) | ||||
| #define MAC05ADDR2   (0x56C / 4) | ||||
| #define MAC06ADDR1   (0x570 / 4) | ||||
| #define MAC06ADDR2   (0x574 / 4) | ||||
| #define MAC07ADDR1   (0x578 / 4) | ||||
| #define MAC07ADDR2   (0x57C / 4) | ||||
| #define MAC08ADDR1   (0x580 / 4) | ||||
| #define MAC08ADDR2   (0x584 / 4) | ||||
| #define MAC09ADDR1   (0x588 / 4) | ||||
| #define MAC09ADDR2   (0x58C / 4) | ||||
| #define MAC10ADDR1   (0x590 / 4) | ||||
| #define MAC10ADDR2   (0x594 / 4) | ||||
| #define MAC11ADDR1   (0x598 / 4) | ||||
| #define MAC11ADDR2   (0x59C / 4) | ||||
| #define MAC12ADDR1   (0x5A0 / 4) | ||||
| #define MAC12ADDR2   (0x5A4 / 4) | ||||
| #define MAC13ADDR1   (0x5A8 / 4) | ||||
| #define MAC13ADDR2   (0x5AC / 4) | ||||
| #define MAC14ADDR1   (0x5B0 / 4) | ||||
| #define MAC14ADDR2   (0x5B4 / 4) | ||||
| #define MAC15ADDR1   (0x5B8 / 4) | ||||
| #define MAC15ADDR2   (0x5BC / 4) | ||||
| #define TR64         (0x680 / 4) | ||||
| #define TR127        (0x684 / 4) | ||||
| #define TR255        (0x688 / 4) | ||||
| #define TR511        (0x68C / 4) | ||||
| #define TR1K         (0x690 / 4) | ||||
| #define TRMAX        (0x694 / 4) | ||||
| #define TRMGV        (0x698 / 4) | ||||
| #define RBYT         (0x69C / 4) | ||||
| #define RPKT         (0x6A0 / 4) | ||||
| #define RFCS         (0x6A4 / 4) | ||||
| #define RMCA         (0x6A8 / 4) | ||||
| #define RBCA         (0x6AC / 4) | ||||
| #define RXCF         (0x6B0 / 4) | ||||
| #define RXPF         (0x6B4 / 4) | ||||
| #define RXUO         (0x6B8 / 4) | ||||
| #define RALN         (0x6BC / 4) | ||||
| #define RFLR         (0x6C0 / 4) | ||||
| #define RCDE         (0x6C4 / 4) | ||||
| #define RCSE         (0x6C8 / 4) | ||||
| #define RUND         (0x6CC / 4) | ||||
| #define ROVR         (0x6D0 / 4) | ||||
| #define RFRG         (0x6D4 / 4) | ||||
| #define RJBR         (0x6D8 / 4) | ||||
| #define RDRP         (0x6DC / 4) | ||||
| #define TBYT         (0x6E0 / 4) | ||||
| #define TPKT         (0x6E4 / 4) | ||||
| #define TMCA         (0x6E8 / 4) | ||||
| #define TBCA         (0x6EC / 4) | ||||
| #define TXPF         (0x6F0 / 4) | ||||
| #define TDFR         (0x6F4 / 4) | ||||
| #define TEDF         (0x6F8 / 4) | ||||
| #define TSCL         (0x6FC / 4) | ||||
| #define TMCL         (0x700 / 4) | ||||
| #define TLCL         (0x704 / 4) | ||||
| #define TXCL         (0x708 / 4) | ||||
| #define TNCL         (0x70C / 4) | ||||
| #define TDRP         (0x714 / 4) | ||||
| #define TJBR         (0x718 / 4) | ||||
| #define TFCS         (0x71C / 4) | ||||
| #define TXCF         (0x720 / 4) | ||||
| #define TOVR         (0x724 / 4) | ||||
| #define TUND         (0x728 / 4) | ||||
| #define TFRG         (0x72C / 4) | ||||
| #define CAR1         (0x730 / 4) | ||||
| #define CAR2         (0x734 / 4) | ||||
| #define CAM1         (0x738 / 4) | ||||
| #define CAM2         (0x73C / 4) | ||||
| #define RREJ         (0x740 / 4) | ||||
| #define IGADDR0      (0x800 / 4) | ||||
| #define IGADDR1      (0x804 / 4) | ||||
| #define IGADDR2      (0x808 / 4) | ||||
| #define IGADDR3      (0x80C / 4) | ||||
| #define IGADDR4      (0x810 / 4) | ||||
| #define IGADDR5      (0x814 / 4) | ||||
| #define IGADDR6      (0x818 / 4) | ||||
| #define IGADDR7      (0x81C / 4) | ||||
| #define GADDR0       (0x880 / 4) | ||||
| #define GADDR1       (0x884 / 4) | ||||
| #define GADDR2       (0x888 / 4) | ||||
| #define GADDR3       (0x88C / 4) | ||||
| #define GADDR4       (0x890 / 4) | ||||
| #define GADDR5       (0x894 / 4) | ||||
| #define GADDR6       (0x898 / 4) | ||||
| #define GADDR7       (0x89C / 4) | ||||
| #define ATTR         (0xBF8 / 4) | ||||
| #define ATTRELI      (0xBFC / 4) | ||||
| #define RQPRM0       (0xC00 / 4) | ||||
| #define RQPRM1       (0xC04 / 4) | ||||
| #define RQPRM2       (0xC08 / 4) | ||||
| #define RQPRM3       (0xC0C / 4) | ||||
| #define RQPRM4       (0xC10 / 4) | ||||
| #define RQPRM5       (0xC14 / 4) | ||||
| #define RQPRM6       (0xC18 / 4) | ||||
| #define RQPRM7       (0xC1C / 4) | ||||
| #define RFBPTR0      (0xC44 / 4) | ||||
| #define RFBPTR1      (0xC4C / 4) | ||||
| #define RFBPTR2      (0xC54 / 4) | ||||
| #define RFBPTR3      (0xC5C / 4) | ||||
| #define RFBPTR4      (0xC64 / 4) | ||||
| #define RFBPTR5      (0xC6C / 4) | ||||
| #define RFBPTR6      (0xC74 / 4) | ||||
| #define RFBPTR7      (0xC7C / 4) | ||||
| #define TMR_CTRL     (0xE00 / 4) | ||||
| #define TMR_TEVENT   (0xE04 / 4) | ||||
| #define TMR_TEMASK   (0xE08 / 4) | ||||
| #define TMR_PEVENT   (0xE0C / 4) | ||||
| #define TMR_PEMASK   (0xE10 / 4) | ||||
| #define TMR_STAT     (0xE14 / 4) | ||||
| #define TMR_CNT_H    (0xE18 / 4) | ||||
| #define TMR_CNT_L    (0xE1C / 4) | ||||
| #define TMR_ADD      (0xE20 / 4) | ||||
| #define TMR_ACC      (0xE24 / 4) | ||||
| #define TMR_PRSC     (0xE28 / 4) | ||||
| #define TMROFF_H     (0xE30 / 4) | ||||
| #define TMROFF_L     (0xE34 / 4) | ||||
| #define TMR_ALARM1_H (0xE40 / 4) | ||||
| #define TMR_ALARM1_L (0xE44 / 4) | ||||
| #define TMR_ALARM2_H (0xE48 / 4) | ||||
| #define TMR_ALARM2_L (0xE4C / 4) | ||||
| #define TMR_FIPER1   (0xE80 / 4) | ||||
| #define TMR_FIPER2   (0xE84 / 4) | ||||
| #define TMR_FIPER3   (0xE88 / 4) | ||||
| #define TMR_ETTS1_H  (0xEA0 / 4) | ||||
| #define TMR_ETTS1_L  (0xEA4 / 4) | ||||
| #define TMR_ETTS2_H  (0xEA8 / 4) | ||||
| #define TMR_ETTS2_L  (0xEAC / 4) | ||||
|  | ||||
| #endif /* ! _ETSEC_REGISTERS_H_ */ | ||||
							
								
								
									
										650
									
								
								hw/net/fsl_etsec/rings.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										650
									
								
								hw/net/fsl_etsec/rings.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,650 @@ | ||||
| /* | ||||
|  * QEMU Freescale eTSEC Emulator | ||||
|  * | ||||
|  * Copyright (c) 2011-2013 AdaCore | ||||
|  * | ||||
|  * 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 "net/checksum.h" | ||||
|  | ||||
| #include "etsec.h" | ||||
| #include "registers.h" | ||||
|  | ||||
| /* #define ETSEC_RING_DEBUG */ | ||||
| /* #define HEX_DUMP */ | ||||
| /* #define DEBUG_BD */ | ||||
|  | ||||
| #ifdef ETSEC_RING_DEBUG | ||||
| static const int debug_etsec = 1; | ||||
| #else | ||||
| static const int debug_etsec; | ||||
| #endif | ||||
|  | ||||
| #define RING_DEBUG(fmt, ...) do {              \ | ||||
|  if (debug_etsec) {                            \ | ||||
|         qemu_log(fmt , ## __VA_ARGS__);        \ | ||||
|     }                                          \ | ||||
|     } while (0) | ||||
|  | ||||
| #ifdef DEBUG_BD | ||||
|  | ||||
| static void print_tx_bd_flags(uint16_t flags) | ||||
| { | ||||
|     qemu_log("      Ready: %d\n", !!(flags & BD_TX_READY)); | ||||
|     qemu_log("      PAD/CRC: %d\n", !!(flags & BD_TX_PADCRC)); | ||||
|     qemu_log("      Wrap: %d\n", !!(flags & BD_WRAP)); | ||||
|     qemu_log("      Interrupt: %d\n", !!(flags & BD_INTERRUPT)); | ||||
|     qemu_log("      Last in frame: %d\n", !!(flags & BD_LAST)); | ||||
|     qemu_log("      Tx CRC: %d\n", !!(flags & BD_TX_TC)); | ||||
|     qemu_log("      User-defined preamble / defer: %d\n", | ||||
|            !!(flags & BD_TX_PREDEF)); | ||||
|     qemu_log("      Huge frame enable / Late collision: %d\n", | ||||
|            !!(flags & BD_TX_HFELC)); | ||||
|     qemu_log("      Control frame / Retransmission Limit: %d\n", | ||||
|            !!(flags & BD_TX_CFRL)); | ||||
|     qemu_log("      Retry count: %d\n", | ||||
|            (flags >> BD_TX_RC_OFFSET) & BD_TX_RC_MASK); | ||||
|     qemu_log("      Underrun / TCP/IP off-load enable: %d\n", | ||||
|            !!(flags & BD_TX_TOEUN)); | ||||
|     qemu_log("      Truncation: %d\n", !!(flags & BD_TX_TR)); | ||||
| } | ||||
|  | ||||
| static void print_rx_bd_flags(uint16_t flags) | ||||
| { | ||||
|     qemu_log("      Empty: %d\n", !!(flags & BD_RX_EMPTY)); | ||||
|     qemu_log("      Receive software ownership: %d\n", !!(flags & BD_RX_RO1)); | ||||
|     qemu_log("      Wrap: %d\n", !!(flags & BD_WRAP)); | ||||
|     qemu_log("      Interrupt: %d\n", !!(flags & BD_INTERRUPT)); | ||||
|     qemu_log("      Last in frame: %d\n", !!(flags & BD_LAST)); | ||||
|     qemu_log("      First in frame: %d\n", !!(flags & BD_RX_FIRST)); | ||||
|     qemu_log("      Miss: %d\n", !!(flags & BD_RX_MISS)); | ||||
|     qemu_log("      Broadcast: %d\n", !!(flags & BD_RX_BROADCAST)); | ||||
|     qemu_log("      Multicast: %d\n", !!(flags & BD_RX_MULTICAST)); | ||||
|     qemu_log("      Rx frame length violation: %d\n", !!(flags & BD_RX_LG)); | ||||
|     qemu_log("      Rx non-octet aligned frame: %d\n", !!(flags & BD_RX_NO)); | ||||
|     qemu_log("      Short frame: %d\n", !!(flags & BD_RX_SH)); | ||||
|     qemu_log("      Rx CRC Error: %d\n", !!(flags & BD_RX_CR)); | ||||
|     qemu_log("      Overrun: %d\n", !!(flags & BD_RX_OV)); | ||||
|     qemu_log("      Truncation: %d\n", !!(flags & BD_RX_TR)); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void print_bd(eTSEC_rxtx_bd bd, int mode, uint32_t index) | ||||
| { | ||||
|     qemu_log("eTSEC %s Data Buffer Descriptor (%u)\n", | ||||
|            mode == eTSEC_TRANSMIT ? "Transmit" : "Receive", | ||||
|            index); | ||||
|     qemu_log("   Flags   : 0x%04x\n", bd.flags); | ||||
|     if (mode == eTSEC_TRANSMIT) { | ||||
|         print_tx_bd_flags(bd.flags); | ||||
|     } else { | ||||
|         print_rx_bd_flags(bd.flags); | ||||
|     } | ||||
|     qemu_log("   Length  : 0x%04x\n", bd.length); | ||||
|     qemu_log("   Pointer : 0x%08x\n", bd.bufptr); | ||||
| } | ||||
|  | ||||
| #endif  /* DEBUG_BD */ | ||||
|  | ||||
| static void read_buffer_descriptor(eTSEC         *etsec, | ||||
|                                    hwaddr         addr, | ||||
|                                    eTSEC_rxtx_bd *bd) | ||||
| { | ||||
|     assert(bd != NULL); | ||||
|  | ||||
|     RING_DEBUG("READ Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr); | ||||
|     cpu_physical_memory_read(addr, | ||||
|                              bd, | ||||
|                              sizeof(eTSEC_rxtx_bd)); | ||||
|  | ||||
|     if (etsec->regs[DMACTRL].value & DMACTRL_LE) { | ||||
|         bd->flags  = lduw_le_p(&bd->flags); | ||||
|         bd->length = lduw_le_p(&bd->length); | ||||
|         bd->bufptr = ldl_le_p(&bd->bufptr); | ||||
|     } else { | ||||
|         bd->flags  = lduw_be_p(&bd->flags); | ||||
|         bd->length = lduw_be_p(&bd->length); | ||||
|         bd->bufptr = ldl_be_p(&bd->bufptr); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void write_buffer_descriptor(eTSEC         *etsec, | ||||
|                                     hwaddr         addr, | ||||
|                                     eTSEC_rxtx_bd *bd) | ||||
| { | ||||
|     assert(bd != NULL); | ||||
|  | ||||
|     if (etsec->regs[DMACTRL].value & DMACTRL_LE) { | ||||
|         stw_le_p(&bd->flags, bd->flags); | ||||
|         stw_le_p(&bd->length, bd->length); | ||||
|         stl_le_p(&bd->bufptr, bd->bufptr); | ||||
|     } else { | ||||
|         stw_be_p(&bd->flags, bd->flags); | ||||
|         stw_be_p(&bd->length, bd->length); | ||||
|         stl_be_p(&bd->bufptr, bd->bufptr); | ||||
|     } | ||||
|  | ||||
|     RING_DEBUG("Write Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr); | ||||
|     cpu_physical_memory_write(addr, | ||||
|                               bd, | ||||
|                               sizeof(eTSEC_rxtx_bd)); | ||||
| } | ||||
|  | ||||
| static void ievent_set(eTSEC    *etsec, | ||||
|                        uint32_t  flags) | ||||
| { | ||||
|     etsec->regs[IEVENT].value |= flags; | ||||
|  | ||||
|     if ((flags & IEVENT_TXB && etsec->regs[IMASK].value & IMASK_TXBEN) | ||||
|         || (flags & IEVENT_TXF && etsec->regs[IMASK].value & IMASK_TXFEN)) { | ||||
|         qemu_irq_raise(etsec->tx_irq); | ||||
|         RING_DEBUG("%s Raise Tx IRQ\n", __func__); | ||||
|     } | ||||
|  | ||||
|     if ((flags & IEVENT_RXB && etsec->regs[IMASK].value & IMASK_RXBEN) | ||||
|         || (flags & IEVENT_RXF && etsec->regs[IMASK].value & IMASK_RXFEN)) { | ||||
|         qemu_irq_pulse(etsec->rx_irq); | ||||
|         RING_DEBUG("%s Raise Rx IRQ\n", __func__); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void tx_padding_and_crc(eTSEC *etsec, uint32_t min_frame_len) | ||||
| { | ||||
|     int add = min_frame_len - etsec->tx_buffer_len; | ||||
|  | ||||
|     /* Padding */ | ||||
|     if (add > 0) { | ||||
|         RING_DEBUG("pad:%u\n", add); | ||||
|         etsec->tx_buffer = g_realloc(etsec->tx_buffer, | ||||
|                                         etsec->tx_buffer_len + add); | ||||
|  | ||||
|         memset(etsec->tx_buffer + etsec->tx_buffer_len, 0x0, add); | ||||
|         etsec->tx_buffer_len += add; | ||||
|     } | ||||
|  | ||||
|     /* Never add CRC in QEMU */ | ||||
| } | ||||
|  | ||||
| static void process_tx_fcb(eTSEC *etsec) | ||||
| { | ||||
|     uint8_t flags = (uint8_t)(*etsec->tx_buffer); | ||||
|     /* L3 header offset from start of frame */ | ||||
|     uint8_t l3_header_offset = (uint8_t)*(etsec->tx_buffer + 3); | ||||
|     /* L4 header offset from start of L3 header */ | ||||
|     uint8_t l4_header_offset = (uint8_t)*(etsec->tx_buffer + 2); | ||||
|     /* L3 header */ | ||||
|     uint8_t *l3_header = etsec->tx_buffer + 8 + l3_header_offset; | ||||
|     /* L4 header */ | ||||
|     uint8_t *l4_header = l3_header + l4_header_offset; | ||||
|  | ||||
|     /* if packet is IP4 and IP checksum is requested */ | ||||
|     if (flags & FCB_TX_IP && flags & FCB_TX_CIP) { | ||||
|         /* do IP4 checksum (TODO This funtion does TCP/UDP checksum but not sure | ||||
|          * if it also does IP4 checksum. */ | ||||
|         net_checksum_calculate(etsec->tx_buffer + 8, | ||||
|                 etsec->tx_buffer_len - 8); | ||||
|     } | ||||
|     /* TODO Check the correct usage of the PHCS field of the FCB in case the NPH | ||||
|      * flag is on */ | ||||
|  | ||||
|     /* if packet is IP4 and TCP or UDP */ | ||||
|     if (flags & FCB_TX_IP && flags & FCB_TX_TUP) { | ||||
|         /* if UDP */ | ||||
|         if (flags & FCB_TX_UDP) { | ||||
|             /* if checksum is requested */ | ||||
|             if (flags & FCB_TX_CTU) { | ||||
|                 /* do UDP checksum */ | ||||
|  | ||||
|                 net_checksum_calculate(etsec->tx_buffer + 8, | ||||
|                         etsec->tx_buffer_len - 8); | ||||
|             } else { | ||||
|                 /* set checksum field to 0 */ | ||||
|                 l4_header[6] = 0; | ||||
|                 l4_header[7] = 0; | ||||
|             } | ||||
|         } else if (flags & FCB_TX_CTU) { /* if TCP and checksum is requested */ | ||||
|             /* do TCP checksum */ | ||||
|             net_checksum_calculate(etsec->tx_buffer + 8, | ||||
|                                    etsec->tx_buffer_len - 8); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void process_tx_bd(eTSEC         *etsec, | ||||
|                           eTSEC_rxtx_bd *bd) | ||||
| { | ||||
|     uint8_t *tmp_buff = NULL; | ||||
|     hwaddr tbdbth     = (hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32; | ||||
|  | ||||
|     if (bd->length == 0) { | ||||
|         /* ERROR */ | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (etsec->tx_buffer_len == 0) { | ||||
|         /* It's the first BD */ | ||||
|         etsec->first_bd = *bd; | ||||
|     } | ||||
|  | ||||
|     /* TODO: if TxBD[TOE/UN] skip the Tx Frame Control Block*/ | ||||
|  | ||||
|     /* Load this Data Buffer */ | ||||
|     etsec->tx_buffer = g_realloc(etsec->tx_buffer, | ||||
|                                     etsec->tx_buffer_len + bd->length); | ||||
|     tmp_buff = etsec->tx_buffer + etsec->tx_buffer_len; | ||||
|     cpu_physical_memory_read(bd->bufptr + tbdbth, tmp_buff, bd->length); | ||||
|  | ||||
|     /* Update buffer length */ | ||||
|     etsec->tx_buffer_len += bd->length; | ||||
|  | ||||
|  | ||||
|     if (etsec->tx_buffer_len != 0 && (bd->flags & BD_LAST)) { | ||||
|         if (etsec->regs[MACCFG1].value & MACCFG1_TX_EN) { | ||||
|             /* MAC Transmit enabled */ | ||||
|  | ||||
|             /* Process offload Tx FCB */ | ||||
|             if (etsec->first_bd.flags & BD_TX_TOEUN) { | ||||
|                 process_tx_fcb(etsec); | ||||
|             } | ||||
|  | ||||
|             if (etsec->first_bd.flags & BD_TX_PADCRC | ||||
|                 || etsec->regs[MACCFG2].value & MACCFG2_PADCRC) { | ||||
|  | ||||
|                 /* Padding and CRC (Padding implies CRC) */ | ||||
|                 tx_padding_and_crc(etsec, 64); | ||||
|  | ||||
|             } else if (etsec->first_bd.flags & BD_TX_TC | ||||
|                        || etsec->regs[MACCFG2].value & MACCFG2_CRC_EN) { | ||||
|  | ||||
|                 /* Only CRC */ | ||||
|                 /* Never add CRC in QEMU */ | ||||
|             } | ||||
|  | ||||
| #if defined(HEX_DUMP) | ||||
|             qemu_log("eTSEC Send packet size:%d\n", etsec->tx_buffer_len); | ||||
|             qemu_hexdump(etsec->tx_buffer, stderr, "", etsec->tx_buffer_len); | ||||
| #endif  /* ETSEC_RING_DEBUG */ | ||||
|  | ||||
|             if (etsec->first_bd.flags & BD_TX_TOEUN) { | ||||
|                 qemu_send_packet(qemu_get_queue(etsec->nic), | ||||
|                         etsec->tx_buffer + 8, | ||||
|                         etsec->tx_buffer_len - 8); | ||||
|             } else { | ||||
|                 qemu_send_packet(qemu_get_queue(etsec->nic), | ||||
|                         etsec->tx_buffer, | ||||
|                         etsec->tx_buffer_len); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         etsec->tx_buffer_len = 0; | ||||
|  | ||||
|         if (bd->flags & BD_INTERRUPT) { | ||||
|             ievent_set(etsec, IEVENT_TXF); | ||||
|         } | ||||
|     } else { | ||||
|         if (bd->flags & BD_INTERRUPT) { | ||||
|             ievent_set(etsec, IEVENT_TXB); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* Update DB flags */ | ||||
|  | ||||
|     /* Clear Ready */ | ||||
|     bd->flags &= ~BD_TX_READY; | ||||
|  | ||||
|     /* Clear Defer */ | ||||
|     bd->flags &= ~BD_TX_PREDEF; | ||||
|  | ||||
|     /* Clear Late Collision */ | ||||
|     bd->flags &= ~BD_TX_HFELC; | ||||
|  | ||||
|     /* Clear Retransmission Limit */ | ||||
|     bd->flags &= ~BD_TX_CFRL; | ||||
|  | ||||
|     /* Clear Retry Count */ | ||||
|     bd->flags &= ~(BD_TX_RC_MASK << BD_TX_RC_OFFSET); | ||||
|  | ||||
|     /* Clear Underrun */ | ||||
|     bd->flags &= ~BD_TX_TOEUN; | ||||
|  | ||||
|     /* Clear Truncation */ | ||||
|     bd->flags &= ~BD_TX_TR; | ||||
| } | ||||
|  | ||||
| void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr) | ||||
| { | ||||
|     hwaddr        ring_base = 0; | ||||
|     hwaddr        bd_addr   = 0; | ||||
|     eTSEC_rxtx_bd bd; | ||||
|     uint16_t      bd_flags; | ||||
|  | ||||
|     if (!(etsec->regs[MACCFG1].value & MACCFG1_TX_EN)) { | ||||
|         RING_DEBUG("%s: MAC Transmit not enabled\n", __func__); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     ring_base = (hwaddr)(etsec->regs[TBASEH].value & 0xF) << 32; | ||||
|     ring_base += etsec->regs[TBASE0 + ring_nbr].value & ~0x7; | ||||
|     bd_addr    = etsec->regs[TBPTR0 + ring_nbr].value & ~0x7; | ||||
|  | ||||
|     do { | ||||
|         read_buffer_descriptor(etsec, bd_addr, &bd); | ||||
|  | ||||
| #ifdef DEBUG_BD | ||||
|         print_bd(bd, | ||||
|                  eTSEC_TRANSMIT, | ||||
|                  (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd)); | ||||
|  | ||||
| #endif  /* DEBUG_BD */ | ||||
|  | ||||
|         /* Save flags before BD update */ | ||||
|         bd_flags = bd.flags; | ||||
|  | ||||
|         if (bd_flags & BD_TX_READY) { | ||||
|             process_tx_bd(etsec, &bd); | ||||
|  | ||||
|             /* Write back BD after update */ | ||||
|             write_buffer_descriptor(etsec, bd_addr, &bd); | ||||
|         } | ||||
|  | ||||
|         /* Wrap or next BD */ | ||||
|         if (bd_flags & BD_WRAP) { | ||||
|             bd_addr = ring_base; | ||||
|         } else { | ||||
|             bd_addr += sizeof(eTSEC_rxtx_bd); | ||||
|         } | ||||
|  | ||||
|     } while (bd_addr != ring_base); | ||||
|  | ||||
|     bd_addr = ring_base; | ||||
|  | ||||
|     /* Save the Buffer Descriptor Pointers to current bd */ | ||||
|     etsec->regs[TBPTR0 + ring_nbr].value = bd_addr; | ||||
|  | ||||
|     /* Set transmit halt THLTx */ | ||||
|     etsec->regs[TSTAT].value |= 1 << (31 - ring_nbr); | ||||
| } | ||||
|  | ||||
| static void fill_rx_bd(eTSEC          *etsec, | ||||
|                        eTSEC_rxtx_bd  *bd, | ||||
|                        const uint8_t **buf, | ||||
|                        size_t         *size) | ||||
| { | ||||
|     uint16_t to_write; | ||||
|     hwaddr   bufptr = bd->bufptr + | ||||
|         ((hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32); | ||||
|     uint8_t  padd[etsec->rx_padding]; | ||||
|     uint8_t  rem; | ||||
|  | ||||
|     RING_DEBUG("eTSEC fill Rx buffer @ 0x%016" HWADDR_PRIx | ||||
|                " size:%zu(padding + crc:%u) + fcb:%u\n", | ||||
|                bufptr, *size, etsec->rx_padding, etsec->rx_fcb_size); | ||||
|  | ||||
|     bd->length = 0; | ||||
|  | ||||
|     /* This operation will only write FCB */ | ||||
|     if (etsec->rx_fcb_size != 0) { | ||||
|  | ||||
|         cpu_physical_memory_write(bufptr, etsec->rx_fcb, etsec->rx_fcb_size); | ||||
|  | ||||
|         bufptr             += etsec->rx_fcb_size; | ||||
|         bd->length         += etsec->rx_fcb_size; | ||||
|         etsec->rx_fcb_size  = 0; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /* We remove padding from the computation of to_write because it is not | ||||
|      * allocated in the buffer. | ||||
|      */ | ||||
|     to_write = MIN(*size - etsec->rx_padding, | ||||
|                    etsec->regs[MRBLR].value - etsec->rx_fcb_size); | ||||
|  | ||||
|     /* This operation can only write packet data and no padding */ | ||||
|     if (to_write > 0) { | ||||
|         cpu_physical_memory_write(bufptr, *buf, to_write); | ||||
|  | ||||
|         *buf   += to_write; | ||||
|         bufptr += to_write; | ||||
|         *size  -= to_write; | ||||
|  | ||||
|         bd->flags  &= ~BD_RX_EMPTY; | ||||
|         bd->length += to_write; | ||||
|     } | ||||
|  | ||||
|     if (*size == etsec->rx_padding) { | ||||
|         /* The remaining bytes are only for padding which is not actually | ||||
|          * allocated in the data buffer. | ||||
|          */ | ||||
|  | ||||
|         rem = MIN(etsec->regs[MRBLR].value - bd->length, etsec->rx_padding); | ||||
|  | ||||
|         if (rem > 0) { | ||||
|             memset(padd, 0x0, sizeof(padd)); | ||||
|             etsec->rx_padding -= rem; | ||||
|             *size             -= rem; | ||||
|             bd->length        += rem; | ||||
|             cpu_physical_memory_write(bufptr, padd, rem); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size) | ||||
| { | ||||
|     uint32_t fcb_size = 0; | ||||
|     uint8_t  prsdep   = (etsec->regs[RCTRL].value >> RCTRL_PRSDEP_OFFSET) | ||||
|         & RCTRL_PRSDEP_MASK; | ||||
|  | ||||
|     if (prsdep != 0) { | ||||
|         /* Prepend FCB (FCB size + RCTRL[PAL]) */ | ||||
|         fcb_size = 8 + ((etsec->regs[RCTRL].value >> 16) & 0x1F); | ||||
|  | ||||
|         etsec->rx_fcb_size = fcb_size; | ||||
|  | ||||
|         /* TODO: fill_FCB(etsec); */ | ||||
|         memset(etsec->rx_fcb, 0x0, sizeof(etsec->rx_fcb)); | ||||
|  | ||||
|     } else { | ||||
|         etsec->rx_fcb_size = 0; | ||||
|     } | ||||
|  | ||||
|     if (etsec->rx_buffer != NULL) { | ||||
|         g_free(etsec->rx_buffer); | ||||
|     } | ||||
|  | ||||
|     /* Do not copy the frame for now */ | ||||
|     etsec->rx_buffer     = (uint8_t *)buf; | ||||
|     etsec->rx_buffer_len = size; | ||||
|  | ||||
|     /* CRC padding (We don't have to compute the CRC) */ | ||||
|     etsec->rx_padding = 4; | ||||
|  | ||||
|     etsec->rx_first_in_frame = 1; | ||||
|     etsec->rx_remaining_data = etsec->rx_buffer_len; | ||||
|     RING_DEBUG("%s: rx_buffer_len:%u rx_padding+crc:%u\n", __func__, | ||||
|                etsec->rx_buffer_len, etsec->rx_padding); | ||||
| } | ||||
|  | ||||
| void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size) | ||||
| { | ||||
|     int ring_nbr = 0;           /* Always use ring0 (no filer) */ | ||||
|  | ||||
|     if (etsec->rx_buffer_len != 0) { | ||||
|         RING_DEBUG("%s: We can't receive now," | ||||
|                    " a buffer is already in the pipe\n", __func__); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (etsec->regs[RSTAT].value & 1 << (23 - ring_nbr)) { | ||||
|         RING_DEBUG("%s: The ring is halted\n", __func__); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (etsec->regs[DMACTRL].value & DMACTRL_GRS) { | ||||
|         RING_DEBUG("%s: Graceful receive stop\n", __func__); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!(etsec->regs[MACCFG1].value & MACCFG1_RX_EN)) { | ||||
|         RING_DEBUG("%s: MAC Receive not enabled\n", __func__); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if ((etsec->regs[RCTRL].value & RCTRL_RSF) && (size < 60)) { | ||||
|         /* CRC is not in the packet yet, so short frame is below 60 bytes */ | ||||
|         RING_DEBUG("%s: Drop short frame\n", __func__); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     rx_init_frame(etsec, buf, size); | ||||
|  | ||||
|     etsec_walk_rx_ring(etsec, ring_nbr); | ||||
| } | ||||
|  | ||||
| void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr) | ||||
| { | ||||
|     hwaddr         ring_base     = 0; | ||||
|     hwaddr         bd_addr       = 0; | ||||
|     hwaddr         start_bd_addr = 0; | ||||
|     eTSEC_rxtx_bd  bd; | ||||
|     uint16_t       bd_flags; | ||||
|     size_t         remaining_data; | ||||
|     const uint8_t *buf; | ||||
|     uint8_t       *tmp_buf; | ||||
|     size_t         size; | ||||
|  | ||||
|     if (etsec->rx_buffer_len == 0) { | ||||
|         /* No frame to send */ | ||||
|         RING_DEBUG("No frame to send\n"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     remaining_data = etsec->rx_remaining_data + etsec->rx_padding; | ||||
|     buf            = etsec->rx_buffer | ||||
|         + (etsec->rx_buffer_len - etsec->rx_remaining_data); | ||||
|     size           = etsec->rx_buffer_len + etsec->rx_padding; | ||||
|  | ||||
|     ring_base = (hwaddr)(etsec->regs[RBASEH].value & 0xF) << 32; | ||||
|     ring_base += etsec->regs[RBASE0 + ring_nbr].value & ~0x7; | ||||
|     start_bd_addr  = bd_addr = etsec->regs[RBPTR0 + ring_nbr].value & ~0x7; | ||||
|  | ||||
|     do { | ||||
|         read_buffer_descriptor(etsec, bd_addr, &bd); | ||||
|  | ||||
| #ifdef DEBUG_BD | ||||
|         print_bd(bd, | ||||
|                  eTSEC_RECEIVE, | ||||
|                  (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd)); | ||||
|  | ||||
| #endif  /* DEBUG_BD */ | ||||
|  | ||||
|         /* Save flags before BD update */ | ||||
|         bd_flags = bd.flags; | ||||
|  | ||||
|         if (bd_flags & BD_RX_EMPTY) { | ||||
|             fill_rx_bd(etsec, &bd, &buf, &remaining_data); | ||||
|  | ||||
|             if (etsec->rx_first_in_frame) { | ||||
|                 bd.flags |= BD_RX_FIRST; | ||||
|                 etsec->rx_first_in_frame = 0; | ||||
|                 etsec->rx_first_bd = bd; | ||||
|             } | ||||
|  | ||||
|             /* Last in frame */ | ||||
|             if (remaining_data == 0) { | ||||
|  | ||||
|                 /* Clear flags */ | ||||
|  | ||||
|                 bd.flags &= ~0x7ff; | ||||
|  | ||||
|                 bd.flags |= BD_LAST; | ||||
|  | ||||
|                 /* NOTE: non-octet aligned frame is impossible in qemu */ | ||||
|  | ||||
|                 if (size >= etsec->regs[MAXFRM].value) { | ||||
|                     /* frame length violation */ | ||||
|                     qemu_log("%s frame length violation: size:%zu MAXFRM:%d\n", | ||||
|                            __func__, size, etsec->regs[MAXFRM].value); | ||||
|  | ||||
|                     bd.flags |= BD_RX_LG; | ||||
|                 } | ||||
|  | ||||
|                 if (size  < 64) { | ||||
|                     /* Short frame */ | ||||
|                     bd.flags |= BD_RX_SH; | ||||
|                 } | ||||
|  | ||||
|                 /* TODO: Broadcast and Multicast */ | ||||
|  | ||||
|                 if (bd.flags | BD_INTERRUPT) { | ||||
|                     /* Set RXFx */ | ||||
|                     etsec->regs[RSTAT].value |= 1 << (7 - ring_nbr); | ||||
|  | ||||
|                     /* Set IEVENT */ | ||||
|                     ievent_set(etsec, IEVENT_RXF); | ||||
|                 } | ||||
|  | ||||
|             } else { | ||||
|                 if (bd.flags | BD_INTERRUPT) { | ||||
|                     /* Set IEVENT */ | ||||
|                     ievent_set(etsec, IEVENT_RXB); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             /* Write back BD after update */ | ||||
|             write_buffer_descriptor(etsec, bd_addr, &bd); | ||||
|         } | ||||
|  | ||||
|         /* Wrap or next BD */ | ||||
|         if (bd_flags & BD_WRAP) { | ||||
|             bd_addr = ring_base; | ||||
|         } else { | ||||
|             bd_addr += sizeof(eTSEC_rxtx_bd); | ||||
|         } | ||||
|     } while (remaining_data != 0 | ||||
|              && (bd_flags & BD_RX_EMPTY) | ||||
|              && bd_addr != start_bd_addr); | ||||
|  | ||||
|     /* Reset ring ptr */ | ||||
|     etsec->regs[RBPTR0 + ring_nbr].value = bd_addr; | ||||
|  | ||||
|     /* The frame is too large to fit in the Rx ring */ | ||||
|     if (remaining_data > 0) { | ||||
|  | ||||
|         /* Set RSTAT[QHLTx] */ | ||||
|         etsec->regs[RSTAT].value |= 1 << (23 - ring_nbr); | ||||
|  | ||||
|         /* Save remaining data to send the end of the frame when the ring will | ||||
|          * be restarted | ||||
|          */ | ||||
|         etsec->rx_remaining_data = remaining_data; | ||||
|  | ||||
|         /* Copy the frame */ | ||||
|         tmp_buf = g_malloc(size); | ||||
|         memcpy(tmp_buf, etsec->rx_buffer, size); | ||||
|         etsec->rx_buffer = tmp_buf; | ||||
|  | ||||
|         RING_DEBUG("no empty RxBD available any more\n"); | ||||
|     } else { | ||||
|         etsec->rx_buffer_len = 0; | ||||
|         etsec->rx_buffer     = NULL; | ||||
|     } | ||||
|  | ||||
|     RING_DEBUG("eTSEC End of ring_write: remaining_data:%zu\n", remaining_data); | ||||
| } | ||||
| @@ -405,6 +405,8 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu, | ||||
|  | ||||
|     dev->rx_bufs++; | ||||
|  | ||||
|     qemu_flush_queued_packets(qemu_get_queue(dev->nic)); | ||||
|  | ||||
|     DPRINTF("h_add_logical_lan_buffer():  Added buf  ptr=%d  rx_bufs=%d" | ||||
|             " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs, | ||||
|             (unsigned long long)buf); | ||||
|   | ||||
| @@ -397,12 +397,15 @@ static int peer_detach(VirtIONet *n, int index) | ||||
| static void virtio_net_set_queues(VirtIONet *n) | ||||
| { | ||||
|     int i; | ||||
|     int r; | ||||
|  | ||||
|     for (i = 0; i < n->max_queues; i++) { | ||||
|         if (i < n->curr_queues) { | ||||
|             assert(!peer_attach(n, i)); | ||||
|             r = peer_attach(n, i); | ||||
|             assert(!r); | ||||
|         } else { | ||||
|             assert(!peer_detach(n, i)); | ||||
|             r = peer_detach(n, i); | ||||
|             assert(!r); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -68,7 +68,7 @@ void init_pam(DeviceState *dev, MemoryRegion *ram_memory, | ||||
|     /* XXX: should distinguish read/write cases */ | ||||
|     memory_region_init_alias(&mem->alias[0], OBJECT(dev), "pam-pci", pci_address_space, | ||||
|                              start, size); | ||||
|     memory_region_init_alias(&mem->alias[2], OBJECT(dev), "pam-pci", pci_address_space, | ||||
|     memory_region_init_alias(&mem->alias[2], OBJECT(dev), "pam-pci", ram_memory, | ||||
|                              start, size); | ||||
|  | ||||
|     for (i = 0; i < 4; ++i) { | ||||
|   | ||||
| @@ -221,29 +221,23 @@ static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev, | ||||
|                                          DeviceState *dev, | ||||
|                                          uint8_t **exp_cap, Error **errp) | ||||
| { | ||||
|     PCIDevice *pci_dev = PCI_DEVICE(dev); | ||||
|     *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap; | ||||
|     uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA); | ||||
|  | ||||
|     PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state); | ||||
|     PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: %d\n", state); | ||||
|     if (sltsta & PCI_EXP_SLTSTA_EIS) { | ||||
|         /* the slot is electromechanically locked. | ||||
|          * This error is propagated up to qdev and then to HMP/QMP. | ||||
|          */ | ||||
|         error_setg_errno(errp, -EBUSY, "slot is electromechanically locked"); | ||||
|     } | ||||
|  | ||||
|     /* TODO: multifunction hot-plug. | ||||
|      * Right now, only a device of function = 0 is allowed to be | ||||
|      * hot plugged/unplugged. | ||||
|      */ | ||||
|     assert(PCI_FUNC(pci_dev->devfn) == 0); | ||||
| } | ||||
|  | ||||
| void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, | ||||
|                               Error **errp) | ||||
| { | ||||
|     uint8_t *exp_cap; | ||||
|     PCIDevice *pci_dev = PCI_DEVICE(dev); | ||||
|  | ||||
|     pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp); | ||||
|  | ||||
| @@ -256,6 +250,12 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /* TODO: multifunction hot-plug. | ||||
|      * Right now, only a device of function = 0 is allowed to be | ||||
|      * hot plugged/unplugged. | ||||
|      */ | ||||
|     assert(PCI_FUNC(pci_dev->devfn) == 0); | ||||
|  | ||||
|     pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, | ||||
|                                PCI_EXP_SLTSTA_PDS); | ||||
|     pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC); | ||||
|   | ||||
| @@ -238,6 +238,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args, | ||||
|        the first node as boot node and be happy */ | ||||
|     for (i = smp_cpus - 1; i >= 0; i--) { | ||||
|         CPUState *cpu; | ||||
|         PowerPCCPU *pcpu; | ||||
|         char cpu_name[128]; | ||||
|         uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20); | ||||
|  | ||||
| @@ -246,14 +247,16 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args, | ||||
|             continue; | ||||
|         } | ||||
|         env = cpu->env_ptr; | ||||
|         pcpu = POWERPC_CPU(cpu); | ||||
|  | ||||
|         snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", | ||||
|                  cpu->cpu_index); | ||||
|                  ppc_get_vcpu_dt_id(pcpu)); | ||||
|         qemu_fdt_add_subnode(fdt, cpu_name); | ||||
|         qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); | ||||
|         qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); | ||||
|         qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu"); | ||||
|         qemu_fdt_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index); | ||||
|         qemu_fdt_setprop_cell(fdt, cpu_name, "reg", | ||||
|                               ppc_get_vcpu_dt_id(pcpu)); | ||||
|         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size", | ||||
|                               env->dcache_line_size); | ||||
|         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size", | ||||
|   | ||||
							
								
								
									
										22
									
								
								hw/ppc/ppc.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								hw/ppc/ppc.c
									
									
									
									
									
								
							| @@ -26,6 +26,7 @@ | ||||
| #include "hw/ppc/ppc_e500.h" | ||||
| #include "qemu/timer.h" | ||||
| #include "sysemu/sysemu.h" | ||||
| #include "sysemu/cpus.h" | ||||
| #include "hw/timer/m48t59.h" | ||||
| #include "qemu/log.h" | ||||
| #include "hw/loader.h" | ||||
| @@ -1362,3 +1363,24 @@ int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /* CPU device-tree ID helpers */ | ||||
| int ppc_get_vcpu_dt_id(PowerPCCPU *cpu) | ||||
| { | ||||
|     return cpu->cpu_dt_id; | ||||
| } | ||||
|  | ||||
| PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id) | ||||
| { | ||||
|     CPUState *cs; | ||||
|  | ||||
|     CPU_FOREACH(cs) { | ||||
|         PowerPCCPU *cpu = POWERPC_CPU(cs); | ||||
|  | ||||
|         if (cpu->cpu_dt_id == cpu_dt_id) { | ||||
|             return cpu; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return NULL; | ||||
| } | ||||
|   | ||||
| @@ -49,6 +49,7 @@ | ||||
| #include "exec/address-spaces.h" | ||||
| #include "hw/usb.h" | ||||
| #include "qemu/config-file.h" | ||||
| #include "qemu/error-report.h" | ||||
|  | ||||
| #include <libfdt.h> | ||||
|  | ||||
| @@ -206,19 +207,20 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) | ||||
|  | ||||
|     CPU_FOREACH(cpu) { | ||||
|         DeviceClass *dc = DEVICE_GET_CLASS(cpu); | ||||
|         int index = ppc_get_vcpu_dt_id(POWERPC_CPU(cpu)); | ||||
|         uint32_t associativity[] = {cpu_to_be32(0x5), | ||||
|                                     cpu_to_be32(0x0), | ||||
|                                     cpu_to_be32(0x0), | ||||
|                                     cpu_to_be32(0x0), | ||||
|                                     cpu_to_be32(cpu->numa_node), | ||||
|                                     cpu_to_be32(cpu->cpu_index)}; | ||||
|                                     cpu_to_be32(index)}; | ||||
|  | ||||
|         if ((cpu->cpu_index % smt) != 0) { | ||||
|         if ((index % smt) != 0) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name, | ||||
|                  cpu->cpu_index); | ||||
|                  index); | ||||
|  | ||||
|         offset = fdt_path_offset(fdt, cpu_model); | ||||
|         if (offset < 0) { | ||||
| @@ -367,7 +369,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, | ||||
|         CPUPPCState *env = &cpu->env; | ||||
|         DeviceClass *dc = DEVICE_GET_CLASS(cs); | ||||
|         PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); | ||||
|         int index = cs->cpu_index; | ||||
|         int index = ppc_get_vcpu_dt_id(cpu); | ||||
|         uint32_t servers_prop[smp_threads]; | ||||
|         uint32_t gservers_prop[smp_threads * 2]; | ||||
|         char *nodename; | ||||
| @@ -685,6 +687,7 @@ static void spapr_reset_htab(sPAPREnvironment *spapr) | ||||
|     if (shift > 0) { | ||||
|         /* Kernel handles htab, we don't need to allocate one */ | ||||
|         spapr->htab_shift = shift; | ||||
|         kvmppc_kern_htab = true; | ||||
|     } else { | ||||
|         if (!spapr->htab) { | ||||
|             /* Allocate an htab if we don't yet have one */ | ||||
| @@ -740,8 +743,21 @@ static void spapr_cpu_reset(void *opaque) | ||||
|     env->spr[SPR_HIOR] = 0; | ||||
|  | ||||
|     env->external_htab = (uint8_t *)spapr->htab; | ||||
|     if (kvm_enabled() && !env->external_htab) { | ||||
|         /* | ||||
|          * HV KVM, set external_htab to 1 so our ppc_hash64_load_hpte* | ||||
|          * functions do the right thing. | ||||
|          */ | ||||
|         env->external_htab = (void *)1; | ||||
|     } | ||||
|     env->htab_base = -1; | ||||
|     env->htab_mask = HTAB_SIZE(spapr) - 1; | ||||
|     /* | ||||
|      * htab_mask is the mask used to normalize hash value to PTEG index. | ||||
|      * htab_shift is log2 of hash table size. | ||||
|      * We have 8 hpte per group, and each hpte is 16 bytes. | ||||
|      * ie have 128 bytes per hpte entry. | ||||
|      */ | ||||
|     env->htab_mask = (1ULL << ((spapr)->htab_shift - 7)) - 1; | ||||
|     env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab | | ||||
|         (spapr->htab_shift - 18); | ||||
| } | ||||
| @@ -1305,20 +1321,15 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) | ||||
|  | ||||
|         kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL, | ||||
|                                NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0); | ||||
|         if (kernel_size < 0) { | ||||
|         if (kernel_size == ELF_LOAD_WRONG_ENDIAN) { | ||||
|             kernel_size = load_elf(kernel_filename, | ||||
|                                    translate_kernel_address, NULL, | ||||
|                                    NULL, &lowaddr, NULL, 0, ELF_MACHINE, 0); | ||||
|             kernel_le = kernel_size > 0; | ||||
|         } | ||||
|         if (kernel_size < 0) { | ||||
|             kernel_size = load_image_targphys(kernel_filename, | ||||
|                                               KERNEL_LOAD_ADDR, | ||||
|                                               load_limit - KERNEL_LOAD_ADDR); | ||||
|         } | ||||
|         if (kernel_size < 0) { | ||||
|             fprintf(stderr, "qemu: could not load kernel '%s'\n", | ||||
|                     kernel_filename); | ||||
|             fprintf(stderr, "qemu: error loading %s: %s\n", | ||||
|                     kernel_filename, load_elf_strerror(kernel_size)); | ||||
|             exit(1); | ||||
|         } | ||||
|  | ||||
| @@ -1366,6 +1377,24 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) | ||||
|     assert(spapr->fdt_skel != NULL); | ||||
| } | ||||
|  | ||||
| static int spapr_kvm_type(const char *vm_type) | ||||
| { | ||||
|     if (!vm_type) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     if (!strcmp(vm_type, "HV")) { | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     if (!strcmp(vm_type, "PR")) { | ||||
|         return 2; | ||||
|     } | ||||
|  | ||||
|     error_report("Unknown kvm-type specified '%s'", vm_type); | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| static QEMUMachine spapr_machine = { | ||||
|     .name = "pseries", | ||||
|     .desc = "pSeries Logical Partition (PAPR compliant)", | ||||
| @@ -1376,6 +1405,7 @@ static QEMUMachine spapr_machine = { | ||||
|     .max_cpus = MAX_CPUS, | ||||
|     .no_parallel = 1, | ||||
|     .default_boot_order = NULL, | ||||
|     .kvm_type = spapr_kvm_type, | ||||
| }; | ||||
|  | ||||
| static void spapr_machine_init(void) | ||||
|   | ||||
| @@ -40,6 +40,17 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r, | ||||
|     return rb; | ||||
| } | ||||
|  | ||||
| static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index) | ||||
| { | ||||
|     /* | ||||
|      * hash value/pteg group index is normalized by htab_mask | ||||
|      */ | ||||
|     if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) { | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
|                             target_ulong opcode, target_ulong *args) | ||||
| { | ||||
| @@ -50,8 +61,8 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
|     target_ulong ptel = args[3]; | ||||
|     target_ulong page_shift = 12; | ||||
|     target_ulong raddr; | ||||
|     target_ulong i; | ||||
|     hwaddr hpte; | ||||
|     target_ulong index; | ||||
|     uint64_t token; | ||||
|  | ||||
|     /* only handle 4k and 16M pages for now */ | ||||
|     if (pteh & HPTE64_V_LARGE) { | ||||
| @@ -91,33 +102,37 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
|  | ||||
|     pteh &= ~0x60ULL; | ||||
|  | ||||
|     if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { | ||||
|     if (!valid_pte_index(env, pte_index)) { | ||||
|         return H_PARAMETER; | ||||
|     } | ||||
|  | ||||
|     index = 0; | ||||
|     if (likely((flags & H_EXACT) == 0)) { | ||||
|         pte_index &= ~7ULL; | ||||
|         hpte = pte_index * HASH_PTE_SIZE_64; | ||||
|         for (i = 0; ; ++i) { | ||||
|             if (i == 8) { | ||||
|         token = ppc_hash64_start_access(cpu, pte_index); | ||||
|         do { | ||||
|             if (index == 8) { | ||||
|                 ppc_hash64_stop_access(token); | ||||
|                 return H_PTEG_FULL; | ||||
|             } | ||||
|             if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) { | ||||
|             if ((ppc_hash64_load_hpte0(env, token, index) & HPTE64_V_VALID) == 0) { | ||||
|                 break; | ||||
|             } | ||||
|             hpte += HASH_PTE_SIZE_64; | ||||
|         } | ||||
|         } while (index++); | ||||
|         ppc_hash64_stop_access(token); | ||||
|     } else { | ||||
|         i = 0; | ||||
|         hpte = pte_index * HASH_PTE_SIZE_64; | ||||
|         if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) { | ||||
|         token = ppc_hash64_start_access(cpu, pte_index); | ||||
|         if (ppc_hash64_load_hpte0(env, token, 0) & HPTE64_V_VALID) { | ||||
|             ppc_hash64_stop_access(token); | ||||
|             return H_PTEG_FULL; | ||||
|         } | ||||
|         ppc_hash64_stop_access(token); | ||||
|     } | ||||
|     ppc_hash64_store_hpte1(env, hpte, ptel); | ||||
|     /* eieio();  FIXME: need some sort of barrier for smp? */ | ||||
|     ppc_hash64_store_hpte0(env, hpte, pteh | HPTE64_V_HPTE_DIRTY); | ||||
|  | ||||
|     args[0] = pte_index + i; | ||||
|     ppc_hash64_store_hpte(env, pte_index + index, | ||||
|                           pteh | HPTE64_V_HPTE_DIRTY, ptel); | ||||
|  | ||||
|     args[0] = pte_index + index; | ||||
|     return H_SUCCESS; | ||||
| } | ||||
|  | ||||
| @@ -133,17 +148,17 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex, | ||||
|                                 target_ulong flags, | ||||
|                                 target_ulong *vp, target_ulong *rp) | ||||
| { | ||||
|     hwaddr hpte; | ||||
|     uint64_t token; | ||||
|     target_ulong v, r, rb; | ||||
|  | ||||
|     if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) { | ||||
|     if (!valid_pte_index(env, ptex)) { | ||||
|         return REMOVE_PARM; | ||||
|     } | ||||
|  | ||||
|     hpte = ptex * HASH_PTE_SIZE_64; | ||||
|  | ||||
|     v = ppc_hash64_load_hpte0(env, hpte); | ||||
|     r = ppc_hash64_load_hpte1(env, hpte); | ||||
|     token = ppc_hash64_start_access(ppc_env_get_cpu(env), ptex); | ||||
|     v = ppc_hash64_load_hpte0(env, token, 0); | ||||
|     r = ppc_hash64_load_hpte1(env, token, 0); | ||||
|     ppc_hash64_stop_access(token); | ||||
|  | ||||
|     if ((v & HPTE64_V_VALID) == 0 || | ||||
|         ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || | ||||
| @@ -152,7 +167,7 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex, | ||||
|     } | ||||
|     *vp = v; | ||||
|     *rp = r; | ||||
|     ppc_hash64_store_hpte0(env, hpte, HPTE64_V_HPTE_DIRTY); | ||||
|     ppc_hash64_store_hpte(env, ptex, HPTE64_V_HPTE_DIRTY, 0); | ||||
|     rb = compute_tlbie_rb(v, r, ptex); | ||||
|     ppc_tlb_invalidate_one(env, rb); | ||||
|     return REMOVE_SUCCESS; | ||||
| @@ -259,17 +274,17 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
|     target_ulong flags = args[0]; | ||||
|     target_ulong pte_index = args[1]; | ||||
|     target_ulong avpn = args[2]; | ||||
|     hwaddr hpte; | ||||
|     uint64_t token; | ||||
|     target_ulong v, r, rb; | ||||
|  | ||||
|     if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { | ||||
|     if (!valid_pte_index(env, pte_index)) { | ||||
|         return H_PARAMETER; | ||||
|     } | ||||
|  | ||||
|     hpte = pte_index * HASH_PTE_SIZE_64; | ||||
|  | ||||
|     v = ppc_hash64_load_hpte0(env, hpte); | ||||
|     r = ppc_hash64_load_hpte1(env, hpte); | ||||
|     token = ppc_hash64_start_access(cpu, pte_index); | ||||
|     v = ppc_hash64_load_hpte0(env, token, 0); | ||||
|     r = ppc_hash64_load_hpte1(env, token, 0); | ||||
|     ppc_hash64_stop_access(token); | ||||
|  | ||||
|     if ((v & HPTE64_V_VALID) == 0 || | ||||
|         ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { | ||||
| @@ -282,11 +297,11 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
|     r |= (flags << 48) & HPTE64_R_KEY_HI; | ||||
|     r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO); | ||||
|     rb = compute_tlbie_rb(v, r, pte_index); | ||||
|     ppc_hash64_store_hpte0(env, hpte, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY); | ||||
|     ppc_hash64_store_hpte(env, pte_index, | ||||
|                           (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0); | ||||
|     ppc_tlb_invalidate_one(env, rb); | ||||
|     ppc_hash64_store_hpte1(env, hpte, r); | ||||
|     /* Don't need a memory barrier, due to qemu's global lock */ | ||||
|     ppc_hash64_store_hpte0(env, hpte, v | HPTE64_V_HPTE_DIRTY); | ||||
|     ppc_hash64_store_hpte(env, pte_index, v | HPTE64_V_HPTE_DIRTY, r); | ||||
|     return H_SUCCESS; | ||||
| } | ||||
|  | ||||
| @@ -299,7 +314,7 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
|     uint8_t *hpte; | ||||
|     int i, ridx, n_entries = 1; | ||||
|  | ||||
|     if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { | ||||
|     if (!valid_pte_index(env, pte_index)) { | ||||
|         return H_PARAMETER; | ||||
|     } | ||||
|  | ||||
| @@ -467,13 +482,13 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
|     target_ulong vpa = args[2]; | ||||
|     target_ulong ret = H_PARAMETER; | ||||
|     CPUPPCState *tenv; | ||||
|     CPUState *tcpu; | ||||
|     PowerPCCPU *tcpu; | ||||
|  | ||||
|     tcpu = qemu_get_cpu(procno); | ||||
|     tcpu = ppc_get_vcpu_by_dt_id(procno); | ||||
|     if (!tcpu) { | ||||
|         return H_PARAMETER; | ||||
|     } | ||||
|     tenv = tcpu->env_ptr; | ||||
|     tenv = &tcpu->env; | ||||
|  | ||||
|     switch (flags) { | ||||
|     case FLAGS_REGISTER_VPA: | ||||
|   | ||||
| @@ -243,6 +243,42 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, | ||||
|                                 target_ulong *tce) | ||||
| { | ||||
|     if (ioba >= tcet->window_size) { | ||||
|         hcall_dprintf("spapr_iommu_get_tce on out-of-bounds IOBA 0x" | ||||
|                       TARGET_FMT_lx "\n", ioba); | ||||
|         return H_PARAMETER; | ||||
|     } | ||||
|  | ||||
|     *tce = tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT]; | ||||
|  | ||||
|     return H_SUCCESS; | ||||
| } | ||||
|  | ||||
| static target_ulong h_get_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr, | ||||
|                               target_ulong opcode, target_ulong *args) | ||||
| { | ||||
|     target_ulong liobn = args[0]; | ||||
|     target_ulong ioba = args[1]; | ||||
|     target_ulong tce = 0; | ||||
|     target_ulong ret = H_PARAMETER; | ||||
|     sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn); | ||||
|  | ||||
|     ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1); | ||||
|  | ||||
|     if (tcet) { | ||||
|         ret = get_tce_emu(tcet, ioba, &tce); | ||||
|         if (!ret) { | ||||
|             args[0] = tce; | ||||
|         } | ||||
|     } | ||||
|     trace_spapr_iommu_get(liobn, ioba, ret, tce); | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| int spapr_dma_dt(void *fdt, int node_off, const char *propname, | ||||
|                  uint32_t liobn, uint64_t window, uint32_t size) | ||||
| { | ||||
| @@ -295,6 +331,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data) | ||||
|  | ||||
|     /* hcall-tce */ | ||||
|     spapr_register_hypercall(H_PUT_TCE, h_put_tce); | ||||
|     spapr_register_hypercall(H_GET_TCE, h_get_tce); | ||||
| } | ||||
|  | ||||
| static TypeInfo spapr_tce_table_info = { | ||||
|   | ||||
| @@ -469,6 +469,8 @@ static const MemoryRegionOps spapr_msi_ops = { | ||||
|  | ||||
| void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr) | ||||
| { | ||||
|     uint64_t window_size = 4096; | ||||
|  | ||||
|     /* | ||||
|      * As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors, | ||||
|      * we need to allocate some memory to catch those writes coming | ||||
| @@ -476,10 +478,19 @@ void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr) | ||||
|      * As MSIMessage:addr is going to be the same and MSIMessage:data | ||||
|      * is going to be a VIRQ number, 4 bytes of the MSI MR will only | ||||
|      * be used. | ||||
|      * | ||||
|      * For KVM we want to ensure that this memory is a full page so that | ||||
|      * our memory slot is of page size granularity. | ||||
|      */ | ||||
| #ifdef CONFIG_KVM | ||||
|     if (kvm_enabled()) { | ||||
|         window_size = getpagesize(); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     spapr->msi_win_addr = addr; | ||||
|     memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr, | ||||
|                           "msi", getpagesize()); | ||||
|                           "msi", window_size); | ||||
|     memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr, | ||||
|                                 &spapr->msiwindow); | ||||
| } | ||||
| @@ -728,6 +739,8 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data) | ||||
|     dc->props = spapr_phb_properties; | ||||
|     dc->reset = spapr_phb_reset; | ||||
|     dc->vmsd = &vmstate_spapr_pci; | ||||
|     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); | ||||
|     dc->cannot_instantiate_with_device_add_yet = false; | ||||
| } | ||||
|  | ||||
| static const TypeInfo spapr_phb_info = { | ||||
|   | ||||
| @@ -131,7 +131,7 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, | ||||
|                                          uint32_t nret, target_ulong rets) | ||||
| { | ||||
|     target_ulong id; | ||||
|     CPUState *cpu; | ||||
|     PowerPCCPU *cpu; | ||||
|  | ||||
|     if (nargs != 1 || nret != 2) { | ||||
|         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); | ||||
| @@ -139,9 +139,9 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, | ||||
|     } | ||||
|  | ||||
|     id = rtas_ld(args, 0); | ||||
|     cpu = qemu_get_cpu(id); | ||||
|     cpu = ppc_get_vcpu_by_dt_id(id); | ||||
|     if (cpu != NULL) { | ||||
|         if (cpu->halted) { | ||||
|         if (CPU(cpu)->halted) { | ||||
|             rtas_st(rets, 1, 0); | ||||
|         } else { | ||||
|             rtas_st(rets, 1, 2); | ||||
| @@ -161,7 +161,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr, | ||||
|                            uint32_t nret, target_ulong rets) | ||||
| { | ||||
|     target_ulong id, start, r3; | ||||
|     CPUState *cs; | ||||
|     PowerPCCPU *cpu; | ||||
|  | ||||
|     if (nargs != 3 || nret != 1) { | ||||
|         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); | ||||
| @@ -172,9 +172,9 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr, | ||||
|     start = rtas_ld(args, 1); | ||||
|     r3 = rtas_ld(args, 2); | ||||
|  | ||||
|     cs = qemu_get_cpu(id); | ||||
|     if (cs != NULL) { | ||||
|         PowerPCCPU *cpu = POWERPC_CPU(cs); | ||||
|     cpu = ppc_get_vcpu_by_dt_id(id); | ||||
|     if (cpu != NULL) { | ||||
|         CPUState *cs = CPU(cpu); | ||||
|         CPUPPCState *env = &cpu->env; | ||||
|  | ||||
|         if (!cs->halted) { | ||||
|   | ||||
| @@ -174,6 +174,19 @@ static int xilinx_load_device_tree(hwaddr addr, | ||||
|     if (!fdt) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", | ||||
|                               initrd_base); | ||||
|     if (r < 0) { | ||||
|         error_report("couldn't set /chosen/linux,initrd-start"); | ||||
|     } | ||||
|  | ||||
|     r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", | ||||
|                               (initrd_base + initrd_size)); | ||||
|     if (r < 0) { | ||||
|         error_report("couldn't set /chosen/linux,initrd-end"); | ||||
|     } | ||||
|  | ||||
|     r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); | ||||
|     if (r < 0) | ||||
|         fprintf(stderr, "couldn't set /chosen/bootargs\n"); | ||||
| @@ -187,6 +200,8 @@ static void virtex_init(QEMUMachineInitArgs *args) | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     hwaddr initrd_base = 0; | ||||
|     int initrd_size = 0; | ||||
|     MemoryRegion *address_space_mem = get_system_memory(); | ||||
|     DeviceState *dev; | ||||
|     PowerPCCPU *cpu; | ||||
| @@ -259,10 +274,27 @@ static void virtex_init(QEMUMachineInitArgs *args) | ||||
|  | ||||
|         boot_info.ima_size = kernel_size; | ||||
|  | ||||
|         /* Load initrd. */ | ||||
|         if (args->initrd_filename) { | ||||
|             initrd_base = high = ROUND_UP(high, 4); | ||||
|             initrd_size = load_image_targphys(args->initrd_filename, | ||||
|                                               high, ram_size - high); | ||||
|  | ||||
|             if (initrd_size < 0) { | ||||
|                 error_report("couldn't load ram disk '%s'", | ||||
|                              args->initrd_filename); | ||||
|                 exit(1); | ||||
|             } | ||||
|             high = ROUND_UP(high + initrd_size, 4); | ||||
|         } | ||||
|  | ||||
|         /* Provide a device-tree.  */ | ||||
|         boot_info.fdt = high + (8192 * 2); | ||||
|         boot_info.fdt &= ~8191; | ||||
|         xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline); | ||||
|  | ||||
|         xilinx_load_device_tree(boot_info.fdt, ram_size, | ||||
|                                 initrd_base, initrd_size, | ||||
|                                 kernel_cmdline); | ||||
|     } | ||||
|     env->load_info = &boot_info; | ||||
| } | ||||
|   | ||||
| @@ -116,6 +116,15 @@ void css_conditional_io_interrupt(SubchDev *sch) | ||||
|     } | ||||
| } | ||||
|  | ||||
| void css_adapter_interrupt(uint8_t isc) | ||||
| { | ||||
|     S390CPU *cpu = s390_cpu_addr2state(0); | ||||
|     uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI; | ||||
|  | ||||
|     trace_css_adapter_interrupt(isc); | ||||
|     s390_io_interrupt(cpu, 0, 0, 0, io_int_word); | ||||
| } | ||||
|  | ||||
| static void sch_handle_clear_func(SubchDev *sch) | ||||
| { | ||||
|     PMCW *p = &sch->curr_status.pmcw; | ||||
| @@ -1259,6 +1268,7 @@ void css_reset_sch(SubchDev *sch) | ||||
|     sch->channel_prog = 0x0; | ||||
|     sch->last_cmd_valid = false; | ||||
|     sch->orb = NULL; | ||||
|     sch->thinint_active = false; | ||||
| } | ||||
|  | ||||
| void css_reset(void) | ||||
|   | ||||
| @@ -77,6 +77,7 @@ struct SubchDev { | ||||
|     CCW1 last_cmd; | ||||
|     bool last_cmd_valid; | ||||
|     ORB *orb; | ||||
|     bool thinint_active; | ||||
|     /* transport-provided data: */ | ||||
|     int (*ccw_cb) (SubchDev *, CCW1); | ||||
|     SenseId id; | ||||
| @@ -97,4 +98,5 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid); | ||||
| void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, | ||||
|                            int hotplugged, int add); | ||||
| void css_generate_chp_crws(uint8_t cssid, uint8_t chpid); | ||||
| void css_adapter_interrupt(uint8_t isc); | ||||
| #endif | ||||
|   | ||||
| @@ -98,10 +98,10 @@ static int s390_ipl_init(SysBusDevice *dev) | ||||
|         uint64_t pentry = KERN_IMAGE_START; | ||||
|         kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL, | ||||
|                                NULL, 1, ELF_MACHINE, 0); | ||||
|         if (kernel_size == -1) { | ||||
|         if (kernel_size < 0) { | ||||
|             kernel_size = load_image_targphys(ipl->kernel, 0, ram_size); | ||||
|         } | ||||
|         if (kernel_size == -1) { | ||||
|         if (kernel_size < 0) { | ||||
|             fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel); | ||||
|             return -1; | ||||
|         } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * virtio ccw target implementation | ||||
|  * | ||||
|  * Copyright 2012 IBM Corp. | ||||
|  * Copyright 2012,2014 IBM Corp. | ||||
|  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> | ||||
|  * | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2 or (at | ||||
| @@ -188,6 +188,13 @@ typedef struct VirtioFeatDesc { | ||||
|     uint8_t index; | ||||
| } QEMU_PACKED VirtioFeatDesc; | ||||
|  | ||||
| typedef struct VirtioThinintInfo { | ||||
|     hwaddr summary_indicator; | ||||
|     hwaddr device_indicator; | ||||
|     uint64_t ind_bit; | ||||
|     uint8_t isc; | ||||
| } QEMU_PACKED VirtioThinintInfo; | ||||
|  | ||||
| /* Specify where the virtqueues for the subchannel are in guest memory. */ | ||||
| static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align, | ||||
|                               uint16_t index, uint16_t num) | ||||
| @@ -237,6 +244,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) | ||||
|     bool check_len; | ||||
|     int len; | ||||
|     hwaddr hw_len; | ||||
|     VirtioThinintInfo *thinint; | ||||
|  | ||||
|     if (!dev) { | ||||
|         return -EINVAL; | ||||
| @@ -428,6 +436,11 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) | ||||
|             ret = -EINVAL; | ||||
|             break; | ||||
|         } | ||||
|         if (sch->thinint_active) { | ||||
|             /* Trigger a command reject. */ | ||||
|             ret = -ENOSYS; | ||||
|             break; | ||||
|         } | ||||
|         if (!ccw.cda) { | ||||
|             ret = -EFAULT; | ||||
|         } else { | ||||
| @@ -480,6 +493,42 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) | ||||
|             ret = 0; | ||||
|         } | ||||
|         break; | ||||
|     case CCW_CMD_SET_IND_ADAPTER: | ||||
|         if (check_len) { | ||||
|             if (ccw.count != sizeof(*thinint)) { | ||||
|                 ret = -EINVAL; | ||||
|                 break; | ||||
|             } | ||||
|         } else if (ccw.count < sizeof(*thinint)) { | ||||
|             /* Can't execute command. */ | ||||
|             ret = -EINVAL; | ||||
|             break; | ||||
|         } | ||||
|         len = sizeof(*thinint); | ||||
|         hw_len = len; | ||||
|         if (!ccw.cda) { | ||||
|             ret = -EFAULT; | ||||
|         } else if (dev->indicators && !sch->thinint_active) { | ||||
|             /* Trigger a command reject. */ | ||||
|             ret = -ENOSYS; | ||||
|         } else { | ||||
|             thinint = cpu_physical_memory_map(ccw.cda, &hw_len, 0); | ||||
|             if (!thinint) { | ||||
|                 ret = -EFAULT; | ||||
|             } else { | ||||
|                 len = hw_len; | ||||
|                 dev->summary_indicator = thinint->summary_indicator; | ||||
|                 dev->indicators = thinint->device_indicator; | ||||
|                 dev->thinint_isc = thinint->isc; | ||||
|                 dev->ind_bit = thinint->ind_bit; | ||||
|                 cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len); | ||||
|                 sch->thinint_active = ((dev->indicators != 0) && | ||||
|                                        (dev->summary_indicator != 0)); | ||||
|                 sch->curr_status.scsw.count = ccw.count - len; | ||||
|                 ret = 0; | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     default: | ||||
|         ret = -ENOSYS; | ||||
|         break; | ||||
| @@ -511,6 +560,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev) | ||||
|     sch->channel_prog = 0x0; | ||||
|     sch->last_cmd_valid = false; | ||||
|     sch->orb = NULL; | ||||
|     sch->thinint_active = false; | ||||
|     /* | ||||
|      * Use a device number if provided. Otherwise, fall back to subchannel | ||||
|      * number. | ||||
| @@ -858,6 +908,28 @@ static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d) | ||||
|     return container_of(d, VirtioCcwDevice, parent_obj); | ||||
| } | ||||
|  | ||||
| static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, | ||||
|                                      uint8_t to_be_set) | ||||
| { | ||||
|     uint8_t ind_old, ind_new; | ||||
|     hwaddr len = 1; | ||||
|     uint8_t *ind_addr; | ||||
|  | ||||
|     ind_addr = cpu_physical_memory_map(ind_loc, &len, 1); | ||||
|     if (!ind_addr) { | ||||
|         error_report("%s(%x.%x.%04x): unable to access indicator", | ||||
|                      __func__, sch->cssid, sch->ssid, sch->schid); | ||||
|         return -1; | ||||
|     } | ||||
|     do { | ||||
|         ind_old = *ind_addr; | ||||
|         ind_new = ind_old | to_be_set; | ||||
|     } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old); | ||||
|     cpu_physical_memory_unmap(ind_addr, len, 1, len); | ||||
|  | ||||
|     return ind_old; | ||||
| } | ||||
|  | ||||
| static void virtio_ccw_notify(DeviceState *d, uint16_t vector) | ||||
| { | ||||
|     VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d); | ||||
| @@ -872,9 +944,26 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector) | ||||
|         if (!dev->indicators) { | ||||
|             return; | ||||
|         } | ||||
|         indicators = ldq_phys(&address_space_memory, dev->indicators); | ||||
|         indicators |= 1ULL << vector; | ||||
|         stq_phys(&address_space_memory, dev->indicators, indicators); | ||||
|         if (sch->thinint_active) { | ||||
|             /* | ||||
|              * In the adapter interrupt case, indicators points to a | ||||
|              * memory area that may be (way) larger than 64 bit and | ||||
|              * ind_bit indicates the start of the indicators in a big | ||||
|              * endian notation. | ||||
|              */ | ||||
|             virtio_set_ind_atomic(sch, dev->indicators + | ||||
|                                   (dev->ind_bit + vector) / 8, | ||||
|                                   0x80 >> ((dev->ind_bit + vector) % 8)); | ||||
|             if (!virtio_set_ind_atomic(sch, dev->summary_indicator, | ||||
|                                        0x01)) { | ||||
|                 css_adapter_interrupt(dev->thinint_isc); | ||||
|             } | ||||
|         } else { | ||||
|             indicators = ldq_phys(&address_space_memory, dev->indicators); | ||||
|             indicators |= 1ULL << vector; | ||||
|             stq_phys(&address_space_memory, dev->indicators, indicators); | ||||
|             css_conditional_io_interrupt(sch); | ||||
|         } | ||||
|     } else { | ||||
|         if (!dev->indicators2) { | ||||
|             return; | ||||
| @@ -883,10 +972,8 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector) | ||||
|         indicators = ldq_phys(&address_space_memory, dev->indicators2); | ||||
|         indicators |= 1ULL << vector; | ||||
|         stq_phys(&address_space_memory, dev->indicators2, indicators); | ||||
|         css_conditional_io_interrupt(sch); | ||||
|     } | ||||
|  | ||||
|     css_conditional_io_interrupt(sch); | ||||
|  | ||||
| } | ||||
|  | ||||
| static unsigned virtio_ccw_get_features(DeviceState *d) | ||||
| @@ -907,6 +994,7 @@ static void virtio_ccw_reset(DeviceState *d) | ||||
|     css_reset_sch(dev->sch); | ||||
|     dev->indicators = 0; | ||||
|     dev->indicators2 = 0; | ||||
|     dev->summary_indicator = 0; | ||||
| } | ||||
|  | ||||
| static void virtio_ccw_vmstate_change(DeviceState *d, bool running) | ||||
|   | ||||
| @@ -38,6 +38,7 @@ | ||||
| #define CCW_CMD_SET_IND      0x43 | ||||
| #define CCW_CMD_SET_CONF_IND 0x53 | ||||
| #define CCW_CMD_READ_VQ_CONF 0x32 | ||||
| #define CCW_CMD_SET_IND_ADAPTER 0x73 | ||||
|  | ||||
| #define TYPE_VIRTIO_CCW_DEVICE "virtio-ccw-device" | ||||
| #define VIRTIO_CCW_DEVICE(obj) \ | ||||
| @@ -83,9 +84,12 @@ struct VirtioCcwDevice { | ||||
|     bool ioeventfd_started; | ||||
|     bool ioeventfd_disabled; | ||||
|     uint32_t flags; | ||||
|     uint8_t thinint_isc; | ||||
|     /* Guest provided values: */ | ||||
|     hwaddr indicators; | ||||
|     hwaddr indicators2; | ||||
|     hwaddr summary_indicator; | ||||
|     uint64_t ind_bit; | ||||
| }; | ||||
|  | ||||
| /* virtual css bus type */ | ||||
|   | ||||
| @@ -62,6 +62,8 @@ | ||||
|  | ||||
| #define SRP_RSP_SENSE_DATA_LEN  18 | ||||
|  | ||||
| #define SRP_REPORT_LUNS_WLUN    0xc10100000000000ULL | ||||
|  | ||||
| typedef union vscsi_crq { | ||||
|     struct viosrp_crq s; | ||||
|     uint8_t raw[16]; | ||||
| @@ -719,12 +721,70 @@ static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req) | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void vscsi_report_luns(VSCSIState *s, vscsi_req *req) | ||||
| { | ||||
|     BusChild *kid; | ||||
|     int i, len, n, rc; | ||||
|     uint8_t *resp_data; | ||||
|     bool found_lun0; | ||||
|  | ||||
|     n = 0; | ||||
|     found_lun0 = false; | ||||
|     QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { | ||||
|         SCSIDevice *dev = SCSI_DEVICE(kid->child); | ||||
|  | ||||
|         n += 8; | ||||
|         if (dev->channel == 0 && dev->id == 0 && dev->lun == 0) { | ||||
|             found_lun0 = true; | ||||
|         } | ||||
|     } | ||||
|     if (!found_lun0) { | ||||
|         n += 8; | ||||
|     } | ||||
|     len = n+8; | ||||
|  | ||||
|     resp_data = g_malloc0(len); | ||||
|     memset(resp_data, 0, len); | ||||
|     stl_be_p(resp_data, n); | ||||
|     i = found_lun0 ? 8 : 16; | ||||
|     QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { | ||||
|         DeviceState *qdev = kid->child; | ||||
|         SCSIDevice *dev = SCSI_DEVICE(qdev); | ||||
|  | ||||
|         if (dev->id == 0 && dev->channel == 0) { | ||||
|             resp_data[i] = 0;         /* Use simple LUN for 0 (SAM5 4.7.7.1) */ | ||||
|         } else { | ||||
|             resp_data[i] = (2 << 6);  /* Otherwise LUN addressing (4.7.7.4)  */ | ||||
|         } | ||||
|         resp_data[i] |= dev->id; | ||||
|         resp_data[i+1] = (dev->channel << 5); | ||||
|         resp_data[i+1] |= dev->lun; | ||||
|         i += 8; | ||||
|     } | ||||
|  | ||||
|     vscsi_preprocess_desc(req); | ||||
|     rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len); | ||||
|     g_free(resp_data); | ||||
|     if (rc < 0) { | ||||
|         vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); | ||||
|         vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); | ||||
|     } else { | ||||
|         vscsi_send_rsp(s, req, 0, len - rc, 0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) | ||||
| { | ||||
|     union srp_iu *srp = &req->iu.srp; | ||||
|     SCSIDevice *sdev; | ||||
|     int n, lun; | ||||
|  | ||||
|     if ((srp->cmd.lun == 0 || be64_to_cpu(srp->cmd.lun) == SRP_REPORT_LUNS_WLUN) | ||||
|       && srp->cmd.cdb[0] == REPORT_LUNS) { | ||||
|         vscsi_report_luns(s, req); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun); | ||||
|     if (!sdev) { | ||||
|         DPRINTF("VSCSI: Command for lun %08" PRIx64 " with no drive\n", | ||||
|   | ||||
| @@ -43,7 +43,7 @@ | ||||
|  | ||||
| /* config register */ | ||||
| #define R_CONFIG            (0x00 / 4) | ||||
| #define IFMODE              (1 << 31) | ||||
| #define IFMODE              (1U << 31) | ||||
| #define ENDIAN              (1 << 26) | ||||
| #define MODEFAIL_GEN_EN     (1 << 17) | ||||
| #define MAN_START_COM       (1 << 16) | ||||
| @@ -87,7 +87,7 @@ | ||||
|  | ||||
| #define R_LQSPI_CFG         (0xa0 / 4) | ||||
| #define R_LQSPI_CFG_RESET       0x03A002EB | ||||
| #define LQSPI_CFG_LQ_MODE       (1 << 31) | ||||
| #define LQSPI_CFG_LQ_MODE       (1U << 31) | ||||
| #define LQSPI_CFG_TWO_MEM       (1 << 30) | ||||
| #define LQSPI_CFG_SEP_BUS       (1 << 30) | ||||
| #define LQSPI_CFG_U_PAGE        (1 << 28) | ||||
|   | ||||
| @@ -546,10 +546,10 @@ static int emulated_initfn(CCIDCardState *base) | ||||
|         printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME); | ||||
|         return -1; | ||||
|     } | ||||
|     qemu_thread_create(&card->event_thread_id, event_thread, card, | ||||
|                        QEMU_THREAD_JOINABLE); | ||||
|     qemu_thread_create(&card->apdu_thread_id, handle_apdu_thread, card, | ||||
|                        QEMU_THREAD_JOINABLE); | ||||
|     qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread, | ||||
|                        card, QEMU_THREAD_JOINABLE); | ||||
|     qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread, | ||||
|                        card, QEMU_THREAD_JOINABLE); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -59,6 +59,7 @@ typedef uint64_t target_ulong; | ||||
| #define EXCP_HLT        0x10001 /* hlt instruction reached */ | ||||
| #define EXCP_DEBUG      0x10002 /* cpu stopped after a breakpoint or singlestep */ | ||||
| #define EXCP_HALTED     0x10003 /* cpu is halted (waiting for external event) */ | ||||
| #define EXCP_YIELD      0x10004 /* cpu wants to yield timeslice to another */ | ||||
|  | ||||
| #define TB_JMP_CACHE_BITS 12 | ||||
| #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) | ||||
|   | ||||
| @@ -836,13 +836,13 @@ void memory_region_set_alias_offset(MemoryRegion *mr, | ||||
|                                     hwaddr offset); | ||||
|  | ||||
| /** | ||||
|  * memory_region_present: translate an address/size relative to a | ||||
|  * MemoryRegion into a #MemoryRegionSection. | ||||
|  * memory_region_present: checks if an address relative to a @parent | ||||
|  * translates into #MemoryRegion within @parent | ||||
|  * | ||||
|  * Answer whether a #MemoryRegion within @parent covers the address | ||||
|  * @addr. | ||||
|  * | ||||
|  * @parent: a MemoryRegion within which @addr is a relative address | ||||
|  * @parent: a #MemoryRegion within which @addr is a relative address | ||||
|  * @addr: the area within @parent to be searched | ||||
|  */ | ||||
| bool memory_region_present(MemoryRegion *parent, hwaddr addr); | ||||
|   | ||||
| @@ -4,10 +4,9 @@ | ||||
| #define HW_BOARDS_H | ||||
|  | ||||
| #include "sysemu/blockdev.h" | ||||
| #include "sysemu/qemumachine.h" | ||||
| #include "hw/qdev.h" | ||||
|  | ||||
| typedef struct QEMUMachine QEMUMachine; | ||||
|  | ||||
| typedef struct QEMUMachineInitArgs { | ||||
|     const QEMUMachine *machine; | ||||
|     ram_addr_t ram_size; | ||||
| @@ -24,6 +23,8 @@ typedef void QEMUMachineResetFunc(void); | ||||
|  | ||||
| typedef void QEMUMachineHotAddCPUFunc(const int64_t id, Error **errp); | ||||
|  | ||||
| typedef int QEMUMachineGetKvmtypeFunc(const char *arg); | ||||
|  | ||||
| struct QEMUMachine { | ||||
|     const char *name; | ||||
|     const char *alias; | ||||
| @@ -31,6 +32,7 @@ struct QEMUMachine { | ||||
|     QEMUMachineInitFunc *init; | ||||
|     QEMUMachineResetFunc *reset; | ||||
|     QEMUMachineHotAddCPUFunc *hot_add_cpu; | ||||
|     QEMUMachineGetKvmtypeFunc *kvm_type; | ||||
|     BlockInterfaceType block_default_type; | ||||
|     int max_cpus; | ||||
|     unsigned int no_serial:1, | ||||
|   | ||||
| @@ -201,6 +201,7 @@ static int glue(load_elf, SZ)(const char *name, int fd, | ||||
|     uint64_t addr, low = (uint64_t)-1, high = 0; | ||||
|     uint8_t *data = NULL; | ||||
|     char label[128]; | ||||
|     int ret = ELF_LOAD_FAILED; | ||||
|  | ||||
|     if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) | ||||
|         goto fail; | ||||
| @@ -211,22 +212,30 @@ static int glue(load_elf, SZ)(const char *name, int fd, | ||||
|     switch (elf_machine) { | ||||
|         case EM_PPC64: | ||||
|             if (EM_PPC64 != ehdr.e_machine) | ||||
|                 if (EM_PPC != ehdr.e_machine) | ||||
|                 if (EM_PPC != ehdr.e_machine) { | ||||
|                     ret = ELF_LOAD_WRONG_ARCH; | ||||
|                     goto fail; | ||||
|                 } | ||||
|             break; | ||||
|         case EM_X86_64: | ||||
|             if (EM_X86_64 != ehdr.e_machine) | ||||
|                 if (EM_386 != ehdr.e_machine) | ||||
|                 if (EM_386 != ehdr.e_machine) { | ||||
|                     ret = ELF_LOAD_WRONG_ARCH; | ||||
|                     goto fail; | ||||
|                 } | ||||
|             break; | ||||
|         case EM_MICROBLAZE: | ||||
|             if (EM_MICROBLAZE != ehdr.e_machine) | ||||
|                 if (EM_MICROBLAZE_OLD != ehdr.e_machine) | ||||
|                 if (EM_MICROBLAZE_OLD != ehdr.e_machine) { | ||||
|                     ret = ELF_LOAD_WRONG_ARCH; | ||||
|                     goto fail; | ||||
|                 } | ||||
|             break; | ||||
|         default: | ||||
|             if (elf_machine != ehdr.e_machine) | ||||
|             if (elf_machine != ehdr.e_machine) { | ||||
|                 ret = ELF_LOAD_WRONG_ARCH; | ||||
|                 goto fail; | ||||
|             } | ||||
|     } | ||||
|  | ||||
|     if (pentry) | ||||
| @@ -305,5 +314,5 @@ static int glue(load_elf, SZ)(const char *name, int fd, | ||||
|  fail: | ||||
|     g_free(data); | ||||
|     g_free(phdr); | ||||
|     return -1; | ||||
|     return ret; | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,12 @@ int get_image_size(const char *filename); | ||||
| int load_image(const char *filename, uint8_t *addr); /* deprecated */ | ||||
| int load_image_targphys(const char *filename, hwaddr, | ||||
|                         uint64_t max_sz); | ||||
|  | ||||
| #define ELF_LOAD_FAILED       -1 | ||||
| #define ELF_LOAD_NOT_ELF      -2 | ||||
| #define ELF_LOAD_WRONG_ARCH   -3 | ||||
| #define ELF_LOAD_WRONG_ENDIAN -4 | ||||
| const char *load_elf_strerror(int error); | ||||
| int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), | ||||
|              void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, | ||||
|              uint64_t *highaddr, int big_endian, int elf_machine, | ||||
|   | ||||
| @@ -176,6 +176,8 @@ struct BusClass { | ||||
|     void (*reset)(BusState *bus); | ||||
|     /* maximum devices allowed on the bus, 0: no limit. */ | ||||
|     int max_dev; | ||||
|     /* number of automatically allocated bus ids (e.g. ide.0) */ | ||||
|     int automatic_ids; | ||||
| }; | ||||
|  | ||||
| typedef struct BusChild { | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
|  | ||||
| #include "hw/irq.h" | ||||
| #include "qemu-common.h" | ||||
| #include "sysemu/qemumachine.h" | ||||
|  | ||||
| /* xen-machine.c */ | ||||
| enum xen_mode { | ||||
| @@ -36,7 +37,7 @@ void xen_cmos_set_s3_resume(void *opaque, int irq, int level); | ||||
|  | ||||
| qemu_irq *xen_interrupt_controller_init(void); | ||||
|  | ||||
| int xen_init(void); | ||||
| int xen_init(QEMUMachine *machine); | ||||
| int xen_hvm_init(MemoryRegion **ram_memory); | ||||
| void xenstore_store_pv_console_info(int i, struct CharDriverState *chr); | ||||
|  | ||||
|   | ||||
| @@ -44,9 +44,37 @@ static inline void muls64(uint64_t *plow, uint64_t *phigh, | ||||
|     *plow = r; | ||||
|     *phigh = r >> 64; | ||||
| } | ||||
|  | ||||
| static inline int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor) | ||||
| { | ||||
|     if (divisor == 0) { | ||||
|         return 1; | ||||
|     } else { | ||||
|         __uint128_t dividend = ((__uint128_t)*phigh << 64) | *plow; | ||||
|         __uint128_t result = dividend / divisor; | ||||
|         *plow = result; | ||||
|         *phigh = dividend % divisor; | ||||
|         return result > UINT64_MAX; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline int divs128(int64_t *plow, int64_t *phigh, int64_t divisor) | ||||
| { | ||||
|     if (divisor == 0) { | ||||
|         return 1; | ||||
|     } else { | ||||
|         __int128_t dividend = ((__int128_t)*phigh << 64) | *plow; | ||||
|         __int128_t result = dividend / divisor; | ||||
|         *plow = result; | ||||
|         *phigh = dividend % divisor; | ||||
|         return result != *plow; | ||||
|     } | ||||
| } | ||||
| #else | ||||
| void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b); | ||||
| void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b); | ||||
| int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor); | ||||
| int divs128(int64_t *plow, int64_t *phigh, int64_t divisor); | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -52,12 +52,13 @@ void qemu_event_reset(QemuEvent *ev); | ||||
| void qemu_event_wait(QemuEvent *ev); | ||||
| void qemu_event_destroy(QemuEvent *ev); | ||||
|  | ||||
| void qemu_thread_create(QemuThread *thread, | ||||
| void qemu_thread_create(QemuThread *thread, const char *name, | ||||
|                         void *(*start_routine)(void *), | ||||
|                         void *arg, int mode); | ||||
| void *qemu_thread_join(QemuThread *thread); | ||||
| void qemu_thread_get_self(QemuThread *thread); | ||||
| bool qemu_thread_is_self(QemuThread *thread); | ||||
| void qemu_thread_exit(void *retval); | ||||
| void qemu_thread_naming(bool enable); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -18,6 +18,7 @@ | ||||
| #include "config-host.h" | ||||
| #include "qemu/queue.h" | ||||
| #include "qom/cpu.h" | ||||
| #include "sysemu/qemumachine.h" | ||||
|  | ||||
| #ifdef CONFIG_KVM | ||||
| #include <linux/kvm.h> | ||||
| @@ -152,7 +153,7 @@ extern KVMState *kvm_state; | ||||
|  | ||||
| /* external API */ | ||||
|  | ||||
| int kvm_init(void); | ||||
| int kvm_init(QEMUMachine *machine); | ||||
|  | ||||
| int kvm_has_sync_mmu(void); | ||||
| int kvm_has_vcpu_events(void); | ||||
|   | ||||
							
								
								
									
										16
									
								
								include/sysemu/qemumachine.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								include/sysemu/qemumachine.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| /* | ||||
|  * QEMU Machine typedef | ||||
|  * | ||||
|  * Copyright Alexander Graf <agraf@suse.de> | ||||
|  * | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||||
|  * See the COPYING file in the top-level directory. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef QEMUMACHINE_H | ||||
| #define QEMUMACHINE_H | ||||
|  | ||||
| typedef struct QEMUMachine QEMUMachine; | ||||
|  | ||||
| #endif /* !QEMUMACHINE_H */ | ||||
| @@ -16,6 +16,7 @@ | ||||
|  | ||||
| #include "qemu-common.h" | ||||
| #include "qapi/error.h" | ||||
| #include "sysemu/qemumachine.h" | ||||
|  | ||||
| extern bool qtest_allowed; | ||||
|  | ||||
| @@ -26,7 +27,7 @@ static inline bool qtest_enabled(void) | ||||
|  | ||||
| bool qtest_driver(void); | ||||
|  | ||||
| int qtest_init_accel(void); | ||||
| int qtest_init_accel(QEMUMachine *machine); | ||||
| void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp); | ||||
|  | ||||
| static inline int qtest_available(void) | ||||
|   | ||||
							
								
								
									
										20
									
								
								kvm-all.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								kvm-all.c
									
									
									
									
									
								
							| @@ -36,6 +36,8 @@ | ||||
| #include "qemu/event_notifier.h" | ||||
| #include "trace.h" | ||||
|  | ||||
| #include "hw/boards.h" | ||||
|  | ||||
| /* This check must be after config-host.h is included */ | ||||
| #ifdef CONFIG_EVENTFD | ||||
| #include <sys/eventfd.h> | ||||
| @@ -1339,7 +1341,7 @@ static int kvm_max_vcpus(KVMState *s) | ||||
|     return (ret) ? ret : kvm_recommended_vcpus(s); | ||||
| } | ||||
|  | ||||
| int kvm_init(void) | ||||
| int kvm_init(QEMUMachine *machine) | ||||
| { | ||||
|     static const char upgrade_note[] = | ||||
|         "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n" | ||||
| @@ -1356,7 +1358,8 @@ int kvm_init(void) | ||||
|     KVMState *s; | ||||
|     const KVMCapabilityInfo *missing_cap; | ||||
|     int ret; | ||||
|     int i; | ||||
|     int i, type = 0; | ||||
|     const char *kvm_type; | ||||
|  | ||||
|     s = g_malloc0(sizeof(KVMState)); | ||||
|  | ||||
| @@ -1420,18 +1423,25 @@ int kvm_init(void) | ||||
|                     nc->name, nc->num, soft_vcpus_limit); | ||||
|  | ||||
|             if (nc->num > hard_vcpus_limit) { | ||||
|                 ret = -EINVAL; | ||||
|                 fprintf(stderr, "Number of %s cpus requested (%d) exceeds " | ||||
|                         "the maximum cpus supported by KVM (%d)\n", | ||||
|                         nc->name, nc->num, hard_vcpus_limit); | ||||
|                 goto err; | ||||
|                 exit(1); | ||||
|             } | ||||
|         } | ||||
|         nc++; | ||||
|     } | ||||
|  | ||||
|     kvm_type = qemu_opt_get(qemu_get_machine_opts(), "kvm-type"); | ||||
|     if (machine->kvm_type) { | ||||
|         type = machine->kvm_type(kvm_type); | ||||
|     } else if (kvm_type) { | ||||
|         fprintf(stderr, "Invalid argument kvm-type=%s\n", kvm_type); | ||||
|         goto err; | ||||
|     } | ||||
|  | ||||
|     do { | ||||
|         ret = kvm_ioctl(s, KVM_CREATE_VM, 0); | ||||
|         ret = kvm_ioctl(s, KVM_CREATE_VM, type); | ||||
|     } while (ret == -EINTR); | ||||
|  | ||||
|     if (ret < 0) { | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
| #include "hw/hw.h" | ||||
| #include "cpu.h" | ||||
| #include "sysemu/kvm.h" | ||||
| #include "sysemu/qemumachine.h" | ||||
|  | ||||
| #ifndef CONFIG_USER_ONLY | ||||
| #include "hw/pci/msi.h" | ||||
| @@ -34,7 +35,7 @@ int kvm_init_vcpu(CPUState *cpu) | ||||
|     return -ENOSYS; | ||||
| } | ||||
|  | ||||
| int kvm_init(void) | ||||
| int kvm_init(QEMUMachine *machine) | ||||
| { | ||||
|     return -ENOSYS; | ||||
| } | ||||
|   | ||||
| @@ -269,7 +269,7 @@ on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming) | ||||
|     send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0); | ||||
|     /* launch the event_thread. This will trigger reader adds for all the | ||||
|      * existing readers */ | ||||
|     qemu_thread_create(&thread_id, event_thread, NULL, 0); | ||||
|     qemu_thread_create(&thread_id, "vsc/event", event_thread, NULL, 0); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -39,6 +39,7 @@ struct target_pt_regs { | ||||
| }; | ||||
|  | ||||
| #define UNAME_MACHINE "alpha" | ||||
| #define UNAME_MINIMUM_RELEASE "2.6.32" | ||||
|  | ||||
| #undef TARGET_EDEADLK | ||||
| #define TARGET_EDEADLK		11 | ||||
|   | ||||
| @@ -40,5 +40,6 @@ struct target_pt_regs { | ||||
| #else | ||||
| #define UNAME_MACHINE "armv5tel" | ||||
| #endif | ||||
| #define UNAME_MINIMUM_RELEASE "2.6.32" | ||||
|  | ||||
| #define TARGET_CLONE_BACKWARDS | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #ifndef CRIS_SYSCALL_H | ||||
| #define CRIS_SYSCALL_H 1 | ||||
|  | ||||
|  | ||||
| #define UNAME_MACHINE "cris" | ||||
| #define UNAME_MINIMUM_RELEASE "2.6.32" | ||||
|  | ||||
| /* pt_regs not only specifices the format in the user-struct during | ||||
|  * ptrace but is also the frame format used in the kernel prologue/epilogues | ||||
|   | ||||
| @@ -144,5 +144,6 @@ struct target_vm86plus_struct { | ||||
| }; | ||||
|  | ||||
| #define UNAME_MACHINE "i686" | ||||
| #define UNAME_MINIMUM_RELEASE "2.6.32" | ||||
|  | ||||
| #define TARGET_CLONE_BACKWARDS | ||||
|   | ||||
| @@ -15,7 +15,7 @@ struct target_pt_regs { | ||||
|     uint16_t __fill; | ||||
| }; | ||||
|  | ||||
|  | ||||
| #define UNAME_MACHINE "m68k" | ||||
| #define UNAME_MINIMUM_RELEASE "2.6.32" | ||||
|  | ||||
| void do_m68k_simcall(CPUM68KState *, int); | ||||
|   | ||||
| @@ -1492,7 +1492,7 @@ static int do_store_exclusive(CPUPPCState *env) | ||||
| { | ||||
|     target_ulong addr; | ||||
|     target_ulong page_addr; | ||||
|     target_ulong val; | ||||
|     target_ulong val, val2 __attribute__((unused)); | ||||
|     int flags; | ||||
|     int segv = 0; | ||||
|  | ||||
| @@ -1515,6 +1515,13 @@ static int do_store_exclusive(CPUPPCState *env) | ||||
|             case 4: segv = get_user_u32(val, addr); break; | ||||
| #if defined(TARGET_PPC64) | ||||
|             case 8: segv = get_user_u64(val, addr); break; | ||||
|             case 16: { | ||||
|                 segv = get_user_u64(val, addr); | ||||
|                 if (!segv) { | ||||
|                     segv = get_user_u64(val2, addr + 8); | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
| #endif | ||||
|             default: abort(); | ||||
|             } | ||||
| @@ -1526,6 +1533,15 @@ static int do_store_exclusive(CPUPPCState *env) | ||||
|                 case 4: segv = put_user_u32(val, addr); break; | ||||
| #if defined(TARGET_PPC64) | ||||
|                 case 8: segv = put_user_u64(val, addr); break; | ||||
|                 case 16: { | ||||
|                     if (val2 == env->reserve_val2) { | ||||
|                         segv = put_user_u64(val, addr); | ||||
|                         if (!segv) { | ||||
|                             segv = put_user_u64(val2, addr + 8); | ||||
|                         } | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
| #endif | ||||
|                 default: abort(); | ||||
|                 } | ||||
| @@ -2384,6 +2400,10 @@ static int do_break(CPUMIPSState *env, target_siginfo_t *info, | ||||
|         ret = 0; | ||||
|         break; | ||||
|     default: | ||||
|         info->si_signo = TARGET_SIGTRAP; | ||||
|         info->si_errno = 0; | ||||
|         queue_signal(env, info->si_signo, &*info); | ||||
|         ret = 0; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #ifndef MICROBLAZE_SYSCALLS_H | ||||
| #define MICROBLAZE_SYSCALLS_H 1 | ||||
|  | ||||
|  | ||||
| #define UNAME_MACHINE "microblaze" | ||||
| #define UNAME_MINIMUM_RELEASE "2.6.32" | ||||
|  | ||||
| /* We use microblaze_reg_t to keep things similar to the kernel sources.  */ | ||||
| typedef uint32_t microblaze_reg_t; | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user