Compare commits
	
		
			318 Commits
		
	
	
		
			pull-ui-20
			...
			pull-ui-20
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | c62e90af8c | ||
|  | 06bb88145c | ||
|  | 67c4c2bd95 | ||
|  | fba958c692 | ||
|  | 4aaddc2976 | ||
|  | 6d5322442a | ||
|  | 0e88d45a33 | ||
|  | df32c8d436 | ||
|  | 232afac113 | ||
|  | 4552a09dd4 | ||
|  | 365162f7c0 | ||
|  | b47d3af755 | ||
|  | 551747491d | ||
|  | 19b6d84316 | ||
|  | fefd749ce2 | ||
|  | d0d7708ba2 | ||
|  | f1c17521e7 | ||
|  | eb38c3b670 | ||
|  | 1a6245a5b0 | ||
|  | 798bfe0006 | ||
|  | ee7d7aabda | ||
|  | e1dc68155c | ||
|  | 1cb6d137ff | ||
|  | 46f296cd3a | ||
|  | fca1031839 | ||
|  | 36fef36b91 | ||
|  | 4c1396cb57 | ||
|  | 76c64d3360 | ||
|  | 3daa41078a | ||
|  | 5a57acb66f | ||
|  | 67736a25f8 | ||
|  | ade0d0c0d3 | ||
|  | 7d68e47f12 | ||
|  | bada8e4470 | ||
|  | da2b91409f | ||
|  | b6e05aa473 | ||
|  | 8161befdd1 | ||
|  | b09afd58e4 | ||
|  | f1cd483004 | ||
|  | dc3b89ef87 | ||
|  | deb2db996c | ||
|  | f02ccf5369 | ||
|  | 17c8a21978 | ||
|  | cd0b19a20b | ||
|  | ed56fdb256 | ||
|  | 91728bda76 | ||
|  | 5d596c245d | ||
|  | 533fdaedeb | ||
|  | 24da21f265 | ||
|  | e6da780d5f | ||
|  | 433672b0d5 | ||
|  | bf89e87427 | ||
|  | c3d2d68ad6 | ||
|  | d28d737fb9 | ||
|  | e4937694b6 | ||
|  | 9af9e0fed7 | ||
|  | b988468149 | ||
|  | d410fe1454 | ||
|  | b83baa6025 | ||
|  | e43bfd9c87 | ||
|  | c29b77f955 | ||
|  | 8aa802a6b7 | ||
|  | 8277d2aa58 | ||
|  | 73eaa04777 | ||
|  | a4699e55f5 | ||
|  | cd5c2dac2e | ||
|  | f4d0064afc | ||
|  | 7828867198 | ||
|  | 193227f9e5 | ||
|  | 4fffeb5e19 | ||
|  | 85b01e0960 | ||
|  | acef5c02e5 | ||
|  | 7e274652e4 | ||
|  | 675463d9b6 | ||
|  | d10e54329b | ||
|  | 3a80ceadcb | ||
|  | c72fbf98cb | ||
|  | 7b55044f9d | ||
|  | 543202c0dd | ||
|  | 9280eb34de | ||
|  | 5a8de107e3 | ||
|  | b097e48121 | ||
|  | 84a3a53cf6 | ||
|  | c525436e69 | ||
|  | 6231a6da9f | ||
|  | 007b06578a | ||
|  | 8d780f4392 | ||
|  | c1bc66263c | ||
|  | 063e760a5f | ||
|  | 4addcd4fdc | ||
|  | 6ba996bb45 | ||
|  | 93d7af6ff0 | ||
|  | 48781e5bf2 | ||
|  | 88bfa2166a | ||
|  | 1789f4e37c | ||
|  | cf87e0a3ee | ||
|  | e11f463295 | ||
|  | de37b0b87f | ||
|  | 3be5c2078b | ||
|  | 7b3fdbd9a8 | ||
|  | 3538fb6f89 | ||
|  | b21b75981f | ||
|  | d9eb0be229 | ||
|  | 649a1bbaf9 | ||
|  | 8acc216b95 | ||
|  | cf57c2f18b | ||
|  | 00588a0aa2 | ||
|  | c5620e658e | ||
|  | e8109694c7 | ||
|  | 9350df7cea | ||
|  | b682d3a7cf | ||
|  | b1b66c3b5e | ||
|  | b88641e236 | ||
|  | d0b282a58c | ||
|  | 54d268b26a | ||
|  | 248de4a899 | ||
|  | 4ab0359a8a | ||
|  | 97225170f6 | ||
|  | 7b8a354d47 | ||
|  | fea9b3ca9c | ||
|  | 5de6f3c0f4 | ||
|  | b3d21a04b8 | ||
|  | fea01f9604 | ||
|  | ac0d9dbf33 | ||
|  | 530c003252 | ||
|  | 692a5519ab | ||
|  | 5a53dc5042 | ||
|  | e73eecbdc2 | ||
|  | cc06ca4c97 | ||
|  | 10e1b75961 | ||
|  | fad6c58a3d | ||
|  | d21ccd7bb9 | ||
|  | fe02fc5209 | ||
|  | 1063477834 | ||
|  | ff433bbb82 | ||
|  | 4e6f7cfbf9 | ||
|  | 529490e5d6 | ||
|  | 8f32510f1c | ||
|  | a2a645d967 | ||
|  | 9f23b27d0d | ||
|  | b429d363ed | ||
|  | 9763af08f8 | ||
|  | f922254c87 | ||
|  | 713572a7b5 | ||
|  | 66c058cb69 | ||
|  | b3afe33526 | ||
|  | 82407515fe | ||
|  | 240125bc49 | ||
|  | 34f22fc034 | ||
|  | 477cea9e6d | ||
|  | 87bbdd9caf | ||
|  | 215e209846 | ||
|  | 57040d4513 | ||
|  | 4b23699c82 | ||
|  | fccbc78500 | ||
|  | fc9f38c3c0 | ||
|  | 5013c54746 | ||
|  | f949b4e5f5 | ||
|  | 877f8931b9 | ||
|  | 0eb9054c60 | ||
|  | 64f0f70a00 | ||
|  | 1c5f29bbc8 | ||
|  | aec39c5349 | ||
|  | 3dc0a66d26 | ||
|  | 7d94a30b54 | ||
|  | 9c7ffe2664 | ||
|  | 3be9b3528d | ||
|  | aa7f9966df | ||
|  | 007cd223de | ||
|  | 7d6d347d06 | ||
|  | 3509866ab3 | ||
|  | f713d4d2f1 | ||
|  | b79f17a9bc | ||
|  | b22e0aef46 | ||
|  | 9c087a0504 | ||
|  | f9262dae13 | ||
|  | 671f66f87f | ||
|  | b50c7d452f | ||
|  | c12d82ef15 | ||
|  | 8856be1512 | ||
|  | 5ae3e91c35 | ||
|  | c469669ef7 | ||
|  | fde58177aa | ||
|  | 663fb1e172 | ||
|  | aa4a3dce1c | ||
|  | dd3c168471 | ||
|  | 71c2f5b9b3 | ||
|  | 2e4ca7dbc1 | ||
|  | 938cdfefee | ||
|  | 54c6de864f | ||
|  | 6e50216461 | ||
|  | 8a1be662a6 | ||
|  | 56a571d9c8 | ||
|  | 50e5ae4dc3 | ||
|  | 2cf0148674 | ||
|  | 424e4a87d2 | ||
|  | 9fc6502606 | ||
|  | 3db119da79 | ||
|  | 9e4afc0995 | ||
|  | afa06e1828 | ||
|  | f97a88a85e | ||
|  | e9fce79861 | ||
|  | 65aef4de5e | ||
|  | 22b5b8bf31 | ||
|  | 0dafe3b336 | ||
|  | 41f95a5200 | ||
|  | 78e1ad0509 | ||
|  | 16682a9d86 | ||
|  | 12e3b1f750 | ||
|  | 80b32df529 | ||
|  | 32b9741f50 | ||
|  | b616ec4d6f | ||
|  | 196e213783 | ||
|  | 06989b8861 | ||
|  | 100681ccf1 | ||
|  | c35b6e8032 | ||
|  | 4c5eebc1fa | ||
|  | e4db279804 | ||
|  | 28f1f0e929 | ||
|  | 8b1da5f8fd | ||
|  | 95ed7e97e4 | ||
|  | c355cb2c0f | ||
|  | f58190e2c2 | ||
|  | ee13584996 | ||
|  | 3892a2b741 | ||
|  | a57d708d17 | ||
|  | 5ca5efa4a6 | ||
|  | 6b30608774 | ||
|  | f294ecbc13 | ||
|  | 40f981a02d | ||
|  | 1d608d13eb | ||
|  | fbd7a6b8e2 | ||
|  | 1295e21a17 | ||
|  | f84548dda4 | ||
|  | 7f4495e1c1 | ||
|  | f177d40ae2 | ||
|  | 2ca66546ce | ||
|  | c943764596 | ||
|  | e328e31660 | ||
|  | 2fbd884372 | ||
|  | fb775d9074 | ||
|  | b98401223d | ||
|  | e8f9db491d | ||
|  | 12fdadb574 | ||
|  | b2344f3e63 | ||
|  | 30bd0cf465 | ||
|  | 7cb08cb2d7 | ||
|  | f070efa8d9 | ||
|  | 349a3b1cc9 | ||
|  | c8e6c93857 | ||
|  | c0d3573632 | ||
|  | 27e112f9fd | ||
|  | e6deac9cf9 | ||
|  | 2a0fa68fb9 | ||
|  | 861d72cd28 | ||
|  | 0cf227229b | ||
|  | 7b36f78274 | ||
|  | 5d4d366585 | ||
|  | ff626f2d9e | ||
|  | 6bb9ead762 | ||
|  | 9df2513730 | ||
|  | d9767f1bfa | ||
|  | 2a0c56aa4c | ||
|  | 60ce86c714 | ||
|  | 72a189770a | ||
|  | 0192cc5d79 | ||
|  | 4b311c5f0b | ||
|  | 0d3716b4e6 | ||
|  | ebe74f8ba2 | ||
|  | 592707af7f | ||
|  | f657b17a63 | ||
|  | fe9fa96d7c | ||
|  | 0e173b24b5 | ||
|  | 3e24bb3f12 | ||
|  | 928bed6a05 | ||
|  | e36800c91a | ||
|  | 0e2082d9e5 | ||
|  | dc295f8353 | ||
|  | ad38ce9ed1 | ||
|  | 2209bd050a | ||
|  | 087462c773 | ||
|  | fd0a10cd20 | ||
|  | ec93e158b1 | ||
|  | c22d5dcd7a | ||
|  | 0922c3f606 | ||
|  | 7d938fd14b | ||
|  | 84d04e2162 | ||
|  | 829dd2861a | ||
|  | 71042cffc0 | ||
|  | 756cb74a59 | ||
|  | 267ae092e2 | ||
|  | 364031f179 | ||
|  | 494a8ebe71 | ||
|  | d57b78002c | ||
|  | f00d4f596b | ||
|  | 3b9ca04653 | ||
|  | fe52840c87 | ||
|  | 94ca2c7395 | ||
|  | df92562e68 | ||
|  | e40e5027f6 | ||
|  | 4193cdd771 | ||
|  | 05e4d14bf3 | ||
|  | dd87de06fa | ||
|  | f943078e42 | ||
|  | 61b422265e | ||
|  | ae7e0bf461 | ||
|  | 1b935e1dc9 | ||
|  | 9b652fbe1d | ||
|  | 5581018400 | ||
|  | 49557d656c | ||
|  | f19f11896e | ||
|  | 71ad761766 | ||
|  | f2bbcd3f7f | ||
|  | 9b337ae90a | ||
|  | 0fa296eb00 | ||
|  | fc27291daf | ||
|  | 7467d94cc4 | ||
|  | 253597d8cf | 
| @@ -1036,7 +1036,8 @@ Device Tree | ||||
| M: Peter Crosthwaite <crosthwaite.peter@gmail.com> | ||||
| M: Alexander Graf <agraf@suse.de> | ||||
| S: Maintained | ||||
| F: device_tree.[ch] | ||||
| F: device_tree.c | ||||
| F: include/sysemu/device_tree.h | ||||
|  | ||||
| Error reporting | ||||
| M: Markus Armbruster <armbru@redhat.com> | ||||
| @@ -1115,8 +1116,9 @@ F: net/netmap.c | ||||
| Network Block Device (NBD) | ||||
| M: Paolo Bonzini <pbonzini@redhat.com> | ||||
| S: Odd Fixes | ||||
| F: block/nbd.c | ||||
| F: nbd.* | ||||
| F: block/nbd* | ||||
| F: nbd/ | ||||
| F: include/block/nbd* | ||||
| F: qemu-nbd.c | ||||
| T: git git://github.com/bonzini/qemu.git nbd-next | ||||
|  | ||||
| @@ -1199,6 +1201,7 @@ SLIRP | ||||
| M: Jan Kiszka <jan.kiszka@siemens.com> | ||||
| S: Maintained | ||||
| F: slirp/ | ||||
| F: net/slirp.c | ||||
| T: git git://git.kiszka.org/qemu.git queues/slirp | ||||
|  | ||||
| Tracing | ||||
|   | ||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -240,7 +240,7 @@ qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(qom-obj-y) libqemuu | ||||
|  | ||||
| qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o | ||||
|  | ||||
| fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o libqemuutil.a libqemustub.a | ||||
| fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o libqemuutil.a libqemustub.a | ||||
| fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap | ||||
|  | ||||
| qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx | ||||
|   | ||||
| @@ -8,7 +8,8 @@ util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o | ||||
| # block-obj-y is code used by both qemu system emulation and qemu-img | ||||
|  | ||||
| block-obj-y = async.o thread-pool.o | ||||
| block-obj-y += nbd.o block.o blockjob.o | ||||
| block-obj-y += nbd/ | ||||
| block-obj-y += block.o blockjob.o | ||||
| block-obj-y += main-loop.o iohandler.o qemu-timer.o | ||||
| block-obj-$(CONFIG_POSIX) += aio-posix.o | ||||
| block-obj-$(CONFIG_WIN32) += aio-win32.o | ||||
|   | ||||
| @@ -258,9 +258,7 @@ void do_acpitable_option(const QemuOpts *opts) | ||||
|  | ||||
|     acpi_table_add(opts, &err); | ||||
|     if (err) { | ||||
|         error_report("Wrong acpi table provided: %s", | ||||
|                      error_get_pretty(err)); | ||||
|         error_free(err); | ||||
|         error_reportf_err(err, "Wrong acpi table provided: "); | ||||
|         exit(1); | ||||
|     } | ||||
| #endif | ||||
|   | ||||
| @@ -1806,9 +1806,6 @@ static void audio_init (void) | ||||
|     atexit (audio_atexit); | ||||
|  | ||||
|     s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s); | ||||
|     if (!s->ts) { | ||||
|         hw_error("Could not create audio timer\n"); | ||||
|     } | ||||
|  | ||||
|     audio_process_options ("AUDIO", audio_options); | ||||
|  | ||||
| @@ -1859,12 +1856,8 @@ static void audio_init (void) | ||||
|  | ||||
|     if (!done) { | ||||
|         done = !audio_driver_init (s, &no_audio_driver); | ||||
|         if (!done) { | ||||
|             hw_error("Could not initialize audio subsystem\n"); | ||||
|         } | ||||
|         else { | ||||
|             dolog ("warning: Using timer based audio emulation\n"); | ||||
|         } | ||||
|         assert(done); | ||||
|         dolog("warning: Using timer based audio emulation\n"); | ||||
|     } | ||||
|  | ||||
|     if (conf.period.hertz <= 0) { | ||||
|   | ||||
| @@ -566,6 +566,7 @@ static CharDriverState *chr_baum_init(const char *id, | ||||
|                                       ChardevReturn *ret, | ||||
|                                       Error **errp) | ||||
| { | ||||
|     ChardevCommon *common = qapi_ChardevDummy_base(backend->u.braille); | ||||
|     BaumDriverState *baum; | ||||
|     CharDriverState *chr; | ||||
|     brlapi_handle_t *handle; | ||||
| @@ -576,8 +577,12 @@ static CharDriverState *chr_baum_init(const char *id, | ||||
| #endif | ||||
|     int tty; | ||||
|  | ||||
|     chr = qemu_chr_alloc(common, errp); | ||||
|     if (!chr) { | ||||
|         return NULL; | ||||
|     } | ||||
|     baum = g_malloc0(sizeof(BaumDriverState)); | ||||
|     baum->chr = chr = qemu_chr_alloc(); | ||||
|     baum->chr = chr; | ||||
|  | ||||
|     chr->opaque = baum; | ||||
|     chr->chr_write = baum_write; | ||||
|   | ||||
| @@ -68,9 +68,13 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id, | ||||
|                                               ChardevReturn *ret, | ||||
|                                               Error **errp) | ||||
| { | ||||
|     ChardevCommon *common = qapi_ChardevDummy_base(backend->u.msmouse); | ||||
|     CharDriverState *chr; | ||||
|  | ||||
|     chr = qemu_chr_alloc(); | ||||
|     chr = qemu_chr_alloc(common, errp); | ||||
|     if (!chr) { | ||||
|         return NULL; | ||||
|     } | ||||
|     chr->chr_write = msmouse_chr_write; | ||||
|     chr->chr_close = msmouse_chr_close; | ||||
|     chr->explicit_be_open = true; | ||||
|   | ||||
							
								
								
									
										24
									
								
								block.c
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								block.c
									
									
									
									
									
								
							| @@ -1349,12 +1349,10 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, | ||||
|     ret = bdrv_open_inherit(&backing_hd, | ||||
|                             *backing_filename ? backing_filename : NULL, | ||||
|                             reference, options, 0, bs, &child_backing, | ||||
|                             &local_err); | ||||
|                             errp); | ||||
|     if (ret < 0) { | ||||
|         bs->open_flags |= BDRV_O_NO_BACKING; | ||||
|         error_setg(errp, "Could not open backing file: %s", | ||||
|                    error_get_pretty(local_err)); | ||||
|         error_free(local_err); | ||||
|         error_prepend(errp, "Could not open backing file: "); | ||||
|         goto free_exit; | ||||
|     } | ||||
|  | ||||
| @@ -1460,13 +1458,11 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) | ||||
|     opts = qemu_opts_create(bdrv_qcow2.create_opts, NULL, 0, | ||||
|                             &error_abort); | ||||
|     qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size, &error_abort); | ||||
|     ret = bdrv_create(&bdrv_qcow2, tmp_filename, opts, &local_err); | ||||
|     ret = bdrv_create(&bdrv_qcow2, tmp_filename, opts, errp); | ||||
|     qemu_opts_del(opts); | ||||
|     if (ret < 0) { | ||||
|         error_setg_errno(errp, -ret, "Could not create temporary overlay " | ||||
|                          "'%s': %s", tmp_filename, | ||||
|                          error_get_pretty(local_err)); | ||||
|         error_free(local_err); | ||||
|         error_prepend(errp, "Could not create temporary overlay '%s': ", | ||||
|                       tmp_filename); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
| @@ -2154,9 +2150,10 @@ void bdrv_close(BlockDriverState *bs) | ||||
|         bdrv_io_limits_disable(bs); | ||||
|     } | ||||
|  | ||||
|     bdrv_drain(bs); /* complete I/O */ | ||||
|     bdrv_drained_begin(bs); /* complete I/O */ | ||||
|     bdrv_flush(bs); | ||||
|     bdrv_drain(bs); /* in case flush left pending I/O */ | ||||
|  | ||||
|     notifier_list_notify(&bs->close_notifiers, bs); | ||||
|  | ||||
|     if (bs->blk) { | ||||
| @@ -2206,6 +2203,7 @@ void bdrv_close(BlockDriverState *bs) | ||||
|         g_free(ban); | ||||
|     } | ||||
|     QLIST_INIT(&bs->aio_notifiers); | ||||
|     bdrv_drained_end(bs); | ||||
| } | ||||
|  | ||||
| void bdrv_close_all(void) | ||||
| @@ -3728,9 +3726,9 @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp) | ||||
|     if (!QLIST_EMPTY(&bs->op_blockers[op])) { | ||||
|         blocker = QLIST_FIRST(&bs->op_blockers[op]); | ||||
|         if (errp) { | ||||
|             error_setg(errp, "Node '%s' is busy: %s", | ||||
|                        bdrv_get_device_or_node_name(bs), | ||||
|                        error_get_pretty(blocker->reason)); | ||||
|             *errp = error_copy(blocker->reason); | ||||
|             error_prepend(errp, "Node '%s' is busy: ", | ||||
|                           bdrv_get_device_or_node_name(bs)); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|   | ||||
| @@ -1033,6 +1033,11 @@ void blk_set_guest_block_size(BlockBackend *blk, int align) | ||||
|     blk->guest_block_size = align; | ||||
| } | ||||
|  | ||||
| void *blk_try_blockalign(BlockBackend *blk, size_t size) | ||||
| { | ||||
|     return qemu_try_blockalign(blk ? blk->bs : NULL, size); | ||||
| } | ||||
|  | ||||
| void *blk_blockalign(BlockBackend *blk, size_t size) | ||||
| { | ||||
|     return qemu_blockalign(blk ? blk->bs : NULL, size); | ||||
|   | ||||
| @@ -1243,8 +1243,13 @@ static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp) | ||||
|                     iscsilun->lbprz = !!rc16->lbprz; | ||||
|                     iscsilun->use_16_for_rw = (rc16->returned_lba > 0xffffffff); | ||||
|                 } | ||||
|             } | ||||
|                 break; | ||||
|             } | ||||
|             if (task != NULL && task->status == SCSI_STATUS_CHECK_CONDITION | ||||
|                 && task->sense.key == SCSI_SENSE_UNIT_ATTENTION) { | ||||
|                 break; | ||||
|             } | ||||
|             /* Fall through and try READ CAPACITY(10) instead.  */ | ||||
|         case TYPE_ROM: | ||||
|             task = iscsi_readcapacity10_sync(iscsilun->iscsi, iscsilun->lun, 0, 0); | ||||
|             if (task != NULL && task->status == SCSI_STATUS_GOOD) { | ||||
| @@ -1270,7 +1275,7 @@ static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp) | ||||
|              && retries-- > 0); | ||||
|  | ||||
|     if (task == NULL || task->status != SCSI_STATUS_GOOD) { | ||||
|         error_setg(errp, "iSCSI: failed to send readcapacity10 command."); | ||||
|         error_setg(errp, "iSCSI: failed to send readcapacity10/16 command"); | ||||
|     } else if (!iscsilun->block_size || | ||||
|                iscsilun->block_size % BDRV_SECTOR_SIZE) { | ||||
|         error_setg(errp, "iSCSI: the target returned an invalid " | ||||
|   | ||||
| @@ -250,6 +250,7 @@ void bdrv_query_image_info(BlockDriverState *bs, | ||||
|             g_free(backing_filename2); | ||||
|             backing_filename2 = NULL; | ||||
|             error_free(err); | ||||
|             err = NULL; | ||||
|         } | ||||
|  | ||||
|         /* Always report the full_backing_filename if present, even if it's the | ||||
|   | ||||
| @@ -1762,9 +1762,8 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) | ||||
|     ret = qcow2_open(bs, options, flags, &local_err); | ||||
|     QDECREF(options); | ||||
|     if (local_err) { | ||||
|         error_setg(errp, "Could not reopen qcow2 layer: %s", | ||||
|                    error_get_pretty(local_err)); | ||||
|         error_free(local_err); | ||||
|         error_propagate(errp, local_err); | ||||
|         error_prepend(errp, "Could not reopen qcow2 layer: "); | ||||
|         return; | ||||
|     } else if (ret < 0) { | ||||
|         error_setg_errno(errp, -ret, "Could not reopen qcow2 layer"); | ||||
|   | ||||
| @@ -1611,9 +1611,8 @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp) | ||||
|     memset(s, 0, sizeof(BDRVQEDState)); | ||||
|     ret = bdrv_qed_open(bs, NULL, bs->open_flags, &local_err); | ||||
|     if (local_err) { | ||||
|         error_setg(errp, "Could not reopen qed layer: %s", | ||||
|                    error_get_pretty(local_err)); | ||||
|         error_free(local_err); | ||||
|         error_propagate(errp, local_err); | ||||
|         error_prepend(errp, "Could not reopen qed layer: "); | ||||
|         return; | ||||
|     } else if (ret < 0) { | ||||
|         error_setg_errno(errp, -ret, "Could not reopen qed layer"); | ||||
|   | ||||
| @@ -1861,8 +1861,7 @@ static int sd_create(const char *filename, QemuOpts *opts, | ||||
|  | ||||
|         fd = connect_to_sdog(s, &local_err); | ||||
|         if (fd < 0) { | ||||
|             error_report("%s", error_get_pretty(local_err)); | ||||
|             error_free(local_err); | ||||
|             error_report_err(local_err); | ||||
|             ret = -EIO; | ||||
|             goto out; | ||||
|         } | ||||
| @@ -2406,9 +2405,8 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) | ||||
|  | ||||
|     ret = do_sd_create(s, &new_vid, 1, &local_err); | ||||
|     if (ret < 0) { | ||||
|         error_report("failed to create inode for snapshot: %s", | ||||
|                      error_get_pretty(local_err)); | ||||
|         error_free(local_err); | ||||
|         error_reportf_err(local_err, | ||||
|                           "failed to create inode for snapshot: "); | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -784,12 +784,13 @@ int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed, | ||||
|     if (logs.valid) { | ||||
|         if (bs->read_only) { | ||||
|             ret = -EPERM; | ||||
|             error_setg_errno(errp, EPERM, | ||||
|             error_setg(errp, | ||||
|                        "VHDX image file '%s' opened read-only, but " | ||||
|                              "contains a log that needs to be replayed.  To " | ||||
|                              "replay the log, execute:\n qemu-img check -r " | ||||
|                              "all '%s'", | ||||
|                              bs->filename, bs->filename); | ||||
|                        "contains a log that needs to be replayed", | ||||
|                        bs->filename); | ||||
|             error_append_hint(errp,  "To replay the log, run:\n" | ||||
|                               "qemu-img check -r all '%s'\n", | ||||
|                               bs->filename); | ||||
|             goto exit; | ||||
|         } | ||||
|         /* now flush the log */ | ||||
|   | ||||
							
								
								
									
										48
									
								
								block/vmdk.c
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								block/vmdk.c
									
									
									
									
									
								
							| @@ -760,6 +760,17 @@ static int vmdk_open_sparse(BlockDriverState *bs, BdrvChild *file, int flags, | ||||
|     } | ||||
| } | ||||
|  | ||||
| static const char *next_line(const char *s) | ||||
| { | ||||
|     while (*s) { | ||||
|         if (*s == '\n') { | ||||
|             return s + 1; | ||||
|         } | ||||
|         s++; | ||||
|     } | ||||
|     return s; | ||||
| } | ||||
|  | ||||
| static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||||
|                               const char *desc_file_path, QDict *options, | ||||
|                               Error **errp) | ||||
| @@ -769,7 +780,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||||
|     char access[11]; | ||||
|     char type[11]; | ||||
|     char fname[512]; | ||||
|     const char *p = desc; | ||||
|     const char *p, *np; | ||||
|     int64_t sectors = 0; | ||||
|     int64_t flat_offset; | ||||
|     char *extent_path; | ||||
| @@ -779,7 +790,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||||
|     char extent_opt_prefix[32]; | ||||
|     Error *local_err = NULL; | ||||
|  | ||||
|     while (*p) { | ||||
|     for (p = desc; *p; p = next_line(p)) { | ||||
|         /* parse extent line in one of below formats: | ||||
|          * | ||||
|          * RW [size in sectors] FLAT "file-name.vmdk" OFFSET | ||||
| @@ -791,29 +802,26 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||||
|         matches = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, | ||||
|                          access, §ors, type, fname, &flat_offset); | ||||
|         if (matches < 4 || strcmp(access, "RW")) { | ||||
|             goto next_line; | ||||
|             continue; | ||||
|         } else if (!strcmp(type, "FLAT")) { | ||||
|             if (matches != 5 || flat_offset < 0) { | ||||
|                 error_setg(errp, "Invalid extent lines: \n%s", p); | ||||
|                 return -EINVAL; | ||||
|                 goto invalid; | ||||
|             } | ||||
|         } else if (!strcmp(type, "VMFS")) { | ||||
|             if (matches == 4) { | ||||
|                 flat_offset = 0; | ||||
|             } else { | ||||
|                 error_setg(errp, "Invalid extent lines:\n%s", p); | ||||
|                 return -EINVAL; | ||||
|                 goto invalid; | ||||
|             } | ||||
|         } else if (matches != 4) { | ||||
|             error_setg(errp, "Invalid extent lines:\n%s", p); | ||||
|             return -EINVAL; | ||||
|             goto invalid; | ||||
|         } | ||||
|  | ||||
|         if (sectors <= 0 || | ||||
|             (strcmp(type, "FLAT") && strcmp(type, "SPARSE") && | ||||
|              strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE")) || | ||||
|             (strcmp(access, "RW"))) { | ||||
|             goto next_line; | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         if (!path_is_absolute(fname) && !path_has_protocol(fname) && | ||||
| @@ -870,17 +878,17 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||||
|             return -ENOTSUP; | ||||
|         } | ||||
|         extent->type = g_strdup(type); | ||||
| next_line: | ||||
|         /* move to next line */ | ||||
|         while (*p) { | ||||
|             if (*p == '\n') { | ||||
|                 p++; | ||||
|                 break; | ||||
|             } | ||||
|             p++; | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
|  | ||||
| invalid: | ||||
|     np = next_line(p); | ||||
|     assert(np != p); | ||||
|     if (np[-1] == '\n') { | ||||
|         np--; | ||||
|     } | ||||
|     error_setg(errp, "Invalid extent line: %.*s", (int)(np - p), p); | ||||
|     return -EINVAL; | ||||
| } | ||||
|  | ||||
| static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, | ||||
| @@ -1494,7 +1502,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, | ||||
|  | ||||
|     if (sector_num > bs->total_sectors) { | ||||
|         error_report("Wrong offset: sector_num=0x%" PRIx64 | ||||
|                 " total_sectors=0x%" PRIx64 "\n", | ||||
|                      " total_sectors=0x%" PRIx64, | ||||
|                      sector_num, bs->total_sectors); | ||||
|         return -EIO; | ||||
|     } | ||||
|   | ||||
| @@ -27,9 +27,8 @@ static void nbd_accept(void *opaque) | ||||
|     socklen_t addr_len = sizeof(addr); | ||||
|  | ||||
|     int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); | ||||
|     if (fd >= 0 && !nbd_client_new(NULL, fd, nbd_client_put)) { | ||||
|         shutdown(fd, 2); | ||||
|         close(fd); | ||||
|     if (fd >= 0) { | ||||
|         nbd_client_new(NULL, fd, nbd_client_put); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										177
									
								
								blockdev.c
									
									
									
									
									
								
							
							
						
						
									
										177
									
								
								blockdev.c
									
									
									
									
									
								
							| @@ -1582,13 +1582,11 @@ static void internal_snapshot_abort(BlkActionState *common) | ||||
|     } | ||||
|  | ||||
|     if (bdrv_snapshot_delete(bs, sn->id_str, sn->name, &local_error) < 0) { | ||||
|         error_report("Failed to delete snapshot with id '%s' and name '%s' on " | ||||
|                      "device '%s' in abort: %s", | ||||
|                      sn->id_str, | ||||
|                      sn->name, | ||||
|                      bdrv_get_device_name(bs), | ||||
|                      error_get_pretty(local_error)); | ||||
|         error_free(local_error); | ||||
|         error_reportf_err(local_error, | ||||
|                           "Failed to delete snapshot with id '%s' and " | ||||
|                           "name '%s' on device '%s' in abort: ", | ||||
|                           sn->id_str, sn->name, | ||||
|                           bdrv_get_device_name(bs)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -3291,29 +3289,23 @@ void qmp_blockdev_backup(const char *device, const char *target, | ||||
|                        NULL, errp); | ||||
| } | ||||
|  | ||||
| void qmp_drive_mirror(const char *device, const char *target, | ||||
|                       bool has_format, const char *format, | ||||
|                       bool has_node_name, const char *node_name, | ||||
| /* Parameter check and block job starting for drive mirroring. | ||||
|  * Caller should hold @device and @target's aio context (must be the same). | ||||
|  **/ | ||||
| static void blockdev_mirror_common(BlockDriverState *bs, | ||||
|                                    BlockDriverState *target, | ||||
|                                    bool has_replaces, const char *replaces, | ||||
|                                    enum MirrorSyncMode sync, | ||||
|                       bool has_mode, enum NewImageMode mode, | ||||
|                                    bool has_speed, int64_t speed, | ||||
|                                    bool has_granularity, uint32_t granularity, | ||||
|                                    bool has_buf_size, int64_t buf_size, | ||||
|                       bool has_on_source_error, BlockdevOnError on_source_error, | ||||
|                       bool has_on_target_error, BlockdevOnError on_target_error, | ||||
|                                    bool has_on_source_error, | ||||
|                                    BlockdevOnError on_source_error, | ||||
|                                    bool has_on_target_error, | ||||
|                                    BlockdevOnError on_target_error, | ||||
|                                    bool has_unmap, bool unmap, | ||||
|                                    Error **errp) | ||||
| { | ||||
|     BlockBackend *blk; | ||||
|     BlockDriverState *bs; | ||||
|     BlockDriverState *source, *target_bs; | ||||
|     AioContext *aio_context; | ||||
|     Error *local_err = NULL; | ||||
|     QDict *options; | ||||
|     int flags; | ||||
|     int64_t size; | ||||
|     int ret; | ||||
|  | ||||
|     if (!has_speed) { | ||||
|         speed = 0; | ||||
| @@ -3324,9 +3316,6 @@ void qmp_drive_mirror(const char *device, const char *target, | ||||
|     if (!has_on_target_error) { | ||||
|         on_target_error = BLOCKDEV_ON_ERROR_REPORT; | ||||
|     } | ||||
|     if (!has_mode) { | ||||
|         mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; | ||||
|     } | ||||
|     if (!has_granularity) { | ||||
|         granularity = 0; | ||||
|     } | ||||
| @@ -3348,6 +3337,55 @@ void qmp_drive_mirror(const char *device, const char *target, | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR_SOURCE, errp)) { | ||||
|         return; | ||||
|     } | ||||
|     if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_MIRROR_TARGET, errp)) { | ||||
|         return; | ||||
|     } | ||||
|     if (target->blk) { | ||||
|         error_setg(errp, "Cannot mirror to an attached block device"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!bs->backing && sync == MIRROR_SYNC_MODE_TOP) { | ||||
|         sync = MIRROR_SYNC_MODE_FULL; | ||||
|     } | ||||
|  | ||||
|     /* pass the node name to replace to mirror start since it's loose coupling | ||||
|      * and will allow to check whether the node still exist at mirror completion | ||||
|      */ | ||||
|     mirror_start(bs, target, | ||||
|                  has_replaces ? replaces : NULL, | ||||
|                  speed, granularity, buf_size, sync, | ||||
|                  on_source_error, on_target_error, unmap, | ||||
|                  block_job_cb, bs, errp); | ||||
| } | ||||
|  | ||||
| void qmp_drive_mirror(const char *device, const char *target, | ||||
|                       bool has_format, const char *format, | ||||
|                       bool has_node_name, const char *node_name, | ||||
|                       bool has_replaces, const char *replaces, | ||||
|                       enum MirrorSyncMode sync, | ||||
|                       bool has_mode, enum NewImageMode mode, | ||||
|                       bool has_speed, int64_t speed, | ||||
|                       bool has_granularity, uint32_t granularity, | ||||
|                       bool has_buf_size, int64_t buf_size, | ||||
|                       bool has_on_source_error, BlockdevOnError on_source_error, | ||||
|                       bool has_on_target_error, BlockdevOnError on_target_error, | ||||
|                       bool has_unmap, bool unmap, | ||||
|                       Error **errp) | ||||
| { | ||||
|     BlockDriverState *bs; | ||||
|     BlockBackend *blk; | ||||
|     BlockDriverState *source, *target_bs; | ||||
|     AioContext *aio_context; | ||||
|     Error *local_err = NULL; | ||||
|     QDict *options = NULL; | ||||
|     int flags; | ||||
|     int64_t size; | ||||
|     int ret; | ||||
|  | ||||
|     blk = blk_by_name(device); | ||||
|     if (!blk) { | ||||
|         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, | ||||
| @@ -3363,15 +3401,14 @@ void qmp_drive_mirror(const char *device, const char *target, | ||||
|         goto out; | ||||
|     } | ||||
|     bs = blk_bs(blk); | ||||
|     if (!has_mode) { | ||||
|         mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; | ||||
|     } | ||||
|  | ||||
|     if (!has_format) { | ||||
|         format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name; | ||||
|     } | ||||
|  | ||||
|     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) { | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     flags = bs->open_flags | BDRV_O_RDWR; | ||||
|     source = backing_bs(bs); | ||||
|     if (!source && sync == MIRROR_SYNC_MODE_TOP) { | ||||
| @@ -3466,22 +3503,78 @@ void qmp_drive_mirror(const char *device, const char *target, | ||||
|  | ||||
|     bdrv_set_aio_context(target_bs, aio_context); | ||||
|  | ||||
|     /* pass the node name to replace to mirror start since it's loose coupling | ||||
|      * and will allow to check whether the node still exist at mirror completion | ||||
|      */ | ||||
|     mirror_start(bs, target_bs, | ||||
|                  has_replaces ? replaces : NULL, | ||||
|                  speed, granularity, buf_size, sync, | ||||
|                  on_source_error, on_target_error, | ||||
|                  unmap, | ||||
|                  block_job_cb, bs, &local_err); | ||||
|     if (local_err != NULL) { | ||||
|         bdrv_unref(target_bs); | ||||
|     blockdev_mirror_common(bs, target_bs, | ||||
|                            has_replaces, replaces, sync, | ||||
|                            has_speed, speed, | ||||
|                            has_granularity, granularity, | ||||
|                            has_buf_size, buf_size, | ||||
|                            has_on_source_error, on_source_error, | ||||
|                            has_on_target_error, on_target_error, | ||||
|                            has_unmap, unmap, | ||||
|                            &local_err); | ||||
|     if (local_err) { | ||||
|         error_propagate(errp, local_err); | ||||
|         goto out; | ||||
|         bdrv_unref(target_bs); | ||||
|     } | ||||
| out: | ||||
|     aio_context_release(aio_context); | ||||
| } | ||||
|  | ||||
| void qmp_blockdev_mirror(const char *device, const char *target, | ||||
|                          bool has_replaces, const char *replaces, | ||||
|                          MirrorSyncMode sync, | ||||
|                          bool has_speed, int64_t speed, | ||||
|                          bool has_granularity, uint32_t granularity, | ||||
|                          bool has_buf_size, int64_t buf_size, | ||||
|                          bool has_on_source_error, | ||||
|                          BlockdevOnError on_source_error, | ||||
|                          bool has_on_target_error, | ||||
|                          BlockdevOnError on_target_error, | ||||
|                          Error **errp) | ||||
| { | ||||
|     BlockDriverState *bs; | ||||
|     BlockBackend *blk; | ||||
|     BlockDriverState *target_bs; | ||||
|     AioContext *aio_context; | ||||
|     Error *local_err = NULL; | ||||
|  | ||||
|     blk = blk_by_name(device); | ||||
|     if (!blk) { | ||||
|         error_setg(errp, "Device '%s' not found", device); | ||||
|         return; | ||||
|     } | ||||
|     bs = blk_bs(blk); | ||||
|  | ||||
|     if (!bs) { | ||||
|         error_setg(errp, "Device '%s' has no media", device); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     target_bs = bdrv_lookup_bs(target, target, errp); | ||||
|     if (!target_bs) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     aio_context = bdrv_get_aio_context(bs); | ||||
|     aio_context_acquire(aio_context); | ||||
|  | ||||
|     bdrv_ref(target_bs); | ||||
|     bdrv_set_aio_context(target_bs, aio_context); | ||||
|  | ||||
|     blockdev_mirror_common(bs, target_bs, | ||||
|                            has_replaces, replaces, sync, | ||||
|                            has_speed, speed, | ||||
|                            has_granularity, granularity, | ||||
|                            has_buf_size, buf_size, | ||||
|                            has_on_source_error, on_source_error, | ||||
|                            has_on_target_error, on_target_error, | ||||
|                            true, true, | ||||
|                            &local_err); | ||||
|     if (local_err) { | ||||
|         error_propagate(errp, local_err); | ||||
|         bdrv_unref(target_bs); | ||||
|     } | ||||
|  | ||||
| out: | ||||
|     aio_context_release(aio_context); | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -4817,7 +4817,7 @@ echo "libcap-ng support $cap_ng" | ||||
| echo "vhost-net support $vhost_net" | ||||
| echo "vhost-scsi support $vhost_scsi" | ||||
| echo "Trace backends    $trace_backends" | ||||
| if test "$trace_backend" = "simple"; then | ||||
| if have_backend "simple"; then | ||||
| echo "Trace output file $trace_file-<pid>" | ||||
| fi | ||||
| if test "$spice" = "yes"; then | ||||
|   | ||||
| @@ -65,7 +65,7 @@ ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[]) | ||||
| { | ||||
|     int c; | ||||
|     unsigned long long v; | ||||
|     Error *errp = NULL; | ||||
|     Error *err = NULL; | ||||
|  | ||||
|     while ((c = getopt(argc, argv, | ||||
|                        "h"  /* help */ | ||||
| @@ -104,11 +104,9 @@ ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[]) | ||||
|             break; | ||||
|  | ||||
|         case 'l': /* shm_size */ | ||||
|             parse_option_size("shm_size", optarg, &args->shm_size, &errp); | ||||
|             if (errp) { | ||||
|                 fprintf(stderr, "cannot parse shm size: %s\n", | ||||
|                         error_get_pretty(errp)); | ||||
|                 error_free(errp); | ||||
|             parse_option_size("shm_size", optarg, &args->shm_size, &err); | ||||
|             if (err) { | ||||
|                 error_report_err(err); | ||||
|                 ivshmem_server_usage(argv[0], 1); | ||||
|             } | ||||
|             break; | ||||
|   | ||||
| @@ -4,7 +4,10 @@ common-obj-$(CONFIG_ARM_DIS) += arm.o | ||||
| common-obj-$(CONFIG_ARM_A64_DIS) += arm-a64.o | ||||
| common-obj-$(CONFIG_ARM_A64_DIS) += libvixl/ | ||||
| libvixldir = $(SRC_PATH)/disas/libvixl | ||||
| arm-a64.o-cflags := -I$(libvixldir) | ||||
| # The -Wno-sign-compare is needed only for gcc 4.6, which complains about | ||||
| # some signed-unsigned equality comparisons in libvixl which later gcc | ||||
| # versions do not. | ||||
| arm-a64.o-cflags := -I$(libvixldir) -Wno-sign-compare | ||||
| common-obj-$(CONFIG_CRIS_DIS) += cris.o | ||||
| common-obj-$(CONFIG_HPPA_DIS) += hppa.o | ||||
| common-obj-$(CONFIG_I386_DIS) += i386.o | ||||
|   | ||||
| @@ -17,7 +17,7 @@ | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| #include "a64/disasm-a64.h" | ||||
| #include "vixl/a64/disasm-a64.h" | ||||
|  | ||||
| extern "C" { | ||||
| #include "disas/bfd.h" | ||||
|   | ||||
| @@ -1,8 +1,11 @@ | ||||
| libvixl_OBJS = utils.o \ | ||||
|                a64/instructions-a64.o \ | ||||
|                a64/decoder-a64.o \ | ||||
|                a64/disasm-a64.o | ||||
| libvixl_OBJS = vixl/utils.o \ | ||||
|                vixl/compiler-intrinsics.o \ | ||||
|                vixl/a64/instructions-a64.o \ | ||||
|                vixl/a64/decoder-a64.o \ | ||||
|                vixl/a64/disasm-a64.o | ||||
|  | ||||
| $(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CFLAGS := -I$(SRC_PATH)/disas/libvixl $(QEMU_CFLAGS) | ||||
| # The -Wno-sign-compare is needed only for gcc 4.6, which complains about | ||||
| # some signed-unsigned equality comparisons which later gcc versions do not. | ||||
| $(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CFLAGS := -I$(SRC_PATH)/disas/libvixl $(QEMU_CFLAGS) -Wno-sign-compare | ||||
|  | ||||
| common-obj-$(CONFIG_ARM_A64_DIS) += $(libvixl_OBJS) | ||||
|   | ||||
| @@ -2,11 +2,10 @@ | ||||
| The code in this directory is a subset of libvixl: | ||||
|  https://github.com/armvixl/vixl | ||||
| (specifically, it is the set of files needed for disassembly only, | ||||
| taken from libvixl 1.7). | ||||
| taken from libvixl 1.12). | ||||
| Bugfixes should preferably be sent upstream initially. | ||||
|  | ||||
| The disassembler does not currently support the entire A64 instruction | ||||
| set. Notably: | ||||
|  * No Advanced SIMD support. | ||||
|  * Limited support for system instructions. | ||||
|  * A few miscellaneous integer and floating point instructions are missing. | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,314 +0,0 @@ | ||||
| // Copyright 2013, ARM Limited | ||||
| // All rights reserved. | ||||
| // | ||||
| // Redistribution and use in source and binary forms, with or without | ||||
| // modification, are permitted provided that the following conditions are met: | ||||
| // | ||||
| //   * Redistributions of source code must retain the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer. | ||||
| //   * Redistributions in binary form must reproduce the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer in the documentation | ||||
| //     and/or other materials provided with the distribution. | ||||
| //   * Neither the name of ARM Limited nor the names of its contributors may be | ||||
| //     used to endorse or promote products derived from this software without | ||||
| //     specific prior written permission. | ||||
| // | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND | ||||
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | ||||
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
| #include "a64/instructions-a64.h" | ||||
| #include "a64/assembler-a64.h" | ||||
|  | ||||
| namespace vixl { | ||||
|  | ||||
|  | ||||
| // Floating-point infinity values. | ||||
| const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000); | ||||
| const float kFP32NegativeInfinity = rawbits_to_float(0xff800000); | ||||
| const double kFP64PositiveInfinity = | ||||
|     rawbits_to_double(UINT64_C(0x7ff0000000000000)); | ||||
| const double kFP64NegativeInfinity = | ||||
|     rawbits_to_double(UINT64_C(0xfff0000000000000)); | ||||
|  | ||||
|  | ||||
| // The default NaN values (for FPCR.DN=1). | ||||
| const double kFP64DefaultNaN = rawbits_to_double(UINT64_C(0x7ff8000000000000)); | ||||
| const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000); | ||||
|  | ||||
|  | ||||
| static uint64_t RotateRight(uint64_t value, | ||||
|                             unsigned int rotate, | ||||
|                             unsigned int width) { | ||||
|   VIXL_ASSERT(width <= 64); | ||||
|   rotate &= 63; | ||||
|   return ((value & ((UINT64_C(1) << rotate) - 1)) << | ||||
|           (width - rotate)) | (value >> rotate); | ||||
| } | ||||
|  | ||||
|  | ||||
| static uint64_t RepeatBitsAcrossReg(unsigned reg_size, | ||||
|                                     uint64_t value, | ||||
|                                     unsigned width) { | ||||
|   VIXL_ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) || | ||||
|               (width == 32)); | ||||
|   VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); | ||||
|   uint64_t result = value & ((UINT64_C(1) << width) - 1); | ||||
|   for (unsigned i = width; i < reg_size; i *= 2) { | ||||
|     result |= (result << i); | ||||
|   } | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| bool Instruction::IsLoad() const { | ||||
|   if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) { | ||||
|     return Mask(LoadStorePairLBit) != 0; | ||||
|   } else { | ||||
|     LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreOpMask)); | ||||
|     switch (op) { | ||||
|       case LDRB_w: | ||||
|       case LDRH_w: | ||||
|       case LDR_w: | ||||
|       case LDR_x: | ||||
|       case LDRSB_w: | ||||
|       case LDRSB_x: | ||||
|       case LDRSH_w: | ||||
|       case LDRSH_x: | ||||
|       case LDRSW_x: | ||||
|       case LDR_s: | ||||
|       case LDR_d: return true; | ||||
|       default: return false; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| bool Instruction::IsStore() const { | ||||
|   if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) { | ||||
|     return Mask(LoadStorePairLBit) == 0; | ||||
|   } else { | ||||
|     LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreOpMask)); | ||||
|     switch (op) { | ||||
|       case STRB_w: | ||||
|       case STRH_w: | ||||
|       case STR_w: | ||||
|       case STR_x: | ||||
|       case STR_s: | ||||
|       case STR_d: return true; | ||||
|       default: return false; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| // Logical immediates can't encode zero, so a return value of zero is used to | ||||
| // indicate a failure case. Specifically, where the constraints on imm_s are | ||||
| // not met. | ||||
| uint64_t Instruction::ImmLogical() const { | ||||
|   unsigned reg_size = SixtyFourBits() ? kXRegSize : kWRegSize; | ||||
|   int64_t n = BitN(); | ||||
|   int64_t imm_s = ImmSetBits(); | ||||
|   int64_t imm_r = ImmRotate(); | ||||
|  | ||||
|   // An integer is constructed from the n, imm_s and imm_r bits according to | ||||
|   // the following table: | ||||
|   // | ||||
|   //  N   imms    immr    size        S             R | ||||
|   //  1  ssssss  rrrrrr    64    UInt(ssssss)  UInt(rrrrrr) | ||||
|   //  0  0sssss  xrrrrr    32    UInt(sssss)   UInt(rrrrr) | ||||
|   //  0  10ssss  xxrrrr    16    UInt(ssss)    UInt(rrrr) | ||||
|   //  0  110sss  xxxrrr     8    UInt(sss)     UInt(rrr) | ||||
|   //  0  1110ss  xxxxrr     4    UInt(ss)      UInt(rr) | ||||
|   //  0  11110s  xxxxxr     2    UInt(s)       UInt(r) | ||||
|   // (s bits must not be all set) | ||||
|   // | ||||
|   // A pattern is constructed of size bits, where the least significant S+1 | ||||
|   // bits are set. The pattern is rotated right by R, and repeated across a | ||||
|   // 32 or 64-bit value, depending on destination register width. | ||||
|   // | ||||
|  | ||||
|   if (n == 1) { | ||||
|     if (imm_s == 0x3F) { | ||||
|       return 0; | ||||
|     } | ||||
|     uint64_t bits = (UINT64_C(1) << (imm_s + 1)) - 1; | ||||
|     return RotateRight(bits, imm_r, 64); | ||||
|   } else { | ||||
|     if ((imm_s >> 1) == 0x1F) { | ||||
|       return 0; | ||||
|     } | ||||
|     for (int width = 0x20; width >= 0x2; width >>= 1) { | ||||
|       if ((imm_s & width) == 0) { | ||||
|         int mask = width - 1; | ||||
|         if ((imm_s & mask) == mask) { | ||||
|           return 0; | ||||
|         } | ||||
|         uint64_t bits = (UINT64_C(1) << ((imm_s & mask) + 1)) - 1; | ||||
|         return RepeatBitsAcrossReg(reg_size, | ||||
|                                    RotateRight(bits, imm_r & mask, width), | ||||
|                                    width); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   VIXL_UNREACHABLE(); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| float Instruction::ImmFP32() const { | ||||
|   //  ImmFP: abcdefgh (8 bits) | ||||
|   // Single: aBbb.bbbc.defg.h000.0000.0000.0000.0000 (32 bits) | ||||
|   // where B is b ^ 1 | ||||
|   uint32_t bits = ImmFP(); | ||||
|   uint32_t bit7 = (bits >> 7) & 0x1; | ||||
|   uint32_t bit6 = (bits >> 6) & 0x1; | ||||
|   uint32_t bit5_to_0 = bits & 0x3f; | ||||
|   uint32_t result = (bit7 << 31) | ((32 - bit6) << 25) | (bit5_to_0 << 19); | ||||
|  | ||||
|   return rawbits_to_float(result); | ||||
| } | ||||
|  | ||||
|  | ||||
| double Instruction::ImmFP64() const { | ||||
|   //  ImmFP: abcdefgh (8 bits) | ||||
|   // Double: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 | ||||
|   //         0000.0000.0000.0000.0000.0000.0000.0000 (64 bits) | ||||
|   // where B is b ^ 1 | ||||
|   uint32_t bits = ImmFP(); | ||||
|   uint64_t bit7 = (bits >> 7) & 0x1; | ||||
|   uint64_t bit6 = (bits >> 6) & 0x1; | ||||
|   uint64_t bit5_to_0 = bits & 0x3f; | ||||
|   uint64_t result = (bit7 << 63) | ((256 - bit6) << 54) | (bit5_to_0 << 48); | ||||
|  | ||||
|   return rawbits_to_double(result); | ||||
| } | ||||
|  | ||||
|  | ||||
| LSDataSize CalcLSPairDataSize(LoadStorePairOp op) { | ||||
|   switch (op) { | ||||
|     case STP_x: | ||||
|     case LDP_x: | ||||
|     case STP_d: | ||||
|     case LDP_d: return LSDoubleWord; | ||||
|     default: return LSWord; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| const Instruction* Instruction::ImmPCOffsetTarget() const { | ||||
|   const Instruction * base = this; | ||||
|   ptrdiff_t offset; | ||||
|   if (IsPCRelAddressing()) { | ||||
|     // ADR and ADRP. | ||||
|     offset = ImmPCRel(); | ||||
|     if (Mask(PCRelAddressingMask) == ADRP) { | ||||
|       base = AlignDown(base, kPageSize); | ||||
|       offset *= kPageSize; | ||||
|     } else { | ||||
|       VIXL_ASSERT(Mask(PCRelAddressingMask) == ADR); | ||||
|     } | ||||
|   } else { | ||||
|     // All PC-relative branches. | ||||
|     VIXL_ASSERT(BranchType() != UnknownBranchType); | ||||
|     // Relative branch offsets are instruction-size-aligned. | ||||
|     offset = ImmBranch() << kInstructionSizeLog2; | ||||
|   } | ||||
|   return base + offset; | ||||
| } | ||||
|  | ||||
|  | ||||
| inline int Instruction::ImmBranch() const { | ||||
|   switch (BranchType()) { | ||||
|     case CondBranchType: return ImmCondBranch(); | ||||
|     case UncondBranchType: return ImmUncondBranch(); | ||||
|     case CompareBranchType: return ImmCmpBranch(); | ||||
|     case TestBranchType: return ImmTestBranch(); | ||||
|     default: VIXL_UNREACHABLE(); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| void Instruction::SetImmPCOffsetTarget(const Instruction* target) { | ||||
|   if (IsPCRelAddressing()) { | ||||
|     SetPCRelImmTarget(target); | ||||
|   } else { | ||||
|     SetBranchImmTarget(target); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void Instruction::SetPCRelImmTarget(const Instruction* target) { | ||||
|   int32_t imm21; | ||||
|   if ((Mask(PCRelAddressingMask) == ADR)) { | ||||
|     imm21 = target - this; | ||||
|   } else { | ||||
|     VIXL_ASSERT(Mask(PCRelAddressingMask) == ADRP); | ||||
|     uintptr_t this_page = reinterpret_cast<uintptr_t>(this) / kPageSize; | ||||
|     uintptr_t target_page = reinterpret_cast<uintptr_t>(target) / kPageSize; | ||||
|     imm21 = target_page - this_page; | ||||
|   } | ||||
|   Instr imm = Assembler::ImmPCRelAddress(imm21); | ||||
|  | ||||
|   SetInstructionBits(Mask(~ImmPCRel_mask) | imm); | ||||
| } | ||||
|  | ||||
|  | ||||
| void Instruction::SetBranchImmTarget(const Instruction* target) { | ||||
|   VIXL_ASSERT(((target - this) & 3) == 0); | ||||
|   Instr branch_imm = 0; | ||||
|   uint32_t imm_mask = 0; | ||||
|   int offset = (target - this) >> kInstructionSizeLog2; | ||||
|   switch (BranchType()) { | ||||
|     case CondBranchType: { | ||||
|       branch_imm = Assembler::ImmCondBranch(offset); | ||||
|       imm_mask = ImmCondBranch_mask; | ||||
|       break; | ||||
|     } | ||||
|     case UncondBranchType: { | ||||
|       branch_imm = Assembler::ImmUncondBranch(offset); | ||||
|       imm_mask = ImmUncondBranch_mask; | ||||
|       break; | ||||
|     } | ||||
|     case CompareBranchType: { | ||||
|       branch_imm = Assembler::ImmCmpBranch(offset); | ||||
|       imm_mask = ImmCmpBranch_mask; | ||||
|       break; | ||||
|     } | ||||
|     case TestBranchType: { | ||||
|       branch_imm = Assembler::ImmTestBranch(offset); | ||||
|       imm_mask = ImmTestBranch_mask; | ||||
|       break; | ||||
|     } | ||||
|     default: VIXL_UNREACHABLE(); | ||||
|   } | ||||
|   SetInstructionBits(Mask(~imm_mask) | branch_imm); | ||||
| } | ||||
|  | ||||
|  | ||||
| void Instruction::SetImmLLiteral(const Instruction* source) { | ||||
|   VIXL_ASSERT(IsWordAligned(source)); | ||||
|   ptrdiff_t offset = (source - this) >> kLiteralEntrySizeLog2; | ||||
|   Instr imm = Assembler::ImmLLiteral(offset); | ||||
|   Instr mask = ImmLLiteral_mask; | ||||
|  | ||||
|   SetInstructionBits(Mask(~mask) | imm); | ||||
| } | ||||
| }  // namespace vixl | ||||
|  | ||||
| @@ -1,384 +0,0 @@ | ||||
| // Copyright 2013, ARM Limited | ||||
| // All rights reserved. | ||||
| // | ||||
| // Redistribution and use in source and binary forms, with or without | ||||
| // modification, are permitted provided that the following conditions are met: | ||||
| // | ||||
| //   * Redistributions of source code must retain the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer. | ||||
| //   * Redistributions in binary form must reproduce the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer in the documentation | ||||
| //     and/or other materials provided with the distribution. | ||||
| //   * Neither the name of ARM Limited nor the names of its contributors may be | ||||
| //     used to endorse or promote products derived from this software without | ||||
| //     specific prior written permission. | ||||
| // | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND | ||||
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | ||||
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
| #ifndef VIXL_A64_INSTRUCTIONS_A64_H_ | ||||
| #define VIXL_A64_INSTRUCTIONS_A64_H_ | ||||
|  | ||||
| #include "globals.h" | ||||
| #include "utils.h" | ||||
| #include "a64/constants-a64.h" | ||||
|  | ||||
| namespace vixl { | ||||
| // ISA constants. -------------------------------------------------------------- | ||||
|  | ||||
| typedef uint32_t Instr; | ||||
| const unsigned kInstructionSize = 4; | ||||
| const unsigned kInstructionSizeLog2 = 2; | ||||
| const unsigned kLiteralEntrySize = 4; | ||||
| const unsigned kLiteralEntrySizeLog2 = 2; | ||||
| const unsigned kMaxLoadLiteralRange = 1 * MBytes; | ||||
|  | ||||
| // This is the nominal page size (as used by the adrp instruction); the actual | ||||
| // size of the memory pages allocated by the kernel is likely to differ. | ||||
| const unsigned kPageSize = 4 * KBytes; | ||||
| const unsigned kPageSizeLog2 = 12; | ||||
|  | ||||
| const unsigned kWRegSize = 32; | ||||
| const unsigned kWRegSizeLog2 = 5; | ||||
| const unsigned kWRegSizeInBytes = kWRegSize / 8; | ||||
| const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3; | ||||
| const unsigned kXRegSize = 64; | ||||
| const unsigned kXRegSizeLog2 = 6; | ||||
| const unsigned kXRegSizeInBytes = kXRegSize / 8; | ||||
| const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3; | ||||
| const unsigned kSRegSize = 32; | ||||
| const unsigned kSRegSizeLog2 = 5; | ||||
| const unsigned kSRegSizeInBytes = kSRegSize / 8; | ||||
| const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3; | ||||
| const unsigned kDRegSize = 64; | ||||
| const unsigned kDRegSizeLog2 = 6; | ||||
| const unsigned kDRegSizeInBytes = kDRegSize / 8; | ||||
| const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3; | ||||
| const uint64_t kWRegMask = UINT64_C(0xffffffff); | ||||
| const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff); | ||||
| const uint64_t kSRegMask = UINT64_C(0xffffffff); | ||||
| const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff); | ||||
| const uint64_t kSSignMask = UINT64_C(0x80000000); | ||||
| const uint64_t kDSignMask = UINT64_C(0x8000000000000000); | ||||
| const uint64_t kWSignMask = UINT64_C(0x80000000); | ||||
| const uint64_t kXSignMask = UINT64_C(0x8000000000000000); | ||||
| const uint64_t kByteMask = UINT64_C(0xff); | ||||
| const uint64_t kHalfWordMask = UINT64_C(0xffff); | ||||
| const uint64_t kWordMask = UINT64_C(0xffffffff); | ||||
| const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff); | ||||
| const uint64_t kWMaxUInt = UINT64_C(0xffffffff); | ||||
| const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff); | ||||
| const int64_t kXMinInt = INT64_C(0x8000000000000000); | ||||
| const int32_t kWMaxInt = INT32_C(0x7fffffff); | ||||
| const int32_t kWMinInt = INT32_C(0x80000000); | ||||
| const unsigned kLinkRegCode = 30; | ||||
| const unsigned kZeroRegCode = 31; | ||||
| const unsigned kSPRegInternalCode = 63; | ||||
| const unsigned kRegCodeMask = 0x1f; | ||||
|  | ||||
| const unsigned kAddressTagOffset = 56; | ||||
| const unsigned kAddressTagWidth = 8; | ||||
| const uint64_t kAddressTagMask = | ||||
|     ((UINT64_C(1) << kAddressTagWidth) - 1) << kAddressTagOffset; | ||||
| VIXL_STATIC_ASSERT(kAddressTagMask == UINT64_C(0xff00000000000000)); | ||||
|  | ||||
| // AArch64 floating-point specifics. These match IEEE-754. | ||||
| const unsigned kDoubleMantissaBits = 52; | ||||
| const unsigned kDoubleExponentBits = 11; | ||||
| const unsigned kFloatMantissaBits = 23; | ||||
| const unsigned kFloatExponentBits = 8; | ||||
|  | ||||
| // Floating-point infinity values. | ||||
| extern const float kFP32PositiveInfinity; | ||||
| extern const float kFP32NegativeInfinity; | ||||
| extern const double kFP64PositiveInfinity; | ||||
| extern const double kFP64NegativeInfinity; | ||||
|  | ||||
| // The default NaN values (for FPCR.DN=1). | ||||
| extern const double kFP64DefaultNaN; | ||||
| extern const float kFP32DefaultNaN; | ||||
|  | ||||
|  | ||||
| enum LSDataSize { | ||||
|   LSByte        = 0, | ||||
|   LSHalfword    = 1, | ||||
|   LSWord        = 2, | ||||
|   LSDoubleWord  = 3 | ||||
| }; | ||||
|  | ||||
| LSDataSize CalcLSPairDataSize(LoadStorePairOp op); | ||||
|  | ||||
| enum ImmBranchType { | ||||
|   UnknownBranchType = 0, | ||||
|   CondBranchType    = 1, | ||||
|   UncondBranchType  = 2, | ||||
|   CompareBranchType = 3, | ||||
|   TestBranchType    = 4 | ||||
| }; | ||||
|  | ||||
| enum AddrMode { | ||||
|   Offset, | ||||
|   PreIndex, | ||||
|   PostIndex | ||||
| }; | ||||
|  | ||||
| enum FPRounding { | ||||
|   // The first four values are encodable directly by FPCR<RMode>. | ||||
|   FPTieEven = 0x0, | ||||
|   FPPositiveInfinity = 0x1, | ||||
|   FPNegativeInfinity = 0x2, | ||||
|   FPZero = 0x3, | ||||
|  | ||||
|   // The final rounding mode is only available when explicitly specified by the | ||||
|   // instruction (such as with fcvta). It cannot be set in FPCR. | ||||
|   FPTieAway | ||||
| }; | ||||
|  | ||||
| enum Reg31Mode { | ||||
|   Reg31IsStackPointer, | ||||
|   Reg31IsZeroRegister | ||||
| }; | ||||
|  | ||||
| // Instructions. --------------------------------------------------------------- | ||||
|  | ||||
| class Instruction { | ||||
|  public: | ||||
|   Instr InstructionBits() const { | ||||
|     return *(reinterpret_cast<const Instr*>(this)); | ||||
|   } | ||||
|  | ||||
|   void SetInstructionBits(Instr new_instr) { | ||||
|     *(reinterpret_cast<Instr*>(this)) = new_instr; | ||||
|   } | ||||
|  | ||||
|   int Bit(int pos) const { | ||||
|     return (InstructionBits() >> pos) & 1; | ||||
|   } | ||||
|  | ||||
|   uint32_t Bits(int msb, int lsb) const { | ||||
|     return unsigned_bitextract_32(msb, lsb, InstructionBits()); | ||||
|   } | ||||
|  | ||||
|   int32_t SignedBits(int msb, int lsb) const { | ||||
|     int32_t bits = *(reinterpret_cast<const int32_t*>(this)); | ||||
|     return signed_bitextract_32(msb, lsb, bits); | ||||
|   } | ||||
|  | ||||
|   Instr Mask(uint32_t mask) const { | ||||
|     return InstructionBits() & mask; | ||||
|   } | ||||
|  | ||||
|   #define DEFINE_GETTER(Name, HighBit, LowBit, Func)             \ | ||||
|   int64_t Name() const { return Func(HighBit, LowBit); } | ||||
|   INSTRUCTION_FIELDS_LIST(DEFINE_GETTER) | ||||
|   #undef DEFINE_GETTER | ||||
|  | ||||
|   // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST), | ||||
|   // formed from ImmPCRelLo and ImmPCRelHi. | ||||
|   int ImmPCRel() const { | ||||
|     int const offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo()); | ||||
|     int const width = ImmPCRelLo_width + ImmPCRelHi_width; | ||||
|     return signed_bitextract_32(width-1, 0, offset); | ||||
|   } | ||||
|  | ||||
|   uint64_t ImmLogical() const; | ||||
|   float ImmFP32() const; | ||||
|   double ImmFP64() const; | ||||
|  | ||||
|   LSDataSize SizeLSPair() const { | ||||
|     return CalcLSPairDataSize( | ||||
|              static_cast<LoadStorePairOp>(Mask(LoadStorePairMask))); | ||||
|   } | ||||
|  | ||||
|   // Helpers. | ||||
|   bool IsCondBranchImm() const { | ||||
|     return Mask(ConditionalBranchFMask) == ConditionalBranchFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsUncondBranchImm() const { | ||||
|     return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsCompareBranch() const { | ||||
|     return Mask(CompareBranchFMask) == CompareBranchFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsTestBranch() const { | ||||
|     return Mask(TestBranchFMask) == TestBranchFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsPCRelAddressing() const { | ||||
|     return Mask(PCRelAddressingFMask) == PCRelAddressingFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsLogicalImmediate() const { | ||||
|     return Mask(LogicalImmediateFMask) == LogicalImmediateFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsAddSubImmediate() const { | ||||
|     return Mask(AddSubImmediateFMask) == AddSubImmediateFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsAddSubExtended() const { | ||||
|     return Mask(AddSubExtendedFMask) == AddSubExtendedFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsLoadOrStore() const { | ||||
|     return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsLoad() const; | ||||
|   bool IsStore() const; | ||||
|  | ||||
|   bool IsLoadLiteral() const { | ||||
|     // This includes PRFM_lit. | ||||
|     return Mask(LoadLiteralFMask) == LoadLiteralFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsMovn() const { | ||||
|     return (Mask(MoveWideImmediateMask) == MOVN_x) || | ||||
|            (Mask(MoveWideImmediateMask) == MOVN_w); | ||||
|   } | ||||
|  | ||||
|   // Indicate whether Rd can be the stack pointer or the zero register. This | ||||
|   // does not check that the instruction actually has an Rd field. | ||||
|   Reg31Mode RdMode() const { | ||||
|     // The following instructions use sp or wsp as Rd: | ||||
|     //  Add/sub (immediate) when not setting the flags. | ||||
|     //  Add/sub (extended) when not setting the flags. | ||||
|     //  Logical (immediate) when not setting the flags. | ||||
|     // Otherwise, r31 is the zero register. | ||||
|     if (IsAddSubImmediate() || IsAddSubExtended()) { | ||||
|       if (Mask(AddSubSetFlagsBit)) { | ||||
|         return Reg31IsZeroRegister; | ||||
|       } else { | ||||
|         return Reg31IsStackPointer; | ||||
|       } | ||||
|     } | ||||
|     if (IsLogicalImmediate()) { | ||||
|       // Of the logical (immediate) instructions, only ANDS (and its aliases) | ||||
|       // can set the flags. The others can all write into sp. | ||||
|       // Note that some logical operations are not available to | ||||
|       // immediate-operand instructions, so we have to combine two masks here. | ||||
|       if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) { | ||||
|         return Reg31IsZeroRegister; | ||||
|       } else { | ||||
|         return Reg31IsStackPointer; | ||||
|       } | ||||
|     } | ||||
|     return Reg31IsZeroRegister; | ||||
|   } | ||||
|  | ||||
|   // Indicate whether Rn can be the stack pointer or the zero register. This | ||||
|   // does not check that the instruction actually has an Rn field. | ||||
|   Reg31Mode RnMode() const { | ||||
|     // The following instructions use sp or wsp as Rn: | ||||
|     //  All loads and stores. | ||||
|     //  Add/sub (immediate). | ||||
|     //  Add/sub (extended). | ||||
|     // Otherwise, r31 is the zero register. | ||||
|     if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) { | ||||
|       return Reg31IsStackPointer; | ||||
|     } | ||||
|     return Reg31IsZeroRegister; | ||||
|   } | ||||
|  | ||||
|   ImmBranchType BranchType() const { | ||||
|     if (IsCondBranchImm()) { | ||||
|       return CondBranchType; | ||||
|     } else if (IsUncondBranchImm()) { | ||||
|       return UncondBranchType; | ||||
|     } else if (IsCompareBranch()) { | ||||
|       return CompareBranchType; | ||||
|     } else if (IsTestBranch()) { | ||||
|       return TestBranchType; | ||||
|     } else { | ||||
|       return UnknownBranchType; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Find the target of this instruction. 'this' may be a branch or a | ||||
|   // PC-relative addressing instruction. | ||||
|   const Instruction* ImmPCOffsetTarget() const; | ||||
|  | ||||
|   // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or | ||||
|   // a PC-relative addressing instruction. | ||||
|   void SetImmPCOffsetTarget(const Instruction* target); | ||||
|   // Patch a literal load instruction to load from 'source'. | ||||
|   void SetImmLLiteral(const Instruction* source); | ||||
|  | ||||
|   // Calculate the address of a literal referred to by a load-literal | ||||
|   // instruction, and return it as the specified type. | ||||
|   // | ||||
|   // The literal itself is safely mutable only if the backing buffer is safely | ||||
|   // mutable. | ||||
|   template <typename T> | ||||
|   T LiteralAddress() const { | ||||
|     uint64_t base_raw = reinterpret_cast<uintptr_t>(this); | ||||
|     ptrdiff_t offset = ImmLLiteral() << kLiteralEntrySizeLog2; | ||||
|     uint64_t address_raw = base_raw + offset; | ||||
|  | ||||
|     // Cast the address using a C-style cast. A reinterpret_cast would be | ||||
|     // appropriate, but it can't cast one integral type to another. | ||||
|     T address = (T)(address_raw); | ||||
|  | ||||
|     // Assert that the address can be represented by the specified type. | ||||
|     VIXL_ASSERT((uint64_t)(address) == address_raw); | ||||
|  | ||||
|     return address; | ||||
|   } | ||||
|  | ||||
|   uint32_t Literal32() const { | ||||
|     uint32_t literal; | ||||
|     memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal)); | ||||
|     return literal; | ||||
|   } | ||||
|  | ||||
|   uint64_t Literal64() const { | ||||
|     uint64_t literal; | ||||
|     memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal)); | ||||
|     return literal; | ||||
|   } | ||||
|  | ||||
|   float LiteralFP32() const { | ||||
|     return rawbits_to_float(Literal32()); | ||||
|   } | ||||
|  | ||||
|   double LiteralFP64() const { | ||||
|     return rawbits_to_double(Literal64()); | ||||
|   } | ||||
|  | ||||
|   const Instruction* NextInstruction() const { | ||||
|     return this + kInstructionSize; | ||||
|   } | ||||
|  | ||||
|   const Instruction* InstructionAtOffset(int64_t offset) const { | ||||
|     VIXL_ASSERT(IsWordAligned(this + offset)); | ||||
|     return this + offset; | ||||
|   } | ||||
|  | ||||
|   template<typename T> static Instruction* Cast(T src) { | ||||
|     return reinterpret_cast<Instruction*>(src); | ||||
|   } | ||||
|  | ||||
|   template<typename T> static const Instruction* CastConst(T src) { | ||||
|     return reinterpret_cast<const Instruction*>(src); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   int ImmBranch() const; | ||||
|  | ||||
|   void SetPCRelImmTarget(const Instruction* target); | ||||
|   void SetBranchImmTarget(const Instruction* target); | ||||
| }; | ||||
| }  // namespace vixl | ||||
|  | ||||
| #endif  // VIXL_A64_INSTRUCTIONS_A64_H_ | ||||
							
								
								
									
										4624
									
								
								disas/libvixl/vixl/a64/assembler-a64.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4624
									
								
								disas/libvixl/vixl/a64/assembler-a64.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2013, ARM Limited
 | ||||
| // Copyright 2014, ARM Limited
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| @@ -27,8 +27,8 @@ | ||||
| #ifndef VIXL_CPU_A64_H | ||||
| #define VIXL_CPU_A64_H | ||||
| 
 | ||||
| #include "globals.h" | ||||
| #include "instructions-a64.h" | ||||
| #include "vixl/globals.h" | ||||
| #include "vixl/a64/instructions-a64.h" | ||||
| 
 | ||||
| namespace vixl { | ||||
| 
 | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2013, ARM Limited
 | ||||
| // Copyright 2014, ARM Limited
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| @@ -24,9 +24,9 @@ | ||||
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| #include "globals.h" | ||||
| #include "utils.h" | ||||
| #include "a64/decoder-a64.h" | ||||
| #include "vixl/globals.h" | ||||
| #include "vixl/utils.h" | ||||
| #include "vixl/a64/decoder-a64.h" | ||||
| 
 | ||||
| namespace vixl { | ||||
| 
 | ||||
| @@ -271,6 +271,11 @@ void Decoder::DecodeLoadStore(const Instruction* instr) { | ||||
|               (instr->Bits(27, 24) == 0x9) || | ||||
|               (instr->Bits(27, 24) == 0xC) || | ||||
|               (instr->Bits(27, 24) == 0xD) ); | ||||
|   // TODO(all): rearrange the tree to integrate this branch.
 | ||||
|   if ((instr->Bit(28) == 0) && (instr->Bit(29) == 0) && (instr->Bit(26) == 1)) { | ||||
|     DecodeNEONLoadStore(instr); | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if (instr->Bit(24) == 0) { | ||||
|     if (instr->Bit(28) == 0) { | ||||
| @@ -278,7 +283,7 @@ void Decoder::DecodeLoadStore(const Instruction* instr) { | ||||
|         if (instr->Bit(26) == 0) { | ||||
|           VisitLoadStoreExclusive(instr); | ||||
|         } else { | ||||
|           DecodeAdvSIMDLoadStore(instr); | ||||
|           VIXL_UNREACHABLE(); | ||||
|         } | ||||
|       } else { | ||||
|         if ((instr->Bits(31, 30) == 0x3) || | ||||
| @@ -483,6 +488,7 @@ void Decoder::DecodeDataProcessing(const Instruction* instr) { | ||||
|         case 6: { | ||||
|           if (instr->Bit(29) == 0x1) { | ||||
|             VisitUnallocated(instr); | ||||
|             VIXL_FALLTHROUGH(); | ||||
|           } else { | ||||
|             if (instr->Bit(30) == 0) { | ||||
|               if ((instr->Bit(15) == 0x1) || | ||||
| @@ -556,18 +562,15 @@ void Decoder::DecodeDataProcessing(const Instruction* instr) { | ||||
| void Decoder::DecodeFP(const Instruction* instr) { | ||||
|   VIXL_ASSERT((instr->Bits(27, 24) == 0xE) || | ||||
|               (instr->Bits(27, 24) == 0xF)); | ||||
| 
 | ||||
|   if (instr->Bit(28) == 0) { | ||||
|     DecodeAdvSIMDDataProcessing(instr); | ||||
|   } else { | ||||
|     if (instr->Bit(29) == 1) { | ||||
|       VisitUnallocated(instr); | ||||
|     DecodeNEONVectorDataProcessing(instr); | ||||
|   } else { | ||||
|     if (instr->Bits(31, 30) == 0x3) { | ||||
|       VisitUnallocated(instr); | ||||
|     } else if (instr->Bits(31, 30) == 0x1) { | ||||
|         DecodeAdvSIMDDataProcessing(instr); | ||||
|       DecodeNEONScalarDataProcessing(instr); | ||||
|     } else { | ||||
|       if (instr->Bit(29) == 0) { | ||||
|         if (instr->Bit(24) == 0) { | ||||
|           if (instr->Bit(21) == 0) { | ||||
|             if ((instr->Bit(23) == 1) || | ||||
| @@ -674,23 +677,190 @@ void Decoder::DecodeFP(const Instruction* instr) { | ||||
|             VisitFPDataProcessing3Source(instr); | ||||
|           } | ||||
|         } | ||||
|       } else { | ||||
|         VisitUnallocated(instr); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void Decoder::DecodeAdvSIMDLoadStore(const Instruction* instr) { | ||||
|   // TODO: Implement Advanced SIMD load/store instruction decode.
 | ||||
| void Decoder::DecodeNEONLoadStore(const Instruction* instr) { | ||||
|   VIXL_ASSERT(instr->Bits(29, 25) == 0x6); | ||||
|   VisitUnimplemented(instr); | ||||
|   if (instr->Bit(31) == 0) { | ||||
|     if ((instr->Bit(24) == 0) && (instr->Bit(21) == 1)) { | ||||
|       VisitUnallocated(instr); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     if (instr->Bit(23) == 0) { | ||||
|       if (instr->Bits(20, 16) == 0) { | ||||
|         if (instr->Bit(24) == 0) { | ||||
|           VisitNEONLoadStoreMultiStruct(instr); | ||||
|         } else { | ||||
|           VisitNEONLoadStoreSingleStruct(instr); | ||||
|         } | ||||
|       } else { | ||||
|         VisitUnallocated(instr); | ||||
|       } | ||||
|     } else { | ||||
|       if (instr->Bit(24) == 0) { | ||||
|         VisitNEONLoadStoreMultiStructPostIndex(instr); | ||||
|       } else { | ||||
|         VisitNEONLoadStoreSingleStructPostIndex(instr); | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     VisitUnallocated(instr); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void Decoder::DecodeAdvSIMDDataProcessing(const Instruction* instr) { | ||||
|   // TODO: Implement Advanced SIMD data processing instruction decode.
 | ||||
|   VIXL_ASSERT(instr->Bits(27, 25) == 0x7); | ||||
|   VisitUnimplemented(instr); | ||||
| void Decoder::DecodeNEONVectorDataProcessing(const Instruction* instr) { | ||||
|   VIXL_ASSERT(instr->Bits(28, 25) == 0x7); | ||||
|   if (instr->Bit(31) == 0) { | ||||
|     if (instr->Bit(24) == 0) { | ||||
|       if (instr->Bit(21) == 0) { | ||||
|         if (instr->Bit(15) == 0) { | ||||
|           if (instr->Bit(10) == 0) { | ||||
|             if (instr->Bit(29) == 0) { | ||||
|               if (instr->Bit(11) == 0) { | ||||
|                 VisitNEONTable(instr); | ||||
|               } else { | ||||
|                 VisitNEONPerm(instr); | ||||
|               } | ||||
|             } else { | ||||
|               VisitNEONExtract(instr); | ||||
|             } | ||||
|           } else { | ||||
|             if (instr->Bits(23, 22) == 0) { | ||||
|               VisitNEONCopy(instr); | ||||
|             } else { | ||||
|               VisitUnallocated(instr); | ||||
|             } | ||||
|           } | ||||
|         } else { | ||||
|           VisitUnallocated(instr); | ||||
|         } | ||||
|       } else { | ||||
|         if (instr->Bit(10) == 0) { | ||||
|           if (instr->Bit(11) == 0) { | ||||
|             VisitNEON3Different(instr); | ||||
|           } else { | ||||
|             if (instr->Bits(18, 17) == 0) { | ||||
|               if (instr->Bit(20) == 0) { | ||||
|                 if (instr->Bit(19) == 0) { | ||||
|                   VisitNEON2RegMisc(instr); | ||||
|                 } else { | ||||
|                   if (instr->Bits(30, 29) == 0x2) { | ||||
|                     VisitCryptoAES(instr); | ||||
|                   } else { | ||||
|                     VisitUnallocated(instr); | ||||
|                   } | ||||
|                 } | ||||
|               } else { | ||||
|                 if (instr->Bit(19) == 0) { | ||||
|                   VisitNEONAcrossLanes(instr); | ||||
|                 } else { | ||||
|                   VisitUnallocated(instr); | ||||
|                 } | ||||
|               } | ||||
|             } else { | ||||
|               VisitUnallocated(instr); | ||||
|             } | ||||
|           } | ||||
|         } else { | ||||
|           VisitNEON3Same(instr); | ||||
|         } | ||||
|       } | ||||
|     } else { | ||||
|       if (instr->Bit(10) == 0) { | ||||
|         VisitNEONByIndexedElement(instr); | ||||
|       } else { | ||||
|         if (instr->Bit(23) == 0) { | ||||
|           if (instr->Bits(22, 19) == 0) { | ||||
|             VisitNEONModifiedImmediate(instr); | ||||
|           } else { | ||||
|             VisitNEONShiftImmediate(instr); | ||||
|           } | ||||
|         } else { | ||||
|           VisitUnallocated(instr); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     VisitUnallocated(instr); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void Decoder::DecodeNEONScalarDataProcessing(const Instruction* instr) { | ||||
|   VIXL_ASSERT(instr->Bits(28, 25) == 0xF); | ||||
|   if (instr->Bit(24) == 0) { | ||||
|     if (instr->Bit(21) == 0) { | ||||
|       if (instr->Bit(15) == 0) { | ||||
|         if (instr->Bit(10) == 0) { | ||||
|           if (instr->Bit(29) == 0) { | ||||
|             if (instr->Bit(11) == 0) { | ||||
|               VisitCrypto3RegSHA(instr); | ||||
|             } else { | ||||
|               VisitUnallocated(instr); | ||||
|             } | ||||
|           } else { | ||||
|             VisitUnallocated(instr); | ||||
|           } | ||||
|         } else { | ||||
|           if (instr->Bits(23, 22) == 0) { | ||||
|             VisitNEONScalarCopy(instr); | ||||
|           } else { | ||||
|             VisitUnallocated(instr); | ||||
|           } | ||||
|         } | ||||
|       } else { | ||||
|         VisitUnallocated(instr); | ||||
|       } | ||||
|     } else { | ||||
|       if (instr->Bit(10) == 0) { | ||||
|         if (instr->Bit(11) == 0) { | ||||
|           VisitNEONScalar3Diff(instr); | ||||
|         } else { | ||||
|           if (instr->Bits(18, 17) == 0) { | ||||
|             if (instr->Bit(20) == 0) { | ||||
|               if (instr->Bit(19) == 0) { | ||||
|                 VisitNEONScalar2RegMisc(instr); | ||||
|               } else { | ||||
|                 if (instr->Bit(29) == 0) { | ||||
|                   VisitCrypto2RegSHA(instr); | ||||
|                 } else { | ||||
|                   VisitUnallocated(instr); | ||||
|                 } | ||||
|               } | ||||
|             } else { | ||||
|               if (instr->Bit(19) == 0) { | ||||
|                 VisitNEONScalarPairwise(instr); | ||||
|               } else { | ||||
|                 VisitUnallocated(instr); | ||||
|               } | ||||
|             } | ||||
|           } else { | ||||
|             VisitUnallocated(instr); | ||||
|           } | ||||
|         } | ||||
|       } else { | ||||
|         VisitNEONScalar3Same(instr); | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     if (instr->Bit(10) == 0) { | ||||
|       VisitNEONScalarByIndexedElement(instr); | ||||
|     } else { | ||||
|       if (instr->Bit(23) == 0) { | ||||
|         VisitNEONScalarShiftImmediate(instr); | ||||
|       } else { | ||||
|         VisitUnallocated(instr); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2013, ARM Limited
 | ||||
| // Copyright 2014, ARM Limited
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| @@ -29,13 +29,13 @@ | ||||
| 
 | ||||
| #include <list> | ||||
| 
 | ||||
| #include "globals.h" | ||||
| #include "a64/instructions-a64.h" | ||||
| #include "vixl/globals.h" | ||||
| #include "vixl/a64/instructions-a64.h" | ||||
| 
 | ||||
| 
 | ||||
| // List macro containing all visitors needed by the decoder class.
 | ||||
| 
 | ||||
| #define VISITOR_LIST(V)             \ | ||||
| #define VISITOR_LIST_THAT_RETURN(V) \ | ||||
|   V(PCRelAddressing)                \ | ||||
|   V(AddSubImmediate)                \ | ||||
|   V(LogicalImmediate)               \ | ||||
| @@ -79,8 +79,39 @@ | ||||
|   V(FPDataProcessing3Source)        \ | ||||
|   V(FPIntegerConvert)               \ | ||||
|   V(FPFixedPointConvert)            \ | ||||
|   V(Crypto2RegSHA)                  \ | ||||
|   V(Crypto3RegSHA)                  \ | ||||
|   V(CryptoAES)                      \ | ||||
|   V(NEON2RegMisc)                   \ | ||||
|   V(NEON3Different)                 \ | ||||
|   V(NEON3Same)                      \ | ||||
|   V(NEONAcrossLanes)                \ | ||||
|   V(NEONByIndexedElement)           \ | ||||
|   V(NEONCopy)                       \ | ||||
|   V(NEONExtract)                    \ | ||||
|   V(NEONLoadStoreMultiStruct)       \ | ||||
|   V(NEONLoadStoreMultiStructPostIndex)  \ | ||||
|   V(NEONLoadStoreSingleStruct)      \ | ||||
|   V(NEONLoadStoreSingleStructPostIndex) \ | ||||
|   V(NEONModifiedImmediate)          \ | ||||
|   V(NEONScalar2RegMisc)             \ | ||||
|   V(NEONScalar3Diff)                \ | ||||
|   V(NEONScalar3Same)                \ | ||||
|   V(NEONScalarByIndexedElement)     \ | ||||
|   V(NEONScalarCopy)                 \ | ||||
|   V(NEONScalarPairwise)             \ | ||||
|   V(NEONScalarShiftImmediate)       \ | ||||
|   V(NEONShiftImmediate)             \ | ||||
|   V(NEONTable)                      \ | ||||
|   V(NEONPerm)                       \ | ||||
| 
 | ||||
| #define VISITOR_LIST_THAT_DONT_RETURN(V)  \ | ||||
|   V(Unallocated)                          \ | ||||
|   V(Unimplemented) | ||||
|   V(Unimplemented)                        \ | ||||
| 
 | ||||
| #define VISITOR_LIST(V)             \ | ||||
|   VISITOR_LIST_THAT_RETURN(V)       \ | ||||
|   VISITOR_LIST_THAT_DONT_RETURN(V)  \ | ||||
| 
 | ||||
| namespace vixl { | ||||
| 
 | ||||
| @@ -222,12 +253,17 @@ class Decoder { | ||||
|   // Decode the Advanced SIMD (NEON) load/store part of the instruction tree,
 | ||||
|   // and call the corresponding visitors.
 | ||||
|   // On entry, instruction bits 29:25 = 0x6.
 | ||||
|   void DecodeAdvSIMDLoadStore(const Instruction* instr); | ||||
|   void DecodeNEONLoadStore(const Instruction* instr); | ||||
| 
 | ||||
|   // Decode the Advanced SIMD (NEON) data processing part of the instruction
 | ||||
|   // tree, and call the corresponding visitors.
 | ||||
|   // On entry, instruction bits 27:25 = 0x7.
 | ||||
|   void DecodeAdvSIMDDataProcessing(const Instruction* instr); | ||||
|   // Decode the Advanced SIMD (NEON) vector data processing part of the
 | ||||
|   // instruction tree, and call the corresponding visitors.
 | ||||
|   // On entry, instruction bits 28:25 = 0x7.
 | ||||
|   void DecodeNEONVectorDataProcessing(const Instruction* instr); | ||||
| 
 | ||||
|   // Decode the Advanced SIMD (NEON) scalar data processing part of the
 | ||||
|   // instruction tree, and call the corresponding visitors.
 | ||||
|   // On entry, instruction bits 28:25 = 0xF.
 | ||||
|   void DecodeNEONScalarDataProcessing(const Instruction* instr); | ||||
| 
 | ||||
|  private: | ||||
|   // Visitors are registered in a list.
 | ||||
							
								
								
									
										3487
									
								
								disas/libvixl/vixl/a64/disasm-a64.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3487
									
								
								disas/libvixl/vixl/a64/disasm-a64.cc
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2013, ARM Limited
 | ||||
| // Copyright 2015, ARM Limited
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| @@ -27,11 +27,11 @@ | ||||
| #ifndef VIXL_A64_DISASM_A64_H | ||||
| #define VIXL_A64_DISASM_A64_H | ||||
| 
 | ||||
| #include "globals.h" | ||||
| #include "utils.h" | ||||
| #include "instructions-a64.h" | ||||
| #include "decoder-a64.h" | ||||
| #include "assembler-a64.h" | ||||
| #include "vixl/globals.h" | ||||
| #include "vixl/utils.h" | ||||
| #include "vixl/a64/instructions-a64.h" | ||||
| #include "vixl/a64/decoder-a64.h" | ||||
| #include "vixl/a64/assembler-a64.h" | ||||
| 
 | ||||
| namespace vixl { | ||||
| 
 | ||||
| @@ -55,6 +55,7 @@ class Disassembler: public DecoderVisitor { | ||||
|   // customize the disassembly output.
 | ||||
| 
 | ||||
|   // Prints the name of a register.
 | ||||
|   // TODO: This currently doesn't allow renaming of V registers.
 | ||||
|   virtual void AppendRegisterNameToOutput(const Instruction* instr, | ||||
|                                           const CPURegister& reg); | ||||
| 
 | ||||
| @@ -122,7 +123,8 @@ class Disassembler: public DecoderVisitor { | ||||
|   int SubstituteLSRegOffsetField(const Instruction* instr, const char* format); | ||||
|   int SubstitutePrefetchField(const Instruction* instr, const char* format); | ||||
|   int SubstituteBarrierField(const Instruction* instr, const char* format); | ||||
| 
 | ||||
|   int SubstituteSysOpField(const Instruction* instr, const char* format); | ||||
|   int SubstituteCrField(const Instruction* instr, const char* format); | ||||
|   bool RdIsZROrSP(const Instruction* instr) const { | ||||
|     return (instr->Rd() == kZeroRegCode); | ||||
|   } | ||||
| @@ -163,7 +165,6 @@ class Disassembler: public DecoderVisitor { | ||||
| class PrintDisassembler: public Disassembler { | ||||
|  public: | ||||
|   explicit PrintDisassembler(FILE* stream) : stream_(stream) { } | ||||
|   virtual ~PrintDisassembler() { } | ||||
| 
 | ||||
|  protected: | ||||
|   virtual void ProcessOutput(const Instruction* instr); | ||||
							
								
								
									
										622
									
								
								disas/libvixl/vixl/a64/instructions-a64.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										622
									
								
								disas/libvixl/vixl/a64/instructions-a64.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,622 @@ | ||||
| // Copyright 2015, ARM Limited | ||||
| // All rights reserved. | ||||
| // | ||||
| // Redistribution and use in source and binary forms, with or without | ||||
| // modification, are permitted provided that the following conditions are met: | ||||
| // | ||||
| //   * Redistributions of source code must retain the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer. | ||||
| //   * Redistributions in binary form must reproduce the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer in the documentation | ||||
| //     and/or other materials provided with the distribution. | ||||
| //   * Neither the name of ARM Limited nor the names of its contributors may be | ||||
| //     used to endorse or promote products derived from this software without | ||||
| //     specific prior written permission. | ||||
| // | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND | ||||
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | ||||
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
| #include "vixl/a64/instructions-a64.h" | ||||
| #include "vixl/a64/assembler-a64.h" | ||||
|  | ||||
| namespace vixl { | ||||
|  | ||||
|  | ||||
| // Floating-point infinity values. | ||||
| const float16 kFP16PositiveInfinity = 0x7c00; | ||||
| const float16 kFP16NegativeInfinity = 0xfc00; | ||||
| const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000); | ||||
| const float kFP32NegativeInfinity = rawbits_to_float(0xff800000); | ||||
| const double kFP64PositiveInfinity = | ||||
|     rawbits_to_double(UINT64_C(0x7ff0000000000000)); | ||||
| const double kFP64NegativeInfinity = | ||||
|     rawbits_to_double(UINT64_C(0xfff0000000000000)); | ||||
|  | ||||
|  | ||||
| // The default NaN values (for FPCR.DN=1). | ||||
| const double kFP64DefaultNaN = rawbits_to_double(UINT64_C(0x7ff8000000000000)); | ||||
| const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000); | ||||
| const float16 kFP16DefaultNaN = 0x7e00; | ||||
|  | ||||
|  | ||||
| static uint64_t RotateRight(uint64_t value, | ||||
|                             unsigned int rotate, | ||||
|                             unsigned int width) { | ||||
|   VIXL_ASSERT(width <= 64); | ||||
|   rotate &= 63; | ||||
|   return ((value & ((UINT64_C(1) << rotate) - 1)) << | ||||
|           (width - rotate)) | (value >> rotate); | ||||
| } | ||||
|  | ||||
|  | ||||
| static uint64_t RepeatBitsAcrossReg(unsigned reg_size, | ||||
|                                     uint64_t value, | ||||
|                                     unsigned width) { | ||||
|   VIXL_ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) || | ||||
|               (width == 32)); | ||||
|   VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); | ||||
|   uint64_t result = value & ((UINT64_C(1) << width) - 1); | ||||
|   for (unsigned i = width; i < reg_size; i *= 2) { | ||||
|     result |= (result << i); | ||||
|   } | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| bool Instruction::IsLoad() const { | ||||
|   if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) { | ||||
|     return Mask(LoadStorePairLBit) != 0; | ||||
|   } else { | ||||
|     LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreMask)); | ||||
|     switch (op) { | ||||
|       case LDRB_w: | ||||
|       case LDRH_w: | ||||
|       case LDR_w: | ||||
|       case LDR_x: | ||||
|       case LDRSB_w: | ||||
|       case LDRSB_x: | ||||
|       case LDRSH_w: | ||||
|       case LDRSH_x: | ||||
|       case LDRSW_x: | ||||
|       case LDR_b: | ||||
|       case LDR_h: | ||||
|       case LDR_s: | ||||
|       case LDR_d: | ||||
|       case LDR_q: return true; | ||||
|       default: return false; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| bool Instruction::IsStore() const { | ||||
|   if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) { | ||||
|     return Mask(LoadStorePairLBit) == 0; | ||||
|   } else { | ||||
|     LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreMask)); | ||||
|     switch (op) { | ||||
|       case STRB_w: | ||||
|       case STRH_w: | ||||
|       case STR_w: | ||||
|       case STR_x: | ||||
|       case STR_b: | ||||
|       case STR_h: | ||||
|       case STR_s: | ||||
|       case STR_d: | ||||
|       case STR_q: return true; | ||||
|       default: return false; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| // Logical immediates can't encode zero, so a return value of zero is used to | ||||
| // indicate a failure case. Specifically, where the constraints on imm_s are | ||||
| // not met. | ||||
| uint64_t Instruction::ImmLogical() const { | ||||
|   unsigned reg_size = SixtyFourBits() ? kXRegSize : kWRegSize; | ||||
|   int32_t n = BitN(); | ||||
|   int32_t imm_s = ImmSetBits(); | ||||
|   int32_t imm_r = ImmRotate(); | ||||
|  | ||||
|   // An integer is constructed from the n, imm_s and imm_r bits according to | ||||
|   // the following table: | ||||
|   // | ||||
|   //  N   imms    immr    size        S             R | ||||
|   //  1  ssssss  rrrrrr    64    UInt(ssssss)  UInt(rrrrrr) | ||||
|   //  0  0sssss  xrrrrr    32    UInt(sssss)   UInt(rrrrr) | ||||
|   //  0  10ssss  xxrrrr    16    UInt(ssss)    UInt(rrrr) | ||||
|   //  0  110sss  xxxrrr     8    UInt(sss)     UInt(rrr) | ||||
|   //  0  1110ss  xxxxrr     4    UInt(ss)      UInt(rr) | ||||
|   //  0  11110s  xxxxxr     2    UInt(s)       UInt(r) | ||||
|   // (s bits must not be all set) | ||||
|   // | ||||
|   // A pattern is constructed of size bits, where the least significant S+1 | ||||
|   // bits are set. The pattern is rotated right by R, and repeated across a | ||||
|   // 32 or 64-bit value, depending on destination register width. | ||||
|   // | ||||
|  | ||||
|   if (n == 1) { | ||||
|     if (imm_s == 0x3f) { | ||||
|       return 0; | ||||
|     } | ||||
|     uint64_t bits = (UINT64_C(1) << (imm_s + 1)) - 1; | ||||
|     return RotateRight(bits, imm_r, 64); | ||||
|   } else { | ||||
|     if ((imm_s >> 1) == 0x1f) { | ||||
|       return 0; | ||||
|     } | ||||
|     for (int width = 0x20; width >= 0x2; width >>= 1) { | ||||
|       if ((imm_s & width) == 0) { | ||||
|         int mask = width - 1; | ||||
|         if ((imm_s & mask) == mask) { | ||||
|           return 0; | ||||
|         } | ||||
|         uint64_t bits = (UINT64_C(1) << ((imm_s & mask) + 1)) - 1; | ||||
|         return RepeatBitsAcrossReg(reg_size, | ||||
|                                    RotateRight(bits, imm_r & mask, width), | ||||
|                                    width); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   VIXL_UNREACHABLE(); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| uint32_t Instruction::ImmNEONabcdefgh() const { | ||||
|   return ImmNEONabc() << 5 | ImmNEONdefgh(); | ||||
| } | ||||
|  | ||||
|  | ||||
| float Instruction::Imm8ToFP32(uint32_t imm8) { | ||||
|   //   Imm8: abcdefgh (8 bits) | ||||
|   // Single: aBbb.bbbc.defg.h000.0000.0000.0000.0000 (32 bits) | ||||
|   // where B is b ^ 1 | ||||
|   uint32_t bits = imm8; | ||||
|   uint32_t bit7 = (bits >> 7) & 0x1; | ||||
|   uint32_t bit6 = (bits >> 6) & 0x1; | ||||
|   uint32_t bit5_to_0 = bits & 0x3f; | ||||
|   uint32_t result = (bit7 << 31) | ((32 - bit6) << 25) | (bit5_to_0 << 19); | ||||
|  | ||||
|   return rawbits_to_float(result); | ||||
| } | ||||
|  | ||||
|  | ||||
| float Instruction::ImmFP32() const { | ||||
|   return Imm8ToFP32(ImmFP()); | ||||
| } | ||||
|  | ||||
|  | ||||
| double Instruction::Imm8ToFP64(uint32_t imm8) { | ||||
|   //   Imm8: abcdefgh (8 bits) | ||||
|   // Double: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 | ||||
|   //         0000.0000.0000.0000.0000.0000.0000.0000 (64 bits) | ||||
|   // where B is b ^ 1 | ||||
|   uint32_t bits = imm8; | ||||
|   uint64_t bit7 = (bits >> 7) & 0x1; | ||||
|   uint64_t bit6 = (bits >> 6) & 0x1; | ||||
|   uint64_t bit5_to_0 = bits & 0x3f; | ||||
|   uint64_t result = (bit7 << 63) | ((256 - bit6) << 54) | (bit5_to_0 << 48); | ||||
|  | ||||
|   return rawbits_to_double(result); | ||||
| } | ||||
|  | ||||
|  | ||||
| double Instruction::ImmFP64() const { | ||||
|   return Imm8ToFP64(ImmFP()); | ||||
| } | ||||
|  | ||||
|  | ||||
| float Instruction::ImmNEONFP32() const { | ||||
|   return Imm8ToFP32(ImmNEONabcdefgh()); | ||||
| } | ||||
|  | ||||
|  | ||||
| double Instruction::ImmNEONFP64() const { | ||||
|   return Imm8ToFP64(ImmNEONabcdefgh()); | ||||
| } | ||||
|  | ||||
|  | ||||
| unsigned CalcLSDataSize(LoadStoreOp op) { | ||||
|   VIXL_ASSERT((LSSize_offset + LSSize_width) == (kInstructionSize * 8)); | ||||
|   unsigned size = static_cast<Instr>(op) >> LSSize_offset; | ||||
|   if ((op & LSVector_mask) != 0) { | ||||
|     // Vector register memory operations encode the access size in the "size" | ||||
|     // and "opc" fields. | ||||
|     if ((size == 0) && ((op & LSOpc_mask) >> LSOpc_offset) >= 2) { | ||||
|       size = kQRegSizeInBytesLog2; | ||||
|     } | ||||
|   } | ||||
|   return size; | ||||
| } | ||||
|  | ||||
|  | ||||
| unsigned CalcLSPairDataSize(LoadStorePairOp op) { | ||||
|   VIXL_STATIC_ASSERT(kXRegSizeInBytes == kDRegSizeInBytes); | ||||
|   VIXL_STATIC_ASSERT(kWRegSizeInBytes == kSRegSizeInBytes); | ||||
|   switch (op) { | ||||
|     case STP_q: | ||||
|     case LDP_q: return kQRegSizeInBytesLog2; | ||||
|     case STP_x: | ||||
|     case LDP_x: | ||||
|     case STP_d: | ||||
|     case LDP_d: return kXRegSizeInBytesLog2; | ||||
|     default: return kWRegSizeInBytesLog2; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| int Instruction::ImmBranchRangeBitwidth(ImmBranchType branch_type) { | ||||
|   switch (branch_type) { | ||||
|     case UncondBranchType: | ||||
|       return ImmUncondBranch_width; | ||||
|     case CondBranchType: | ||||
|       return ImmCondBranch_width; | ||||
|     case CompareBranchType: | ||||
|       return ImmCmpBranch_width; | ||||
|     case TestBranchType: | ||||
|       return ImmTestBranch_width; | ||||
|     default: | ||||
|       VIXL_UNREACHABLE(); | ||||
|       return 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| int32_t Instruction::ImmBranchForwardRange(ImmBranchType branch_type) { | ||||
|   int32_t encoded_max = 1 << (ImmBranchRangeBitwidth(branch_type) - 1); | ||||
|   return encoded_max * kInstructionSize; | ||||
| } | ||||
|  | ||||
|  | ||||
| bool Instruction::IsValidImmPCOffset(ImmBranchType branch_type, | ||||
|                                      int64_t offset) { | ||||
|   return is_intn(ImmBranchRangeBitwidth(branch_type), offset); | ||||
| } | ||||
|  | ||||
|  | ||||
| const Instruction* Instruction::ImmPCOffsetTarget() const { | ||||
|   const Instruction * base = this; | ||||
|   ptrdiff_t offset; | ||||
|   if (IsPCRelAddressing()) { | ||||
|     // ADR and ADRP. | ||||
|     offset = ImmPCRel(); | ||||
|     if (Mask(PCRelAddressingMask) == ADRP) { | ||||
|       base = AlignDown(base, kPageSize); | ||||
|       offset *= kPageSize; | ||||
|     } else { | ||||
|       VIXL_ASSERT(Mask(PCRelAddressingMask) == ADR); | ||||
|     } | ||||
|   } else { | ||||
|     // All PC-relative branches. | ||||
|     VIXL_ASSERT(BranchType() != UnknownBranchType); | ||||
|     // Relative branch offsets are instruction-size-aligned. | ||||
|     offset = ImmBranch() << kInstructionSizeLog2; | ||||
|   } | ||||
|   return base + offset; | ||||
| } | ||||
|  | ||||
|  | ||||
| int Instruction::ImmBranch() const { | ||||
|   switch (BranchType()) { | ||||
|     case CondBranchType: return ImmCondBranch(); | ||||
|     case UncondBranchType: return ImmUncondBranch(); | ||||
|     case CompareBranchType: return ImmCmpBranch(); | ||||
|     case TestBranchType: return ImmTestBranch(); | ||||
|     default: VIXL_UNREACHABLE(); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| void Instruction::SetImmPCOffsetTarget(const Instruction* target) { | ||||
|   if (IsPCRelAddressing()) { | ||||
|     SetPCRelImmTarget(target); | ||||
|   } else { | ||||
|     SetBranchImmTarget(target); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| void Instruction::SetPCRelImmTarget(const Instruction* target) { | ||||
|   ptrdiff_t imm21; | ||||
|   if ((Mask(PCRelAddressingMask) == ADR)) { | ||||
|     imm21 = target - this; | ||||
|   } else { | ||||
|     VIXL_ASSERT(Mask(PCRelAddressingMask) == ADRP); | ||||
|     uintptr_t this_page = reinterpret_cast<uintptr_t>(this) / kPageSize; | ||||
|     uintptr_t target_page = reinterpret_cast<uintptr_t>(target) / kPageSize; | ||||
|     imm21 = target_page - this_page; | ||||
|   } | ||||
|   Instr imm = Assembler::ImmPCRelAddress(static_cast<int32_t>(imm21)); | ||||
|  | ||||
|   SetInstructionBits(Mask(~ImmPCRel_mask) | imm); | ||||
| } | ||||
|  | ||||
|  | ||||
| void Instruction::SetBranchImmTarget(const Instruction* target) { | ||||
|   VIXL_ASSERT(((target - this) & 3) == 0); | ||||
|   Instr branch_imm = 0; | ||||
|   uint32_t imm_mask = 0; | ||||
|   int offset = static_cast<int>((target - this) >> kInstructionSizeLog2); | ||||
|   switch (BranchType()) { | ||||
|     case CondBranchType: { | ||||
|       branch_imm = Assembler::ImmCondBranch(offset); | ||||
|       imm_mask = ImmCondBranch_mask; | ||||
|       break; | ||||
|     } | ||||
|     case UncondBranchType: { | ||||
|       branch_imm = Assembler::ImmUncondBranch(offset); | ||||
|       imm_mask = ImmUncondBranch_mask; | ||||
|       break; | ||||
|     } | ||||
|     case CompareBranchType: { | ||||
|       branch_imm = Assembler::ImmCmpBranch(offset); | ||||
|       imm_mask = ImmCmpBranch_mask; | ||||
|       break; | ||||
|     } | ||||
|     case TestBranchType: { | ||||
|       branch_imm = Assembler::ImmTestBranch(offset); | ||||
|       imm_mask = ImmTestBranch_mask; | ||||
|       break; | ||||
|     } | ||||
|     default: VIXL_UNREACHABLE(); | ||||
|   } | ||||
|   SetInstructionBits(Mask(~imm_mask) | branch_imm); | ||||
| } | ||||
|  | ||||
|  | ||||
| void Instruction::SetImmLLiteral(const Instruction* source) { | ||||
|   VIXL_ASSERT(IsWordAligned(source)); | ||||
|   ptrdiff_t offset = (source - this) >> kLiteralEntrySizeLog2; | ||||
|   Instr imm = Assembler::ImmLLiteral(static_cast<int>(offset)); | ||||
|   Instr mask = ImmLLiteral_mask; | ||||
|  | ||||
|   SetInstructionBits(Mask(~mask) | imm); | ||||
| } | ||||
|  | ||||
|  | ||||
| VectorFormat VectorFormatHalfWidth(const VectorFormat vform) { | ||||
|   VIXL_ASSERT(vform == kFormat8H || vform == kFormat4S || vform == kFormat2D || | ||||
|               vform == kFormatH || vform == kFormatS || vform == kFormatD); | ||||
|   switch (vform) { | ||||
|     case kFormat8H: return kFormat8B; | ||||
|     case kFormat4S: return kFormat4H; | ||||
|     case kFormat2D: return kFormat2S; | ||||
|     case kFormatH:  return kFormatB; | ||||
|     case kFormatS:  return kFormatH; | ||||
|     case kFormatD:  return kFormatS; | ||||
|     default: VIXL_UNREACHABLE(); return kFormatUndefined; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| VectorFormat VectorFormatDoubleWidth(const VectorFormat vform) { | ||||
|   VIXL_ASSERT(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S || | ||||
|               vform == kFormatB || vform == kFormatH || vform == kFormatS); | ||||
|   switch (vform) { | ||||
|     case kFormat8B: return kFormat8H; | ||||
|     case kFormat4H: return kFormat4S; | ||||
|     case kFormat2S: return kFormat2D; | ||||
|     case kFormatB:  return kFormatH; | ||||
|     case kFormatH:  return kFormatS; | ||||
|     case kFormatS:  return kFormatD; | ||||
|     default: VIXL_UNREACHABLE(); return kFormatUndefined; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| VectorFormat VectorFormatFillQ(const VectorFormat vform) { | ||||
|   switch (vform) { | ||||
|     case kFormatB: | ||||
|     case kFormat8B: | ||||
|     case kFormat16B: return kFormat16B; | ||||
|     case kFormatH: | ||||
|     case kFormat4H: | ||||
|     case kFormat8H:  return kFormat8H; | ||||
|     case kFormatS: | ||||
|     case kFormat2S: | ||||
|     case kFormat4S:  return kFormat4S; | ||||
|     case kFormatD: | ||||
|     case kFormat1D: | ||||
|     case kFormat2D:  return kFormat2D; | ||||
|     default: VIXL_UNREACHABLE(); return kFormatUndefined; | ||||
|   } | ||||
| } | ||||
|  | ||||
| VectorFormat VectorFormatHalfWidthDoubleLanes(const VectorFormat vform) { | ||||
|   switch (vform) { | ||||
|     case kFormat4H: return kFormat8B; | ||||
|     case kFormat8H: return kFormat16B; | ||||
|     case kFormat2S: return kFormat4H; | ||||
|     case kFormat4S: return kFormat8H; | ||||
|     case kFormat1D: return kFormat2S; | ||||
|     case kFormat2D: return kFormat4S; | ||||
|     default: VIXL_UNREACHABLE(); return kFormatUndefined; | ||||
|   } | ||||
| } | ||||
|  | ||||
| VectorFormat VectorFormatDoubleLanes(const VectorFormat vform) { | ||||
|   VIXL_ASSERT(vform == kFormat8B || vform == kFormat4H || vform == kFormat2S); | ||||
|   switch (vform) { | ||||
|     case kFormat8B: return kFormat16B; | ||||
|     case kFormat4H: return kFormat8H; | ||||
|     case kFormat2S: return kFormat4S; | ||||
|     default: VIXL_UNREACHABLE(); return kFormatUndefined; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| VectorFormat VectorFormatHalfLanes(const VectorFormat vform) { | ||||
|   VIXL_ASSERT(vform == kFormat16B || vform == kFormat8H || vform == kFormat4S); | ||||
|   switch (vform) { | ||||
|     case kFormat16B: return kFormat8B; | ||||
|     case kFormat8H: return kFormat4H; | ||||
|     case kFormat4S: return kFormat2S; | ||||
|     default: VIXL_UNREACHABLE(); return kFormatUndefined; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| VectorFormat ScalarFormatFromLaneSize(int laneSize) { | ||||
|   switch (laneSize) { | ||||
|     case 8:  return kFormatB; | ||||
|     case 16: return kFormatH; | ||||
|     case 32: return kFormatS; | ||||
|     case 64: return kFormatD; | ||||
|     default: VIXL_UNREACHABLE(); return kFormatUndefined; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| unsigned RegisterSizeInBitsFromFormat(VectorFormat vform) { | ||||
|   VIXL_ASSERT(vform != kFormatUndefined); | ||||
|   switch (vform) { | ||||
|     case kFormatB: return kBRegSize; | ||||
|     case kFormatH: return kHRegSize; | ||||
|     case kFormatS: return kSRegSize; | ||||
|     case kFormatD: return kDRegSize; | ||||
|     case kFormat8B: | ||||
|     case kFormat4H: | ||||
|     case kFormat2S: | ||||
|     case kFormat1D: return kDRegSize; | ||||
|     default: return kQRegSize; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| unsigned RegisterSizeInBytesFromFormat(VectorFormat vform) { | ||||
|   return RegisterSizeInBitsFromFormat(vform) / 8; | ||||
| } | ||||
|  | ||||
|  | ||||
| unsigned LaneSizeInBitsFromFormat(VectorFormat vform) { | ||||
|   VIXL_ASSERT(vform != kFormatUndefined); | ||||
|   switch (vform) { | ||||
|     case kFormatB: | ||||
|     case kFormat8B: | ||||
|     case kFormat16B: return 8; | ||||
|     case kFormatH: | ||||
|     case kFormat4H: | ||||
|     case kFormat8H: return 16; | ||||
|     case kFormatS: | ||||
|     case kFormat2S: | ||||
|     case kFormat4S: return 32; | ||||
|     case kFormatD: | ||||
|     case kFormat1D: | ||||
|     case kFormat2D: return 64; | ||||
|     default: VIXL_UNREACHABLE(); return 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| int LaneSizeInBytesFromFormat(VectorFormat vform) { | ||||
|   return LaneSizeInBitsFromFormat(vform) / 8; | ||||
| } | ||||
|  | ||||
|  | ||||
| int LaneSizeInBytesLog2FromFormat(VectorFormat vform) { | ||||
|   VIXL_ASSERT(vform != kFormatUndefined); | ||||
|   switch (vform) { | ||||
|     case kFormatB: | ||||
|     case kFormat8B: | ||||
|     case kFormat16B: return 0; | ||||
|     case kFormatH: | ||||
|     case kFormat4H: | ||||
|     case kFormat8H: return 1; | ||||
|     case kFormatS: | ||||
|     case kFormat2S: | ||||
|     case kFormat4S: return 2; | ||||
|     case kFormatD: | ||||
|     case kFormat1D: | ||||
|     case kFormat2D: return 3; | ||||
|     default: VIXL_UNREACHABLE(); return 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| int LaneCountFromFormat(VectorFormat vform) { | ||||
|   VIXL_ASSERT(vform != kFormatUndefined); | ||||
|   switch (vform) { | ||||
|     case kFormat16B: return 16; | ||||
|     case kFormat8B: | ||||
|     case kFormat8H: return 8; | ||||
|     case kFormat4H: | ||||
|     case kFormat4S: return 4; | ||||
|     case kFormat2S: | ||||
|     case kFormat2D: return 2; | ||||
|     case kFormat1D: | ||||
|     case kFormatB: | ||||
|     case kFormatH: | ||||
|     case kFormatS: | ||||
|     case kFormatD: return 1; | ||||
|     default: VIXL_UNREACHABLE(); return 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| int MaxLaneCountFromFormat(VectorFormat vform) { | ||||
|   VIXL_ASSERT(vform != kFormatUndefined); | ||||
|   switch (vform) { | ||||
|     case kFormatB: | ||||
|     case kFormat8B: | ||||
|     case kFormat16B: return 16; | ||||
|     case kFormatH: | ||||
|     case kFormat4H: | ||||
|     case kFormat8H: return 8; | ||||
|     case kFormatS: | ||||
|     case kFormat2S: | ||||
|     case kFormat4S: return 4; | ||||
|     case kFormatD: | ||||
|     case kFormat1D: | ||||
|     case kFormat2D: return 2; | ||||
|     default: VIXL_UNREACHABLE(); return 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| // Does 'vform' indicate a vector format or a scalar format? | ||||
| bool IsVectorFormat(VectorFormat vform) { | ||||
|   VIXL_ASSERT(vform != kFormatUndefined); | ||||
|   switch (vform) { | ||||
|     case kFormatB: | ||||
|     case kFormatH: | ||||
|     case kFormatS: | ||||
|     case kFormatD: return false; | ||||
|     default: return true; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| int64_t MaxIntFromFormat(VectorFormat vform) { | ||||
|   return INT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform)); | ||||
| } | ||||
|  | ||||
|  | ||||
| int64_t MinIntFromFormat(VectorFormat vform) { | ||||
|   return INT64_MIN >> (64 - LaneSizeInBitsFromFormat(vform)); | ||||
| } | ||||
|  | ||||
|  | ||||
| uint64_t MaxUintFromFormat(VectorFormat vform) { | ||||
|   return UINT64_MAX >> (64 - LaneSizeInBitsFromFormat(vform)); | ||||
| } | ||||
| }  // namespace vixl | ||||
|  | ||||
							
								
								
									
										757
									
								
								disas/libvixl/vixl/a64/instructions-a64.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										757
									
								
								disas/libvixl/vixl/a64/instructions-a64.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,757 @@ | ||||
| // Copyright 2015, ARM Limited | ||||
| // All rights reserved. | ||||
| // | ||||
| // Redistribution and use in source and binary forms, with or without | ||||
| // modification, are permitted provided that the following conditions are met: | ||||
| // | ||||
| //   * Redistributions of source code must retain the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer. | ||||
| //   * Redistributions in binary form must reproduce the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer in the documentation | ||||
| //     and/or other materials provided with the distribution. | ||||
| //   * Neither the name of ARM Limited nor the names of its contributors may be | ||||
| //     used to endorse or promote products derived from this software without | ||||
| //     specific prior written permission. | ||||
| // | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND | ||||
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | ||||
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
| #ifndef VIXL_A64_INSTRUCTIONS_A64_H_ | ||||
| #define VIXL_A64_INSTRUCTIONS_A64_H_ | ||||
|  | ||||
| #include "vixl/globals.h" | ||||
| #include "vixl/utils.h" | ||||
| #include "vixl/a64/constants-a64.h" | ||||
|  | ||||
| namespace vixl { | ||||
| // ISA constants. -------------------------------------------------------------- | ||||
|  | ||||
| typedef uint32_t Instr; | ||||
| const unsigned kInstructionSize = 4; | ||||
| const unsigned kInstructionSizeLog2 = 2; | ||||
| const unsigned kLiteralEntrySize = 4; | ||||
| const unsigned kLiteralEntrySizeLog2 = 2; | ||||
| const unsigned kMaxLoadLiteralRange = 1 * MBytes; | ||||
|  | ||||
| // This is the nominal page size (as used by the adrp instruction); the actual | ||||
| // size of the memory pages allocated by the kernel is likely to differ. | ||||
| const unsigned kPageSize = 4 * KBytes; | ||||
| const unsigned kPageSizeLog2 = 12; | ||||
|  | ||||
| const unsigned kBRegSize = 8; | ||||
| const unsigned kBRegSizeLog2 = 3; | ||||
| const unsigned kBRegSizeInBytes = kBRegSize / 8; | ||||
| const unsigned kBRegSizeInBytesLog2 = kBRegSizeLog2 - 3; | ||||
| const unsigned kHRegSize = 16; | ||||
| const unsigned kHRegSizeLog2 = 4; | ||||
| const unsigned kHRegSizeInBytes = kHRegSize / 8; | ||||
| const unsigned kHRegSizeInBytesLog2 = kHRegSizeLog2 - 3; | ||||
| const unsigned kWRegSize = 32; | ||||
| const unsigned kWRegSizeLog2 = 5; | ||||
| const unsigned kWRegSizeInBytes = kWRegSize / 8; | ||||
| const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3; | ||||
| const unsigned kXRegSize = 64; | ||||
| const unsigned kXRegSizeLog2 = 6; | ||||
| const unsigned kXRegSizeInBytes = kXRegSize / 8; | ||||
| const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3; | ||||
| const unsigned kSRegSize = 32; | ||||
| const unsigned kSRegSizeLog2 = 5; | ||||
| const unsigned kSRegSizeInBytes = kSRegSize / 8; | ||||
| const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3; | ||||
| const unsigned kDRegSize = 64; | ||||
| const unsigned kDRegSizeLog2 = 6; | ||||
| const unsigned kDRegSizeInBytes = kDRegSize / 8; | ||||
| const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3; | ||||
| const unsigned kQRegSize = 128; | ||||
| const unsigned kQRegSizeLog2 = 7; | ||||
| const unsigned kQRegSizeInBytes = kQRegSize / 8; | ||||
| const unsigned kQRegSizeInBytesLog2 = kQRegSizeLog2 - 3; | ||||
| const uint64_t kWRegMask = UINT64_C(0xffffffff); | ||||
| const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff); | ||||
| const uint64_t kSRegMask = UINT64_C(0xffffffff); | ||||
| const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff); | ||||
| const uint64_t kSSignMask = UINT64_C(0x80000000); | ||||
| const uint64_t kDSignMask = UINT64_C(0x8000000000000000); | ||||
| const uint64_t kWSignMask = UINT64_C(0x80000000); | ||||
| const uint64_t kXSignMask = UINT64_C(0x8000000000000000); | ||||
| const uint64_t kByteMask = UINT64_C(0xff); | ||||
| const uint64_t kHalfWordMask = UINT64_C(0xffff); | ||||
| const uint64_t kWordMask = UINT64_C(0xffffffff); | ||||
| const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff); | ||||
| const uint64_t kWMaxUInt = UINT64_C(0xffffffff); | ||||
| const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff); | ||||
| const int64_t kXMinInt = INT64_C(0x8000000000000000); | ||||
| const int32_t kWMaxInt = INT32_C(0x7fffffff); | ||||
| const int32_t kWMinInt = INT32_C(0x80000000); | ||||
| const unsigned kLinkRegCode = 30; | ||||
| const unsigned kZeroRegCode = 31; | ||||
| const unsigned kSPRegInternalCode = 63; | ||||
| const unsigned kRegCodeMask = 0x1f; | ||||
|  | ||||
| const unsigned kAddressTagOffset = 56; | ||||
| const unsigned kAddressTagWidth = 8; | ||||
| const uint64_t kAddressTagMask = | ||||
|     ((UINT64_C(1) << kAddressTagWidth) - 1) << kAddressTagOffset; | ||||
| VIXL_STATIC_ASSERT(kAddressTagMask == UINT64_C(0xff00000000000000)); | ||||
|  | ||||
| // AArch64 floating-point specifics. These match IEEE-754. | ||||
| const unsigned kDoubleMantissaBits = 52; | ||||
| const unsigned kDoubleExponentBits = 11; | ||||
| const unsigned kFloatMantissaBits = 23; | ||||
| const unsigned kFloatExponentBits = 8; | ||||
| const unsigned kFloat16MantissaBits = 10; | ||||
| const unsigned kFloat16ExponentBits = 5; | ||||
|  | ||||
| // Floating-point infinity values. | ||||
| extern const float16 kFP16PositiveInfinity; | ||||
| extern const float16 kFP16NegativeInfinity; | ||||
| extern const float kFP32PositiveInfinity; | ||||
| extern const float kFP32NegativeInfinity; | ||||
| extern const double kFP64PositiveInfinity; | ||||
| extern const double kFP64NegativeInfinity; | ||||
|  | ||||
| // The default NaN values (for FPCR.DN=1). | ||||
| extern const float16 kFP16DefaultNaN; | ||||
| extern const float kFP32DefaultNaN; | ||||
| extern const double kFP64DefaultNaN; | ||||
|  | ||||
| unsigned CalcLSDataSize(LoadStoreOp op); | ||||
| unsigned CalcLSPairDataSize(LoadStorePairOp op); | ||||
|  | ||||
| enum ImmBranchType { | ||||
|   UnknownBranchType = 0, | ||||
|   CondBranchType    = 1, | ||||
|   UncondBranchType  = 2, | ||||
|   CompareBranchType = 3, | ||||
|   TestBranchType    = 4 | ||||
| }; | ||||
|  | ||||
| enum AddrMode { | ||||
|   Offset, | ||||
|   PreIndex, | ||||
|   PostIndex | ||||
| }; | ||||
|  | ||||
| enum FPRounding { | ||||
|   // The first four values are encodable directly by FPCR<RMode>. | ||||
|   FPTieEven = 0x0, | ||||
|   FPPositiveInfinity = 0x1, | ||||
|   FPNegativeInfinity = 0x2, | ||||
|   FPZero = 0x3, | ||||
|  | ||||
|   // The final rounding modes are only available when explicitly specified by | ||||
|   // the instruction (such as with fcvta). It cannot be set in FPCR. | ||||
|   FPTieAway, | ||||
|   FPRoundOdd | ||||
| }; | ||||
|  | ||||
| enum Reg31Mode { | ||||
|   Reg31IsStackPointer, | ||||
|   Reg31IsZeroRegister | ||||
| }; | ||||
|  | ||||
| // Instructions. --------------------------------------------------------------- | ||||
|  | ||||
| class Instruction { | ||||
|  public: | ||||
|   Instr InstructionBits() const { | ||||
|     return *(reinterpret_cast<const Instr*>(this)); | ||||
|   } | ||||
|  | ||||
|   void SetInstructionBits(Instr new_instr) { | ||||
|     *(reinterpret_cast<Instr*>(this)) = new_instr; | ||||
|   } | ||||
|  | ||||
|   int Bit(int pos) const { | ||||
|     return (InstructionBits() >> pos) & 1; | ||||
|   } | ||||
|  | ||||
|   uint32_t Bits(int msb, int lsb) const { | ||||
|     return unsigned_bitextract_32(msb, lsb, InstructionBits()); | ||||
|   } | ||||
|  | ||||
|   int32_t SignedBits(int msb, int lsb) const { | ||||
|     int32_t bits = *(reinterpret_cast<const int32_t*>(this)); | ||||
|     return signed_bitextract_32(msb, lsb, bits); | ||||
|   } | ||||
|  | ||||
|   Instr Mask(uint32_t mask) const { | ||||
|     return InstructionBits() & mask; | ||||
|   } | ||||
|  | ||||
|   #define DEFINE_GETTER(Name, HighBit, LowBit, Func)             \ | ||||
|   int32_t Name() const { return Func(HighBit, LowBit); } | ||||
|   INSTRUCTION_FIELDS_LIST(DEFINE_GETTER) | ||||
|   #undef DEFINE_GETTER | ||||
|  | ||||
|   // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST), | ||||
|   // formed from ImmPCRelLo and ImmPCRelHi. | ||||
|   int ImmPCRel() const { | ||||
|     int offset = | ||||
|         static_cast<int>((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo()); | ||||
|     int width = ImmPCRelLo_width + ImmPCRelHi_width; | ||||
|     return signed_bitextract_32(width - 1, 0, offset); | ||||
|   } | ||||
|  | ||||
|   uint64_t ImmLogical() const; | ||||
|   unsigned ImmNEONabcdefgh() const; | ||||
|   float ImmFP32() const; | ||||
|   double ImmFP64() const; | ||||
|   float ImmNEONFP32() const; | ||||
|   double ImmNEONFP64() const; | ||||
|  | ||||
|   unsigned SizeLS() const { | ||||
|     return CalcLSDataSize(static_cast<LoadStoreOp>(Mask(LoadStoreMask))); | ||||
|   } | ||||
|  | ||||
|   unsigned SizeLSPair() const { | ||||
|     return CalcLSPairDataSize( | ||||
|         static_cast<LoadStorePairOp>(Mask(LoadStorePairMask))); | ||||
|   } | ||||
|  | ||||
|   int NEONLSIndex(int access_size_shift) const { | ||||
|     int64_t q = NEONQ(); | ||||
|     int64_t s = NEONS(); | ||||
|     int64_t size = NEONLSSize(); | ||||
|     int64_t index = (q << 3) | (s << 2) | size; | ||||
|     return static_cast<int>(index >> access_size_shift); | ||||
|   } | ||||
|  | ||||
|   // Helpers. | ||||
|   bool IsCondBranchImm() const { | ||||
|     return Mask(ConditionalBranchFMask) == ConditionalBranchFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsUncondBranchImm() const { | ||||
|     return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsCompareBranch() const { | ||||
|     return Mask(CompareBranchFMask) == CompareBranchFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsTestBranch() const { | ||||
|     return Mask(TestBranchFMask) == TestBranchFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsImmBranch() const { | ||||
|     return BranchType() != UnknownBranchType; | ||||
|   } | ||||
|  | ||||
|   bool IsPCRelAddressing() const { | ||||
|     return Mask(PCRelAddressingFMask) == PCRelAddressingFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsLogicalImmediate() const { | ||||
|     return Mask(LogicalImmediateFMask) == LogicalImmediateFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsAddSubImmediate() const { | ||||
|     return Mask(AddSubImmediateFMask) == AddSubImmediateFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsAddSubExtended() const { | ||||
|     return Mask(AddSubExtendedFMask) == AddSubExtendedFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsLoadOrStore() const { | ||||
|     return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsLoad() const; | ||||
|   bool IsStore() const; | ||||
|  | ||||
|   bool IsLoadLiteral() const { | ||||
|     // This includes PRFM_lit. | ||||
|     return Mask(LoadLiteralFMask) == LoadLiteralFixed; | ||||
|   } | ||||
|  | ||||
|   bool IsMovn() const { | ||||
|     return (Mask(MoveWideImmediateMask) == MOVN_x) || | ||||
|            (Mask(MoveWideImmediateMask) == MOVN_w); | ||||
|   } | ||||
|  | ||||
|   static int ImmBranchRangeBitwidth(ImmBranchType branch_type); | ||||
|   static int32_t ImmBranchForwardRange(ImmBranchType branch_type); | ||||
|   static bool IsValidImmPCOffset(ImmBranchType branch_type, int64_t offset); | ||||
|  | ||||
|   // Indicate whether Rd can be the stack pointer or the zero register. This | ||||
|   // does not check that the instruction actually has an Rd field. | ||||
|   Reg31Mode RdMode() const { | ||||
|     // The following instructions use sp or wsp as Rd: | ||||
|     //  Add/sub (immediate) when not setting the flags. | ||||
|     //  Add/sub (extended) when not setting the flags. | ||||
|     //  Logical (immediate) when not setting the flags. | ||||
|     // Otherwise, r31 is the zero register. | ||||
|     if (IsAddSubImmediate() || IsAddSubExtended()) { | ||||
|       if (Mask(AddSubSetFlagsBit)) { | ||||
|         return Reg31IsZeroRegister; | ||||
|       } else { | ||||
|         return Reg31IsStackPointer; | ||||
|       } | ||||
|     } | ||||
|     if (IsLogicalImmediate()) { | ||||
|       // Of the logical (immediate) instructions, only ANDS (and its aliases) | ||||
|       // can set the flags. The others can all write into sp. | ||||
|       // Note that some logical operations are not available to | ||||
|       // immediate-operand instructions, so we have to combine two masks here. | ||||
|       if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) { | ||||
|         return Reg31IsZeroRegister; | ||||
|       } else { | ||||
|         return Reg31IsStackPointer; | ||||
|       } | ||||
|     } | ||||
|     return Reg31IsZeroRegister; | ||||
|   } | ||||
|  | ||||
|   // Indicate whether Rn can be the stack pointer or the zero register. This | ||||
|   // does not check that the instruction actually has an Rn field. | ||||
|   Reg31Mode RnMode() const { | ||||
|     // The following instructions use sp or wsp as Rn: | ||||
|     //  All loads and stores. | ||||
|     //  Add/sub (immediate). | ||||
|     //  Add/sub (extended). | ||||
|     // Otherwise, r31 is the zero register. | ||||
|     if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) { | ||||
|       return Reg31IsStackPointer; | ||||
|     } | ||||
|     return Reg31IsZeroRegister; | ||||
|   } | ||||
|  | ||||
|   ImmBranchType BranchType() const { | ||||
|     if (IsCondBranchImm()) { | ||||
|       return CondBranchType; | ||||
|     } else if (IsUncondBranchImm()) { | ||||
|       return UncondBranchType; | ||||
|     } else if (IsCompareBranch()) { | ||||
|       return CompareBranchType; | ||||
|     } else if (IsTestBranch()) { | ||||
|       return TestBranchType; | ||||
|     } else { | ||||
|       return UnknownBranchType; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Find the target of this instruction. 'this' may be a branch or a | ||||
|   // PC-relative addressing instruction. | ||||
|   const Instruction* ImmPCOffsetTarget() const; | ||||
|  | ||||
|   // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or | ||||
|   // a PC-relative addressing instruction. | ||||
|   void SetImmPCOffsetTarget(const Instruction* target); | ||||
|   // Patch a literal load instruction to load from 'source'. | ||||
|   void SetImmLLiteral(const Instruction* source); | ||||
|  | ||||
|   // The range of a load literal instruction, expressed as 'instr +- range'. | ||||
|   // The range is actually the 'positive' range; the branch instruction can | ||||
|   // target [instr - range - kInstructionSize, instr + range]. | ||||
|   static const int kLoadLiteralImmBitwidth = 19; | ||||
|   static const int kLoadLiteralRange = | ||||
|       (1 << kLoadLiteralImmBitwidth) / 2 - kInstructionSize; | ||||
|  | ||||
|   // Calculate the address of a literal referred to by a load-literal | ||||
|   // instruction, and return it as the specified type. | ||||
|   // | ||||
|   // The literal itself is safely mutable only if the backing buffer is safely | ||||
|   // mutable. | ||||
|   template <typename T> | ||||
|   T LiteralAddress() const { | ||||
|     uint64_t base_raw = reinterpret_cast<uint64_t>(this); | ||||
|     int64_t offset = ImmLLiteral() << kLiteralEntrySizeLog2; | ||||
|     uint64_t address_raw = base_raw + offset; | ||||
|  | ||||
|     // Cast the address using a C-style cast. A reinterpret_cast would be | ||||
|     // appropriate, but it can't cast one integral type to another. | ||||
|     T address = (T)(address_raw); | ||||
|  | ||||
|     // Assert that the address can be represented by the specified type. | ||||
|     VIXL_ASSERT((uint64_t)(address) == address_raw); | ||||
|  | ||||
|     return address; | ||||
|   } | ||||
|  | ||||
|   uint32_t Literal32() const { | ||||
|     uint32_t literal; | ||||
|     memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal)); | ||||
|     return literal; | ||||
|   } | ||||
|  | ||||
|   uint64_t Literal64() const { | ||||
|     uint64_t literal; | ||||
|     memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal)); | ||||
|     return literal; | ||||
|   } | ||||
|  | ||||
|   float LiteralFP32() const { | ||||
|     return rawbits_to_float(Literal32()); | ||||
|   } | ||||
|  | ||||
|   double LiteralFP64() const { | ||||
|     return rawbits_to_double(Literal64()); | ||||
|   } | ||||
|  | ||||
|   const Instruction* NextInstruction() const { | ||||
|     return this + kInstructionSize; | ||||
|   } | ||||
|  | ||||
|   const Instruction* InstructionAtOffset(int64_t offset) const { | ||||
|     VIXL_ASSERT(IsWordAligned(this + offset)); | ||||
|     return this + offset; | ||||
|   } | ||||
|  | ||||
|   template<typename T> static Instruction* Cast(T src) { | ||||
|     return reinterpret_cast<Instruction*>(src); | ||||
|   } | ||||
|  | ||||
|   template<typename T> static const Instruction* CastConst(T src) { | ||||
|     return reinterpret_cast<const Instruction*>(src); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   int ImmBranch() const; | ||||
|  | ||||
|   static float Imm8ToFP32(uint32_t imm8); | ||||
|   static double Imm8ToFP64(uint32_t imm8); | ||||
|  | ||||
|   void SetPCRelImmTarget(const Instruction* target); | ||||
|   void SetBranchImmTarget(const Instruction* target); | ||||
| }; | ||||
|  | ||||
|  | ||||
| // Functions for handling NEON vector format information. | ||||
| enum VectorFormat { | ||||
|   kFormatUndefined = 0xffffffff, | ||||
|   kFormat8B  = NEON_8B, | ||||
|   kFormat16B = NEON_16B, | ||||
|   kFormat4H  = NEON_4H, | ||||
|   kFormat8H  = NEON_8H, | ||||
|   kFormat2S  = NEON_2S, | ||||
|   kFormat4S  = NEON_4S, | ||||
|   kFormat1D  = NEON_1D, | ||||
|   kFormat2D  = NEON_2D, | ||||
|  | ||||
|   // Scalar formats. We add the scalar bit to distinguish between scalar and | ||||
|   // vector enumerations; the bit is always set in the encoding of scalar ops | ||||
|   // and always clear for vector ops. Although kFormatD and kFormat1D appear | ||||
|   // to be the same, their meaning is subtly different. The first is a scalar | ||||
|   // operation, the second a vector operation that only affects one lane. | ||||
|   kFormatB = NEON_B | NEONScalar, | ||||
|   kFormatH = NEON_H | NEONScalar, | ||||
|   kFormatS = NEON_S | NEONScalar, | ||||
|   kFormatD = NEON_D | NEONScalar | ||||
| }; | ||||
|  | ||||
| VectorFormat VectorFormatHalfWidth(const VectorFormat vform); | ||||
| VectorFormat VectorFormatDoubleWidth(const VectorFormat vform); | ||||
| VectorFormat VectorFormatDoubleLanes(const VectorFormat vform); | ||||
| VectorFormat VectorFormatHalfLanes(const VectorFormat vform); | ||||
| VectorFormat ScalarFormatFromLaneSize(int lanesize); | ||||
| VectorFormat VectorFormatHalfWidthDoubleLanes(const VectorFormat vform); | ||||
| VectorFormat VectorFormatFillQ(const VectorFormat vform); | ||||
| unsigned RegisterSizeInBitsFromFormat(VectorFormat vform); | ||||
| unsigned RegisterSizeInBytesFromFormat(VectorFormat vform); | ||||
| // TODO: Make the return types of these functions consistent. | ||||
| unsigned LaneSizeInBitsFromFormat(VectorFormat vform); | ||||
| int LaneSizeInBytesFromFormat(VectorFormat vform); | ||||
| int LaneSizeInBytesLog2FromFormat(VectorFormat vform); | ||||
| int LaneCountFromFormat(VectorFormat vform); | ||||
| int MaxLaneCountFromFormat(VectorFormat vform); | ||||
| bool IsVectorFormat(VectorFormat vform); | ||||
| int64_t MaxIntFromFormat(VectorFormat vform); | ||||
| int64_t MinIntFromFormat(VectorFormat vform); | ||||
| uint64_t MaxUintFromFormat(VectorFormat vform); | ||||
|  | ||||
|  | ||||
| enum NEONFormat { | ||||
|   NF_UNDEF = 0, | ||||
|   NF_8B    = 1, | ||||
|   NF_16B   = 2, | ||||
|   NF_4H    = 3, | ||||
|   NF_8H    = 4, | ||||
|   NF_2S    = 5, | ||||
|   NF_4S    = 6, | ||||
|   NF_1D    = 7, | ||||
|   NF_2D    = 8, | ||||
|   NF_B     = 9, | ||||
|   NF_H     = 10, | ||||
|   NF_S     = 11, | ||||
|   NF_D     = 12 | ||||
| }; | ||||
|  | ||||
| static const unsigned kNEONFormatMaxBits = 6; | ||||
|  | ||||
| struct NEONFormatMap { | ||||
|   // The bit positions in the instruction to consider. | ||||
|   uint8_t bits[kNEONFormatMaxBits]; | ||||
|  | ||||
|   // Mapping from concatenated bits to format. | ||||
|   NEONFormat map[1 << kNEONFormatMaxBits]; | ||||
| }; | ||||
|  | ||||
| class NEONFormatDecoder { | ||||
|  public: | ||||
|   enum SubstitutionMode { | ||||
|     kPlaceholder, | ||||
|     kFormat | ||||
|   }; | ||||
|  | ||||
|   // Construct a format decoder with increasingly specific format maps for each | ||||
|   // subsitution. If no format map is specified, the default is the integer | ||||
|   // format map. | ||||
|   explicit NEONFormatDecoder(const Instruction* instr) { | ||||
|     instrbits_ = instr->InstructionBits(); | ||||
|     SetFormatMaps(IntegerFormatMap()); | ||||
|   } | ||||
|   NEONFormatDecoder(const Instruction* instr, | ||||
|                     const NEONFormatMap* format) { | ||||
|     instrbits_ = instr->InstructionBits(); | ||||
|     SetFormatMaps(format); | ||||
|   } | ||||
|   NEONFormatDecoder(const Instruction* instr, | ||||
|                     const NEONFormatMap* format0, | ||||
|                     const NEONFormatMap* format1) { | ||||
|     instrbits_ = instr->InstructionBits(); | ||||
|     SetFormatMaps(format0, format1); | ||||
|   } | ||||
|   NEONFormatDecoder(const Instruction* instr, | ||||
|                     const NEONFormatMap* format0, | ||||
|                     const NEONFormatMap* format1, | ||||
|                     const NEONFormatMap* format2) { | ||||
|     instrbits_ = instr->InstructionBits(); | ||||
|     SetFormatMaps(format0, format1, format2); | ||||
|   } | ||||
|  | ||||
|   // Set the format mapping for all or individual substitutions. | ||||
|   void SetFormatMaps(const NEONFormatMap* format0, | ||||
|                      const NEONFormatMap* format1 = NULL, | ||||
|                      const NEONFormatMap* format2 = NULL) { | ||||
|     VIXL_ASSERT(format0 != NULL); | ||||
|     formats_[0] = format0; | ||||
|     formats_[1] = (format1 == NULL) ? formats_[0] : format1; | ||||
|     formats_[2] = (format2 == NULL) ? formats_[1] : format2; | ||||
|   } | ||||
|   void SetFormatMap(unsigned index, const NEONFormatMap* format) { | ||||
|     VIXL_ASSERT(index <= (sizeof(formats_) / sizeof(formats_[0]))); | ||||
|     VIXL_ASSERT(format != NULL); | ||||
|     formats_[index] = format; | ||||
|   } | ||||
|  | ||||
|   // Substitute %s in the input string with the placeholder string for each | ||||
|   // register, ie. "'B", "'H", etc. | ||||
|   const char* SubstitutePlaceholders(const char* string) { | ||||
|     return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder); | ||||
|   } | ||||
|  | ||||
|   // Substitute %s in the input string with a new string based on the | ||||
|   // substitution mode. | ||||
|   const char* Substitute(const char* string, | ||||
|                          SubstitutionMode mode0 = kFormat, | ||||
|                          SubstitutionMode mode1 = kFormat, | ||||
|                          SubstitutionMode mode2 = kFormat) { | ||||
|     snprintf(form_buffer_, sizeof(form_buffer_), string, | ||||
|              GetSubstitute(0, mode0), | ||||
|              GetSubstitute(1, mode1), | ||||
|              GetSubstitute(2, mode2)); | ||||
|     return form_buffer_; | ||||
|   } | ||||
|  | ||||
|   // Append a "2" to a mnemonic string based of the state of the Q bit. | ||||
|   const char* Mnemonic(const char* mnemonic) { | ||||
|     if ((instrbits_ & NEON_Q) != 0) { | ||||
|       snprintf(mne_buffer_, sizeof(mne_buffer_), "%s2", mnemonic); | ||||
|       return mne_buffer_; | ||||
|     } | ||||
|     return mnemonic; | ||||
|   } | ||||
|  | ||||
|   VectorFormat GetVectorFormat(int format_index = 0) { | ||||
|     return GetVectorFormat(formats_[format_index]); | ||||
|   } | ||||
|  | ||||
|   VectorFormat GetVectorFormat(const NEONFormatMap* format_map) { | ||||
|     static const VectorFormat vform[] = { | ||||
|       kFormatUndefined, | ||||
|       kFormat8B, kFormat16B, kFormat4H, kFormat8H, | ||||
|       kFormat2S, kFormat4S, kFormat1D, kFormat2D, | ||||
|       kFormatB, kFormatH, kFormatS, kFormatD | ||||
|     }; | ||||
|     VIXL_ASSERT(GetNEONFormat(format_map) < (sizeof(vform) / sizeof(vform[0]))); | ||||
|     return vform[GetNEONFormat(format_map)]; | ||||
|   } | ||||
|  | ||||
|   // Built in mappings for common cases. | ||||
|  | ||||
|   // The integer format map uses three bits (Q, size<1:0>) to encode the | ||||
|   // "standard" set of NEON integer vector formats. | ||||
|   static const NEONFormatMap* IntegerFormatMap() { | ||||
|     static const NEONFormatMap map = { | ||||
|       {23, 22, 30}, | ||||
|       {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_2D} | ||||
|     }; | ||||
|     return ↦ | ||||
|   } | ||||
|  | ||||
|   // The long integer format map uses two bits (size<1:0>) to encode the | ||||
|   // long set of NEON integer vector formats. These are used in narrow, wide | ||||
|   // and long operations. | ||||
|   static const NEONFormatMap* LongIntegerFormatMap() { | ||||
|     static const NEONFormatMap map = { | ||||
|       {23, 22}, {NF_8H, NF_4S, NF_2D} | ||||
|     }; | ||||
|     return ↦ | ||||
|   } | ||||
|  | ||||
|   // The FP format map uses two bits (Q, size<0>) to encode the NEON FP vector | ||||
|   // formats: NF_2S, NF_4S, NF_2D. | ||||
|   static const NEONFormatMap* FPFormatMap() { | ||||
|     // The FP format map assumes two bits (Q, size<0>) are used to encode the | ||||
|     // NEON FP vector formats: NF_2S, NF_4S, NF_2D. | ||||
|     static const NEONFormatMap map = { | ||||
|       {22, 30}, {NF_2S, NF_4S, NF_UNDEF, NF_2D} | ||||
|     }; | ||||
|     return ↦ | ||||
|   } | ||||
|  | ||||
|   // The load/store format map uses three bits (Q, 11, 10) to encode the | ||||
|   // set of NEON vector formats. | ||||
|   static const NEONFormatMap* LoadStoreFormatMap() { | ||||
|     static const NEONFormatMap map = { | ||||
|       {11, 10, 30}, | ||||
|       {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D} | ||||
|     }; | ||||
|     return ↦ | ||||
|   } | ||||
|  | ||||
|   // The logical format map uses one bit (Q) to encode the NEON vector format: | ||||
|   // NF_8B, NF_16B. | ||||
|   static const NEONFormatMap* LogicalFormatMap() { | ||||
|     static const NEONFormatMap map = { | ||||
|       {30}, {NF_8B, NF_16B} | ||||
|     }; | ||||
|     return ↦ | ||||
|   } | ||||
|  | ||||
|   // The triangular format map uses between two and five bits to encode the NEON | ||||
|   // vector format: | ||||
|   // xxx10->8B, xxx11->16B, xx100->4H, xx101->8H | ||||
|   // x1000->2S, x1001->4S,  10001->2D, all others undefined. | ||||
|   static const NEONFormatMap* TriangularFormatMap() { | ||||
|     static const NEONFormatMap map = { | ||||
|       {19, 18, 17, 16, 30}, | ||||
|       {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_2S, | ||||
|        NF_4S, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_UNDEF, NF_2D, | ||||
|        NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_2S, NF_4S, NF_8B, NF_16B, | ||||
|        NF_4H, NF_8H, NF_8B, NF_16B} | ||||
|     }; | ||||
|     return ↦ | ||||
|   } | ||||
|  | ||||
|   // The scalar format map uses two bits (size<1:0>) to encode the NEON scalar | ||||
|   // formats: NF_B, NF_H, NF_S, NF_D. | ||||
|   static const NEONFormatMap* ScalarFormatMap() { | ||||
|     static const NEONFormatMap map = { | ||||
|       {23, 22}, {NF_B, NF_H, NF_S, NF_D} | ||||
|     }; | ||||
|     return ↦ | ||||
|   } | ||||
|  | ||||
|   // The long scalar format map uses two bits (size<1:0>) to encode the longer | ||||
|   // NEON scalar formats: NF_H, NF_S, NF_D. | ||||
|   static const NEONFormatMap* LongScalarFormatMap() { | ||||
|     static const NEONFormatMap map = { | ||||
|       {23, 22}, {NF_H, NF_S, NF_D} | ||||
|     }; | ||||
|     return ↦ | ||||
|   } | ||||
|  | ||||
|   // The FP scalar format map assumes one bit (size<0>) is used to encode the | ||||
|   // NEON FP scalar formats: NF_S, NF_D. | ||||
|   static const NEONFormatMap* FPScalarFormatMap() { | ||||
|     static const NEONFormatMap map = { | ||||
|       {22}, {NF_S, NF_D} | ||||
|     }; | ||||
|     return ↦ | ||||
|   } | ||||
|  | ||||
|   // The triangular scalar format map uses between one and four bits to encode | ||||
|   // the NEON FP scalar formats: | ||||
|   // xxx1->B, xx10->H, x100->S, 1000->D, all others undefined. | ||||
|   static const NEONFormatMap* TriangularScalarFormatMap() { | ||||
|     static const NEONFormatMap map = { | ||||
|       {19, 18, 17, 16}, | ||||
|       {NF_UNDEF, NF_B, NF_H, NF_B, NF_S, NF_B, NF_H, NF_B, | ||||
|        NF_D,     NF_B, NF_H, NF_B, NF_S, NF_B, NF_H, NF_B} | ||||
|     }; | ||||
|     return ↦ | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   // Get a pointer to a string that represents the format or placeholder for | ||||
|   // the specified substitution index, based on the format map and instruction. | ||||
|   const char* GetSubstitute(int index, SubstitutionMode mode) { | ||||
|     if (mode == kFormat) { | ||||
|       return NEONFormatAsString(GetNEONFormat(formats_[index])); | ||||
|     } | ||||
|     VIXL_ASSERT(mode == kPlaceholder); | ||||
|     return NEONFormatAsPlaceholder(GetNEONFormat(formats_[index])); | ||||
|   } | ||||
|  | ||||
|   // Get the NEONFormat enumerated value for bits obtained from the | ||||
|   // instruction based on the specified format mapping. | ||||
|   NEONFormat GetNEONFormat(const NEONFormatMap* format_map) { | ||||
|     return format_map->map[PickBits(format_map->bits)]; | ||||
|   } | ||||
|  | ||||
|   // Convert a NEONFormat into a string. | ||||
|   static const char* NEONFormatAsString(NEONFormat format) { | ||||
|     static const char* formats[] = { | ||||
|       "undefined", | ||||
|       "8b", "16b", "4h", "8h", "2s", "4s", "1d", "2d", | ||||
|       "b", "h", "s", "d" | ||||
|     }; | ||||
|     VIXL_ASSERT(format < (sizeof(formats) / sizeof(formats[0]))); | ||||
|     return formats[format]; | ||||
|   } | ||||
|  | ||||
|   // Convert a NEONFormat into a register placeholder string. | ||||
|   static const char* NEONFormatAsPlaceholder(NEONFormat format) { | ||||
|     VIXL_ASSERT((format == NF_B) || (format == NF_H) || | ||||
|                 (format == NF_S) || (format == NF_D) || | ||||
|                 (format == NF_UNDEF)); | ||||
|     static const char* formats[] = { | ||||
|       "undefined", | ||||
|       "undefined", "undefined", "undefined", "undefined", | ||||
|       "undefined", "undefined", "undefined", "undefined", | ||||
|       "'B", "'H", "'S", "'D" | ||||
|     }; | ||||
|     return formats[format]; | ||||
|   } | ||||
|  | ||||
|   // Select bits from instrbits_ defined by the bits array, concatenate them, | ||||
|   // and return the value. | ||||
|   uint8_t PickBits(const uint8_t bits[]) { | ||||
|     uint8_t result = 0; | ||||
|     for (unsigned b = 0; b < kNEONFormatMaxBits; b++) { | ||||
|       if (bits[b] == 0) break; | ||||
|       result <<= 1; | ||||
|       result |= ((instrbits_ & (1 << bits[b])) == 0) ? 0 : 1; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   Instr instrbits_; | ||||
|   const NEONFormatMap* formats_[3]; | ||||
|   char form_buffer_[64]; | ||||
|   char mne_buffer_[16]; | ||||
| }; | ||||
| }  // namespace vixl | ||||
|  | ||||
| #endif  // VIXL_A64_INSTRUCTIONS_A64_H_ | ||||
| @@ -28,7 +28,7 @@ | ||||
| #define VIXL_CODE_BUFFER_H | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include "globals.h" | ||||
| #include "vixl/globals.h" | ||||
| 
 | ||||
| namespace vixl { | ||||
| 
 | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2013, ARM Limited
 | ||||
| // Copyright 2015, ARM Limited
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| @@ -24,53 +24,13 @@ | ||||
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| #include "utils.h" | ||||
| #include <stdio.h> | ||||
| #include "compiler-intrinsics.h" | ||||
| 
 | ||||
| namespace vixl { | ||||
| 
 | ||||
| uint32_t float_to_rawbits(float value) { | ||||
|   uint32_t bits = 0; | ||||
|   memcpy(&bits, &value, 4); | ||||
|   return bits; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| uint64_t double_to_rawbits(double value) { | ||||
|   uint64_t bits = 0; | ||||
|   memcpy(&bits, &value, 8); | ||||
|   return bits; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| float rawbits_to_float(uint32_t bits) { | ||||
|   float value = 0.0; | ||||
|   memcpy(&value, &bits, 4); | ||||
|   return value; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| double rawbits_to_double(uint64_t bits) { | ||||
|   double value = 0.0; | ||||
|   memcpy(&value, &bits, 8); | ||||
|   return value; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int CountLeadingZeros(uint64_t value, int width) { | ||||
|   VIXL_ASSERT((width == 32) || (width == 64)); | ||||
|   int count = 0; | ||||
|   uint64_t bit_test = UINT64_C(1) << (width - 1); | ||||
|   while ((count < width) && ((bit_test & value) == 0)) { | ||||
|     count++; | ||||
|     bit_test >>= 1; | ||||
|   } | ||||
|   return count; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int CountLeadingSignBits(int64_t value, int width) { | ||||
|   VIXL_ASSERT((width == 32) || (width == 64)); | ||||
| int CountLeadingSignBitsFallBack(int64_t value, int width) { | ||||
|   VIXL_ASSERT(IsPowerOf2(width) && (width <= 64)); | ||||
|   if (value >= 0) { | ||||
|     return CountLeadingZeros(value, width) - 1; | ||||
|   } else { | ||||
| @@ -79,23 +39,46 @@ int CountLeadingSignBits(int64_t value, int width) { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int CountTrailingZeros(uint64_t value, int width) { | ||||
|   VIXL_ASSERT((width == 32) || (width == 64)); | ||||
|   int count = 0; | ||||
|   while ((count < width) && (((value >> count) & 1) == 0)) { | ||||
|     count++; | ||||
| int CountLeadingZerosFallBack(uint64_t value, int width) { | ||||
|   VIXL_ASSERT(IsPowerOf2(width) && (width <= 64)); | ||||
|   if (value == 0) { | ||||
|     return width; | ||||
|   } | ||||
|   int count = 0; | ||||
|   value = value << (64 - width); | ||||
|   if ((value & UINT64_C(0xffffffff00000000)) == 0) { | ||||
|     count += 32; | ||||
|     value = value << 32; | ||||
|   } | ||||
|   if ((value & UINT64_C(0xffff000000000000)) == 0) { | ||||
|     count += 16; | ||||
|     value = value << 16; | ||||
|   } | ||||
|   if ((value & UINT64_C(0xff00000000000000)) == 0) { | ||||
|     count += 8; | ||||
|     value = value << 8; | ||||
|   } | ||||
|   if ((value & UINT64_C(0xf000000000000000)) == 0) { | ||||
|     count += 4; | ||||
|     value = value << 4; | ||||
|   } | ||||
|   if ((value & UINT64_C(0xc000000000000000)) == 0) { | ||||
|     count += 2; | ||||
|     value = value << 2; | ||||
|   } | ||||
|   if ((value & UINT64_C(0x8000000000000000)) == 0) { | ||||
|     count += 1; | ||||
|   } | ||||
|   count += (value == 0); | ||||
|   return count; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int CountSetBits(uint64_t value, int width) { | ||||
|   // TODO: Other widths could be added here, as the implementation already
 | ||||
|   // supports them.
 | ||||
|   VIXL_ASSERT((width == 32) || (width == 64)); | ||||
| int CountSetBitsFallBack(uint64_t value, int width) { | ||||
|   VIXL_ASSERT(IsPowerOf2(width) && (width <= 64)); | ||||
| 
 | ||||
|   // Mask out unused bits to ensure that they are not counted.
 | ||||
|   value &= (UINT64_C(0xffffffffffffffff) >> (64-width)); | ||||
|   value &= (UINT64_C(0xffffffffffffffff) >> (64 - width)); | ||||
| 
 | ||||
|   // Add up the set bits.
 | ||||
|   // The algorithm works by adding pairs of bit fields together iteratively,
 | ||||
| @@ -122,30 +105,40 @@ int CountSetBits(uint64_t value, int width) { | ||||
|     value = ((value >> shift) & kMasks[i]) + (value & kMasks[i]); | ||||
|   } | ||||
| 
 | ||||
|   return value; | ||||
|   return static_cast<int>(value); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| uint64_t LowestSetBit(uint64_t value) { | ||||
|   return value & -value; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool IsPowerOf2(int64_t value) { | ||||
|   return (value != 0) && ((value & (value - 1)) == 0); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size) { | ||||
|   VIXL_ASSERT((reg_size % 8) == 0); | ||||
| int CountTrailingZerosFallBack(uint64_t value, int width) { | ||||
|   VIXL_ASSERT(IsPowerOf2(width) && (width <= 64)); | ||||
|   int count = 0; | ||||
|   for (unsigned i = 0; i < (reg_size / 16); i++) { | ||||
|     if ((imm & 0xffff) == 0) { | ||||
|       count++; | ||||
|   value = value << (64 - width); | ||||
|   if ((value & UINT64_C(0xffffffff)) == 0) { | ||||
|     count += 32; | ||||
|     value = value >> 32; | ||||
|   } | ||||
|     imm >>= 16; | ||||
|   if ((value & 0xffff) == 0) { | ||||
|     count += 16; | ||||
|     value = value >> 16; | ||||
|   } | ||||
|   return count; | ||||
|   if ((value & 0xff) == 0) { | ||||
|     count += 8; | ||||
|     value = value >> 8; | ||||
|   } | ||||
|   if ((value & 0xf) == 0) { | ||||
|     count += 4; | ||||
|     value = value >> 4; | ||||
|   } | ||||
|   if ((value & 0x3) == 0) { | ||||
|     count += 2; | ||||
|     value = value >> 2; | ||||
|   } | ||||
|   if ((value & 0x1) == 0) { | ||||
|     count += 1; | ||||
|   } | ||||
|   count += (value == 0); | ||||
|   return count - (64 - width); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| }  // namespace vixl
 | ||||
							
								
								
									
										155
									
								
								disas/libvixl/vixl/compiler-intrinsics.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								disas/libvixl/vixl/compiler-intrinsics.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| // Copyright 2015, ARM Limited | ||||
| // All rights reserved. | ||||
| // | ||||
| // Redistribution and use in source and binary forms, with or without | ||||
| // modification, are permitted provided that the following conditions are met: | ||||
| // | ||||
| //   * Redistributions of source code must retain the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer. | ||||
| //   * Redistributions in binary form must reproduce the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer in the documentation | ||||
| //     and/or other materials provided with the distribution. | ||||
| //   * Neither the name of ARM Limited nor the names of its contributors may be | ||||
| //     used to endorse or promote products derived from this software without | ||||
| //     specific prior written permission. | ||||
| // | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND | ||||
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | ||||
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
|  | ||||
| #ifndef VIXL_COMPILER_INTRINSICS_H | ||||
| #define VIXL_COMPILER_INTRINSICS_H | ||||
|  | ||||
| #include "globals.h" | ||||
|  | ||||
| namespace vixl { | ||||
|  | ||||
| // Helper to check whether the version of GCC used is greater than the specified | ||||
| // requirement. | ||||
| #define MAJOR 1000000 | ||||
| #define MINOR 1000 | ||||
| #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) | ||||
| #define GCC_VERSION_OR_NEWER(major, minor, patchlevel)                         \ | ||||
|     ((__GNUC__ * MAJOR + __GNUC_MINOR__ * MINOR + __GNUC_PATCHLEVEL__) >=      \ | ||||
|      ((major) * MAJOR + (minor) * MINOR + (patchlevel))) | ||||
| #elif defined(__GNUC__) && defined(__GNUC_MINOR__) | ||||
| #define GCC_VERSION_OR_NEWER(major, minor, patchlevel)                         \ | ||||
|     ((__GNUC__ * MAJOR + __GNUC_MINOR__ * MINOR) >=                            \ | ||||
|      ((major) * MAJOR + (minor) * MINOR + (patchlevel))) | ||||
| #else | ||||
| #define GCC_VERSION_OR_NEWER(major, minor, patchlevel) 0 | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #if defined(__clang__) && !defined(VIXL_NO_COMPILER_BUILTINS) | ||||
|  | ||||
| #define COMPILER_HAS_BUILTIN_CLRSB    (__has_builtin(__builtin_clrsb)) | ||||
| #define COMPILER_HAS_BUILTIN_CLZ      (__has_builtin(__builtin_clz)) | ||||
| #define COMPILER_HAS_BUILTIN_CTZ      (__has_builtin(__builtin_ctz)) | ||||
| #define COMPILER_HAS_BUILTIN_FFS      (__has_builtin(__builtin_ffs)) | ||||
| #define COMPILER_HAS_BUILTIN_POPCOUNT (__has_builtin(__builtin_popcount)) | ||||
|  | ||||
| #elif defined(__GNUC__) && !defined(VIXL_NO_COMPILER_BUILTINS) | ||||
| // The documentation for these builtins is available at: | ||||
| // https://gcc.gnu.org/onlinedocs/gcc-$MAJOR.$MINOR.$PATCHLEVEL/gcc//Other-Builtins.html | ||||
|  | ||||
| # define COMPILER_HAS_BUILTIN_CLRSB    (GCC_VERSION_OR_NEWER(4, 7, 0)) | ||||
| # define COMPILER_HAS_BUILTIN_CLZ      (GCC_VERSION_OR_NEWER(3, 4, 0)) | ||||
| # define COMPILER_HAS_BUILTIN_CTZ      (GCC_VERSION_OR_NEWER(3, 4, 0)) | ||||
| # define COMPILER_HAS_BUILTIN_FFS      (GCC_VERSION_OR_NEWER(3, 4, 0)) | ||||
| # define COMPILER_HAS_BUILTIN_POPCOUNT (GCC_VERSION_OR_NEWER(3, 4, 0)) | ||||
|  | ||||
| #else | ||||
| // One can define VIXL_NO_COMPILER_BUILTINS to force using the manually | ||||
| // implemented C++ methods. | ||||
|  | ||||
| #define COMPILER_HAS_BUILTIN_BSWAP    false | ||||
| #define COMPILER_HAS_BUILTIN_CLRSB    false | ||||
| #define COMPILER_HAS_BUILTIN_CLZ      false | ||||
| #define COMPILER_HAS_BUILTIN_CTZ      false | ||||
| #define COMPILER_HAS_BUILTIN_FFS      false | ||||
| #define COMPILER_HAS_BUILTIN_POPCOUNT false | ||||
|  | ||||
| #endif | ||||
|  | ||||
|  | ||||
| template<typename V> | ||||
| inline bool IsPowerOf2(V value) { | ||||
|   return (value != 0) && ((value & (value - 1)) == 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| // Declaration of fallback functions. | ||||
| int CountLeadingSignBitsFallBack(int64_t value, int width); | ||||
| int CountLeadingZerosFallBack(uint64_t value, int width); | ||||
| int CountSetBitsFallBack(uint64_t value, int width); | ||||
| int CountTrailingZerosFallBack(uint64_t value, int width); | ||||
|  | ||||
|  | ||||
| // Implementation of intrinsics functions. | ||||
| // TODO: The implementations could be improved for sizes different from 32bit | ||||
| // and 64bit: we could mask the values and call the appropriate builtin. | ||||
|  | ||||
| template<typename V> | ||||
| inline int CountLeadingSignBits(V value, int width = (sizeof(V) * 8)) { | ||||
| #if COMPILER_HAS_BUILTIN_CLRSB | ||||
|   if (width == 32) { | ||||
|     return __builtin_clrsb(value); | ||||
|   } else if (width == 64) { | ||||
|     return __builtin_clrsbll(value); | ||||
|   } | ||||
| #endif | ||||
|   return CountLeadingSignBitsFallBack(value, width); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<typename V> | ||||
| inline int CountLeadingZeros(V value, int width = (sizeof(V) * 8)) { | ||||
| #if COMPILER_HAS_BUILTIN_CLZ | ||||
|   if (width == 32) { | ||||
|     return (value == 0) ? 32 : __builtin_clz(static_cast<unsigned>(value)); | ||||
|   } else if (width == 64) { | ||||
|     return (value == 0) ? 64 : __builtin_clzll(value); | ||||
|   } | ||||
| #endif | ||||
|   return CountLeadingZerosFallBack(value, width); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<typename V> | ||||
| inline int CountSetBits(V value, int width = (sizeof(V) * 8)) { | ||||
| #if COMPILER_HAS_BUILTIN_POPCOUNT | ||||
|   if (width == 32) { | ||||
|     return __builtin_popcount(static_cast<unsigned>(value)); | ||||
|   } else if (width == 64) { | ||||
|     return __builtin_popcountll(value); | ||||
|   } | ||||
| #endif | ||||
|   return CountSetBitsFallBack(value, width); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<typename V> | ||||
| inline int CountTrailingZeros(V value, int width = (sizeof(V) * 8)) { | ||||
| #if COMPILER_HAS_BUILTIN_CTZ | ||||
|   if (width == 32) { | ||||
|     return (value == 0) ? 32 : __builtin_ctz(static_cast<unsigned>(value)); | ||||
|   } else if (width == 64) { | ||||
|     return (value == 0) ? 64 : __builtin_ctzll(value); | ||||
|   } | ||||
| #endif | ||||
|   return CountTrailingZerosFallBack(value, width); | ||||
| } | ||||
|  | ||||
| }  // namespace vixl | ||||
|  | ||||
| #endif  // VIXL_COMPILER_INTRINSICS_H | ||||
|  | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2013, ARM Limited
 | ||||
| // Copyright 2015, ARM Limited
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| @@ -49,20 +49,26 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdlib.h> | ||||
| #include <stddef.h> | ||||
| #include "platform.h" | ||||
| #include "vixl/platform.h" | ||||
| 
 | ||||
| 
 | ||||
| typedef uint8_t byte; | ||||
| 
 | ||||
| // Type for half-precision (16 bit) floating point numbers.
 | ||||
| typedef uint16_t float16; | ||||
| 
 | ||||
| const int KBytes = 1024; | ||||
| const int MBytes = 1024 * KBytes; | ||||
| 
 | ||||
| #define VIXL_ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort() | ||||
| #define VIXL_ABORT() \ | ||||
|     do { printf("in %s, line %i", __FILE__, __LINE__); abort(); } while (false) | ||||
| #ifdef VIXL_DEBUG | ||||
|   #define VIXL_ASSERT(condition) assert(condition) | ||||
|   #define VIXL_CHECK(condition) VIXL_ASSERT(condition) | ||||
|   #define VIXL_UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); VIXL_ABORT() | ||||
|   #define VIXL_UNREACHABLE() printf("UNREACHABLE\t"); VIXL_ABORT() | ||||
|   #define VIXL_UNIMPLEMENTED() \ | ||||
|     do { fprintf(stderr, "UNIMPLEMENTED\t"); VIXL_ABORT(); } while (false) | ||||
|   #define VIXL_UNREACHABLE() \ | ||||
|     do { fprintf(stderr, "UNREACHABLE\t"); VIXL_ABORT(); } while (false) | ||||
| #else | ||||
|   #define VIXL_ASSERT(condition) ((void) 0) | ||||
|   #define VIXL_CHECK(condition) assert(condition) | ||||
| @@ -76,10 +82,70 @@ const int MBytes = 1024 * KBytes; | ||||
| #define VIXL_STATIC_ASSERT_LINE(line, condition) \ | ||||
|   typedef char VIXL_CONCAT(STATIC_ASSERT_LINE_, line)[(condition) ? 1 : -1] \ | ||||
|   __attribute__((unused)) | ||||
| #define VIXL_STATIC_ASSERT(condition) VIXL_STATIC_ASSERT_LINE(__LINE__, condition) //NOLINT
 | ||||
| #define VIXL_STATIC_ASSERT(condition) \ | ||||
|     VIXL_STATIC_ASSERT_LINE(__LINE__, condition) | ||||
| 
 | ||||
| template <typename T> inline void USE(T) {} | ||||
| template <typename T1> | ||||
| inline void USE(T1) {} | ||||
| 
 | ||||
| #define VIXL_ALIGNMENT_EXCEPTION() printf("ALIGNMENT EXCEPTION\t"); VIXL_ABORT() | ||||
| template <typename T1, typename T2> | ||||
| inline void USE(T1, T2) {} | ||||
| 
 | ||||
| template <typename T1, typename T2, typename T3> | ||||
| inline void USE(T1, T2, T3) {} | ||||
| 
 | ||||
| template <typename T1, typename T2, typename T3, typename T4> | ||||
| inline void USE(T1, T2, T3, T4) {} | ||||
| 
 | ||||
| #define VIXL_ALIGNMENT_EXCEPTION() \ | ||||
|     do { fprintf(stderr, "ALIGNMENT EXCEPTION\t"); VIXL_ABORT(); } while (0) | ||||
| 
 | ||||
| // The clang::fallthrough attribute is used along with the Wimplicit-fallthrough
 | ||||
| // argument to annotate intentional fall-through between switch labels.
 | ||||
| // For more information please refer to:
 | ||||
| // http://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
 | ||||
| #ifndef __has_warning | ||||
|   #define __has_warning(x)  0 | ||||
| #endif | ||||
| 
 | ||||
| // Note: This option is only available for Clang. And will only be enabled for
 | ||||
| // C++11(201103L).
 | ||||
| #if __has_warning("-Wimplicit-fallthrough") && __cplusplus >= 201103L | ||||
|   #define VIXL_FALLTHROUGH() [[clang::fallthrough]] //NOLINT
 | ||||
| #else | ||||
|   #define VIXL_FALLTHROUGH() do {} while (0) | ||||
| #endif | ||||
| 
 | ||||
| #if __cplusplus >= 201103L | ||||
|   #define VIXL_NO_RETURN  [[noreturn]] //NOLINT
 | ||||
| #else | ||||
|   #define VIXL_NO_RETURN  __attribute__((noreturn)) | ||||
| #endif | ||||
| 
 | ||||
| // Some functions might only be marked as "noreturn" for the DEBUG build. This
 | ||||
| // macro should be used for such cases (for more details see what
 | ||||
| // VIXL_UNREACHABLE expands to).
 | ||||
| #ifdef VIXL_DEBUG | ||||
|   #define VIXL_DEBUG_NO_RETURN  VIXL_NO_RETURN | ||||
| #else | ||||
|   #define VIXL_DEBUG_NO_RETURN | ||||
| #endif | ||||
| 
 | ||||
| #ifdef VIXL_INCLUDE_SIMULATOR | ||||
| #ifndef VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE | ||||
|   #define VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE  1 | ||||
| #endif | ||||
| #else | ||||
| #ifndef VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE | ||||
|   #define VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE  0 | ||||
| #endif | ||||
| #if VIXL_GENERATE_SIMULATOR_INSTRUCTIONS_VALUE | ||||
|   #warning "Generating Simulator instructions without Simulator support." | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_SIMULATOR | ||||
|   #error "Please see the release notes for USE_SIMULATOR." | ||||
| #endif | ||||
| 
 | ||||
| #endif  // VIXL_GLOBALS_H
 | ||||
							
								
								
									
										775
									
								
								disas/libvixl/vixl/invalset.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										775
									
								
								disas/libvixl/vixl/invalset.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,775 @@ | ||||
| // Copyright 2015, ARM Limited | ||||
| // All rights reserved. | ||||
| // | ||||
| // Redistribution and use in source and binary forms, with or without | ||||
| // modification, are permitted provided that the following conditions are met: | ||||
| // | ||||
| //   * Redistributions of source code must retain the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer. | ||||
| //   * Redistributions in binary form must reproduce the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer in the documentation | ||||
| //     and/or other materials provided with the distribution. | ||||
| //   * Neither the name of ARM Limited nor the names of its contributors may be | ||||
| //     used to endorse or promote products derived from this software without | ||||
| //     specific prior written permission. | ||||
| // | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND | ||||
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | ||||
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
| #ifndef VIXL_INVALSET_H_ | ||||
| #define VIXL_INVALSET_H_ | ||||
|  | ||||
| #include <string.h> | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <vector> | ||||
|  | ||||
| #include "vixl/globals.h" | ||||
|  | ||||
| namespace vixl { | ||||
|  | ||||
| // We define a custom data structure template and its iterator as `std` | ||||
| // containers do not fit the performance requirements for some of our use cases. | ||||
| // | ||||
| // The structure behaves like an iterable unordered set with special properties | ||||
| // and restrictions. "InvalSet" stands for "Invalidatable Set". | ||||
| // | ||||
| // Restrictions and requirements: | ||||
| // - Adding an element already present in the set is illegal. In debug mode, | ||||
| //   this is checked at insertion time. | ||||
| // - The templated class `ElementType` must provide comparison operators so that | ||||
| //   `std::sort()` can be used. | ||||
| // - A key must be available to represent invalid elements. | ||||
| // - Elements with an invalid key must compare higher or equal to any other | ||||
| //   element. | ||||
| // | ||||
| // Use cases and performance considerations: | ||||
| // Our use cases present two specificities that allow us to design this | ||||
| // structure to provide fast insertion *and* fast search and deletion | ||||
| // operations: | ||||
| // - Elements are (generally) inserted in order (sorted according to their key). | ||||
| // - A key is available to mark elements as invalid (deleted). | ||||
| // The backing `std::vector` allows for fast insertions. When | ||||
| // searching for an element we ensure the elements are sorted (this is generally | ||||
| // the case) and perform a binary search. When deleting an element we do not | ||||
| // free the associated memory immediately. Instead, an element to be deleted is | ||||
| // marked with the 'invalid' key. Other methods of the container take care of | ||||
| // ignoring entries marked as invalid. | ||||
| // To avoid the overhead of the `std::vector` container when only few entries | ||||
| // are used, a number of elements are preallocated. | ||||
|  | ||||
| // 'ElementType' and 'KeyType' are respectively the types of the elements and | ||||
| // their key.  The structure only reclaims memory when safe to do so, if the | ||||
| // number of elements that can be reclaimed is greater than `RECLAIM_FROM` and | ||||
| // greater than `<total number of elements> / RECLAIM_FACTOR. | ||||
| #define TEMPLATE_INVALSET_P_DECL                                               \ | ||||
|   class ElementType,                                                           \ | ||||
|   unsigned N_PREALLOCATED_ELEMENTS,                                            \ | ||||
|   class KeyType,                                                               \ | ||||
|   KeyType INVALID_KEY,                                                         \ | ||||
|   size_t RECLAIM_FROM,                                                         \ | ||||
|   unsigned RECLAIM_FACTOR | ||||
|  | ||||
| #define TEMPLATE_INVALSET_P_DEF                                                \ | ||||
| ElementType, N_PREALLOCATED_ELEMENTS,                                          \ | ||||
| KeyType, INVALID_KEY, RECLAIM_FROM, RECLAIM_FACTOR | ||||
|  | ||||
| template<class S> class InvalSetIterator;  // Forward declaration. | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> class InvalSet { | ||||
|  public: | ||||
|   InvalSet(); | ||||
|   ~InvalSet(); | ||||
|  | ||||
|   static const size_t kNPreallocatedElements = N_PREALLOCATED_ELEMENTS; | ||||
|   static const KeyType kInvalidKey = INVALID_KEY; | ||||
|  | ||||
|   // It is illegal to insert an element already present in the set. | ||||
|   void insert(const ElementType& element); | ||||
|  | ||||
|   // Looks for the specified element in the set and - if found - deletes it. | ||||
|   void erase(const ElementType& element); | ||||
|  | ||||
|   // This indicates the number of (valid) elements stored in this set. | ||||
|   size_t size() const; | ||||
|  | ||||
|   // Returns true if no elements are stored in the set. | ||||
|   // Note that this does not mean the the backing storage is empty: it can still | ||||
|   // contain invalid elements. | ||||
|   bool empty() const; | ||||
|  | ||||
|   void clear(); | ||||
|  | ||||
|   const ElementType min_element(); | ||||
|  | ||||
|   // This returns the key of the minimum element in the set. | ||||
|   KeyType min_element_key(); | ||||
|  | ||||
|   static bool IsValid(const ElementType& element); | ||||
|   static KeyType Key(const ElementType& element); | ||||
|   static void SetKey(ElementType* element, KeyType key); | ||||
|  | ||||
|  protected: | ||||
|   // Returns a pointer to the element in vector_ if it was found, or NULL | ||||
|   // otherwise. | ||||
|   ElementType* Search(const ElementType& element); | ||||
|  | ||||
|   // The argument *must* point to an element stored in *this* set. | ||||
|   // This function is not allowed to move elements in the backing vector | ||||
|   // storage. | ||||
|   void EraseInternal(ElementType* element); | ||||
|  | ||||
|   // The elements in the range searched must be sorted. | ||||
|   ElementType* BinarySearch(const ElementType& element, | ||||
|                             ElementType* start, | ||||
|                             ElementType* end) const; | ||||
|  | ||||
|   // Sort the elements. | ||||
|   enum SortType { | ||||
|     // The 'hard' version guarantees that invalid elements are moved to the end | ||||
|     // of the container. | ||||
|     kHardSort, | ||||
|     // The 'soft' version only guarantees that the elements will be sorted. | ||||
|     // Invalid elements may still be present anywhere in the set. | ||||
|     kSoftSort | ||||
|   }; | ||||
|   void Sort(SortType sort_type); | ||||
|  | ||||
|   // Delete the elements that have an invalid key. The complexity is linear | ||||
|   // with the size of the vector. | ||||
|   void Clean(); | ||||
|  | ||||
|   const ElementType Front() const; | ||||
|   const ElementType Back() const; | ||||
|  | ||||
|   // Delete invalid trailing elements and return the last valid element in the | ||||
|   // set. | ||||
|   const ElementType CleanBack(); | ||||
|  | ||||
|   // Returns a pointer to the start or end of the backing storage. | ||||
|   const ElementType* StorageBegin() const; | ||||
|   const ElementType* StorageEnd() const; | ||||
|   ElementType* StorageBegin(); | ||||
|   ElementType* StorageEnd(); | ||||
|  | ||||
|   // Returns the index of the element within the backing storage. The element | ||||
|   // must belong to the backing storage. | ||||
|   size_t ElementIndex(const ElementType* element) const; | ||||
|  | ||||
|   // Returns the element at the specified index in the backing storage. | ||||
|   const ElementType* ElementAt(size_t index) const; | ||||
|   ElementType* ElementAt(size_t index); | ||||
|  | ||||
|   static const ElementType* FirstValidElement(const ElementType* from, | ||||
|                                               const ElementType* end); | ||||
|  | ||||
|   void CacheMinElement(); | ||||
|   const ElementType CachedMinElement() const; | ||||
|  | ||||
|   bool ShouldReclaimMemory() const; | ||||
|   void ReclaimMemory(); | ||||
|  | ||||
|   bool IsUsingVector() const { return vector_ != NULL; } | ||||
|   void set_sorted(bool sorted) { sorted_ = sorted; } | ||||
|  | ||||
|   // We cache some data commonly required by users to improve performance. | ||||
|   // We cannot cache pointers to elements as we do not control the backing | ||||
|   // storage. | ||||
|   bool valid_cached_min_; | ||||
|   size_t cached_min_index_;  // Valid iff `valid_cached_min_` is true. | ||||
|   KeyType cached_min_key_;         // Valid iff `valid_cached_min_` is true. | ||||
|  | ||||
|   // Indicates whether the elements are sorted. | ||||
|   bool sorted_; | ||||
|  | ||||
|   // This represents the number of (valid) elements in this set. | ||||
|   size_t size_; | ||||
|  | ||||
|   // The backing storage is either the array of preallocated elements or the | ||||
|   // vector. The structure starts by using the preallocated elements, and | ||||
|   // transitions (permanently) to using the vector once more than | ||||
|   // kNPreallocatedElements are used. | ||||
|   // Elements are only invalidated when using the vector. The preallocated | ||||
|   // storage always only contains valid elements. | ||||
|   ElementType preallocated_[kNPreallocatedElements]; | ||||
|   std::vector<ElementType>* vector_; | ||||
|  | ||||
| #ifdef VIXL_DEBUG | ||||
|   // Iterators acquire and release this monitor. While a set is acquired, | ||||
|   // certain operations are illegal to ensure that the iterator will | ||||
|   // correctly iterate over the elements in the set. | ||||
|   int monitor_; | ||||
|   int monitor() const { return monitor_; } | ||||
|   void Acquire() { monitor_++; } | ||||
|   void Release() { | ||||
|     monitor_--; | ||||
|     VIXL_ASSERT(monitor_ >= 0); | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   friend class InvalSetIterator<InvalSet<TEMPLATE_INVALSET_P_DEF> >; | ||||
|   typedef ElementType _ElementType; | ||||
|   typedef KeyType _KeyType; | ||||
| }; | ||||
|  | ||||
|  | ||||
| template<class S> class InvalSetIterator { | ||||
|  private: | ||||
|   // Redefine types to mirror the associated set types. | ||||
|   typedef typename S::_ElementType ElementType; | ||||
|   typedef typename S::_KeyType KeyType; | ||||
|  | ||||
|  public: | ||||
|   explicit InvalSetIterator(S* inval_set); | ||||
|   ~InvalSetIterator(); | ||||
|  | ||||
|   ElementType* Current() const; | ||||
|   void Advance(); | ||||
|   bool Done() const; | ||||
|  | ||||
|   // Mark this iterator as 'done'. | ||||
|   void Finish(); | ||||
|  | ||||
|   // Delete the current element and advance the iterator to point to the next | ||||
|   // element. | ||||
|   void DeleteCurrentAndAdvance(); | ||||
|  | ||||
|   static bool IsValid(const ElementType& element); | ||||
|   static KeyType Key(const ElementType& element); | ||||
|  | ||||
|  protected: | ||||
|   void MoveToValidElement(); | ||||
|  | ||||
|   // Indicates if the iterator is looking at the vector or at the preallocated | ||||
|   // elements. | ||||
|   const bool using_vector_; | ||||
|   // Used when looking at the preallocated elements, or in debug mode when using | ||||
|   // the vector to track how many times the iterator has advanced. | ||||
|   size_t index_; | ||||
|   typename std::vector<ElementType>::iterator iterator_; | ||||
|   S* inval_set_; | ||||
| }; | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| InvalSet<TEMPLATE_INVALSET_P_DEF>::InvalSet() | ||||
|   : valid_cached_min_(false), | ||||
|     sorted_(true), size_(0), vector_(NULL) { | ||||
| #ifdef VIXL_DEBUG | ||||
|   monitor_ = 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| InvalSet<TEMPLATE_INVALSET_P_DEF>::~InvalSet() { | ||||
|   VIXL_ASSERT(monitor_ == 0); | ||||
|   delete vector_; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::insert(const ElementType& element) { | ||||
|   VIXL_ASSERT(monitor() == 0); | ||||
|   VIXL_ASSERT(IsValid(element)); | ||||
|   VIXL_ASSERT(Search(element) == NULL); | ||||
|   set_sorted(empty() || (sorted_ && (element > CleanBack()))); | ||||
|   if (IsUsingVector()) { | ||||
|     vector_->push_back(element); | ||||
|   } else { | ||||
|     if (size_ < kNPreallocatedElements) { | ||||
|       preallocated_[size_] = element; | ||||
|     } else { | ||||
|       // Transition to using the vector. | ||||
|       vector_ = new std::vector<ElementType>(preallocated_, | ||||
|                                              preallocated_ + size_); | ||||
|       vector_->push_back(element); | ||||
|     } | ||||
|   } | ||||
|   size_++; | ||||
|  | ||||
|   if (valid_cached_min_ && (element < min_element())) { | ||||
|     cached_min_index_ = IsUsingVector() ? vector_->size() - 1 : size_ - 1; | ||||
|     cached_min_key_ = Key(element); | ||||
|     valid_cached_min_ = true; | ||||
|   } | ||||
|  | ||||
|   if (ShouldReclaimMemory()) { | ||||
|     ReclaimMemory(); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::erase(const ElementType& element) { | ||||
|   VIXL_ASSERT(monitor() == 0); | ||||
|   VIXL_ASSERT(IsValid(element)); | ||||
|   ElementType* local_element = Search(element); | ||||
|   if (local_element != NULL) { | ||||
|     EraseInternal(local_element); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::Search( | ||||
|     const ElementType& element) { | ||||
|   VIXL_ASSERT(monitor() == 0); | ||||
|   if (empty()) { | ||||
|     return NULL; | ||||
|   } | ||||
|   if (ShouldReclaimMemory()) { | ||||
|     ReclaimMemory(); | ||||
|   } | ||||
|   if (!sorted_) { | ||||
|     Sort(kHardSort); | ||||
|   } | ||||
|   if (!valid_cached_min_) { | ||||
|     CacheMinElement(); | ||||
|   } | ||||
|   return BinarySearch(element, ElementAt(cached_min_index_), StorageEnd()); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::size() const { | ||||
|   return size_; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| bool InvalSet<TEMPLATE_INVALSET_P_DEF>::empty() const { | ||||
|   return size_ == 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::clear() { | ||||
|   VIXL_ASSERT(monitor() == 0); | ||||
|   size_ = 0; | ||||
|   if (IsUsingVector()) { | ||||
|     vector_->clear(); | ||||
|   } | ||||
|   set_sorted(true); | ||||
|   valid_cached_min_ = false; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::min_element() { | ||||
|   VIXL_ASSERT(monitor() == 0); | ||||
|   VIXL_ASSERT(!empty()); | ||||
|   CacheMinElement(); | ||||
|   return *ElementAt(cached_min_index_); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| KeyType InvalSet<TEMPLATE_INVALSET_P_DEF>::min_element_key() { | ||||
|   VIXL_ASSERT(monitor() == 0); | ||||
|   if (valid_cached_min_) { | ||||
|     return cached_min_key_; | ||||
|   } else { | ||||
|     return Key(min_element()); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| bool InvalSet<TEMPLATE_INVALSET_P_DEF>::IsValid(const ElementType& element) { | ||||
|   return Key(element) != kInvalidKey; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::EraseInternal(ElementType* element) { | ||||
|   // Note that this function must be safe even while an iterator has acquired | ||||
|   // this set. | ||||
|   VIXL_ASSERT(element != NULL); | ||||
|   size_t deleted_index = ElementIndex(element); | ||||
|   if (IsUsingVector()) { | ||||
|     VIXL_ASSERT((&(vector_->front()) <= element) && | ||||
|                 (element <= &(vector_->back()))); | ||||
|     SetKey(element, kInvalidKey); | ||||
|   } else { | ||||
|     VIXL_ASSERT((preallocated_ <= element) && | ||||
|                 (element < (preallocated_ + kNPreallocatedElements))); | ||||
|     ElementType* end = preallocated_ + kNPreallocatedElements; | ||||
|     size_t copy_size = sizeof(*element) * (end - element - 1); | ||||
|     memmove(element, element + 1, copy_size); | ||||
|   } | ||||
|   size_--; | ||||
|  | ||||
|   if (valid_cached_min_ && | ||||
|       (deleted_index == cached_min_index_)) { | ||||
|     if (sorted_ && !empty()) { | ||||
|       const ElementType* min = FirstValidElement(element, StorageEnd()); | ||||
|       cached_min_index_ = ElementIndex(min); | ||||
|       cached_min_key_ = Key(*min); | ||||
|       valid_cached_min_ = true; | ||||
|     } else { | ||||
|       valid_cached_min_ = false; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::BinarySearch( | ||||
|     const ElementType& element, ElementType* start, ElementType* end) const { | ||||
|   if (start == end) { | ||||
|     return NULL; | ||||
|   } | ||||
|   VIXL_ASSERT(sorted_); | ||||
|   VIXL_ASSERT(start < end); | ||||
|   VIXL_ASSERT(!empty()); | ||||
|  | ||||
|   // Perform a binary search through the elements while ignoring invalid | ||||
|   // elements. | ||||
|   ElementType* elements = start; | ||||
|   size_t low = 0; | ||||
|   size_t high = (end - start) - 1; | ||||
|   while (low < high) { | ||||
|     // Find valid bounds. | ||||
|     while (!IsValid(elements[low]) && (low < high)) ++low; | ||||
|     while (!IsValid(elements[high]) && (low < high)) --high; | ||||
|     VIXL_ASSERT(low <= high); | ||||
|     // Avoid overflow when computing the middle index. | ||||
|     size_t middle = low / 2 + high / 2 + (low & high & 1); | ||||
|     if ((middle == low) || (middle == high)) { | ||||
|       break; | ||||
|     } | ||||
|     while (!IsValid(elements[middle]) && (middle < high - 1)) ++middle; | ||||
|     while (!IsValid(elements[middle]) && (low + 1 < middle)) --middle; | ||||
|     if (!IsValid(elements[middle])) { | ||||
|       break; | ||||
|     } | ||||
|     if (elements[middle] < element) { | ||||
|       low = middle; | ||||
|     } else { | ||||
|       high = middle; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (elements[low] == element) return &elements[low]; | ||||
|   if (elements[high] == element) return &elements[high]; | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::Sort(SortType sort_type) { | ||||
|   VIXL_ASSERT(monitor() == 0); | ||||
|   if (sort_type == kSoftSort) { | ||||
|     if (sorted_) { | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|   if (empty()) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   Clean(); | ||||
|   std::sort(StorageBegin(), StorageEnd()); | ||||
|  | ||||
|   set_sorted(true); | ||||
|   cached_min_index_ = 0; | ||||
|   cached_min_key_ = Key(Front()); | ||||
|   valid_cached_min_ = true; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::Clean() { | ||||
|   VIXL_ASSERT(monitor() == 0); | ||||
|   if (empty() || !IsUsingVector()) { | ||||
|     return; | ||||
|   } | ||||
|   // Manually iterate through the vector storage to discard invalid elements. | ||||
|   ElementType* start = &(vector_->front()); | ||||
|   ElementType* end = start + vector_->size(); | ||||
|   ElementType* c = start; | ||||
|   ElementType* first_invalid; | ||||
|   ElementType* first_valid; | ||||
|   ElementType* next_invalid; | ||||
|  | ||||
|   while (c < end && IsValid(*c)) { c++; } | ||||
|   first_invalid = c; | ||||
|  | ||||
|   while (c < end) { | ||||
|     while (c < end && !IsValid(*c)) { c++; } | ||||
|     first_valid = c; | ||||
|     while (c < end && IsValid(*c)) { c++; } | ||||
|     next_invalid = c; | ||||
|  | ||||
|     ptrdiff_t n_moved_elements = (next_invalid - first_valid); | ||||
|     memmove(first_invalid, first_valid,  n_moved_elements * sizeof(*c)); | ||||
|     first_invalid = first_invalid + n_moved_elements; | ||||
|     c = next_invalid; | ||||
|   } | ||||
|  | ||||
|   // Delete the trailing invalid elements. | ||||
|   vector_->erase(vector_->begin() + (first_invalid - start), vector_->end()); | ||||
|   VIXL_ASSERT(vector_->size() == size_); | ||||
|  | ||||
|   if (sorted_) { | ||||
|     valid_cached_min_ = true; | ||||
|     cached_min_index_ = 0; | ||||
|     cached_min_key_ = Key(*ElementAt(0)); | ||||
|   } else { | ||||
|     valid_cached_min_ = false; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Front() const { | ||||
|   VIXL_ASSERT(!empty()); | ||||
|   return IsUsingVector() ? vector_->front() : preallocated_[0]; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Back() const { | ||||
|   VIXL_ASSERT(!empty()); | ||||
|   return IsUsingVector() ? vector_->back() : preallocated_[size_ - 1]; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::CleanBack() { | ||||
|   VIXL_ASSERT(monitor() == 0); | ||||
|   if (IsUsingVector()) { | ||||
|     // Delete the invalid trailing elements. | ||||
|     typename std::vector<ElementType>::reverse_iterator it = vector_->rbegin(); | ||||
|     while (!IsValid(*it)) { | ||||
|       it++; | ||||
|     } | ||||
|     vector_->erase(it.base(), vector_->end()); | ||||
|   } | ||||
|   return Back(); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() const { | ||||
|   return IsUsingVector() ? &(vector_->front()) : preallocated_; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() const { | ||||
|   return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() { | ||||
|   return IsUsingVector() ? &(vector_->front()) : preallocated_; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() { | ||||
|   return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::ElementIndex( | ||||
|     const ElementType* element) const { | ||||
|   VIXL_ASSERT((StorageBegin() <= element) && (element < StorageEnd())); | ||||
|   return element - StorageBegin(); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::ElementAt( | ||||
|     size_t index) const { | ||||
|   VIXL_ASSERT( | ||||
|       (IsUsingVector() && (index < vector_->size())) || (index < size_)); | ||||
|   return StorageBegin() + index; | ||||
| } | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::ElementAt(size_t index) { | ||||
|   VIXL_ASSERT( | ||||
|       (IsUsingVector() && (index < vector_->size())) || (index < size_)); | ||||
|   return StorageBegin() + index; | ||||
| } | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::FirstValidElement( | ||||
|     const ElementType* from, const ElementType* end) { | ||||
|   while ((from < end) && !IsValid(*from)) { | ||||
|     from++; | ||||
|   } | ||||
|   return from; | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::CacheMinElement() { | ||||
|   VIXL_ASSERT(monitor() == 0); | ||||
|   VIXL_ASSERT(!empty()); | ||||
|  | ||||
|   if (valid_cached_min_) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   if (sorted_) { | ||||
|     const ElementType* min = FirstValidElement(StorageBegin(), StorageEnd()); | ||||
|     cached_min_index_ = ElementIndex(min); | ||||
|     cached_min_key_ = Key(*min); | ||||
|     valid_cached_min_ = true; | ||||
|   } else { | ||||
|     Sort(kHardSort); | ||||
|   } | ||||
|   VIXL_ASSERT(valid_cached_min_); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| bool InvalSet<TEMPLATE_INVALSET_P_DEF>::ShouldReclaimMemory() const { | ||||
|   if (!IsUsingVector()) { | ||||
|     return false; | ||||
|   } | ||||
|   size_t n_invalid_elements = vector_->size() - size_; | ||||
|   return (n_invalid_elements > RECLAIM_FROM) && | ||||
|          (n_invalid_elements > vector_->size() / RECLAIM_FACTOR); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<TEMPLATE_INVALSET_P_DECL> | ||||
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::ReclaimMemory() { | ||||
|   VIXL_ASSERT(monitor() == 0); | ||||
|   Clean(); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class S> | ||||
| InvalSetIterator<S>::InvalSetIterator(S* inval_set) | ||||
|     : using_vector_((inval_set != NULL) && inval_set->IsUsingVector()), | ||||
|       index_(0), | ||||
|       inval_set_(inval_set) { | ||||
|   if (inval_set != NULL) { | ||||
|     inval_set->Sort(S::kSoftSort); | ||||
| #ifdef VIXL_DEBUG | ||||
|     inval_set->Acquire(); | ||||
| #endif | ||||
|     if (using_vector_) { | ||||
|       iterator_ = typename std::vector<ElementType>::iterator( | ||||
|           inval_set_->vector_->begin()); | ||||
|     } | ||||
|     MoveToValidElement(); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class S> | ||||
| InvalSetIterator<S>::~InvalSetIterator() { | ||||
| #ifdef VIXL_DEBUG | ||||
|   if (inval_set_ != NULL) { | ||||
|     inval_set_->Release(); | ||||
|   } | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class S> | ||||
| typename S::_ElementType* InvalSetIterator<S>::Current() const { | ||||
|   VIXL_ASSERT(!Done()); | ||||
|   if (using_vector_) { | ||||
|     return &(*iterator_); | ||||
|   } else { | ||||
|     return &(inval_set_->preallocated_[index_]); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class S> | ||||
| void InvalSetIterator<S>::Advance() { | ||||
|   VIXL_ASSERT(!Done()); | ||||
|   if (using_vector_) { | ||||
|     iterator_++; | ||||
| #ifdef VIXL_DEBUG | ||||
|     index_++; | ||||
| #endif | ||||
|     MoveToValidElement(); | ||||
|   } else { | ||||
|     index_++; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class S> | ||||
| bool InvalSetIterator<S>::Done() const { | ||||
|   if (using_vector_) { | ||||
|     bool done = (iterator_ == inval_set_->vector_->end()); | ||||
|     VIXL_ASSERT(done == (index_ == inval_set_->size())); | ||||
|     return done; | ||||
|   } else { | ||||
|     return index_ == inval_set_->size(); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class S> | ||||
| void InvalSetIterator<S>::Finish() { | ||||
|   VIXL_ASSERT(inval_set_->sorted_); | ||||
|   if (using_vector_) { | ||||
|     iterator_ = inval_set_->vector_->end(); | ||||
|   } | ||||
|   index_ = inval_set_->size(); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class S> | ||||
| void InvalSetIterator<S>::DeleteCurrentAndAdvance() { | ||||
|   if (using_vector_) { | ||||
|     inval_set_->EraseInternal(&(*iterator_)); | ||||
|     MoveToValidElement(); | ||||
|   } else { | ||||
|     inval_set_->EraseInternal(inval_set_->preallocated_ + index_); | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class S> | ||||
| bool InvalSetIterator<S>::IsValid(const ElementType& element) { | ||||
|   return S::IsValid(element); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class S> | ||||
| typename S::_KeyType InvalSetIterator<S>::Key(const ElementType& element) { | ||||
|   return S::Key(element); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<class S> | ||||
| void InvalSetIterator<S>::MoveToValidElement() { | ||||
|   if (using_vector_) { | ||||
|     while ((iterator_ != inval_set_->vector_->end()) && !IsValid(*iterator_)) { | ||||
|       iterator_++; | ||||
|     } | ||||
|   } else { | ||||
|     VIXL_ASSERT(inval_set_->empty() || IsValid(inval_set_->preallocated_[0])); | ||||
|     // Nothing to do. | ||||
|   } | ||||
| } | ||||
|  | ||||
| #undef TEMPLATE_INVALSET_P_DECL | ||||
| #undef TEMPLATE_INVALSET_P_DEF | ||||
|  | ||||
| }  // namespace vixl | ||||
|  | ||||
| #endif  // VIXL_INVALSET_H_ | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2013, ARM Limited
 | ||||
| // Copyright 2014, ARM Limited
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
							
								
								
									
										142
									
								
								disas/libvixl/vixl/utils.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								disas/libvixl/vixl/utils.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| // Copyright 2015, ARM Limited | ||||
| // All rights reserved. | ||||
| // | ||||
| // Redistribution and use in source and binary forms, with or without | ||||
| // modification, are permitted provided that the following conditions are met: | ||||
| // | ||||
| //   * Redistributions of source code must retain the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer. | ||||
| //   * Redistributions in binary form must reproduce the above copyright notice, | ||||
| //     this list of conditions and the following disclaimer in the documentation | ||||
| //     and/or other materials provided with the distribution. | ||||
| //   * Neither the name of ARM Limited nor the names of its contributors may be | ||||
| //     used to endorse or promote products derived from this software without | ||||
| //     specific prior written permission. | ||||
| // | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND | ||||
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | ||||
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
| #include "vixl/utils.h" | ||||
| #include <stdio.h> | ||||
|  | ||||
| namespace vixl { | ||||
|  | ||||
| uint32_t float_to_rawbits(float value) { | ||||
|   uint32_t bits = 0; | ||||
|   memcpy(&bits, &value, 4); | ||||
|   return bits; | ||||
| } | ||||
|  | ||||
|  | ||||
| uint64_t double_to_rawbits(double value) { | ||||
|   uint64_t bits = 0; | ||||
|   memcpy(&bits, &value, 8); | ||||
|   return bits; | ||||
| } | ||||
|  | ||||
|  | ||||
| float rawbits_to_float(uint32_t bits) { | ||||
|   float value = 0.0; | ||||
|   memcpy(&value, &bits, 4); | ||||
|   return value; | ||||
| } | ||||
|  | ||||
|  | ||||
| double rawbits_to_double(uint64_t bits) { | ||||
|   double value = 0.0; | ||||
|   memcpy(&value, &bits, 8); | ||||
|   return value; | ||||
| } | ||||
|  | ||||
|  | ||||
| uint32_t float_sign(float val) { | ||||
|   uint32_t rawbits = float_to_rawbits(val); | ||||
|   return unsigned_bitextract_32(31, 31, rawbits); | ||||
| } | ||||
|  | ||||
|  | ||||
| uint32_t float_exp(float val) { | ||||
|   uint32_t rawbits = float_to_rawbits(val); | ||||
|   return unsigned_bitextract_32(30, 23, rawbits); | ||||
| } | ||||
|  | ||||
|  | ||||
| uint32_t float_mantissa(float val) { | ||||
|   uint32_t rawbits = float_to_rawbits(val); | ||||
|   return unsigned_bitextract_32(22, 0, rawbits); | ||||
| } | ||||
|  | ||||
|  | ||||
| uint32_t double_sign(double val) { | ||||
|   uint64_t rawbits = double_to_rawbits(val); | ||||
|   return static_cast<uint32_t>(unsigned_bitextract_64(63, 63, rawbits)); | ||||
| } | ||||
|  | ||||
|  | ||||
| uint32_t double_exp(double val) { | ||||
|   uint64_t rawbits = double_to_rawbits(val); | ||||
|   return static_cast<uint32_t>(unsigned_bitextract_64(62, 52, rawbits)); | ||||
| } | ||||
|  | ||||
|  | ||||
| uint64_t double_mantissa(double val) { | ||||
|   uint64_t rawbits = double_to_rawbits(val); | ||||
|   return unsigned_bitextract_64(51, 0, rawbits); | ||||
| } | ||||
|  | ||||
|  | ||||
| float float_pack(uint32_t sign, uint32_t exp, uint32_t mantissa) { | ||||
|   uint32_t bits = (sign << 31) | (exp << 23) | mantissa; | ||||
|   return rawbits_to_float(bits); | ||||
| } | ||||
|  | ||||
|  | ||||
| double double_pack(uint64_t sign, uint64_t exp, uint64_t mantissa) { | ||||
|   uint64_t bits = (sign << 63) | (exp << 52) | mantissa; | ||||
|   return rawbits_to_double(bits); | ||||
| } | ||||
|  | ||||
|  | ||||
| int float16classify(float16 value) { | ||||
|   uint16_t exponent_max = (1 << 5) - 1; | ||||
|   uint16_t exponent_mask = exponent_max << 10; | ||||
|   uint16_t mantissa_mask = (1 << 10) - 1; | ||||
|  | ||||
|   uint16_t exponent = (value & exponent_mask) >> 10; | ||||
|   uint16_t mantissa = value & mantissa_mask; | ||||
|   if (exponent == 0) { | ||||
|     if (mantissa == 0) { | ||||
|       return FP_ZERO; | ||||
|     } | ||||
|     return FP_SUBNORMAL; | ||||
|   } else if (exponent == exponent_max) { | ||||
|     if (mantissa == 0) { | ||||
|       return FP_INFINITE; | ||||
|     } | ||||
|     return FP_NAN; | ||||
|   } | ||||
|   return FP_NORMAL; | ||||
| } | ||||
|  | ||||
|  | ||||
| unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size) { | ||||
|   VIXL_ASSERT((reg_size % 8) == 0); | ||||
|   int count = 0; | ||||
|   for (unsigned i = 0; i < (reg_size / 16); i++) { | ||||
|     if ((imm & 0xffff) == 0) { | ||||
|       count++; | ||||
|     } | ||||
|     imm >>= 16; | ||||
|   } | ||||
|   return count; | ||||
| } | ||||
|  | ||||
| }  // namespace vixl | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2013, ARM Limited
 | ||||
| // Copyright 2015, ARM Limited
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| @@ -27,16 +27,17 @@ | ||||
| #ifndef VIXL_UTILS_H | ||||
| #define VIXL_UTILS_H | ||||
| 
 | ||||
| #include <math.h> | ||||
| #include <string.h> | ||||
| #include "globals.h" | ||||
| #include <cmath> | ||||
| #include "vixl/globals.h" | ||||
| #include "vixl/compiler-intrinsics.h" | ||||
| 
 | ||||
| namespace vixl { | ||||
| 
 | ||||
| // Macros for compile-time format checking.
 | ||||
| #if defined(__GNUC__) | ||||
| #if GCC_VERSION_OR_NEWER(4, 4, 0) | ||||
| #define PRINTF_CHECK(format_index, varargs_index) \ | ||||
|   __attribute__((format(printf, format_index, varargs_index))) | ||||
|   __attribute__((format(gnu_printf, format_index, varargs_index))) | ||||
| #else | ||||
| #define PRINTF_CHECK(format_index, varargs_index) | ||||
| #endif | ||||
| @@ -53,9 +54,9 @@ inline bool is_uintn(unsigned n, int64_t x) { | ||||
|   return !(x >> n); | ||||
| } | ||||
| 
 | ||||
| inline unsigned truncate_to_intn(unsigned n, int64_t x) { | ||||
| inline uint32_t truncate_to_intn(unsigned n, int64_t x) { | ||||
|   VIXL_ASSERT((0 < n) && (n < 64)); | ||||
|   return (x & ((INT64_C(1) << n) - 1)); | ||||
|   return static_cast<uint32_t>(x & ((INT64_C(1) << n) - 1)); | ||||
| } | ||||
| 
 | ||||
| #define INT_1_TO_63_LIST(V)                                                    \ | ||||
| @@ -73,7 +74,7 @@ inline bool is_int##N(int64_t x) { return is_intn(N, x); } | ||||
| #define DECLARE_IS_UINT_N(N)                                                   \ | ||||
| inline bool is_uint##N(int64_t x) { return is_uintn(N, x); } | ||||
| #define DECLARE_TRUNCATE_TO_INT_N(N)                                           \ | ||||
| inline int truncate_to_int##N(int x) { return truncate_to_intn(N, x); } | ||||
| inline uint32_t truncate_to_int##N(int x) { return truncate_to_intn(N, x); } | ||||
| INT_1_TO_63_LIST(DECLARE_IS_INT_N) | ||||
| INT_1_TO_63_LIST(DECLARE_IS_UINT_N) | ||||
| INT_1_TO_63_LIST(DECLARE_TRUNCATE_TO_INT_N) | ||||
| @@ -104,12 +105,24 @@ uint64_t double_to_rawbits(double value); | ||||
| float rawbits_to_float(uint32_t bits); | ||||
| double rawbits_to_double(uint64_t bits); | ||||
| 
 | ||||
| uint32_t float_sign(float val); | ||||
| uint32_t float_exp(float val); | ||||
| uint32_t float_mantissa(float val); | ||||
| uint32_t double_sign(double val); | ||||
| uint32_t double_exp(double val); | ||||
| uint64_t double_mantissa(double val); | ||||
| 
 | ||||
| float float_pack(uint32_t sign, uint32_t exp, uint32_t mantissa); | ||||
| double double_pack(uint64_t sign, uint64_t exp, uint64_t mantissa); | ||||
| 
 | ||||
| // An fpclassify() function for 16-bit half-precision floats.
 | ||||
| int float16classify(float16 value); | ||||
| 
 | ||||
| // NaN tests.
 | ||||
| inline bool IsSignallingNaN(double num) { | ||||
|   const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000); | ||||
|   uint64_t raw = double_to_rawbits(num); | ||||
|   if (isnan(num) && ((raw & kFP64QuietNaNMask) == 0)) { | ||||
|   if (std::isnan(num) && ((raw & kFP64QuietNaNMask) == 0)) { | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
| @@ -119,30 +132,37 @@ inline bool IsSignallingNaN(double num) { | ||||
| inline bool IsSignallingNaN(float num) { | ||||
|   const uint32_t kFP32QuietNaNMask = 0x00400000; | ||||
|   uint32_t raw = float_to_rawbits(num); | ||||
|   if (isnan(num) && ((raw & kFP32QuietNaNMask) == 0)) { | ||||
|   if (std::isnan(num) && ((raw & kFP32QuietNaNMask) == 0)) { | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| inline bool IsSignallingNaN(float16 num) { | ||||
|   const uint16_t kFP16QuietNaNMask = 0x0200; | ||||
|   return (float16classify(num) == FP_NAN) && | ||||
|          ((num & kFP16QuietNaNMask) == 0); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| template <typename T> | ||||
| inline bool IsQuietNaN(T num) { | ||||
|   return isnan(num) && !IsSignallingNaN(num); | ||||
|   return std::isnan(num) && !IsSignallingNaN(num); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // Convert the NaN in 'num' to a quiet NaN.
 | ||||
| inline double ToQuietNaN(double num) { | ||||
|   const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000); | ||||
|   VIXL_ASSERT(isnan(num)); | ||||
|   VIXL_ASSERT(std::isnan(num)); | ||||
|   return rawbits_to_double(double_to_rawbits(num) | kFP64QuietNaNMask); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| inline float ToQuietNaN(float num) { | ||||
|   const uint32_t kFP32QuietNaNMask = 0x00400000; | ||||
|   VIXL_ASSERT(isnan(num)); | ||||
|   VIXL_ASSERT(std::isnan(num)); | ||||
|   return rawbits_to_float(float_to_rawbits(num) | kFP32QuietNaNMask); | ||||
| } | ||||
| 
 | ||||
| @@ -158,16 +178,71 @@ inline float FusedMultiplyAdd(float op1, float op2, float a) { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // Bit counting.
 | ||||
| int CountLeadingZeros(uint64_t value, int width); | ||||
| int CountLeadingSignBits(int64_t value, int width); | ||||
| int CountTrailingZeros(uint64_t value, int width); | ||||
| int CountSetBits(uint64_t value, int width); | ||||
| uint64_t LowestSetBit(uint64_t value); | ||||
| bool IsPowerOf2(int64_t value); | ||||
| inline uint64_t LowestSetBit(uint64_t value) { | ||||
|   return value & -value; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| template<typename T> | ||||
| inline int HighestSetBitPosition(T value) { | ||||
|   VIXL_ASSERT(value != 0); | ||||
|   return (sizeof(value) * 8 - 1) - CountLeadingZeros(value); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| template<typename V> | ||||
| inline int WhichPowerOf2(V value) { | ||||
|   VIXL_ASSERT(IsPowerOf2(value)); | ||||
|   return CountTrailingZeros(value); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size); | ||||
| 
 | ||||
| 
 | ||||
| template <typename T> | ||||
| T ReverseBits(T value) { | ||||
|   VIXL_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) || | ||||
|               (sizeof(value) == 4) || (sizeof(value) == 8)); | ||||
|   T result = 0; | ||||
|   for (unsigned i = 0; i < (sizeof(value) * 8); i++) { | ||||
|     result = (result << 1) | (value & 1); | ||||
|     value >>= 1; | ||||
|   } | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| template <typename T> | ||||
| T ReverseBytes(T value, int block_bytes_log2) { | ||||
|   VIXL_ASSERT((sizeof(value) == 4) || (sizeof(value) == 8)); | ||||
|   VIXL_ASSERT((1U << block_bytes_log2) <= sizeof(value)); | ||||
|   // Split the 64-bit value into an 8-bit array, where b[0] is the least
 | ||||
|   // significant byte, and b[7] is the most significant.
 | ||||
|   uint8_t bytes[8]; | ||||
|   uint64_t mask = UINT64_C(0xff00000000000000); | ||||
|   for (int i = 7; i >= 0; i--) { | ||||
|     bytes[i] = (static_cast<uint64_t>(value) & mask) >> (i * 8); | ||||
|     mask >>= 8; | ||||
|   } | ||||
| 
 | ||||
|   // Permutation tables for REV instructions.
 | ||||
|   //  permute_table[0] is used by REV16_x, REV16_w
 | ||||
|   //  permute_table[1] is used by REV32_x, REV_w
 | ||||
|   //  permute_table[2] is used by REV_x
 | ||||
|   VIXL_ASSERT((0 < block_bytes_log2) && (block_bytes_log2 < 4)); | ||||
|   static const uint8_t permute_table[3][8] = { {6, 7, 4, 5, 2, 3, 0, 1}, | ||||
|                                                {4, 5, 6, 7, 0, 1, 2, 3}, | ||||
|                                                {0, 1, 2, 3, 4, 5, 6, 7} }; | ||||
|   T result = 0; | ||||
|   for (int i = 0; i < 8; i++) { | ||||
|     result <<= 8; | ||||
|     result |= bytes[permute_table[block_bytes_log2 - 1][i]]; | ||||
|   } | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // Pointer alignment
 | ||||
| // TODO: rename/refactor to make it specific to instructions.
 | ||||
| template<typename T> | ||||
| @@ -496,6 +496,20 @@ Example: | ||||
| {"timestamp": {"seconds": 1432121972, "microseconds": 744001}, | ||||
|  "event": "MIGRATION", "data": {"status": "completed"}} | ||||
|  | ||||
| MIGRATION_PASS | ||||
| -------------- | ||||
|  | ||||
| Emitted from the source side of a migration at the start of each pass | ||||
| (when it syncs the dirty bitmap) | ||||
|  | ||||
| Data: None. | ||||
|  | ||||
|   - "pass": An incrementing count (starting at 1 on the first pass) | ||||
|  | ||||
| Example: | ||||
| {"timestamp": {"seconds": 1449669631, "microseconds": 239225}, | ||||
|  "event": "MIGRATION_PASS", "data": {"pass": 2}} | ||||
|  | ||||
| STOP | ||||
| ---- | ||||
|  | ||||
|   | ||||
							
								
								
									
										131
									
								
								dump.c
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								dump.c
									
									
									
									
									
								
							| @@ -347,18 +347,18 @@ static void write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start, | ||||
|     int64_t i; | ||||
|     Error *local_err = NULL; | ||||
|  | ||||
|     for (i = 0; i < size / TARGET_PAGE_SIZE; i++) { | ||||
|         write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, | ||||
|                    TARGET_PAGE_SIZE, &local_err); | ||||
|     for (i = 0; i < size / s->dump_info.page_size; i++) { | ||||
|         write_data(s, block->host_addr + start + i * s->dump_info.page_size, | ||||
|                    s->dump_info.page_size, &local_err); | ||||
|         if (local_err) { | ||||
|             error_propagate(errp, local_err); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if ((size % TARGET_PAGE_SIZE) != 0) { | ||||
|         write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, | ||||
|                    size % TARGET_PAGE_SIZE, &local_err); | ||||
|     if ((size % s->dump_info.page_size) != 0) { | ||||
|         write_data(s, block->host_addr + start + i * s->dump_info.page_size, | ||||
|                    size % s->dump_info.page_size, &local_err); | ||||
|         if (local_err) { | ||||
|             error_propagate(errp, local_err); | ||||
|             return; | ||||
| @@ -737,7 +737,7 @@ static void create_header32(DumpState *s, Error **errp) | ||||
|  | ||||
|     strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE)); | ||||
|     dh->header_version = cpu_to_dump32(s, 6); | ||||
|     block_size = TARGET_PAGE_SIZE; | ||||
|     block_size = s->dump_info.page_size; | ||||
|     dh->block_size = cpu_to_dump32(s, block_size); | ||||
|     sub_hdr_size = sizeof(struct KdumpSubHeader32) + s->note_size; | ||||
|     sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size); | ||||
| @@ -775,7 +775,7 @@ static void create_header32(DumpState *s, Error **errp) | ||||
|  | ||||
|     /* 64bit max_mapnr_64 */ | ||||
|     kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr); | ||||
|     kh->phys_base = cpu_to_dump32(s, PHYS_BASE); | ||||
|     kh->phys_base = cpu_to_dump32(s, s->dump_info.phys_base); | ||||
|     kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); | ||||
|  | ||||
|     offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; | ||||
| @@ -837,7 +837,7 @@ static void create_header64(DumpState *s, Error **errp) | ||||
|  | ||||
|     strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE)); | ||||
|     dh->header_version = cpu_to_dump32(s, 6); | ||||
|     block_size = TARGET_PAGE_SIZE; | ||||
|     block_size = s->dump_info.page_size; | ||||
|     dh->block_size = cpu_to_dump32(s, block_size); | ||||
|     sub_hdr_size = sizeof(struct KdumpSubHeader64) + s->note_size; | ||||
|     sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size); | ||||
| @@ -875,7 +875,7 @@ static void create_header64(DumpState *s, Error **errp) | ||||
|  | ||||
|     /* 64bit max_mapnr_64 */ | ||||
|     kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr); | ||||
|     kh->phys_base = cpu_to_dump64(s, PHYS_BASE); | ||||
|     kh->phys_base = cpu_to_dump64(s, s->dump_info.phys_base); | ||||
|     kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); | ||||
|  | ||||
|     offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; | ||||
| @@ -933,6 +933,11 @@ static void write_dump_header(DumpState *s, Error **errp) | ||||
|     } | ||||
| } | ||||
|  | ||||
| static size_t dump_bitmap_get_bufsize(DumpState *s) | ||||
| { | ||||
|     return s->dump_info.page_size; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * set dump_bitmap sequencely. the bit before last_pfn is not allowed to be | ||||
|  * rewritten, so if need to set the first bit, set last_pfn and pfn to 0. | ||||
| @@ -946,6 +951,8 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value, | ||||
|     off_t old_offset, new_offset; | ||||
|     off_t offset_bitmap1, offset_bitmap2; | ||||
|     uint32_t byte, bit; | ||||
|     size_t bitmap_bufsize = dump_bitmap_get_bufsize(s); | ||||
|     size_t bits_per_buf = bitmap_bufsize * CHAR_BIT; | ||||
|  | ||||
|     /* should not set the previous place */ | ||||
|     assert(last_pfn <= pfn); | ||||
| @@ -956,14 +963,14 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value, | ||||
|      * making new_offset be bigger than old_offset can also sync remained data | ||||
|      * into vmcore. | ||||
|      */ | ||||
|     old_offset = BUFSIZE_BITMAP * (last_pfn / PFN_BUFBITMAP); | ||||
|     new_offset = BUFSIZE_BITMAP * (pfn / PFN_BUFBITMAP); | ||||
|     old_offset = bitmap_bufsize * (last_pfn / bits_per_buf); | ||||
|     new_offset = bitmap_bufsize * (pfn / bits_per_buf); | ||||
|  | ||||
|     while (old_offset < new_offset) { | ||||
|         /* calculate the offset and write dump_bitmap */ | ||||
|         offset_bitmap1 = s->offset_dump_bitmap + old_offset; | ||||
|         if (write_buffer(s->fd, offset_bitmap1, buf, | ||||
|                          BUFSIZE_BITMAP) < 0) { | ||||
|                          bitmap_bufsize) < 0) { | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
| @@ -971,17 +978,17 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value, | ||||
|         offset_bitmap2 = s->offset_dump_bitmap + s->len_dump_bitmap + | ||||
|                          old_offset; | ||||
|         if (write_buffer(s->fd, offset_bitmap2, buf, | ||||
|                          BUFSIZE_BITMAP) < 0) { | ||||
|                          bitmap_bufsize) < 0) { | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         memset(buf, 0, BUFSIZE_BITMAP); | ||||
|         old_offset += BUFSIZE_BITMAP; | ||||
|         memset(buf, 0, bitmap_bufsize); | ||||
|         old_offset += bitmap_bufsize; | ||||
|     } | ||||
|  | ||||
|     /* get the exact place of the bit in the buf, and set it */ | ||||
|     byte = (pfn % PFN_BUFBITMAP) / CHAR_BIT; | ||||
|     bit = (pfn % PFN_BUFBITMAP) % CHAR_BIT; | ||||
|     byte = (pfn % bits_per_buf) / CHAR_BIT; | ||||
|     bit = (pfn % bits_per_buf) % CHAR_BIT; | ||||
|     if (value) { | ||||
|         buf[byte] |= 1u << bit; | ||||
|     } else { | ||||
| @@ -991,6 +998,20 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value, | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static uint64_t dump_paddr_to_pfn(DumpState *s, uint64_t addr) | ||||
| { | ||||
|     int target_page_shift = ctz32(s->dump_info.page_size); | ||||
|  | ||||
|     return (addr >> target_page_shift) - ARCH_PFN_OFFSET; | ||||
| } | ||||
|  | ||||
| static uint64_t dump_pfn_to_paddr(DumpState *s, uint64_t pfn) | ||||
| { | ||||
|     int target_page_shift = ctz32(s->dump_info.page_size); | ||||
|  | ||||
|     return (pfn + ARCH_PFN_OFFSET) << target_page_shift; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * exam every page and return the page frame number and the address of the page. | ||||
|  * bufptr can be NULL. note: the blocks here is supposed to reflect guest-phys | ||||
| @@ -1001,16 +1022,16 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr, | ||||
|                           uint8_t **bufptr, DumpState *s) | ||||
| { | ||||
|     GuestPhysBlock *block = *blockptr; | ||||
|     hwaddr addr; | ||||
|     hwaddr addr, target_page_mask = ~((hwaddr)s->dump_info.page_size - 1); | ||||
|     uint8_t *buf; | ||||
|  | ||||
|     /* block == NULL means the start of the iteration */ | ||||
|     if (!block) { | ||||
|         block = QTAILQ_FIRST(&s->guest_phys_blocks.head); | ||||
|         *blockptr = block; | ||||
|         assert((block->target_start & ~TARGET_PAGE_MASK) == 0); | ||||
|         assert((block->target_end & ~TARGET_PAGE_MASK) == 0); | ||||
|         *pfnptr = paddr_to_pfn(block->target_start); | ||||
|         assert((block->target_start & ~target_page_mask) == 0); | ||||
|         assert((block->target_end & ~target_page_mask) == 0); | ||||
|         *pfnptr = dump_paddr_to_pfn(s, block->target_start); | ||||
|         if (bufptr) { | ||||
|             *bufptr = block->host_addr; | ||||
|         } | ||||
| @@ -1018,10 +1039,10 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr, | ||||
|     } | ||||
|  | ||||
|     *pfnptr = *pfnptr + 1; | ||||
|     addr = pfn_to_paddr(*pfnptr); | ||||
|     addr = dump_pfn_to_paddr(s, *pfnptr); | ||||
|  | ||||
|     if ((addr >= block->target_start) && | ||||
|         (addr + TARGET_PAGE_SIZE <= block->target_end)) { | ||||
|         (addr + s->dump_info.page_size <= block->target_end)) { | ||||
|         buf = block->host_addr + (addr - block->target_start); | ||||
|     } else { | ||||
|         /* the next page is in the next block */ | ||||
| @@ -1030,9 +1051,9 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr, | ||||
|         if (!block) { | ||||
|             return false; | ||||
|         } | ||||
|         assert((block->target_start & ~TARGET_PAGE_MASK) == 0); | ||||
|         assert((block->target_end & ~TARGET_PAGE_MASK) == 0); | ||||
|         *pfnptr = paddr_to_pfn(block->target_start); | ||||
|         assert((block->target_start & ~target_page_mask) == 0); | ||||
|         assert((block->target_end & ~target_page_mask) == 0); | ||||
|         *pfnptr = dump_paddr_to_pfn(s, block->target_start); | ||||
|         buf = block->host_addr; | ||||
|     } | ||||
|  | ||||
| @@ -1050,9 +1071,11 @@ static void write_dump_bitmap(DumpState *s, Error **errp) | ||||
|     void *dump_bitmap_buf; | ||||
|     size_t num_dumpable; | ||||
|     GuestPhysBlock *block_iter = NULL; | ||||
|     size_t bitmap_bufsize = dump_bitmap_get_bufsize(s); | ||||
|     size_t bits_per_buf = bitmap_bufsize * CHAR_BIT; | ||||
|  | ||||
|     /* dump_bitmap_buf is used to store dump_bitmap temporarily */ | ||||
|     dump_bitmap_buf = g_malloc0(BUFSIZE_BITMAP); | ||||
|     dump_bitmap_buf = g_malloc0(bitmap_bufsize); | ||||
|  | ||||
|     num_dumpable = 0; | ||||
|     last_pfn = 0; | ||||
| @@ -1074,11 +1097,11 @@ static void write_dump_bitmap(DumpState *s, Error **errp) | ||||
|  | ||||
|     /* | ||||
|      * set_dump_bitmap will always leave the recently set bit un-sync. Here we | ||||
|      * set last_pfn + PFN_BUFBITMAP to 0 and those set but un-sync bit will be | ||||
|      * synchronized into vmcore. | ||||
|      * set the remaining bits from last_pfn to the end of the bitmap buffer to | ||||
|      * 0. With those set, the un-sync bit will be synchronized into the vmcore. | ||||
|      */ | ||||
|     if (num_dumpable > 0) { | ||||
|         ret = set_dump_bitmap(last_pfn, last_pfn + PFN_BUFBITMAP, false, | ||||
|         ret = set_dump_bitmap(last_pfn, last_pfn + bits_per_buf, false, | ||||
|                               dump_bitmap_buf, s); | ||||
|         if (ret < 0) { | ||||
|             dump_error(s, "dump: failed to sync dump_bitmap", errp); | ||||
| @@ -1098,8 +1121,8 @@ static void prepare_data_cache(DataCache *data_cache, DumpState *s, | ||||
| { | ||||
|     data_cache->fd = s->fd; | ||||
|     data_cache->data_size = 0; | ||||
|     data_cache->buf_size = BUFSIZE_DATA_CACHE; | ||||
|     data_cache->buf = g_malloc0(BUFSIZE_DATA_CACHE); | ||||
|     data_cache->buf_size = 4 * dump_bitmap_get_bufsize(s); | ||||
|     data_cache->buf = g_malloc0(data_cache->buf_size); | ||||
|     data_cache->offset = offset; | ||||
| } | ||||
|  | ||||
| @@ -1193,7 +1216,7 @@ static void write_dump_pages(DumpState *s, Error **errp) | ||||
|     prepare_data_cache(&page_data, s, offset_data); | ||||
|  | ||||
|     /* prepare buffer to store compressed data */ | ||||
|     len_buf_out = get_len_buf_out(TARGET_PAGE_SIZE, s->flag_compress); | ||||
|     len_buf_out = get_len_buf_out(s->dump_info.page_size, s->flag_compress); | ||||
|     assert(len_buf_out != 0); | ||||
|  | ||||
| #ifdef CONFIG_LZO | ||||
| @@ -1206,19 +1229,19 @@ static void write_dump_pages(DumpState *s, Error **errp) | ||||
|      * init zero page's page_desc and page_data, because every zero page | ||||
|      * uses the same page_data | ||||
|      */ | ||||
|     pd_zero.size = cpu_to_dump32(s, TARGET_PAGE_SIZE); | ||||
|     pd_zero.size = cpu_to_dump32(s, s->dump_info.page_size); | ||||
|     pd_zero.flags = cpu_to_dump32(s, 0); | ||||
|     pd_zero.offset = cpu_to_dump64(s, offset_data); | ||||
|     pd_zero.page_flags = cpu_to_dump64(s, 0); | ||||
|     buf = g_malloc0(TARGET_PAGE_SIZE); | ||||
|     ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false); | ||||
|     buf = g_malloc0(s->dump_info.page_size); | ||||
|     ret = write_cache(&page_data, buf, s->dump_info.page_size, false); | ||||
|     g_free(buf); | ||||
|     if (ret < 0) { | ||||
|         dump_error(s, "dump: failed to write page data (zero page)", errp); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     offset_data += TARGET_PAGE_SIZE; | ||||
|     offset_data += s->dump_info.page_size; | ||||
|  | ||||
|     /* | ||||
|      * dump memory to vmcore page by page. zero page will all be resided in the | ||||
| @@ -1226,7 +1249,7 @@ static void write_dump_pages(DumpState *s, Error **errp) | ||||
|      */ | ||||
|     while (get_next_page(&block_iter, &pfn_iter, &buf, s)) { | ||||
|         /* check zero page */ | ||||
|         if (is_zero_page(buf, TARGET_PAGE_SIZE)) { | ||||
|         if (is_zero_page(buf, s->dump_info.page_size)) { | ||||
|             ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor), | ||||
|                               false); | ||||
|             if (ret < 0) { | ||||
| @@ -1248,8 +1271,8 @@ static void write_dump_pages(DumpState *s, Error **errp) | ||||
|              size_out = len_buf_out; | ||||
|              if ((s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) && | ||||
|                     (compress2(buf_out, (uLongf *)&size_out, buf, | ||||
|                                TARGET_PAGE_SIZE, Z_BEST_SPEED) == Z_OK) && | ||||
|                     (size_out < TARGET_PAGE_SIZE)) { | ||||
|                                s->dump_info.page_size, Z_BEST_SPEED) == Z_OK) && | ||||
|                     (size_out < s->dump_info.page_size)) { | ||||
|                 pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_ZLIB); | ||||
|                 pd.size  = cpu_to_dump32(s, size_out); | ||||
|  | ||||
| @@ -1260,9 +1283,9 @@ static void write_dump_pages(DumpState *s, Error **errp) | ||||
|                 } | ||||
| #ifdef CONFIG_LZO | ||||
|             } else if ((s->flag_compress & DUMP_DH_COMPRESSED_LZO) && | ||||
|                     (lzo1x_1_compress(buf, TARGET_PAGE_SIZE, buf_out, | ||||
|                     (lzo1x_1_compress(buf, s->dump_info.page_size, buf_out, | ||||
|                     (lzo_uint *)&size_out, wrkmem) == LZO_E_OK) && | ||||
|                     (size_out < TARGET_PAGE_SIZE)) { | ||||
|                     (size_out < s->dump_info.page_size)) { | ||||
|                 pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_LZO); | ||||
|                 pd.size  = cpu_to_dump32(s, size_out); | ||||
|  | ||||
| @@ -1274,9 +1297,9 @@ static void write_dump_pages(DumpState *s, Error **errp) | ||||
| #endif | ||||
| #ifdef CONFIG_SNAPPY | ||||
|             } else if ((s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) && | ||||
|                     (snappy_compress((char *)buf, TARGET_PAGE_SIZE, | ||||
|                     (snappy_compress((char *)buf, s->dump_info.page_size, | ||||
|                     (char *)buf_out, &size_out) == SNAPPY_OK) && | ||||
|                     (size_out < TARGET_PAGE_SIZE)) { | ||||
|                     (size_out < s->dump_info.page_size)) { | ||||
|                 pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_SNAPPY); | ||||
|                 pd.size  = cpu_to_dump32(s, size_out); | ||||
|  | ||||
| @@ -1289,13 +1312,14 @@ static void write_dump_pages(DumpState *s, Error **errp) | ||||
|             } else { | ||||
|                 /* | ||||
|                  * fall back to save in plaintext, size_out should be | ||||
|                  * assigned TARGET_PAGE_SIZE | ||||
|                  * assigned the target's page size | ||||
|                  */ | ||||
|                 pd.flags = cpu_to_dump32(s, 0); | ||||
|                 size_out = TARGET_PAGE_SIZE; | ||||
|                 size_out = s->dump_info.page_size; | ||||
|                 pd.size = cpu_to_dump32(s, size_out); | ||||
|  | ||||
|                 ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false); | ||||
|                 ret = write_cache(&page_data, buf, | ||||
|                                   s->dump_info.page_size, false); | ||||
|                 if (ret < 0) { | ||||
|                     dump_error(s, "dump: failed to write page data", errp); | ||||
|                     goto out; | ||||
| @@ -1430,7 +1454,7 @@ static void get_max_mapnr(DumpState *s) | ||||
|     GuestPhysBlock *last_block; | ||||
|  | ||||
|     last_block = QTAILQ_LAST(&s->guest_phys_blocks.head, GuestPhysBlockHead); | ||||
|     s->max_mapnr = paddr_to_pfn(last_block->target_end); | ||||
|     s->max_mapnr = dump_paddr_to_pfn(s, last_block->target_end); | ||||
| } | ||||
|  | ||||
| static void dump_init(DumpState *s, int fd, bool has_format, | ||||
| @@ -1489,6 +1513,10 @@ static void dump_init(DumpState *s, int fd, bool has_format, | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|     if (!s->dump_info.page_size) { | ||||
|         s->dump_info.page_size = TARGET_PAGE_SIZE; | ||||
|     } | ||||
|  | ||||
|     s->note_size = cpu_get_note_size(s->dump_info.d_class, | ||||
|                                      s->dump_info.d_machine, nr_cpus); | ||||
|     if (s->note_size < 0) { | ||||
| @@ -1512,8 +1540,9 @@ static void dump_init(DumpState *s, int fd, bool has_format, | ||||
|     get_max_mapnr(s); | ||||
|  | ||||
|     uint64_t tmp; | ||||
|     tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT), TARGET_PAGE_SIZE); | ||||
|     s->len_dump_bitmap = tmp * TARGET_PAGE_SIZE; | ||||
|     tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT), | ||||
|                        s->dump_info.page_size); | ||||
|     s->len_dump_bitmap = tmp * s->dump_info.page_size; | ||||
|  | ||||
|     /* init for kdump-compressed format */ | ||||
|     if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { | ||||
|   | ||||
							
								
								
									
										10
									
								
								exec.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								exec.c
									
									
									
									
									
								
							| @@ -1757,6 +1757,16 @@ int qemu_get_ram_fd(ram_addr_t addr) | ||||
|     return fd; | ||||
| } | ||||
|  | ||||
| void qemu_set_ram_fd(ram_addr_t addr, int fd) | ||||
| { | ||||
|     RAMBlock *block; | ||||
|  | ||||
|     rcu_read_lock(); | ||||
|     block = qemu_get_ram_block(addr); | ||||
|     block->fd = fd; | ||||
|     rcu_read_unlock(); | ||||
| } | ||||
|  | ||||
| void *qemu_get_ram_block_host_ptr(ram_addr_t addr) | ||||
| { | ||||
|     RAMBlock *block; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p backend | ||||
|  * 9p backend | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2010 | ||||
|  * | ||||
| @@ -22,40 +22,9 @@ | ||||
| #include <errno.h> | ||||
| 
 | ||||
| #include "qemu/compiler.h" | ||||
| #include "virtio-9p-marshal.h" | ||||
| #include "9p-iov-marshal.h" | ||||
| #include "qemu/bswap.h" | ||||
| 
 | ||||
| void v9fs_string_free(V9fsString *str) | ||||
| { | ||||
|     g_free(str->data); | ||||
|     str->data = NULL; | ||||
|     str->size = 0; | ||||
| } | ||||
| 
 | ||||
| void v9fs_string_null(V9fsString *str) | ||||
| { | ||||
|     v9fs_string_free(str); | ||||
| } | ||||
| 
 | ||||
| void GCC_FMT_ATTR(2, 3) | ||||
| v9fs_string_sprintf(V9fsString *str, const char *fmt, ...) | ||||
| { | ||||
|     va_list ap; | ||||
| 
 | ||||
|     v9fs_string_free(str); | ||||
| 
 | ||||
|     va_start(ap, fmt); | ||||
|     str->size = g_vasprintf(&str->data, fmt, ap); | ||||
|     va_end(ap); | ||||
| } | ||||
| 
 | ||||
| void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs) | ||||
| { | ||||
|     v9fs_string_free(lhs); | ||||
|     v9fs_string_sprintf(lhs, "%s", rhs->data); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count, | ||||
|                                size_t offset, size_t size, int pack) | ||||
| { | ||||
| @@ -107,15 +76,13 @@ ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset, | ||||
|     return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1); | ||||
| } | ||||
| 
 | ||||
| ssize_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset, | ||||
|                        int bswap, const char *fmt, ...) | ||||
| ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset, | ||||
|                             int bswap, const char *fmt, va_list ap) | ||||
| { | ||||
|     int i; | ||||
|     va_list ap; | ||||
|     ssize_t copied = 0; | ||||
|     size_t old_offset = offset; | ||||
| 
 | ||||
|     va_start(ap, fmt); | ||||
|     for (i = 0; fmt[i]; i++) { | ||||
|         switch (fmt[i]) { | ||||
|         case 'b': { | ||||
| @@ -158,7 +125,7 @@ ssize_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset, | ||||
|         } | ||||
|         case 's': { | ||||
|             V9fsString *str = va_arg(ap, V9fsString *); | ||||
|             copied = v9fs_unmarshal(out_sg, out_num, offset, bswap, | ||||
|             copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap, | ||||
|                                         "w", &str->size); | ||||
|             if (copied > 0) { | ||||
|                 offset += copied; | ||||
| @@ -175,56 +142,70 @@ ssize_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset, | ||||
|         } | ||||
|         case 'Q': { | ||||
|             V9fsQID *qidp = va_arg(ap, V9fsQID *); | ||||
|             copied = v9fs_unmarshal(out_sg, out_num, offset, bswap, "bdq", | ||||
|                                     &qidp->type, &qidp->version, &qidp->path); | ||||
|             copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap, | ||||
|                                         "bdq", &qidp->type, &qidp->version, | ||||
|                                         &qidp->path); | ||||
|             break; | ||||
|         } | ||||
|         case 'S': { | ||||
|             V9fsStat *statp = va_arg(ap, V9fsStat *); | ||||
|             copied = v9fs_unmarshal(out_sg, out_num, offset, bswap, | ||||
|             copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap, | ||||
|                                         "wwdQdddqsssssddd", | ||||
|                                     &statp->size, &statp->type, &statp->dev, | ||||
|                                     &statp->qid, &statp->mode, &statp->atime, | ||||
|                                         &statp->size, &statp->type, | ||||
|                                         &statp->dev, &statp->qid, | ||||
|                                         &statp->mode, &statp->atime, | ||||
|                                         &statp->mtime, &statp->length, | ||||
|                                     &statp->name, &statp->uid, &statp->gid, | ||||
|                                     &statp->muid, &statp->extension, | ||||
|                                         &statp->name, &statp->uid, | ||||
|                                         &statp->gid, &statp->muid, | ||||
|                                         &statp->extension, | ||||
|                                         &statp->n_uid, &statp->n_gid, | ||||
|                                         &statp->n_muid); | ||||
|             break; | ||||
|         } | ||||
|         case 'I': { | ||||
|             V9fsIattr *iattr = va_arg(ap, V9fsIattr *); | ||||
|             copied = v9fs_unmarshal(out_sg, out_num, offset, bswap, | ||||
|             copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap, | ||||
|                                         "ddddqqqqq", | ||||
|                                         &iattr->valid, &iattr->mode, | ||||
|                                     &iattr->uid, &iattr->gid, &iattr->size, | ||||
|                                     &iattr->atime_sec, &iattr->atime_nsec, | ||||
|                                     &iattr->mtime_sec, &iattr->mtime_nsec); | ||||
|                                         &iattr->uid, &iattr->gid, | ||||
|                                         &iattr->size, &iattr->atime_sec, | ||||
|                                         &iattr->atime_nsec, | ||||
|                                         &iattr->mtime_sec, | ||||
|                                         &iattr->mtime_nsec); | ||||
|             break; | ||||
|         } | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|         if (copied < 0) { | ||||
|             va_end(ap); | ||||
|             return copied; | ||||
|         } | ||||
|         offset += copied; | ||||
|     } | ||||
|     va_end(ap); | ||||
| 
 | ||||
|     return offset - old_offset; | ||||
| } | ||||
| 
 | ||||
| ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset, | ||||
| ssize_t v9fs_iov_unmarshal(struct iovec *out_sg, int out_num, size_t offset, | ||||
|                            int bswap, const char *fmt, ...) | ||||
| { | ||||
|     int i; | ||||
|     ssize_t ret; | ||||
|     va_list ap; | ||||
| 
 | ||||
|     va_start(ap, fmt); | ||||
|     ret = v9fs_iov_vunmarshal(out_sg, out_num, offset, bswap, fmt, ap); | ||||
|     va_end(ap); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| ssize_t v9fs_iov_vmarshal(struct iovec *in_sg, int in_num, size_t offset, | ||||
|                           int bswap, const char *fmt, va_list ap) | ||||
| { | ||||
|     int i; | ||||
|     ssize_t copied = 0; | ||||
|     size_t old_offset = offset; | ||||
| 
 | ||||
|     va_start(ap, fmt); | ||||
|     for (i = 0; fmt[i]; i++) { | ||||
|         switch (fmt[i]) { | ||||
|         case 'b': { | ||||
| @@ -264,7 +245,7 @@ ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset, | ||||
|         } | ||||
|         case 's': { | ||||
|             V9fsString *str = va_arg(ap, V9fsString *); | ||||
|             copied = v9fs_marshal(in_sg, in_num, offset, bswap, | ||||
|             copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, | ||||
|                                       "w", str->size); | ||||
|             if (copied > 0) { | ||||
|                 offset += copied; | ||||
| @@ -274,17 +255,19 @@ ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset, | ||||
|         } | ||||
|         case 'Q': { | ||||
|             V9fsQID *qidp = va_arg(ap, V9fsQID *); | ||||
|             copied = v9fs_marshal(in_sg, in_num, offset, bswap, "bdq", | ||||
|                                   qidp->type, qidp->version, qidp->path); | ||||
|             copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, "bdq", | ||||
|                                       qidp->type, qidp->version, | ||||
|                                       qidp->path); | ||||
|             break; | ||||
|         } | ||||
|         case 'S': { | ||||
|             V9fsStat *statp = va_arg(ap, V9fsStat *); | ||||
|             copied = v9fs_marshal(in_sg, in_num, offset, bswap, | ||||
|             copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, | ||||
|                                       "wwdQdddqsssssddd", | ||||
|                                       statp->size, statp->type, statp->dev, | ||||
|                                       &statp->qid, statp->mode, statp->atime, | ||||
|                                   statp->mtime, statp->length, &statp->name, | ||||
|                                       statp->mtime, statp->length, | ||||
|                                       &statp->name, | ||||
|                                       &statp->uid, &statp->gid, &statp->muid, | ||||
|                                       &statp->extension, statp->n_uid, | ||||
|                                       statp->n_gid, statp->n_muid); | ||||
| @@ -292,7 +275,7 @@ ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset, | ||||
|         } | ||||
|         case 'A': { | ||||
|             V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *); | ||||
|             copied = v9fs_marshal(in_sg, in_num, offset, bswap, | ||||
|             copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, | ||||
|                                       "qQdddqqqqqqqqqqqqqqq", | ||||
|                                       statp->st_result_mask, | ||||
|                                       &statp->qid, statp->st_mode, | ||||
| @@ -300,9 +283,12 @@ ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset, | ||||
|                                       statp->st_nlink, statp->st_rdev, | ||||
|                                       statp->st_size, statp->st_blksize, | ||||
|                                       statp->st_blocks, statp->st_atime_sec, | ||||
|                                    statp->st_atime_nsec, statp->st_mtime_sec, | ||||
|                                    statp->st_mtime_nsec, statp->st_ctime_sec, | ||||
|                                    statp->st_ctime_nsec, statp->st_btime_sec, | ||||
|                                       statp->st_atime_nsec, | ||||
|                                       statp->st_mtime_sec, | ||||
|                                       statp->st_mtime_nsec, | ||||
|                                       statp->st_ctime_sec, | ||||
|                                       statp->st_ctime_nsec, | ||||
|                                       statp->st_btime_sec, | ||||
|                                       statp->st_btime_nsec, statp->st_gen, | ||||
|                                       statp->st_data_version); | ||||
|             break; | ||||
| @@ -311,12 +297,23 @@ ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset, | ||||
|             break; | ||||
|         } | ||||
|         if (copied < 0) { | ||||
|             va_end(ap); | ||||
|             return copied; | ||||
|         } | ||||
|         offset += copied; | ||||
|     } | ||||
|     va_end(ap); | ||||
| 
 | ||||
|     return offset - old_offset; | ||||
| } | ||||
| 
 | ||||
| ssize_t v9fs_iov_marshal(struct iovec *in_sg, int in_num, size_t offset, | ||||
|                          int bswap, const char *fmt, ...) | ||||
| { | ||||
|     ssize_t ret; | ||||
|     va_list ap; | ||||
| 
 | ||||
|     va_start(ap, fmt); | ||||
|     ret = v9fs_iov_vmarshal(in_sg, in_num, offset, bswap, fmt, ap); | ||||
|     va_end(ap); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
							
								
								
									
										18
									
								
								fsdev/9p-iov-marshal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								fsdev/9p-iov-marshal.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| #ifndef _QEMU_9P_IOV_MARSHAL_H | ||||
| #define _QEMU_9P_IOV_MARSHAL_H | ||||
|  | ||||
| #include "9p-marshal.h" | ||||
|  | ||||
|  | ||||
| ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset, | ||||
|                   const void *src, size_t size); | ||||
| ssize_t v9fs_iov_unmarshal(struct iovec *out_sg, int out_num, size_t offset, | ||||
|                            int bswap, const char *fmt, ...); | ||||
| ssize_t v9fs_iov_marshal(struct iovec *in_sg, int in_num, size_t offset, | ||||
|                          int bswap, const char *fmt, ...); | ||||
|  | ||||
| ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset, | ||||
|                             int bswap, const char *fmt, va_list ap); | ||||
| ssize_t v9fs_iov_vmarshal(struct iovec *in_sg, int in_num, size_t offset, | ||||
|                           int bswap, const char *fmt, va_list ap); | ||||
| #endif | ||||
							
								
								
									
										56
									
								
								fsdev/9p-marshal.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								fsdev/9p-marshal.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| /* | ||||
|  * 9p backend | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2010 | ||||
|  * | ||||
|  * Authors: | ||||
|  *  Anthony Liguori   <aliguori@us.ibm.com> | ||||
|  * | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2.  See | ||||
|  * the COPYING file in the top-level directory. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <glib.h> | ||||
| #include <glib/gprintf.h> | ||||
| #include <sys/types.h> | ||||
| #include <dirent.h> | ||||
| #include <sys/time.h> | ||||
| #include <utime.h> | ||||
| #include <sys/uio.h> | ||||
| #include <string.h> | ||||
| #include <stdint.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #include "qemu/compiler.h" | ||||
| #include "9p-marshal.h" | ||||
|  | ||||
| void v9fs_string_free(V9fsString *str) | ||||
| { | ||||
|     g_free(str->data); | ||||
|     str->data = NULL; | ||||
|     str->size = 0; | ||||
| } | ||||
|  | ||||
| void v9fs_string_null(V9fsString *str) | ||||
| { | ||||
|     v9fs_string_free(str); | ||||
| } | ||||
|  | ||||
| void GCC_FMT_ATTR(2, 3) | ||||
| v9fs_string_sprintf(V9fsString *str, const char *fmt, ...) | ||||
| { | ||||
|     va_list ap; | ||||
|  | ||||
|     v9fs_string_free(str); | ||||
|  | ||||
|     va_start(ap, fmt); | ||||
|     str->size = g_vasprintf(&str->data, fmt, ap); | ||||
|     va_end(ap); | ||||
| } | ||||
|  | ||||
| void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs) | ||||
| { | ||||
|     v9fs_string_free(lhs); | ||||
|     v9fs_string_sprintf(lhs, "%s", rhs->data); | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| #ifndef _QEMU_VIRTIO_9P_MARSHAL_H | ||||
| #define _QEMU_VIRTIO_9P_MARSHAL_H | ||||
| #ifndef _QEMU_9P_MARSHAL_H | ||||
| #define _QEMU_9P_MARSHAL_H | ||||
| 
 | ||||
| typedef struct V9fsString | ||||
| { | ||||
| @@ -81,10 +81,4 @@ extern void v9fs_string_null(V9fsString *str); | ||||
| extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...); | ||||
| extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs); | ||||
| 
 | ||||
| ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset, | ||||
|                   const void *src, size_t size); | ||||
| ssize_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset, | ||||
|                        int bswap, const char *fmt, ...); | ||||
| ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset, | ||||
|                      int bswap, const char *fmt, ...); | ||||
| #endif | ||||
| @@ -1,7 +1,7 @@ | ||||
| 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 | ||||
| common-obj-y = qemu-fsdev.o 9p-marshal.o 9p-iov-marshal.o | ||||
| else | ||||
| common-obj-y = qemu-fsdev-dummy.o | ||||
| endif | ||||
|   | ||||
| @@ -23,9 +23,9 @@ | ||||
| #include "qemu-common.h" | ||||
| #include "qemu/sockets.h" | ||||
| #include "qemu/xattr.h" | ||||
| #include "virtio-9p-marshal.h" | ||||
| #include "hw/9pfs/virtio-9p-proxy.h" | ||||
| #include "fsdev/virtio-9p-marshal.h" | ||||
| #include "9p-iov-marshal.h" | ||||
| #include "hw/9pfs/9p-proxy.h" | ||||
| #include "fsdev/9p-iov-marshal.h" | ||||
|  | ||||
| #define PROGNAME "virtfs-proxy-helper" | ||||
|  | ||||
|   | ||||
| @@ -1732,6 +1732,7 @@ int gdbserver_start(const char *device) | ||||
|     char gdbstub_device_name[128]; | ||||
|     CharDriverState *chr = NULL; | ||||
|     CharDriverState *mon_chr; | ||||
|     ChardevCommon common = { 0 }; | ||||
|  | ||||
|     if (!device) | ||||
|         return -1; | ||||
| @@ -1768,7 +1769,7 @@ int gdbserver_start(const char *device) | ||||
|         qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL); | ||||
|  | ||||
|         /* Initialize a monitor terminal for gdb */ | ||||
|         mon_chr = qemu_chr_alloc(); | ||||
|         mon_chr = qemu_chr_alloc(&common, &error_abort); | ||||
|         mon_chr->chr_write = gdb_monitor_write; | ||||
|         monitor_init(mon_chr, 0); | ||||
|     } else { | ||||
|   | ||||
							
								
								
									
										61
									
								
								hmp.c
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								hmp.c
									
									
									
									
									
								
							| @@ -41,8 +41,7 @@ static void hmp_handle_error(Monitor *mon, Error **errp) | ||||
| { | ||||
|     assert(errp); | ||||
|     if (*errp) { | ||||
|         monitor_printf(mon, "%s\n", error_get_pretty(*errp)); | ||||
|         error_free(*errp); | ||||
|         error_report_err(*errp); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -556,8 +555,7 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict) | ||||
|  | ||||
|     info = qmp_query_vnc(&err); | ||||
|     if (err) { | ||||
|         monitor_printf(mon, "%s\n", error_get_pretty(err)); | ||||
|         error_free(err); | ||||
|         error_report_err(err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -679,8 +677,7 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict) | ||||
|  | ||||
|     info = qmp_query_balloon(&err); | ||||
|     if (err) { | ||||
|         monitor_printf(mon, "%s\n", error_get_pretty(err)); | ||||
|         error_free(err); | ||||
|         error_report_err(err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -948,8 +945,7 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict) | ||||
|  | ||||
|     data = qmp_ringbuf_read(chardev, size, false, 0, &err); | ||||
|     if (err) { | ||||
|         monitor_printf(mon, "%s\n", error_get_pretty(err)); | ||||
|         error_free(err); | ||||
|         error_report_err(err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -1042,8 +1038,7 @@ void hmp_balloon(Monitor *mon, const QDict *qdict) | ||||
|  | ||||
|     qmp_balloon(value, &err); | ||||
|     if (err) { | ||||
|         monitor_printf(mon, "balloon: %s\n", error_get_pretty(err)); | ||||
|         error_free(err); | ||||
|         error_report_err(err); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1191,8 +1186,7 @@ void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict) | ||||
|  | ||||
|     qmp_migrate_set_cache_size(value, &err); | ||||
|     if (err) { | ||||
|         monitor_printf(mon, "%s\n", error_get_pretty(err)); | ||||
|         error_free(err); | ||||
|         error_report_err(err); | ||||
|         return; | ||||
|     } | ||||
| } | ||||
| @@ -1229,9 +1223,7 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict) | ||||
|     qapi_free_MigrationCapabilityStatusList(caps); | ||||
|  | ||||
|     if (err) { | ||||
|         monitor_printf(mon, "migrate_set_capability: %s\n", | ||||
|                        error_get_pretty(err)); | ||||
|         error_free(err); | ||||
|         error_report_err(err); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1281,9 +1273,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) | ||||
|     } | ||||
|  | ||||
|     if (err) { | ||||
|         monitor_printf(mon, "migrate_set_parameter: %s\n", | ||||
|                        error_get_pretty(err)); | ||||
|         error_free(err); | ||||
|         error_report_err(err); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1544,8 +1534,7 @@ void hmp_migrate(Monitor *mon, const QDict *qdict) | ||||
|  | ||||
|     qmp_migrate(uri, !!blk, blk, !!inc, inc, false, false, &err); | ||||
|     if (err) { | ||||
|         monitor_printf(mon, "migrate: %s\n", error_get_pretty(err)); | ||||
|         error_free(err); | ||||
|         error_report_err(err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -2089,11 +2078,11 @@ void hmp_rocker(Monitor *mon, const QDict *qdict) | ||||
| { | ||||
|     const char *name = qdict_get_str(qdict, "name"); | ||||
|     RockerSwitch *rocker; | ||||
|     Error *errp = NULL; | ||||
|     Error *err = NULL; | ||||
|  | ||||
|     rocker = qmp_query_rocker(name, &errp); | ||||
|     if (errp != NULL) { | ||||
|         hmp_handle_error(mon, &errp); | ||||
|     rocker = qmp_query_rocker(name, &err); | ||||
|     if (err != NULL) { | ||||
|         hmp_handle_error(mon, &err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -2108,11 +2097,11 @@ void hmp_rocker_ports(Monitor *mon, const QDict *qdict) | ||||
| { | ||||
|     RockerPortList *list, *port; | ||||
|     const char *name = qdict_get_str(qdict, "name"); | ||||
|     Error *errp = NULL; | ||||
|     Error *err = NULL; | ||||
|  | ||||
|     list = qmp_query_rocker_ports(name, &errp); | ||||
|     if (errp != NULL) { | ||||
|         hmp_handle_error(mon, &errp); | ||||
|     list = qmp_query_rocker_ports(name, &err); | ||||
|     if (err != NULL) { | ||||
|         hmp_handle_error(mon, &err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -2137,11 +2126,11 @@ void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict) | ||||
|     RockerOfDpaFlowList *list, *info; | ||||
|     const char *name = qdict_get_str(qdict, "name"); | ||||
|     uint32_t tbl_id = qdict_get_try_int(qdict, "tbl_id", -1); | ||||
|     Error *errp = NULL; | ||||
|     Error *err = NULL; | ||||
|  | ||||
|     list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &errp); | ||||
|     if (errp != NULL) { | ||||
|         hmp_handle_error(mon, &errp); | ||||
|     list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &err); | ||||
|     if (err != NULL) { | ||||
|         hmp_handle_error(mon, &err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -2287,12 +2276,12 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict) | ||||
|     RockerOfDpaGroupList *list, *g; | ||||
|     const char *name = qdict_get_str(qdict, "name"); | ||||
|     uint8_t type = qdict_get_try_int(qdict, "type", 9); | ||||
|     Error *errp = NULL; | ||||
|     Error *err = NULL; | ||||
|     bool set = false; | ||||
|  | ||||
|     list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &errp); | ||||
|     if (errp != NULL) { | ||||
|         hmp_handle_error(mon, &errp); | ||||
|     list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &err); | ||||
|     if (err != NULL) { | ||||
|         hmp_handle_error(mon, &err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p handle callback | ||||
|  * 9p handle callback | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2011 | ||||
|  * | ||||
| @@ -11,9 +11,8 @@ | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "hw/virtio/virtio.h" | ||||
| #include "virtio-9p.h" | ||||
| #include "virtio-9p-xattr.h" | ||||
| #include "9p.h" | ||||
| #include "9p-xattr.h" | ||||
| #include <arpa/inet.h> | ||||
| #include <pwd.h> | ||||
| #include <grp.h> | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p Posix callback | ||||
|  * 9p Posix callback | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2010 | ||||
|  * | ||||
| @@ -11,9 +11,8 @@ | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "hw/virtio/virtio.h" | ||||
| #include "virtio-9p.h" | ||||
| #include "virtio-9p-xattr.h" | ||||
| #include "9p.h" | ||||
| #include "9p-xattr.h" | ||||
| #include "fsdev/qemu-fsdev.h"   /* local_ops */ | ||||
| #include <arpa/inet.h> | ||||
| #include <pwd.h> | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p system.posix* xattr callback | ||||
|  * 9p system.posix* xattr callback | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2010 | ||||
|  * | ||||
| @@ -13,10 +13,9 @@ | ||||
| 
 | ||||
| #include <sys/types.h> | ||||
| #include "qemu/xattr.h" | ||||
| #include "hw/virtio/virtio.h" | ||||
| #include "virtio-9p.h" | ||||
| #include "9p.h" | ||||
| #include "fsdev/file-op-9p.h" | ||||
| #include "virtio-9p-xattr.h" | ||||
| #include "9p-xattr.h" | ||||
| 
 | ||||
| #define MAP_ACL_ACCESS "user.virtfs.system.posix_acl_access" | ||||
| #define MAP_ACL_DEFAULT "user.virtfs.system.posix_acl_default" | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p Proxy callback | ||||
|  * 9p Proxy callback | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2011 | ||||
|  * | ||||
| @@ -11,11 +11,10 @@ | ||||
|  */ | ||||
| #include <sys/socket.h> | ||||
| #include <sys/un.h> | ||||
| #include "hw/virtio/virtio.h" | ||||
| #include "virtio-9p.h" | ||||
| #include "9p.h" | ||||
| #include "qemu/error-report.h" | ||||
| #include "fsdev/qemu-fsdev.h" | ||||
| #include "virtio-9p-proxy.h" | ||||
| #include "9p-proxy.h" | ||||
| 
 | ||||
| typedef struct V9fsProxy { | ||||
|     int sockfd; | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p Proxy callback | ||||
|  * 9p Proxy callback | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2011 | ||||
|  * | ||||
| @@ -9,8 +9,8 @@ | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2.  See | ||||
|  * the COPYING file in the top-level directory. | ||||
|  */ | ||||
| #ifndef _QEMU_VIRTIO_9P_PROXY_H | ||||
| #define _QEMU_VIRTIO_9P_PROXY_H | ||||
| #ifndef _QEMU_9P_PROXY_H | ||||
| #define _QEMU_9P_PROXY_H | ||||
| 
 | ||||
| #define PROXY_MAX_IO_SZ (64 * 1024) | ||||
| #define V9FS_FD_VALID INT_MAX | ||||
| @@ -20,9 +20,9 @@ | ||||
|  * marsha/unmarshal doesn't do little endian conversion. | ||||
|  */ | ||||
| #define proxy_unmarshal(in_sg, offset, fmt, args...) \ | ||||
|     v9fs_unmarshal(in_sg, 1, offset, 0, fmt, ##args) | ||||
|     v9fs_iov_unmarshal(in_sg, 1, offset, 0, fmt, ##args) | ||||
| #define proxy_marshal(out_sg, offset, fmt, args...) \ | ||||
|     v9fs_marshal(out_sg, 1, offset, 0, fmt, ##args) | ||||
|     v9fs_iov_marshal(out_sg, 1, offset, 0, fmt, ##args) | ||||
| 
 | ||||
| union MsgControl { | ||||
|     struct cmsghdr cmsg; | ||||
| @@ -13,10 +13,10 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include "hw/virtio/virtio.h" | ||||
| #include "virtio-9p.h" | ||||
| #include "virtio-9p-xattr.h" | ||||
| #include "9p.h" | ||||
| #include "9p-xattr.h" | ||||
| #include "fsdev/qemu-fsdev.h" | ||||
| #include "virtio-9p-synth.h" | ||||
| #include "9p-synth.h" | ||||
| #include "qemu/rcu.h" | ||||
| #include "qemu/rcu_queue.h" | ||||
| #include <sys/stat.h> | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p | ||||
|  * 9p | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2011 | ||||
|  * | ||||
| @@ -10,8 +10,8 @@ | ||||
|  * the COPYING file in the top-level directory. | ||||
|  * | ||||
|  */ | ||||
| #ifndef HW_9PFS_VIRTIO9P_SYNTH_H | ||||
| #define HW_9PFS_VIRTIO9P_SYNTH_H 1 | ||||
| #ifndef HW_9PFS_SYNTH_H | ||||
| #define HW_9PFS_SYNTH_H 1 | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| #include <sys/types.h> | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p user. xattr callback | ||||
|  * 9p user. xattr callback | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2010 | ||||
|  * | ||||
| @@ -12,10 +12,9 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include <sys/types.h> | ||||
| #include "hw/virtio/virtio.h" | ||||
| #include "virtio-9p.h" | ||||
| #include "9p.h" | ||||
| #include "fsdev/file-op-9p.h" | ||||
| #include "virtio-9p-xattr.h" | ||||
| #include "9p-xattr.h" | ||||
| 
 | ||||
| 
 | ||||
| static ssize_t mp_user_getxattr(FsContext *ctx, const char *path, | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p  xattr callback | ||||
|  * 9p  xattr callback | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2010 | ||||
|  * | ||||
| @@ -11,10 +11,9 @@ | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "hw/virtio/virtio.h" | ||||
| #include "virtio-9p.h" | ||||
| #include "9p.h" | ||||
| #include "fsdev/file-op-9p.h" | ||||
| #include "virtio-9p-xattr.h" | ||||
| #include "9p-xattr.h" | ||||
| 
 | ||||
| 
 | ||||
| static XattrOperations *get_xattr_operations(XattrOperations **h, | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p | ||||
|  * 9p | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2010 | ||||
|  * | ||||
| @@ -10,8 +10,8 @@ | ||||
|  * the COPYING file in the top-level directory. | ||||
|  * | ||||
|  */ | ||||
| #ifndef _QEMU_VIRTIO_9P_XATTR_H | ||||
| #define _QEMU_VIRTIO_9P_XATTR_H | ||||
| #ifndef _QEMU_9P_XATTR_H | ||||
| #define _QEMU_9P_XATTR_H | ||||
| 
 | ||||
| #include "qemu/xattr.h" | ||||
| 
 | ||||
| @@ -18,8 +18,8 @@ | ||||
| #include "qemu/sockets.h" | ||||
| #include "virtio-9p.h" | ||||
| #include "fsdev/qemu-fsdev.h" | ||||
| #include "virtio-9p-xattr.h" | ||||
| #include "virtio-9p-coth.h" | ||||
| #include "9p-xattr.h" | ||||
| #include "coth.h" | ||||
| #include "trace.h" | ||||
| #include "migration/migration.h" | ||||
| 
 | ||||
| @@ -39,6 +39,35 @@ enum { | ||||
|     Oappend = 0x80, | ||||
| }; | ||||
| 
 | ||||
| ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) | ||||
| { | ||||
|     ssize_t ret; | ||||
|     va_list ap; | ||||
| 
 | ||||
|     va_start(ap, fmt); | ||||
|     ret = virtio_pdu_vmarshal(pdu, offset, fmt, ap); | ||||
|     va_end(ap); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) | ||||
| { | ||||
|     ssize_t ret; | ||||
|     va_list ap; | ||||
| 
 | ||||
|     va_start(ap, fmt); | ||||
|     ret = virtio_pdu_vunmarshal(pdu, offset, fmt, ap); | ||||
|     va_end(ap); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static void pdu_push_and_notify(V9fsPDU *pdu) | ||||
| { | ||||
|     virtio_9p_push_and_notify(pdu); | ||||
| } | ||||
| 
 | ||||
| static int omode_to_uflags(int8_t mode) | ||||
| { | ||||
|     int ret = 0; | ||||
| @@ -563,7 +592,7 @@ static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp) | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static V9fsPDU *alloc_pdu(V9fsState *s) | ||||
| V9fsPDU *pdu_alloc(V9fsState *s) | ||||
| { | ||||
|     V9fsPDU *pdu = NULL; | ||||
| 
 | ||||
| @@ -575,9 +604,10 @@ static V9fsPDU *alloc_pdu(V9fsState *s) | ||||
|     return pdu; | ||||
| } | ||||
| 
 | ||||
| static void free_pdu(V9fsState *s, V9fsPDU *pdu) | ||||
| void pdu_free(V9fsPDU *pdu) | ||||
| { | ||||
|     if (pdu) { | ||||
|         V9fsState *s = pdu->s; | ||||
|         /*
 | ||||
|          * Cancelled pdu are added back to the freelist | ||||
|          * by flush request . | ||||
| @@ -594,9 +624,10 @@ static void free_pdu(V9fsState *s, V9fsPDU *pdu) | ||||
|  * because we always expect to have enough space to encode | ||||
|  * error details | ||||
|  */ | ||||
| static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len) | ||||
| static void pdu_complete(V9fsPDU *pdu, ssize_t len) | ||||
| { | ||||
|     int8_t id = pdu->id + 1; /* Response */ | ||||
|     V9fsState *s = pdu->s; | ||||
| 
 | ||||
|     if (len < 0) { | ||||
|         int err = -len; | ||||
| @@ -627,16 +658,12 @@ static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len) | ||||
|     pdu->size = len; | ||||
|     pdu->id = id; | ||||
| 
 | ||||
|     /* push onto queue and notify */ | ||||
|     virtqueue_push(s->vq, &pdu->elem, len); | ||||
| 
 | ||||
|     /* FIXME: we should batch these completions */ | ||||
|     virtio_notify(VIRTIO_DEVICE(s), s->vq); | ||||
|     pdu_push_and_notify(pdu); | ||||
| 
 | ||||
|     /* Now wakeup anybody waiting in flush for this request */ | ||||
|     qemu_co_queue_next(&pdu->complete); | ||||
| 
 | ||||
|     free_pdu(s, pdu); | ||||
|     pdu_free(pdu); | ||||
| } | ||||
| 
 | ||||
| static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension) | ||||
| @@ -931,7 +958,7 @@ static void v9fs_version(void *opaque) | ||||
|     offset += err; | ||||
|     trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data); | ||||
| out: | ||||
|     complete_pdu(s, pdu, offset); | ||||
|     pdu_complete(pdu, offset); | ||||
|     v9fs_string_free(&version); | ||||
| } | ||||
| 
 | ||||
| @@ -995,7 +1022,7 @@ static void v9fs_attach(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&uname); | ||||
|     v9fs_string_free(&aname); | ||||
| } | ||||
| @@ -1009,7 +1036,6 @@ static void v9fs_stat(void *opaque) | ||||
|     struct stat stbuf; | ||||
|     V9fsFidState *fidp; | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     V9fsState *s = pdu->s; | ||||
| 
 | ||||
|     err = pdu_unmarshal(pdu, offset, "d", &fid); | ||||
|     if (err < 0) { | ||||
| @@ -1042,7 +1068,7 @@ static void v9fs_stat(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
| } | ||||
| 
 | ||||
| static void v9fs_getattr(void *opaque) | ||||
| @@ -1105,7 +1131,7 @@ static void v9fs_getattr(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, retval); | ||||
|     pdu_complete(pdu, retval); | ||||
| } | ||||
| 
 | ||||
| /* Attribute flags */ | ||||
| @@ -1129,7 +1155,6 @@ static void v9fs_setattr(void *opaque) | ||||
|     size_t offset = 7; | ||||
|     V9fsIattr v9iattr; | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     V9fsState *s = pdu->s; | ||||
| 
 | ||||
|     err = pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr); | ||||
|     if (err < 0) { | ||||
| @@ -1203,7 +1228,7 @@ static void v9fs_setattr(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
| } | ||||
| 
 | ||||
| static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids) | ||||
| @@ -1245,7 +1270,7 @@ static void v9fs_walk(void *opaque) | ||||
| 
 | ||||
|     err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames); | ||||
|     if (err < 0) { | ||||
|         complete_pdu(s, pdu, err); | ||||
|         pdu_complete(pdu, err); | ||||
|         return ; | ||||
|     } | ||||
|     offset += err; | ||||
| @@ -1313,7 +1338,7 @@ out: | ||||
|     v9fs_path_free(&dpath); | ||||
|     v9fs_path_free(&path); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     if (nwnames && nwnames <= P9_MAXWELEM) { | ||||
|         for (name_idx = 0; name_idx < nwnames; name_idx++) { | ||||
|             v9fs_string_free(&wnames[name_idx]); | ||||
| @@ -1430,7 +1455,7 @@ static void v9fs_open(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
| } | ||||
| 
 | ||||
| static void v9fs_lcreate(void *opaque) | ||||
| @@ -1487,7 +1512,7 @@ static void v9fs_lcreate(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(pdu->s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&name); | ||||
| } | ||||
| 
 | ||||
| @@ -1499,7 +1524,6 @@ static void v9fs_fsync(void *opaque) | ||||
|     size_t offset = 7; | ||||
|     V9fsFidState *fidp; | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     V9fsState *s = pdu->s; | ||||
| 
 | ||||
|     err = pdu_unmarshal(pdu, offset, "dd", &fid, &datasync); | ||||
|     if (err < 0) { | ||||
| @@ -1518,7 +1542,7 @@ static void v9fs_fsync(void *opaque) | ||||
|     } | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
| } | ||||
| 
 | ||||
| static void v9fs_clunk(void *opaque) | ||||
| @@ -1551,7 +1575,7 @@ static void v9fs_clunk(void *opaque) | ||||
|         err = offset; | ||||
|     } | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
| } | ||||
| 
 | ||||
| static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, | ||||
| @@ -1561,6 +1585,8 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, | ||||
|     size_t offset = 7; | ||||
|     int read_count; | ||||
|     int64_t xattr_len; | ||||
|     V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); | ||||
|     VirtQueueElement *elem = &v->elems[pdu->idx]; | ||||
| 
 | ||||
|     xattr_len = fidp->fs.xattr.len; | ||||
|     read_count = xattr_len - off; | ||||
| @@ -1577,7 +1603,8 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, | ||||
|         return err; | ||||
|     } | ||||
|     offset += err; | ||||
|     err = v9fs_pack(pdu->elem.in_sg, pdu->elem.in_num, offset, | ||||
| 
 | ||||
|     err = v9fs_pack(elem->in_sg, elem->in_num, offset, | ||||
|                     ((char *)fidp->fs.xattr.value) + off, | ||||
|                     read_count); | ||||
|     if (err < 0) { | ||||
| @@ -1667,13 +1694,7 @@ static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu, | ||||
|     struct iovec *iov; | ||||
|     unsigned int niov; | ||||
| 
 | ||||
|     if (is_write) { | ||||
|         iov = pdu->elem.out_sg; | ||||
|         niov = pdu->elem.out_num; | ||||
|     } else { | ||||
|         iov = pdu->elem.in_sg; | ||||
|         niov = pdu->elem.in_num; | ||||
|     } | ||||
|     virtio_init_iov_from_pdu(pdu, &iov, &niov, is_write); | ||||
| 
 | ||||
|     qemu_iovec_init_external(&elem, iov, niov); | ||||
|     qemu_iovec_init(qiov, niov); | ||||
| @@ -1761,7 +1782,7 @@ static void v9fs_read(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
| } | ||||
| 
 | ||||
| static size_t v9fs_readdir_data_size(V9fsString *name) | ||||
| @@ -1848,7 +1869,6 @@ static void v9fs_readdir(void *opaque) | ||||
|     int32_t count; | ||||
|     uint32_t max_count; | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     V9fsState *s = pdu->s; | ||||
| 
 | ||||
|     retval = pdu_unmarshal(pdu, offset, "dqd", &fid, | ||||
|                            &initial_offset, &max_count); | ||||
| @@ -1885,7 +1905,7 @@ static void v9fs_readdir(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, retval); | ||||
|     pdu_complete(pdu, retval); | ||||
| } | ||||
| 
 | ||||
| static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, | ||||
| @@ -1952,7 +1972,7 @@ static void v9fs_write(void *opaque) | ||||
| 
 | ||||
|     err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count); | ||||
|     if (err < 0) { | ||||
|         complete_pdu(s, pdu, err); | ||||
|         pdu_complete(pdu, err); | ||||
|         return; | ||||
|     } | ||||
|     offset += err; | ||||
| @@ -2015,7 +2035,7 @@ out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     qemu_iovec_destroy(&qiov_full); | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
| } | ||||
| 
 | ||||
| static void v9fs_create(void *opaque) | ||||
| @@ -2182,7 +2202,7 @@ static void v9fs_create(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|    complete_pdu(pdu->s, pdu, err); | ||||
|    pdu_complete(pdu, err); | ||||
|    v9fs_string_free(&name); | ||||
|    v9fs_string_free(&extension); | ||||
|    v9fs_path_free(&path); | ||||
| @@ -2229,7 +2249,7 @@ static void v9fs_symlink(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, dfidp); | ||||
| out_nofid: | ||||
|     complete_pdu(pdu->s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&name); | ||||
|     v9fs_string_free(&symname); | ||||
| } | ||||
| @@ -2245,7 +2265,7 @@ static void v9fs_flush(void *opaque) | ||||
| 
 | ||||
|     err = pdu_unmarshal(pdu, offset, "w", &tag); | ||||
|     if (err < 0) { | ||||
|         complete_pdu(s, pdu, err); | ||||
|         pdu_complete(pdu, err); | ||||
|         return; | ||||
|     } | ||||
|     trace_v9fs_flush(pdu->tag, pdu->id, tag); | ||||
| @@ -2262,15 +2282,14 @@ static void v9fs_flush(void *opaque) | ||||
|          */ | ||||
|         qemu_co_queue_wait(&cancel_pdu->complete); | ||||
|         cancel_pdu->cancelled = 0; | ||||
|         free_pdu(pdu->s, cancel_pdu); | ||||
|         pdu_free(cancel_pdu); | ||||
|     } | ||||
|     complete_pdu(s, pdu, 7); | ||||
|     pdu_complete(pdu, 7); | ||||
| } | ||||
| 
 | ||||
| static void v9fs_link(void *opaque) | ||||
| { | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     V9fsState *s = pdu->s; | ||||
|     int32_t dfid, oldfid; | ||||
|     V9fsFidState *dfidp, *oldfidp; | ||||
|     V9fsString name; | ||||
| @@ -2303,7 +2322,7 @@ out: | ||||
|     put_fid(pdu, dfidp); | ||||
| out_nofid: | ||||
|     v9fs_string_free(&name); | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
| } | ||||
| 
 | ||||
| /* Only works with path name based fid */ | ||||
| @@ -2348,7 +2367,7 @@ out_err: | ||||
|     clunk_fid(pdu->s, fidp->fid); | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(pdu->s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
| } | ||||
| 
 | ||||
| static void v9fs_unlinkat(void *opaque) | ||||
| @@ -2392,7 +2411,7 @@ out_err: | ||||
|     put_fid(pdu, dfidp); | ||||
|     v9fs_path_free(&path); | ||||
| out_nofid: | ||||
|     complete_pdu(pdu->s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&name); | ||||
| } | ||||
| 
 | ||||
| @@ -2492,7 +2511,7 @@ static void v9fs_rename(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&name); | ||||
| } | ||||
| 
 | ||||
| @@ -2593,7 +2612,7 @@ static void v9fs_renameat(void *opaque) | ||||
|     } | ||||
| 
 | ||||
| out_err: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&old_name); | ||||
|     v9fs_string_free(&new_name); | ||||
| } | ||||
| @@ -2608,7 +2627,6 @@ static void v9fs_wstat(void *opaque) | ||||
|     struct stat stbuf; | ||||
|     V9fsFidState *fidp; | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     V9fsState *s = pdu->s; | ||||
| 
 | ||||
|     v9fs_stat_init(&v9stat); | ||||
|     err = pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat); | ||||
| @@ -2690,7 +2708,7 @@ out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     v9fs_stat_free(&v9stat); | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
| } | ||||
| 
 | ||||
| static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf) | ||||
| @@ -2769,7 +2787,7 @@ static void v9fs_statfs(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, retval); | ||||
|     pdu_complete(pdu, retval); | ||||
| } | ||||
| 
 | ||||
| static void v9fs_mknod(void *opaque) | ||||
| @@ -2786,7 +2804,6 @@ static void v9fs_mknod(void *opaque) | ||||
|     struct stat stbuf; | ||||
|     V9fsFidState *fidp; | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     V9fsState *s = pdu->s; | ||||
| 
 | ||||
|     v9fs_string_init(&name); | ||||
|     err = pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode, | ||||
| @@ -2817,7 +2834,7 @@ static void v9fs_mknod(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&name); | ||||
| } | ||||
| 
 | ||||
| @@ -2838,7 +2855,6 @@ static void v9fs_lock(void *opaque) | ||||
|     V9fsFidState *fidp; | ||||
|     int32_t fid, err = 0; | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     V9fsState *s = pdu->s; | ||||
| 
 | ||||
|     status = P9_LOCK_ERROR; | ||||
|     v9fs_string_init(&flock.client_id); | ||||
| @@ -2875,7 +2891,7 @@ out_nofid: | ||||
|         err += offset; | ||||
|     } | ||||
|     trace_v9fs_lock_return(pdu->tag, pdu->id, status); | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&flock.client_id); | ||||
| } | ||||
| 
 | ||||
| @@ -2891,7 +2907,6 @@ static void v9fs_getlock(void *opaque) | ||||
|     V9fsGetlock glock; | ||||
|     int32_t fid, err = 0; | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     V9fsState *s = pdu->s; | ||||
| 
 | ||||
|     v9fs_string_init(&glock.client_id); | ||||
|     err = pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock.type, | ||||
| @@ -2925,7 +2940,7 @@ static void v9fs_getlock(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&glock.client_id); | ||||
| } | ||||
| 
 | ||||
| @@ -2969,7 +2984,7 @@ static void v9fs_mkdir(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(pdu->s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&name); | ||||
| } | ||||
| 
 | ||||
| @@ -3075,7 +3090,7 @@ out: | ||||
|         put_fid(pdu, xattr_fidp); | ||||
|     } | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&name); | ||||
| } | ||||
| 
 | ||||
| @@ -3090,7 +3105,6 @@ static void v9fs_xattrcreate(void *opaque) | ||||
|     V9fsFidState *file_fidp; | ||||
|     V9fsFidState *xattr_fidp; | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     V9fsState *s = pdu->s; | ||||
| 
 | ||||
|     v9fs_string_init(&name); | ||||
|     err = pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags); | ||||
| @@ -3116,7 +3130,7 @@ static void v9fs_xattrcreate(void *opaque) | ||||
|     err = offset; | ||||
|     put_fid(pdu, file_fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
|     v9fs_string_free(&name); | ||||
| } | ||||
| 
 | ||||
| @@ -3156,7 +3170,7 @@ static void v9fs_readlink(void *opaque) | ||||
| out: | ||||
|     put_fid(pdu, fidp); | ||||
| out_nofid: | ||||
|     complete_pdu(pdu->s, pdu, err); | ||||
|     pdu_complete(pdu, err); | ||||
| } | ||||
| 
 | ||||
| static CoroutineEntry *pdu_co_handlers[] = { | ||||
| @@ -3199,13 +3213,13 @@ static CoroutineEntry *pdu_co_handlers[] = { | ||||
| static void v9fs_op_not_supp(void *opaque) | ||||
| { | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     complete_pdu(pdu->s, pdu, -EOPNOTSUPP); | ||||
|     pdu_complete(pdu, -EOPNOTSUPP); | ||||
| } | ||||
| 
 | ||||
| static void v9fs_fs_ro(void *opaque) | ||||
| { | ||||
|     V9fsPDU *pdu = opaque; | ||||
|     complete_pdu(pdu->s, pdu, -EROFS); | ||||
|     pdu_complete(pdu, -EROFS); | ||||
| } | ||||
| 
 | ||||
| static inline bool is_read_only_op(V9fsPDU *pdu) | ||||
| @@ -3235,10 +3249,11 @@ static inline bool is_read_only_op(V9fsPDU *pdu) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void submit_pdu(V9fsState *s, V9fsPDU *pdu) | ||||
| void pdu_submit(V9fsPDU *pdu) | ||||
| { | ||||
|     Coroutine *co; | ||||
|     CoroutineEntry *handler; | ||||
|     V9fsState *s = pdu->s; | ||||
| 
 | ||||
|     if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) || | ||||
|         (pdu_co_handlers[pdu->id] == NULL)) { | ||||
| @@ -3254,41 +3269,104 @@ static void submit_pdu(V9fsState *s, V9fsPDU *pdu) | ||||
|     qemu_coroutine_enter(co, pdu); | ||||
| } | ||||
| 
 | ||||
| void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq) | ||||
| /* Returns 0 on success, 1 on failure. */ | ||||
| int v9fs_device_realize_common(V9fsState *s, Error **errp) | ||||
| { | ||||
|     V9fsState *s = (V9fsState *)vdev; | ||||
|     V9fsPDU *pdu; | ||||
|     ssize_t len; | ||||
|     V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); | ||||
|     int i, len; | ||||
|     struct stat stat; | ||||
|     FsDriverEntry *fse; | ||||
|     V9fsPath path; | ||||
|     int rc = 1; | ||||
| 
 | ||||
|     while ((pdu = alloc_pdu(s)) && | ||||
|             (len = virtqueue_pop(vq, &pdu->elem)) != 0) { | ||||
|         struct { | ||||
|             uint32_t size_le; | ||||
|             uint8_t id; | ||||
|             uint16_t tag_le; | ||||
|         } QEMU_PACKED out; | ||||
|         int len; | ||||
| 
 | ||||
|         pdu->s = s; | ||||
|         BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0); | ||||
|         QEMU_BUILD_BUG_ON(sizeof out != 7); | ||||
| 
 | ||||
|         len = iov_to_buf(pdu->elem.out_sg, pdu->elem.out_num, 0, | ||||
|                          &out, sizeof out); | ||||
|         BUG_ON(len != sizeof out); | ||||
| 
 | ||||
|         pdu->size = le32_to_cpu(out.size_le); | ||||
| 
 | ||||
|         pdu->id = out.id; | ||||
|         pdu->tag = le16_to_cpu(out.tag_le); | ||||
| 
 | ||||
|         qemu_co_queue_init(&pdu->complete); | ||||
|         submit_pdu(s, pdu); | ||||
|     /* initialize pdu allocator */ | ||||
|     QLIST_INIT(&s->free_list); | ||||
|     QLIST_INIT(&s->active_list); | ||||
|     for (i = 0; i < (MAX_REQ - 1); i++) { | ||||
|         QLIST_INSERT_HEAD(&s->free_list, &v->pdus[i], next); | ||||
|         v->pdus[i].s = s; | ||||
|         v->pdus[i].idx = i; | ||||
|     } | ||||
|     free_pdu(s, pdu); | ||||
| 
 | ||||
|     v9fs_path_init(&path); | ||||
| 
 | ||||
|     fse = get_fsdev_fsentry(s->fsconf.fsdev_id); | ||||
| 
 | ||||
|     if (!fse) { | ||||
|         /* We don't have a fsdev identified by fsdev_id */ | ||||
|         error_setg(errp, "9pfs device couldn't find fsdev with the " | ||||
|                    "id = %s", | ||||
|                    s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL"); | ||||
|         goto out; | ||||
|     } | ||||
| 
 | ||||
|     if (!s->fsconf.tag) { | ||||
|         /* we haven't specified a mount_tag */ | ||||
|         error_setg(errp, "fsdev with id %s needs mount_tag arguments", | ||||
|                    s->fsconf.fsdev_id); | ||||
|         goto out; | ||||
|     } | ||||
| 
 | ||||
|     s->ctx.export_flags = fse->export_flags; | ||||
|     s->ctx.fs_root = g_strdup(fse->path); | ||||
|     s->ctx.exops.get_st_gen = NULL; | ||||
|     len = strlen(s->fsconf.tag); | ||||
|     if (len > MAX_TAG_LEN - 1) { | ||||
|         error_setg(errp, "mount tag '%s' (%d bytes) is longer than " | ||||
|                    "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1); | ||||
|         goto out; | ||||
|     } | ||||
| 
 | ||||
|     s->tag = g_strdup(s->fsconf.tag); | ||||
|     s->ctx.uid = -1; | ||||
| 
 | ||||
|     s->ops = fse->ops; | ||||
| 
 | ||||
|     s->fid_list = NULL; | ||||
|     qemu_co_rwlock_init(&s->rename_lock); | ||||
| 
 | ||||
|     if (s->ops->init(&s->ctx) < 0) { | ||||
|         error_setg(errp, "9pfs Failed to initialize fs-driver with id:%s" | ||||
|                    " and export path:%s", s->fsconf.fsdev_id, s->ctx.fs_root); | ||||
|         goto out; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * Check details of export path, We need to use fs driver | ||||
|      * call back to do that. Since we are in the init path, we don't | ||||
|      * use co-routines here. | ||||
|      */ | ||||
|     if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) { | ||||
|         error_setg(errp, | ||||
|                    "error in converting name to path %s", strerror(errno)); | ||||
|         goto out; | ||||
|     } | ||||
|     if (s->ops->lstat(&s->ctx, &path, &stat)) { | ||||
|         error_setg(errp, "share path %s does not exist", fse->path); | ||||
|         goto out; | ||||
|     } else if (!S_ISDIR(stat.st_mode)) { | ||||
|         error_setg(errp, "share path %s is not a directory", fse->path); | ||||
|         goto out; | ||||
|     } | ||||
|     v9fs_path_free(&path); | ||||
| 
 | ||||
|     rc = 0; | ||||
| out: | ||||
|     if (rc) { | ||||
|         g_free(s->ctx.fs_root); | ||||
|         g_free(s->tag); | ||||
|         v9fs_path_free(&path); | ||||
|     } | ||||
|     return rc; | ||||
| } | ||||
| 
 | ||||
| static void __attribute__((__constructor__)) virtio_9p_set_fd_limit(void) | ||||
| void v9fs_device_unrealize_common(V9fsState *s, Error **errp) | ||||
| { | ||||
|     g_free(s->ctx.fs_root); | ||||
|     g_free(s->tag); | ||||
| } | ||||
| 
 | ||||
| static void __attribute__((__constructor__)) v9fs_set_fd_limit(void) | ||||
| { | ||||
|     struct rlimit rlim; | ||||
|     if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { | ||||
							
								
								
									
										326
									
								
								hw/9pfs/9p.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								hw/9pfs/9p.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,326 @@ | ||||
| #ifndef _QEMU_9P_H | ||||
| #define _QEMU_9P_H | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <dirent.h> | ||||
| #include <sys/time.h> | ||||
| #include <utime.h> | ||||
| #include <sys/resource.h> | ||||
| #include <glib.h> | ||||
| #include "standard-headers/linux/virtio_9p.h" | ||||
| #include "hw/virtio/virtio.h" | ||||
| #include "fsdev/file-op-9p.h" | ||||
| #include "fsdev/9p-iov-marshal.h" | ||||
| #include "qemu/thread.h" | ||||
| #include "qemu/coroutine.h" | ||||
|  | ||||
| enum { | ||||
|     P9_TLERROR = 6, | ||||
|     P9_RLERROR, | ||||
|     P9_TSTATFS = 8, | ||||
|     P9_RSTATFS, | ||||
|     P9_TLOPEN = 12, | ||||
|     P9_RLOPEN, | ||||
|     P9_TLCREATE = 14, | ||||
|     P9_RLCREATE, | ||||
|     P9_TSYMLINK = 16, | ||||
|     P9_RSYMLINK, | ||||
|     P9_TMKNOD = 18, | ||||
|     P9_RMKNOD, | ||||
|     P9_TRENAME = 20, | ||||
|     P9_RRENAME, | ||||
|     P9_TREADLINK = 22, | ||||
|     P9_RREADLINK, | ||||
|     P9_TGETATTR = 24, | ||||
|     P9_RGETATTR, | ||||
|     P9_TSETATTR = 26, | ||||
|     P9_RSETATTR, | ||||
|     P9_TXATTRWALK = 30, | ||||
|     P9_RXATTRWALK, | ||||
|     P9_TXATTRCREATE = 32, | ||||
|     P9_RXATTRCREATE, | ||||
|     P9_TREADDIR = 40, | ||||
|     P9_RREADDIR, | ||||
|     P9_TFSYNC = 50, | ||||
|     P9_RFSYNC, | ||||
|     P9_TLOCK = 52, | ||||
|     P9_RLOCK, | ||||
|     P9_TGETLOCK = 54, | ||||
|     P9_RGETLOCK, | ||||
|     P9_TLINK = 70, | ||||
|     P9_RLINK, | ||||
|     P9_TMKDIR = 72, | ||||
|     P9_RMKDIR, | ||||
|     P9_TRENAMEAT = 74, | ||||
|     P9_RRENAMEAT, | ||||
|     P9_TUNLINKAT = 76, | ||||
|     P9_RUNLINKAT, | ||||
|     P9_TVERSION = 100, | ||||
|     P9_RVERSION, | ||||
|     P9_TAUTH = 102, | ||||
|     P9_RAUTH, | ||||
|     P9_TATTACH = 104, | ||||
|     P9_RATTACH, | ||||
|     P9_TERROR = 106, | ||||
|     P9_RERROR, | ||||
|     P9_TFLUSH = 108, | ||||
|     P9_RFLUSH, | ||||
|     P9_TWALK = 110, | ||||
|     P9_RWALK, | ||||
|     P9_TOPEN = 112, | ||||
|     P9_ROPEN, | ||||
|     P9_TCREATE = 114, | ||||
|     P9_RCREATE, | ||||
|     P9_TREAD = 116, | ||||
|     P9_RREAD, | ||||
|     P9_TWRITE = 118, | ||||
|     P9_RWRITE, | ||||
|     P9_TCLUNK = 120, | ||||
|     P9_RCLUNK, | ||||
|     P9_TREMOVE = 122, | ||||
|     P9_RREMOVE, | ||||
|     P9_TSTAT = 124, | ||||
|     P9_RSTAT, | ||||
|     P9_TWSTAT = 126, | ||||
|     P9_RWSTAT, | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* qid.types */ | ||||
| enum { | ||||
|     P9_QTDIR = 0x80, | ||||
|     P9_QTAPPEND = 0x40, | ||||
|     P9_QTEXCL = 0x20, | ||||
|     P9_QTMOUNT = 0x10, | ||||
|     P9_QTAUTH = 0x08, | ||||
|     P9_QTTMP = 0x04, | ||||
|     P9_QTSYMLINK = 0x02, | ||||
|     P9_QTLINK = 0x01, | ||||
|     P9_QTFILE = 0x00, | ||||
| }; | ||||
|  | ||||
| enum p9_proto_version { | ||||
|     V9FS_PROTO_2000U = 0x01, | ||||
|     V9FS_PROTO_2000L = 0x02, | ||||
| }; | ||||
|  | ||||
| #define P9_NOTAG    (u16)(~0) | ||||
| #define P9_NOFID    (u32)(~0) | ||||
| #define P9_MAXWELEM 16 | ||||
|  | ||||
| #define FID_REFERENCED          0x1 | ||||
| #define FID_NON_RECLAIMABLE     0x2 | ||||
| static inline char *rpath(FsContext *ctx, const char *path) | ||||
| { | ||||
|     return g_strdup_printf("%s/%s", ctx->fs_root, path); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * ample room for Twrite/Rread header | ||||
|  * size[4] Tread/Twrite tag[2] fid[4] offset[8] count[4] | ||||
|  */ | ||||
| #define P9_IOHDRSZ 24 | ||||
|  | ||||
| typedef struct V9fsPDU V9fsPDU; | ||||
| struct V9fsState; | ||||
|  | ||||
| struct V9fsPDU | ||||
| { | ||||
|     uint32_t size; | ||||
|     uint16_t tag; | ||||
|     uint8_t id; | ||||
|     uint8_t cancelled; | ||||
|     CoQueue complete; | ||||
|     struct V9fsState *s; | ||||
|     QLIST_ENTRY(V9fsPDU) next; | ||||
|     uint32_t idx; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* FIXME | ||||
|  * 1) change user needs to set groups and stuff | ||||
|  */ | ||||
|  | ||||
| #define MAX_REQ         128 | ||||
| #define MAX_TAG_LEN     32 | ||||
|  | ||||
| #define BUG_ON(cond) assert(!(cond)) | ||||
|  | ||||
| typedef struct V9fsFidState V9fsFidState; | ||||
|  | ||||
| enum { | ||||
|     P9_FID_NONE = 0, | ||||
|     P9_FID_FILE, | ||||
|     P9_FID_DIR, | ||||
|     P9_FID_XATTR, | ||||
| }; | ||||
|  | ||||
| typedef struct V9fsConf | ||||
| { | ||||
|     /* tag name for the device */ | ||||
|     char *tag; | ||||
|     char *fsdev_id; | ||||
| } V9fsConf; | ||||
|  | ||||
| typedef struct V9fsXattr | ||||
| { | ||||
|     int64_t copied_len; | ||||
|     int64_t len; | ||||
|     void *value; | ||||
|     V9fsString name; | ||||
|     int flags; | ||||
| } V9fsXattr; | ||||
|  | ||||
| /* | ||||
|  * Filled by fs driver on open and other | ||||
|  * calls. | ||||
|  */ | ||||
| union V9fsFidOpenState { | ||||
|     int fd; | ||||
|     DIR *dir; | ||||
|     V9fsXattr xattr; | ||||
|     /* | ||||
|      * private pointer for fs drivers, that | ||||
|      * have its own internal representation of | ||||
|      * open files. | ||||
|      */ | ||||
|     void *private; | ||||
| }; | ||||
|  | ||||
| struct V9fsFidState | ||||
| { | ||||
|     int fid_type; | ||||
|     int32_t fid; | ||||
|     V9fsPath path; | ||||
|     V9fsFidOpenState fs; | ||||
|     V9fsFidOpenState fs_reclaim; | ||||
|     int flags; | ||||
|     int open_flags; | ||||
|     uid_t uid; | ||||
|     int ref; | ||||
|     int clunked; | ||||
|     V9fsFidState *next; | ||||
|     V9fsFidState *rclm_lst; | ||||
| }; | ||||
|  | ||||
| typedef struct V9fsState | ||||
| { | ||||
|     QLIST_HEAD(, V9fsPDU) free_list; | ||||
|     QLIST_HEAD(, V9fsPDU) active_list; | ||||
|     V9fsFidState *fid_list; | ||||
|     FileOperations *ops; | ||||
|     FsContext ctx; | ||||
|     char *tag; | ||||
|     enum p9_proto_version proto_version; | ||||
|     int32_t msize; | ||||
|     /* | ||||
|      * lock ensuring atomic path update | ||||
|      * on rename. | ||||
|      */ | ||||
|     CoRwlock rename_lock; | ||||
|     int32_t root_fid; | ||||
|     Error *migration_blocker; | ||||
|     V9fsConf fsconf; | ||||
| } V9fsState; | ||||
|  | ||||
| /* 9p2000.L open flags */ | ||||
| #define P9_DOTL_RDONLY        00000000 | ||||
| #define P9_DOTL_WRONLY        00000001 | ||||
| #define P9_DOTL_RDWR          00000002 | ||||
| #define P9_DOTL_NOACCESS      00000003 | ||||
| #define P9_DOTL_CREATE        00000100 | ||||
| #define P9_DOTL_EXCL          00000200 | ||||
| #define P9_DOTL_NOCTTY        00000400 | ||||
| #define P9_DOTL_TRUNC         00001000 | ||||
| #define P9_DOTL_APPEND        00002000 | ||||
| #define P9_DOTL_NONBLOCK      00004000 | ||||
| #define P9_DOTL_DSYNC         00010000 | ||||
| #define P9_DOTL_FASYNC        00020000 | ||||
| #define P9_DOTL_DIRECT        00040000 | ||||
| #define P9_DOTL_LARGEFILE     00100000 | ||||
| #define P9_DOTL_DIRECTORY     00200000 | ||||
| #define P9_DOTL_NOFOLLOW      00400000 | ||||
| #define P9_DOTL_NOATIME       01000000 | ||||
| #define P9_DOTL_CLOEXEC       02000000 | ||||
| #define P9_DOTL_SYNC          04000000 | ||||
|  | ||||
| /* 9p2000.L at flags */ | ||||
| #define P9_DOTL_AT_REMOVEDIR         0x200 | ||||
|  | ||||
| /* 9P2000.L lock type */ | ||||
| #define P9_LOCK_TYPE_RDLCK 0 | ||||
| #define P9_LOCK_TYPE_WRLCK 1 | ||||
| #define P9_LOCK_TYPE_UNLCK 2 | ||||
|  | ||||
| #define P9_LOCK_SUCCESS 0 | ||||
| #define P9_LOCK_BLOCKED 1 | ||||
| #define P9_LOCK_ERROR 2 | ||||
| #define P9_LOCK_GRACE 3 | ||||
|  | ||||
| #define P9_LOCK_FLAGS_BLOCK 1 | ||||
| #define P9_LOCK_FLAGS_RECLAIM 2 | ||||
|  | ||||
| typedef struct V9fsFlock | ||||
| { | ||||
|     uint8_t type; | ||||
|     uint32_t flags; | ||||
|     uint64_t start; /* absolute offset */ | ||||
|     uint64_t length; | ||||
|     uint32_t proc_id; | ||||
|     V9fsString client_id; | ||||
| } V9fsFlock; | ||||
|  | ||||
| typedef struct V9fsGetlock | ||||
| { | ||||
|     uint8_t type; | ||||
|     uint64_t start; /* absolute offset */ | ||||
|     uint64_t length; | ||||
|     uint32_t proc_id; | ||||
|     V9fsString client_id; | ||||
| } V9fsGetlock; | ||||
|  | ||||
| extern int open_fd_hw; | ||||
| extern int total_open_fd; | ||||
|  | ||||
| static inline void v9fs_path_write_lock(V9fsState *s) | ||||
| { | ||||
|     if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { | ||||
|         qemu_co_rwlock_wrlock(&s->rename_lock); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline void v9fs_path_read_lock(V9fsState *s) | ||||
| { | ||||
|     if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { | ||||
|         qemu_co_rwlock_rdlock(&s->rename_lock); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline void v9fs_path_unlock(V9fsState *s) | ||||
| { | ||||
|     if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { | ||||
|         qemu_co_rwlock_unlock(&s->rename_lock); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu) | ||||
| { | ||||
|     return pdu->cancelled; | ||||
| } | ||||
|  | ||||
| extern void v9fs_reclaim_fd(V9fsPDU *pdu); | ||||
| extern void v9fs_path_init(V9fsPath *path); | ||||
| extern void v9fs_path_free(V9fsPath *path); | ||||
| extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs); | ||||
| extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, | ||||
|                              const char *name, V9fsPath *path); | ||||
| extern int v9fs_device_realize_common(V9fsState *s, Error **errp); | ||||
| extern void v9fs_device_unrealize_common(V9fsState *s, Error **errp); | ||||
|  | ||||
| ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...); | ||||
| ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...); | ||||
| V9fsPDU *pdu_alloc(V9fsState *s); | ||||
| void pdu_free(V9fsPDU *pdu); | ||||
| void pdu_submit(V9fsPDU *pdu); | ||||
|  | ||||
| #endif | ||||
| @@ -1,9 +1,9 @@ | ||||
| common-obj-y  = virtio-9p.o | ||||
| common-obj-y += virtio-9p-local.o virtio-9p-xattr.o | ||||
| common-obj-y += virtio-9p-xattr-user.o virtio-9p-posix-acl.o | ||||
| common-obj-y += virtio-9p-coth.o cofs.o codir.o cofile.o | ||||
| common-obj-y += coxattr.o virtio-9p-synth.o | ||||
| common-obj-$(CONFIG_OPEN_BY_HANDLE) +=  virtio-9p-handle.o | ||||
| common-obj-y += virtio-9p-proxy.o | ||||
| common-obj-y  = 9p.o | ||||
| common-obj-y += 9p-local.o 9p-xattr.o | ||||
| common-obj-y += 9p-xattr-user.o 9p-posix-acl.o | ||||
| common-obj-y += coth.o cofs.o codir.o cofile.o | ||||
| common-obj-y += coxattr.o 9p-synth.o | ||||
| common-obj-$(CONFIG_OPEN_BY_HANDLE) +=  9p-handle.o | ||||
| common-obj-y += 9p-proxy.o | ||||
|  | ||||
| obj-y += virtio-9p-device.o | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
| #include "fsdev/qemu-fsdev.h" | ||||
| #include "qemu/thread.h" | ||||
| #include "qemu/coroutine.h" | ||||
| #include "virtio-9p-coth.h" | ||||
| #include "coth.h" | ||||
|  | ||||
| int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent, | ||||
|                       struct dirent **result) | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
| #include "fsdev/qemu-fsdev.h" | ||||
| #include "qemu/thread.h" | ||||
| #include "qemu/coroutine.h" | ||||
| #include "virtio-9p-coth.h" | ||||
| #include "coth.h" | ||||
|  | ||||
| int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, | ||||
|                    V9fsStatDotl *v9stat) | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
| #include "fsdev/qemu-fsdev.h" | ||||
| #include "qemu/thread.h" | ||||
| #include "qemu/coroutine.h" | ||||
| #include "virtio-9p-coth.h" | ||||
| #include "coth.h" | ||||
|  | ||||
| static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf) | ||||
| { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p backend | ||||
|  * 9p backend | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2010 | ||||
|  * | ||||
| @@ -16,7 +16,7 @@ | ||||
| #include "block/thread-pool.h" | ||||
| #include "qemu/coroutine.h" | ||||
| #include "qemu/main-loop.h" | ||||
| #include "virtio-9p-coth.h" | ||||
| #include "coth.h" | ||||
| 
 | ||||
| /* Called from QEMU I/O thread.  */ | ||||
| static void coroutine_enter_cb(void *opaque, int ret) | ||||
| @@ -1,5 +1,5 @@ | ||||
| /*
 | ||||
|  * Virtio 9p backend | ||||
|  * 9p backend | ||||
|  * | ||||
|  * Copyright IBM, Corp. 2010 | ||||
|  * | ||||
| @@ -12,8 +12,8 @@ | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _QEMU_VIRTIO_9P_COTH_H | ||||
| #define _QEMU_VIRTIO_9P_COTH_H | ||||
| #ifndef _QEMU_9P_COTH_H | ||||
| #define _QEMU_9P_COTH_H | ||||
| 
 | ||||
| #include "qemu/thread.h" | ||||
| #include "qemu/coroutine.h" | ||||
| @@ -15,7 +15,7 @@ | ||||
| #include "fsdev/qemu-fsdev.h" | ||||
| #include "qemu/thread.h" | ||||
| #include "qemu/coroutine.h" | ||||
| #include "virtio-9p-coth.h" | ||||
| #include "coth.h" | ||||
|  | ||||
| int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size) | ||||
| { | ||||
|   | ||||
| @@ -12,14 +12,65 @@ | ||||
|  */ | ||||
|  | ||||
| #include "hw/virtio/virtio.h" | ||||
| #include "hw/virtio/virtio-9p.h" | ||||
| #include "hw/i386/pc.h" | ||||
| #include "qemu/sockets.h" | ||||
| #include "virtio-9p.h" | ||||
| #include "fsdev/qemu-fsdev.h" | ||||
| #include "virtio-9p-xattr.h" | ||||
| #include "virtio-9p-coth.h" | ||||
| #include "9p-xattr.h" | ||||
| #include "coth.h" | ||||
| #include "hw/virtio/virtio-access.h" | ||||
| #include "qemu/iov.h" | ||||
|  | ||||
| void virtio_9p_push_and_notify(V9fsPDU *pdu) | ||||
| { | ||||
|     V9fsState *s = pdu->s; | ||||
|     V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); | ||||
|     VirtQueueElement *elem = &v->elems[pdu->idx]; | ||||
|  | ||||
|     /* push onto queue and notify */ | ||||
|     virtqueue_push(v->vq, elem, pdu->size); | ||||
|  | ||||
|     /* FIXME: we should batch these completions */ | ||||
|     virtio_notify(VIRTIO_DEVICE(v), v->vq); | ||||
| } | ||||
|  | ||||
| static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq) | ||||
| { | ||||
|     V9fsVirtioState *v = (V9fsVirtioState *)vdev; | ||||
|     V9fsState *s = &v->state; | ||||
|     V9fsPDU *pdu; | ||||
|     ssize_t len; | ||||
|  | ||||
|     while ((pdu = pdu_alloc(s))) { | ||||
|         struct { | ||||
|             uint32_t size_le; | ||||
|             uint8_t id; | ||||
|             uint16_t tag_le; | ||||
|         } QEMU_PACKED out; | ||||
|         VirtQueueElement *elem = &v->elems[pdu->idx]; | ||||
|  | ||||
|         len = virtqueue_pop(vq, elem); | ||||
|         if (!len) { | ||||
|             pdu_free(pdu); | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         BUG_ON(elem->out_num == 0 || elem->in_num == 0); | ||||
|         QEMU_BUILD_BUG_ON(sizeof out != 7); | ||||
|  | ||||
|         len = iov_to_buf(elem->out_sg, elem->out_num, 0, | ||||
|                          &out, sizeof out); | ||||
|         BUG_ON(len != sizeof out); | ||||
|  | ||||
|         pdu->size = le32_to_cpu(out.size_le); | ||||
|  | ||||
|         pdu->id = out.id; | ||||
|         pdu->tag = le16_to_cpu(out.tag_le); | ||||
|  | ||||
|         qemu_co_queue_init(&pdu->complete); | ||||
|         pdu_submit(pdu); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features, | ||||
|                                        Error **errp) | ||||
| @@ -32,14 +83,15 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config) | ||||
| { | ||||
|     int len; | ||||
|     struct virtio_9p_config *cfg; | ||||
|     V9fsState *s = VIRTIO_9P(vdev); | ||||
|     V9fsVirtioState *v = VIRTIO_9P(vdev); | ||||
|     V9fsState *s = &v->state; | ||||
|  | ||||
|     len = strlen(s->tag); | ||||
|     cfg = g_malloc0(sizeof(struct virtio_9p_config) + len); | ||||
|     virtio_stw_p(vdev, &cfg->tag_len, len); | ||||
|     /* We don't copy the terminating null to config space */ | ||||
|     memcpy(cfg->tag, s->tag, len); | ||||
|     memcpy(config, cfg, s->config_size); | ||||
|     memcpy(config, cfg, v->config_size); | ||||
|     g_free(cfg); | ||||
| } | ||||
|  | ||||
| @@ -56,111 +108,74 @@ static int virtio_9p_load(QEMUFile *f, void *opaque, int version_id) | ||||
| static void virtio_9p_device_realize(DeviceState *dev, Error **errp) | ||||
| { | ||||
|     VirtIODevice *vdev = VIRTIO_DEVICE(dev); | ||||
|     V9fsState *s = VIRTIO_9P(dev); | ||||
|     int i, len; | ||||
|     struct stat stat; | ||||
|     FsDriverEntry *fse; | ||||
|     V9fsPath path; | ||||
|     V9fsVirtioState *v = VIRTIO_9P(dev); | ||||
|     V9fsState *s = &v->state; | ||||
|  | ||||
|     virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, | ||||
|                 sizeof(struct virtio_9p_config) + MAX_TAG_LEN); | ||||
|  | ||||
|     /* initialize pdu allocator */ | ||||
|     QLIST_INIT(&s->free_list); | ||||
|     QLIST_INIT(&s->active_list); | ||||
|     for (i = 0; i < (MAX_REQ - 1); i++) { | ||||
|         QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next); | ||||
|     } | ||||
|  | ||||
|     s->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); | ||||
|  | ||||
|     v9fs_path_init(&path); | ||||
|  | ||||
|     fse = get_fsdev_fsentry(s->fsconf.fsdev_id); | ||||
|  | ||||
|     if (!fse) { | ||||
|         /* We don't have a fsdev identified by fsdev_id */ | ||||
|         error_setg(errp, "Virtio-9p device couldn't find fsdev with the " | ||||
|                    "id = %s", | ||||
|                    s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL"); | ||||
|     if (v9fs_device_realize_common(s, errp)) { | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     if (!s->fsconf.tag) { | ||||
|         /* we haven't specified a mount_tag */ | ||||
|         error_setg(errp, "fsdev with id %s needs mount_tag arguments", | ||||
|                    s->fsconf.fsdev_id); | ||||
|         goto out; | ||||
|     } | ||||
|     v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag); | ||||
|     virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size); | ||||
|     v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); | ||||
|     register_savevm(dev, "virtio-9p", -1, 1, virtio_9p_save, virtio_9p_load, v); | ||||
|  | ||||
|     s->ctx.export_flags = fse->export_flags; | ||||
|     s->ctx.fs_root = g_strdup(fse->path); | ||||
|     s->ctx.exops.get_st_gen = NULL; | ||||
|     len = strlen(s->fsconf.tag); | ||||
|     if (len > MAX_TAG_LEN - 1) { | ||||
|         error_setg(errp, "mount tag '%s' (%d bytes) is longer than " | ||||
|                    "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     s->tag = g_strdup(s->fsconf.tag); | ||||
|     s->ctx.uid = -1; | ||||
|  | ||||
|     s->ops = fse->ops; | ||||
|     s->config_size = sizeof(struct virtio_9p_config) + len; | ||||
|     s->fid_list = NULL; | ||||
|     qemu_co_rwlock_init(&s->rename_lock); | ||||
|  | ||||
|     if (s->ops->init(&s->ctx) < 0) { | ||||
|         error_setg(errp, "Virtio-9p Failed to initialize fs-driver with id:%s" | ||||
|                    " and export path:%s", s->fsconf.fsdev_id, s->ctx.fs_root); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Check details of export path, We need to use fs driver | ||||
|      * call back to do that. Since we are in the init path, we don't | ||||
|      * use co-routines here. | ||||
|      */ | ||||
|     if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) { | ||||
|         error_setg(errp, | ||||
|                    "error in converting name to path %s", strerror(errno)); | ||||
|         goto out; | ||||
|     } | ||||
|     if (s->ops->lstat(&s->ctx, &path, &stat)) { | ||||
|         error_setg(errp, "share path %s does not exist", fse->path); | ||||
|         goto out; | ||||
|     } else if (!S_ISDIR(stat.st_mode)) { | ||||
|         error_setg(errp, "share path %s is not a directory", fse->path); | ||||
|         goto out; | ||||
|     } | ||||
|     v9fs_path_free(&path); | ||||
|  | ||||
|     register_savevm(dev, "virtio-9p", -1, 1, virtio_9p_save, virtio_9p_load, s); | ||||
|     return; | ||||
| out: | ||||
|     g_free(s->ctx.fs_root); | ||||
|     g_free(s->tag); | ||||
|     virtio_cleanup(vdev); | ||||
|     v9fs_path_free(&path); | ||||
|     return; | ||||
| } | ||||
|  | ||||
| static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp) | ||||
| { | ||||
|     VirtIODevice *vdev = VIRTIO_DEVICE(dev); | ||||
|     V9fsState *s = VIRTIO_9P(dev); | ||||
|     V9fsVirtioState *v = VIRTIO_9P(dev); | ||||
|     V9fsState *s = &v->state; | ||||
|  | ||||
|     virtio_cleanup(vdev); | ||||
|     unregister_savevm(dev, "virtio-9p", s); | ||||
|     g_free(s->ctx.fs_root); | ||||
|     g_free(s->tag); | ||||
|     unregister_savevm(dev, "virtio-9p", v); | ||||
|     v9fs_device_unrealize_common(s, errp); | ||||
| } | ||||
|  | ||||
| ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset, | ||||
|                             const char *fmt, va_list ap) | ||||
| { | ||||
|     V9fsState *s = pdu->s; | ||||
|     V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); | ||||
|     VirtQueueElement *elem = &v->elems[pdu->idx]; | ||||
|  | ||||
|     return v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap); | ||||
| } | ||||
|  | ||||
| ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset, | ||||
|                               const char *fmt, va_list ap) | ||||
| { | ||||
|     V9fsState *s = pdu->s; | ||||
|     V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); | ||||
|     VirtQueueElement *elem = &v->elems[pdu->idx]; | ||||
|  | ||||
|     return v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap); | ||||
| } | ||||
|  | ||||
| void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, | ||||
|                               unsigned int *pniov, bool is_write) | ||||
| { | ||||
|     V9fsState *s = pdu->s; | ||||
|     V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); | ||||
|     VirtQueueElement *elem = &v->elems[pdu->idx]; | ||||
|  | ||||
|     if (is_write) { | ||||
|         *piov = elem->out_sg; | ||||
|         *pniov = elem->out_num; | ||||
|     } else { | ||||
|         *piov = elem->in_sg; | ||||
|         *pniov = elem->in_num; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* virtio-9p device */ | ||||
|  | ||||
| static Property virtio_9p_properties[] = { | ||||
|     DEFINE_PROP_STRING("mount_tag", V9fsState, fsconf.tag), | ||||
|     DEFINE_PROP_STRING("fsdev", V9fsState, fsconf.fsdev_id), | ||||
|     DEFINE_PROP_STRING("mount_tag", V9fsVirtioState, state.fsconf.tag), | ||||
|     DEFINE_PROP_STRING("fsdev", V9fsVirtioState, state.fsconf.fsdev_id), | ||||
|     DEFINE_PROP_END_OF_LIST(), | ||||
| }; | ||||
|  | ||||
| @@ -180,7 +195,7 @@ static void virtio_9p_class_init(ObjectClass *klass, void *data) | ||||
| static const TypeInfo virtio_device_info = { | ||||
|     .name = TYPE_VIRTIO_9P, | ||||
|     .parent = TYPE_VIRTIO_DEVICE, | ||||
|     .instance_size = sizeof(V9fsState), | ||||
|     .instance_size = sizeof(V9fsVirtioState), | ||||
|     .class_init = virtio_9p_class_init, | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -1,394 +1,31 @@ | ||||
| #ifndef _QEMU_VIRTIO_9P_H | ||||
| #define _QEMU_VIRTIO_9P_H | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <dirent.h> | ||||
| #include <sys/time.h> | ||||
| #include <utime.h> | ||||
| #include <sys/resource.h> | ||||
| #include <glib.h> | ||||
| #include "standard-headers/linux/virtio_9p.h" | ||||
| #include "hw/virtio/virtio.h" | ||||
| #include "hw/virtio/virtio-9p.h" | ||||
| #include "fsdev/file-op-9p.h" | ||||
| #include "fsdev/virtio-9p-marshal.h" | ||||
| #include "qemu/thread.h" | ||||
| #include "qemu/coroutine.h" | ||||
| #include "9p.h" | ||||
|  | ||||
| enum { | ||||
|     P9_TLERROR = 6, | ||||
|     P9_RLERROR, | ||||
|     P9_TSTATFS = 8, | ||||
|     P9_RSTATFS, | ||||
|     P9_TLOPEN = 12, | ||||
|     P9_RLOPEN, | ||||
|     P9_TLCREATE = 14, | ||||
|     P9_RLCREATE, | ||||
|     P9_TSYMLINK = 16, | ||||
|     P9_RSYMLINK, | ||||
|     P9_TMKNOD = 18, | ||||
|     P9_RMKNOD, | ||||
|     P9_TRENAME = 20, | ||||
|     P9_RRENAME, | ||||
|     P9_TREADLINK = 22, | ||||
|     P9_RREADLINK, | ||||
|     P9_TGETATTR = 24, | ||||
|     P9_RGETATTR, | ||||
|     P9_TSETATTR = 26, | ||||
|     P9_RSETATTR, | ||||
|     P9_TXATTRWALK = 30, | ||||
|     P9_RXATTRWALK, | ||||
|     P9_TXATTRCREATE = 32, | ||||
|     P9_RXATTRCREATE, | ||||
|     P9_TREADDIR = 40, | ||||
|     P9_RREADDIR, | ||||
|     P9_TFSYNC = 50, | ||||
|     P9_RFSYNC, | ||||
|     P9_TLOCK = 52, | ||||
|     P9_RLOCK, | ||||
|     P9_TGETLOCK = 54, | ||||
|     P9_RGETLOCK, | ||||
|     P9_TLINK = 70, | ||||
|     P9_RLINK, | ||||
|     P9_TMKDIR = 72, | ||||
|     P9_RMKDIR, | ||||
|     P9_TRENAMEAT = 74, | ||||
|     P9_RRENAMEAT, | ||||
|     P9_TUNLINKAT = 76, | ||||
|     P9_RUNLINKAT, | ||||
|     P9_TVERSION = 100, | ||||
|     P9_RVERSION, | ||||
|     P9_TAUTH = 102, | ||||
|     P9_RAUTH, | ||||
|     P9_TATTACH = 104, | ||||
|     P9_RATTACH, | ||||
|     P9_TERROR = 106, | ||||
|     P9_RERROR, | ||||
|     P9_TFLUSH = 108, | ||||
|     P9_RFLUSH, | ||||
|     P9_TWALK = 110, | ||||
|     P9_RWALK, | ||||
|     P9_TOPEN = 112, | ||||
|     P9_ROPEN, | ||||
|     P9_TCREATE = 114, | ||||
|     P9_RCREATE, | ||||
|     P9_TREAD = 116, | ||||
|     P9_RREAD, | ||||
|     P9_TWRITE = 118, | ||||
|     P9_RWRITE, | ||||
|     P9_TCLUNK = 120, | ||||
|     P9_RCLUNK, | ||||
|     P9_TREMOVE = 122, | ||||
|     P9_RREMOVE, | ||||
|     P9_TSTAT = 124, | ||||
|     P9_RSTAT, | ||||
|     P9_TWSTAT = 126, | ||||
|     P9_RWSTAT, | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* qid.types */ | ||||
| enum { | ||||
|     P9_QTDIR = 0x80, | ||||
|     P9_QTAPPEND = 0x40, | ||||
|     P9_QTEXCL = 0x20, | ||||
|     P9_QTMOUNT = 0x10, | ||||
|     P9_QTAUTH = 0x08, | ||||
|     P9_QTTMP = 0x04, | ||||
|     P9_QTSYMLINK = 0x02, | ||||
|     P9_QTLINK = 0x01, | ||||
|     P9_QTFILE = 0x00, | ||||
| }; | ||||
|  | ||||
| enum p9_proto_version { | ||||
|     V9FS_PROTO_2000U = 0x01, | ||||
|     V9FS_PROTO_2000L = 0x02, | ||||
| }; | ||||
|  | ||||
| #define P9_NOTAG    (u16)(~0) | ||||
| #define P9_NOFID    (u32)(~0) | ||||
| #define P9_MAXWELEM 16 | ||||
|  | ||||
| #define FID_REFERENCED          0x1 | ||||
| #define FID_NON_RECLAIMABLE     0x2 | ||||
| static inline char *rpath(FsContext *ctx, const char *path) | ||||
| { | ||||
|     return g_strdup_printf("%s/%s", ctx->fs_root, path); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * ample room for Twrite/Rread header | ||||
|  * size[4] Tread/Twrite tag[2] fid[4] offset[8] count[4] | ||||
|  */ | ||||
| #define P9_IOHDRSZ 24 | ||||
|  | ||||
| typedef struct V9fsPDU V9fsPDU; | ||||
| struct V9fsState; | ||||
|  | ||||
| struct V9fsPDU | ||||
| { | ||||
|     uint32_t size; | ||||
|     uint16_t tag; | ||||
|     uint8_t id; | ||||
|     uint8_t cancelled; | ||||
|     CoQueue complete; | ||||
|     VirtQueueElement elem; | ||||
|     struct V9fsState *s; | ||||
|     QLIST_ENTRY(V9fsPDU) next; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* FIXME | ||||
|  * 1) change user needs to set groups and stuff | ||||
|  */ | ||||
|  | ||||
| #define MAX_REQ         128 | ||||
| #define MAX_TAG_LEN     32 | ||||
|  | ||||
| #define BUG_ON(cond) assert(!(cond)) | ||||
|  | ||||
| typedef struct V9fsFidState V9fsFidState; | ||||
|  | ||||
| enum { | ||||
|     P9_FID_NONE = 0, | ||||
|     P9_FID_FILE, | ||||
|     P9_FID_DIR, | ||||
|     P9_FID_XATTR, | ||||
| }; | ||||
|  | ||||
| typedef struct V9fsXattr | ||||
| { | ||||
|     int64_t copied_len; | ||||
|     int64_t len; | ||||
|     void *value; | ||||
|     V9fsString name; | ||||
|     int flags; | ||||
| } V9fsXattr; | ||||
|  | ||||
| /* | ||||
|  * Filled by fs driver on open and other | ||||
|  * calls. | ||||
|  */ | ||||
| union V9fsFidOpenState { | ||||
|     int fd; | ||||
|     DIR *dir; | ||||
|     V9fsXattr xattr; | ||||
|     /* | ||||
|      * private pointer for fs drivers, that | ||||
|      * have its own internal representation of | ||||
|      * open files. | ||||
|      */ | ||||
|     void *private; | ||||
| }; | ||||
|  | ||||
| struct V9fsFidState | ||||
| { | ||||
|     int fid_type; | ||||
|     int32_t fid; | ||||
|     V9fsPath path; | ||||
|     V9fsFidOpenState fs; | ||||
|     V9fsFidOpenState fs_reclaim; | ||||
|     int flags; | ||||
|     int open_flags; | ||||
|     uid_t uid; | ||||
|     int ref; | ||||
|     int clunked; | ||||
|     V9fsFidState *next; | ||||
|     V9fsFidState *rclm_lst; | ||||
| }; | ||||
|  | ||||
| typedef struct V9fsState | ||||
| typedef struct V9fsVirtioState | ||||
| { | ||||
|     VirtIODevice parent_obj; | ||||
|     VirtQueue *vq; | ||||
|     V9fsPDU pdus[MAX_REQ]; | ||||
|     QLIST_HEAD(, V9fsPDU) free_list; | ||||
|     QLIST_HEAD(, V9fsPDU) active_list; | ||||
|     V9fsFidState *fid_list; | ||||
|     FileOperations *ops; | ||||
|     FsContext ctx; | ||||
|     char *tag; | ||||
|     size_t config_size; | ||||
|     enum p9_proto_version proto_version; | ||||
|     int32_t msize; | ||||
|     /* | ||||
|      * lock ensuring atomic path update | ||||
|      * on rename. | ||||
|      */ | ||||
|     CoRwlock rename_lock; | ||||
|     int32_t root_fid; | ||||
|     Error *migration_blocker; | ||||
|     V9fsConf fsconf; | ||||
| } V9fsState; | ||||
|     V9fsPDU pdus[MAX_REQ]; | ||||
|     VirtQueueElement elems[MAX_REQ]; | ||||
|     V9fsState state; | ||||
| } V9fsVirtioState; | ||||
|  | ||||
| typedef struct V9fsStatState { | ||||
|     V9fsPDU *pdu; | ||||
|     size_t offset; | ||||
|     V9fsStat v9stat; | ||||
|     V9fsFidState *fidp; | ||||
|     struct stat stbuf; | ||||
| } V9fsStatState; | ||||
| extern void virtio_9p_push_and_notify(V9fsPDU *pdu); | ||||
|  | ||||
| typedef struct V9fsOpenState { | ||||
|     V9fsPDU *pdu; | ||||
|     size_t offset; | ||||
|     int32_t mode; | ||||
|     V9fsFidState *fidp; | ||||
|     V9fsQID qid; | ||||
|     struct stat stbuf; | ||||
|     int iounit; | ||||
| } V9fsOpenState; | ||||
|  | ||||
| typedef struct V9fsReadState { | ||||
|     V9fsPDU *pdu; | ||||
|     size_t offset; | ||||
|     int32_t count; | ||||
|     int32_t total; | ||||
|     int64_t off; | ||||
|     V9fsFidState *fidp; | ||||
|     struct iovec iov[128]; /* FIXME: bad, bad, bad */ | ||||
|     struct iovec *sg; | ||||
|     off_t dir_pos; | ||||
|     struct dirent *dent; | ||||
|     struct stat stbuf; | ||||
|     V9fsString name; | ||||
|     V9fsStat v9stat; | ||||
|     int32_t len; | ||||
|     int32_t cnt; | ||||
|     int32_t max_count; | ||||
| } V9fsReadState; | ||||
|  | ||||
| typedef struct V9fsWriteState { | ||||
|     V9fsPDU *pdu; | ||||
|     size_t offset; | ||||
|     int32_t len; | ||||
|     int32_t count; | ||||
|     int32_t total; | ||||
|     int64_t off; | ||||
|     V9fsFidState *fidp; | ||||
|     struct iovec iov[128]; /* FIXME: bad, bad, bad */ | ||||
|     struct iovec *sg; | ||||
|     int cnt; | ||||
| } V9fsWriteState; | ||||
|  | ||||
| typedef struct V9fsMkState { | ||||
|     V9fsPDU *pdu; | ||||
|     size_t offset; | ||||
|     V9fsQID qid; | ||||
|     struct stat stbuf; | ||||
|     V9fsString name; | ||||
|     V9fsString fullname; | ||||
| } V9fsMkState; | ||||
|  | ||||
| /* 9p2000.L open flags */ | ||||
| #define P9_DOTL_RDONLY        00000000 | ||||
| #define P9_DOTL_WRONLY        00000001 | ||||
| #define P9_DOTL_RDWR          00000002 | ||||
| #define P9_DOTL_NOACCESS      00000003 | ||||
| #define P9_DOTL_CREATE        00000100 | ||||
| #define P9_DOTL_EXCL          00000200 | ||||
| #define P9_DOTL_NOCTTY        00000400 | ||||
| #define P9_DOTL_TRUNC         00001000 | ||||
| #define P9_DOTL_APPEND        00002000 | ||||
| #define P9_DOTL_NONBLOCK      00004000 | ||||
| #define P9_DOTL_DSYNC         00010000 | ||||
| #define P9_DOTL_FASYNC        00020000 | ||||
| #define P9_DOTL_DIRECT        00040000 | ||||
| #define P9_DOTL_LARGEFILE     00100000 | ||||
| #define P9_DOTL_DIRECTORY     00200000 | ||||
| #define P9_DOTL_NOFOLLOW      00400000 | ||||
| #define P9_DOTL_NOATIME       01000000 | ||||
| #define P9_DOTL_CLOEXEC       02000000 | ||||
| #define P9_DOTL_SYNC          04000000 | ||||
|  | ||||
| /* 9p2000.L at flags */ | ||||
| #define P9_DOTL_AT_REMOVEDIR         0x200 | ||||
|  | ||||
| /* 9P2000.L lock type */ | ||||
| #define P9_LOCK_TYPE_RDLCK 0 | ||||
| #define P9_LOCK_TYPE_WRLCK 1 | ||||
| #define P9_LOCK_TYPE_UNLCK 2 | ||||
|  | ||||
| #define P9_LOCK_SUCCESS 0 | ||||
| #define P9_LOCK_BLOCKED 1 | ||||
| #define P9_LOCK_ERROR 2 | ||||
| #define P9_LOCK_GRACE 3 | ||||
|  | ||||
| #define P9_LOCK_FLAGS_BLOCK 1 | ||||
| #define P9_LOCK_FLAGS_RECLAIM 2 | ||||
|  | ||||
| typedef struct V9fsFlock | ||||
| { | ||||
|     uint8_t type; | ||||
|     uint32_t flags; | ||||
|     uint64_t start; /* absolute offset */ | ||||
|     uint64_t length; | ||||
|     uint32_t proc_id; | ||||
|     V9fsString client_id; | ||||
| } V9fsFlock; | ||||
|  | ||||
| typedef struct V9fsGetlock | ||||
| { | ||||
|     uint8_t type; | ||||
|     uint64_t start; /* absolute offset */ | ||||
|     uint64_t length; | ||||
|     uint32_t proc_id; | ||||
|     V9fsString client_id; | ||||
| } V9fsGetlock; | ||||
|  | ||||
| extern int open_fd_hw; | ||||
| extern int total_open_fd; | ||||
|  | ||||
| size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count, | ||||
|                       size_t offset, size_t size, int pack); | ||||
|  | ||||
| static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count, | ||||
|                         size_t offset, size_t size) | ||||
| { | ||||
|     return pdu_packunpack(dst, sg, sg_count, offset, size, 0); | ||||
| } | ||||
|  | ||||
| static inline void v9fs_path_write_lock(V9fsState *s) | ||||
| { | ||||
|     if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { | ||||
|         qemu_co_rwlock_wrlock(&s->rename_lock); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline void v9fs_path_read_lock(V9fsState *s) | ||||
| { | ||||
|     if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { | ||||
|         qemu_co_rwlock_rdlock(&s->rename_lock); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline void v9fs_path_unlock(V9fsState *s) | ||||
| { | ||||
|     if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { | ||||
|         qemu_co_rwlock_unlock(&s->rename_lock); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu) | ||||
| { | ||||
|     return pdu->cancelled; | ||||
| } | ||||
|  | ||||
| extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq); | ||||
| extern void v9fs_reclaim_fd(V9fsPDU *pdu); | ||||
| extern void v9fs_path_init(V9fsPath *path); | ||||
| extern void v9fs_path_free(V9fsPath *path); | ||||
| extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs); | ||||
| extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, | ||||
|                              const char *name, V9fsPath *path); | ||||
|  | ||||
| #define pdu_marshal(pdu, offset, fmt, args...)  \ | ||||
|     v9fs_marshal(pdu->elem.in_sg, pdu->elem.in_num, offset, 1, fmt, ##args) | ||||
| #define pdu_unmarshal(pdu, offset, fmt, args...)  \ | ||||
|     v9fs_unmarshal(pdu->elem.out_sg, pdu->elem.out_num, offset, 1, fmt, ##args) | ||||
| ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset, | ||||
|                             const char *fmt, va_list ap); | ||||
| ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset, | ||||
|                               const char *fmt, va_list ap); | ||||
| void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, | ||||
|                               unsigned int *pniov, bool is_write); | ||||
|  | ||||
| #define TYPE_VIRTIO_9P "virtio-9p-device" | ||||
| #define VIRTIO_9P(obj) \ | ||||
|         OBJECT_CHECK(V9fsState, (obj), TYPE_VIRTIO_9P) | ||||
|         OBJECT_CHECK(V9fsVirtioState, (obj), TYPE_VIRTIO_9P) | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o | ||||
| common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o | ||||
| common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o | ||||
| common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o | ||||
| common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o cpu_hotplug_acpi_table.o | ||||
| common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o | ||||
| common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o | ||||
| common-obj-$(CONFIG_ACPI) += acpi_interface.o | ||||
| common-obj-$(CONFIG_ACPI) += bios-linker-loader.o | ||||
|   | ||||
							
								
								
									
										135
									
								
								hw/acpi/cpu_hotplug_acpi_table.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								hw/acpi/cpu_hotplug_acpi_table.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | ||||
| /* | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| #include "hw/acpi/cpu_hotplug.h" | ||||
|  | ||||
| void build_cpu_hotplug_aml(Aml *ctx) | ||||
| { | ||||
|     Aml *method; | ||||
|     Aml *if_ctx; | ||||
|     Aml *else_ctx; | ||||
|     Aml *sb_scope = aml_scope("_SB"); | ||||
|     uint8_t madt_tmpl[8] = {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}; | ||||
|     Aml *cpu_id = aml_arg(0); | ||||
|     Aml *cpu_on = aml_local(0); | ||||
|     Aml *madt = aml_local(1); | ||||
|     Aml *cpus_map = aml_name(CPU_ON_BITMAP); | ||||
|     Aml *zero = aml_int(0); | ||||
|     Aml *one = aml_int(1); | ||||
|  | ||||
|     /* | ||||
|      * _MAT method - creates an madt apic buffer | ||||
|      * cpu_id = Arg0 = Processor ID = Local APIC ID | ||||
|      * cpu_on = Local0 = CPON flag for this cpu | ||||
|      * madt = Local1 = Buffer (in madt apic form) to return | ||||
|      */ | ||||
|     method = aml_method(CPU_MAT_METHOD, 1, AML_NOTSERIALIZED); | ||||
|     aml_append(method, | ||||
|         aml_store(aml_derefof(aml_index(cpus_map, cpu_id)), cpu_on)); | ||||
|     aml_append(method, | ||||
|         aml_store(aml_buffer(sizeof(madt_tmpl), madt_tmpl), madt)); | ||||
|     /* Update the processor id, lapic id, and enable/disable status */ | ||||
|     aml_append(method, aml_store(cpu_id, aml_index(madt, aml_int(2)))); | ||||
|     aml_append(method, aml_store(cpu_id, aml_index(madt, aml_int(3)))); | ||||
|     aml_append(method, aml_store(cpu_on, aml_index(madt, aml_int(4)))); | ||||
|     aml_append(method, aml_return(madt)); | ||||
|     aml_append(sb_scope, method); | ||||
|  | ||||
|     /* | ||||
|      * _STA method - return ON status of cpu | ||||
|      * cpu_id = Arg0 = Processor ID = Local APIC ID | ||||
|      * cpu_on = Local0 = CPON flag for this cpu | ||||
|      */ | ||||
|     method = aml_method(CPU_STATUS_METHOD, 1, AML_NOTSERIALIZED); | ||||
|     aml_append(method, | ||||
|         aml_store(aml_derefof(aml_index(cpus_map, cpu_id)), cpu_on)); | ||||
|     if_ctx = aml_if(cpu_on); | ||||
|     { | ||||
|         aml_append(if_ctx, aml_return(aml_int(0xF))); | ||||
|     } | ||||
|     aml_append(method, if_ctx); | ||||
|     else_ctx = aml_else(); | ||||
|     { | ||||
|         aml_append(else_ctx, aml_return(zero)); | ||||
|     } | ||||
|     aml_append(method, else_ctx); | ||||
|     aml_append(sb_scope, method); | ||||
|  | ||||
|     method = aml_method(CPU_EJECT_METHOD, 2, AML_NOTSERIALIZED); | ||||
|     aml_append(method, aml_sleep(200)); | ||||
|     aml_append(sb_scope, method); | ||||
|  | ||||
|     method = aml_method(CPU_SCAN_METHOD, 0, AML_NOTSERIALIZED); | ||||
|     { | ||||
|         Aml *while_ctx, *if_ctx2, *else_ctx2; | ||||
|         Aml *bus_check_evt = aml_int(1); | ||||
|         Aml *remove_evt = aml_int(3); | ||||
|         Aml *status_map = aml_local(5); /* Local5 = active cpu bitmap */ | ||||
|         Aml *byte = aml_local(2); /* Local2 = last read byte from bitmap */ | ||||
|         Aml *idx = aml_local(0); /* Processor ID / APIC ID iterator */ | ||||
|         Aml *is_cpu_on = aml_local(1); /* Local1 = CPON flag for cpu */ | ||||
|         Aml *status = aml_local(3); /* Local3 = active state for cpu */ | ||||
|  | ||||
|         aml_append(method, aml_store(aml_name(CPU_STATUS_MAP), status_map)); | ||||
|         aml_append(method, aml_store(zero, byte)); | ||||
|         aml_append(method, aml_store(zero, idx)); | ||||
|  | ||||
|         /* While (idx < SizeOf(CPON)) */ | ||||
|         while_ctx = aml_while(aml_lless(idx, aml_sizeof(cpus_map))); | ||||
|         aml_append(while_ctx, | ||||
|             aml_store(aml_derefof(aml_index(cpus_map, idx)), is_cpu_on)); | ||||
|  | ||||
|         if_ctx = aml_if(aml_and(idx, aml_int(0x07), NULL)); | ||||
|         { | ||||
|             /* Shift down previously read bitmap byte */ | ||||
|             aml_append(if_ctx, aml_shiftright(byte, one, byte)); | ||||
|         } | ||||
|         aml_append(while_ctx, if_ctx); | ||||
|  | ||||
|         else_ctx = aml_else(); | ||||
|         { | ||||
|             /* Read next byte from cpu bitmap */ | ||||
|             aml_append(else_ctx, aml_store(aml_derefof(aml_index(status_map, | ||||
|                        aml_shiftright(idx, aml_int(3), NULL))), byte)); | ||||
|         } | ||||
|         aml_append(while_ctx, else_ctx); | ||||
|  | ||||
|         aml_append(while_ctx, aml_store(aml_and(byte, one, NULL), status)); | ||||
|         if_ctx = aml_if(aml_lnot(aml_equal(is_cpu_on, status))); | ||||
|         { | ||||
|             /* State change - update CPON with new state */ | ||||
|             aml_append(if_ctx, aml_store(status, aml_index(cpus_map, idx))); | ||||
|             if_ctx2 = aml_if(aml_equal(status, one)); | ||||
|             { | ||||
|                 aml_append(if_ctx2, | ||||
|                     aml_call2(AML_NOTIFY_METHOD, idx, bus_check_evt)); | ||||
|             } | ||||
|             aml_append(if_ctx, if_ctx2); | ||||
|             else_ctx2 = aml_else(); | ||||
|             { | ||||
|                 aml_append(else_ctx2, | ||||
|                     aml_call2(AML_NOTIFY_METHOD, idx, remove_evt)); | ||||
|             } | ||||
|         } | ||||
|         aml_append(if_ctx, else_ctx2); | ||||
|         aml_append(while_ctx, if_ctx); | ||||
|  | ||||
|         aml_append(while_ctx, aml_increment(idx)); /* go to next cpu */ | ||||
|         aml_append(method, while_ctx); | ||||
|     } | ||||
|     aml_append(sb_scope, method); | ||||
|  | ||||
|     aml_append(ctx, sb_scope); | ||||
| } | ||||
| @@ -250,7 +250,6 @@ void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st, | ||||
|         /* do ACPI magic */ | ||||
|         acpi_send_gpe_event(ar, irq, ACPI_MEMORY_HOTPLUG_STATUS); | ||||
|     } | ||||
|     return; | ||||
| } | ||||
|  | ||||
| void acpi_memory_unplug_request_cb(ACPIREGS *ar, qemu_irq irq, | ||||
|   | ||||
							
								
								
									
										262
									
								
								hw/acpi/memory_hotplug_acpi_table.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								hw/acpi/memory_hotplug_acpi_table.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | ||||
| /* | ||||
|  * Memory hotplug AML code of DSDT ACPI table | ||||
|  * | ||||
|  * Copyright (C) 2015 Red Hat Inc | ||||
|  * | ||||
|  * Author: Igor Mammedov <imammedo@redhat.com> | ||||
|  * | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||||
|  * See the COPYING file in the top-level directory. | ||||
|  */ | ||||
|  | ||||
| #include <stdbool.h> | ||||
| #include "hw/acpi/memory_hotplug.h" | ||||
| #include "include/hw/acpi/pc-hotplug.h" | ||||
| #include "hw/boards.h" | ||||
|  | ||||
| void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem, | ||||
|                               uint16_t io_base, uint16_t io_len) | ||||
| { | ||||
|     Aml *ifctx; | ||||
|     Aml *method; | ||||
|     Aml *pci_scope; | ||||
|     Aml *mem_ctrl_dev; | ||||
|  | ||||
|     /* scope for memory hotplug controller device node */ | ||||
|     pci_scope = aml_scope("_SB.PCI0"); | ||||
|     mem_ctrl_dev = aml_device(MEMORY_HOTPLUG_DEVICE); | ||||
|     { | ||||
|         Aml *one = aml_int(1); | ||||
|         Aml *zero = aml_int(0); | ||||
|         Aml *ret_val = aml_local(0); | ||||
|         Aml *slot_arg0 = aml_arg(0); | ||||
|         Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER); | ||||
|         Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK); | ||||
|         Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR); | ||||
|  | ||||
|         aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06"))); | ||||
|         aml_append(mem_ctrl_dev, | ||||
|             aml_name_decl("_UID", aml_string("Memory hotplug resources"))); | ||||
|  | ||||
|         method = aml_method("_STA", 0, AML_NOTSERIALIZED); | ||||
|         ifctx = aml_if(aml_equal(slots_nr, zero)); | ||||
|         { | ||||
|             aml_append(ifctx, aml_return(zero)); | ||||
|         } | ||||
|         aml_append(method, ifctx); | ||||
|         /* present, functioning, decoding, not shown in UI */ | ||||
|         aml_append(method, aml_return(aml_int(0xB))); | ||||
|         aml_append(mem_ctrl_dev, method); | ||||
|  | ||||
|         aml_append(mem_ctrl_dev, aml_mutex(MEMORY_SLOT_LOCK, 0)); | ||||
|  | ||||
|         method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED); | ||||
|         { | ||||
|             Aml *else_ctx; | ||||
|             Aml *while_ctx; | ||||
|             Aml *idx = aml_local(0); | ||||
|             Aml *eject_req = aml_int(3); | ||||
|             Aml *dev_chk = aml_int(1); | ||||
|  | ||||
|             ifctx = aml_if(aml_equal(slots_nr, zero)); | ||||
|             { | ||||
|                 aml_append(ifctx, aml_return(zero)); | ||||
|             } | ||||
|             aml_append(method, ifctx); | ||||
|  | ||||
|             aml_append(method, aml_store(zero, idx)); | ||||
|             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); | ||||
|             /* build AML that: | ||||
|              * loops over all slots and Notifies DIMMs with | ||||
|              * Device Check or Eject Request notifications if | ||||
|              * slot has corresponding status bit set and clears | ||||
|              * slot status. | ||||
|              */ | ||||
|             while_ctx = aml_while(aml_lless(idx, slots_nr)); | ||||
|             { | ||||
|                 Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT); | ||||
|                 Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT); | ||||
|  | ||||
|                 aml_append(while_ctx, aml_store(idx, slot_selector)); | ||||
|                 ifctx = aml_if(aml_equal(ins_evt, one)); | ||||
|                 { | ||||
|                     aml_append(ifctx, | ||||
|                                aml_call2(MEMORY_SLOT_NOTIFY_METHOD, | ||||
|                                          idx, dev_chk)); | ||||
|                     aml_append(ifctx, aml_store(one, ins_evt)); | ||||
|                 } | ||||
|                 aml_append(while_ctx, ifctx); | ||||
|  | ||||
|                 else_ctx = aml_else(); | ||||
|                 ifctx = aml_if(aml_equal(rm_evt, one)); | ||||
|                 { | ||||
|                     aml_append(ifctx, | ||||
|                         aml_call2(MEMORY_SLOT_NOTIFY_METHOD, | ||||
|                                   idx, eject_req)); | ||||
|                     aml_append(ifctx, aml_store(one, rm_evt)); | ||||
|                 } | ||||
|                 aml_append(else_ctx, ifctx); | ||||
|                 aml_append(while_ctx, else_ctx); | ||||
|  | ||||
|                 aml_append(while_ctx, aml_add(idx, one, idx)); | ||||
|             } | ||||
|             aml_append(method, while_ctx); | ||||
|             aml_append(method, aml_release(ctrl_lock)); | ||||
|             aml_append(method, aml_return(one)); | ||||
|         } | ||||
|         aml_append(mem_ctrl_dev, method); | ||||
|  | ||||
|         method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED); | ||||
|         { | ||||
|             Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED); | ||||
|  | ||||
|             aml_append(method, aml_store(zero, ret_val)); | ||||
|             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); | ||||
|             aml_append(method, | ||||
|                 aml_store(aml_to_integer(slot_arg0), slot_selector)); | ||||
|  | ||||
|             ifctx = aml_if(aml_equal(slot_enabled, one)); | ||||
|             { | ||||
|                 aml_append(ifctx, aml_store(aml_int(0xF), ret_val)); | ||||
|             } | ||||
|             aml_append(method, ifctx); | ||||
|  | ||||
|             aml_append(method, aml_release(ctrl_lock)); | ||||
|             aml_append(method, aml_return(ret_val)); | ||||
|         } | ||||
|         aml_append(mem_ctrl_dev, method); | ||||
|  | ||||
|         method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED); | ||||
|         { | ||||
|             Aml *mr64 = aml_name("MR64"); | ||||
|             Aml *mr32 = aml_name("MR32"); | ||||
|             Aml *crs_tmpl = aml_resource_template(); | ||||
|             Aml *minl = aml_name("MINL"); | ||||
|             Aml *minh = aml_name("MINH"); | ||||
|             Aml *maxl =  aml_name("MAXL"); | ||||
|             Aml *maxh =  aml_name("MAXH"); | ||||
|             Aml *lenl = aml_name("LENL"); | ||||
|             Aml *lenh = aml_name("LENH"); | ||||
|  | ||||
|             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); | ||||
|             aml_append(method, aml_store(aml_to_integer(slot_arg0), | ||||
|                                          slot_selector)); | ||||
|  | ||||
|             aml_append(crs_tmpl, | ||||
|                 aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, | ||||
|                                  AML_CACHEABLE, AML_READ_WRITE, | ||||
|                                  0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0, | ||||
|                                  0xFFFFFFFFFFFFFFFFULL)); | ||||
|             aml_append(method, aml_name_decl("MR64", crs_tmpl)); | ||||
|             aml_append(method, | ||||
|                 aml_create_dword_field(mr64, aml_int(14), "MINL")); | ||||
|             aml_append(method, | ||||
|                 aml_create_dword_field(mr64, aml_int(18), "MINH")); | ||||
|             aml_append(method, | ||||
|                 aml_create_dword_field(mr64, aml_int(38), "LENL")); | ||||
|             aml_append(method, | ||||
|                 aml_create_dword_field(mr64, aml_int(42), "LENH")); | ||||
|             aml_append(method, | ||||
|                 aml_create_dword_field(mr64, aml_int(22), "MAXL")); | ||||
|             aml_append(method, | ||||
|                 aml_create_dword_field(mr64, aml_int(26), "MAXH")); | ||||
|  | ||||
|             aml_append(method, | ||||
|                 aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh)); | ||||
|             aml_append(method, | ||||
|                 aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl)); | ||||
|             aml_append(method, | ||||
|                 aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh)); | ||||
|             aml_append(method, | ||||
|                 aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl)); | ||||
|  | ||||
|             /* 64-bit math: MAX = MIN + LEN - 1 */ | ||||
|             aml_append(method, aml_add(minl, lenl, maxl)); | ||||
|             aml_append(method, aml_add(minh, lenh, maxh)); | ||||
|             ifctx = aml_if(aml_lless(maxl, minl)); | ||||
|             { | ||||
|                 aml_append(ifctx, aml_add(maxh, one, maxh)); | ||||
|             } | ||||
|             aml_append(method, ifctx); | ||||
|             ifctx = aml_if(aml_lless(maxl, one)); | ||||
|             { | ||||
|                 aml_append(ifctx, aml_subtract(maxh, one, maxh)); | ||||
|             } | ||||
|             aml_append(method, ifctx); | ||||
|             aml_append(method, aml_subtract(maxl, one, maxl)); | ||||
|  | ||||
|             /* return 32-bit _CRS if addr/size is in low mem */ | ||||
|             /* TODO: remove it since all hotplugged DIMMs are in high mem */ | ||||
|             ifctx = aml_if(aml_equal(maxh, zero)); | ||||
|             { | ||||
|                 crs_tmpl = aml_resource_template(); | ||||
|                 aml_append(crs_tmpl, | ||||
|                     aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, | ||||
|                                      AML_MAX_FIXED, AML_CACHEABLE, | ||||
|                                      AML_READ_WRITE, | ||||
|                                      0, 0x0, 0xFFFFFFFE, 0, | ||||
|                                      0xFFFFFFFF)); | ||||
|                 aml_append(ifctx, aml_name_decl("MR32", crs_tmpl)); | ||||
|                 aml_append(ifctx, | ||||
|                     aml_create_dword_field(mr32, aml_int(10), "MIN")); | ||||
|                 aml_append(ifctx, | ||||
|                     aml_create_dword_field(mr32, aml_int(14), "MAX")); | ||||
|                 aml_append(ifctx, | ||||
|                     aml_create_dword_field(mr32, aml_int(22), "LEN")); | ||||
|                 aml_append(ifctx, aml_store(minl, aml_name("MIN"))); | ||||
|                 aml_append(ifctx, aml_store(maxl, aml_name("MAX"))); | ||||
|                 aml_append(ifctx, aml_store(lenl, aml_name("LEN"))); | ||||
|  | ||||
|                 aml_append(ifctx, aml_release(ctrl_lock)); | ||||
|                 aml_append(ifctx, aml_return(mr32)); | ||||
|             } | ||||
|             aml_append(method, ifctx); | ||||
|  | ||||
|             aml_append(method, aml_release(ctrl_lock)); | ||||
|             aml_append(method, aml_return(mr64)); | ||||
|         } | ||||
|         aml_append(mem_ctrl_dev, method); | ||||
|  | ||||
|         method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1, | ||||
|                             AML_NOTSERIALIZED); | ||||
|         { | ||||
|             Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY); | ||||
|  | ||||
|             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); | ||||
|             aml_append(method, aml_store(aml_to_integer(slot_arg0), | ||||
|                                          slot_selector)); | ||||
|             aml_append(method, aml_store(proximity, ret_val)); | ||||
|             aml_append(method, aml_release(ctrl_lock)); | ||||
|             aml_append(method, aml_return(ret_val)); | ||||
|         } | ||||
|         aml_append(mem_ctrl_dev, method); | ||||
|  | ||||
|         method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED); | ||||
|         { | ||||
|             Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT); | ||||
|             Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS); | ||||
|  | ||||
|             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); | ||||
|             aml_append(method, aml_store(aml_to_integer(slot_arg0), | ||||
|                                          slot_selector)); | ||||
|             aml_append(method, aml_store(aml_arg(1), ost_evt)); | ||||
|             aml_append(method, aml_store(aml_arg(2), ost_status)); | ||||
|             aml_append(method, aml_release(ctrl_lock)); | ||||
|         } | ||||
|         aml_append(mem_ctrl_dev, method); | ||||
|  | ||||
|         method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED); | ||||
|         { | ||||
|             Aml *eject = aml_name(MEMORY_SLOT_EJECT); | ||||
|  | ||||
|             aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); | ||||
|             aml_append(method, aml_store(aml_to_integer(slot_arg0), | ||||
|                                          slot_selector)); | ||||
|             aml_append(method, aml_store(one, eject)); | ||||
|             aml_append(method, aml_release(ctrl_lock)); | ||||
|         } | ||||
|         aml_append(mem_ctrl_dev, method); | ||||
|     } | ||||
|     aml_append(pci_scope, mem_ctrl_dev); | ||||
|     aml_append(ctx, pci_scope); | ||||
| } | ||||
| @@ -353,16 +353,18 @@ static void nvdimm_build_nfit(GSList *device_list, GArray *table_offsets, | ||||
|                               GArray *table_data, GArray *linker) | ||||
| { | ||||
|     GArray *structures = nvdimm_build_device_structure(device_list); | ||||
|     void *header; | ||||
|     unsigned int header; | ||||
|  | ||||
|     acpi_add_table(table_offsets, table_data); | ||||
|  | ||||
|     /* NFIT header. */ | ||||
|     header = acpi_data_push(table_data, sizeof(NvdimmNfitHeader)); | ||||
|     header = table_data->len; | ||||
|     acpi_data_push(table_data, sizeof(NvdimmNfitHeader)); | ||||
|     /* NVDIMM device structures. */ | ||||
|     g_array_append_vals(table_data, structures->data, structures->len); | ||||
|  | ||||
|     build_header(linker, table_data, header, "NFIT", | ||||
|     build_header(linker, table_data, | ||||
|                  (void *)(table_data->data + header), "NFIT", | ||||
|                  sizeof(NvdimmNfitHeader) + structures->len, 1, NULL); | ||||
|     g_array_free(structures, true); | ||||
| } | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
| #include "hw/loader.h" | ||||
| #include "hw/boards.h" | ||||
| #include "alpha_sys.h" | ||||
| #include "qemu/error-report.h" | ||||
| #include "sysemu/sysemu.h" | ||||
| #include "hw/timer/mc146818rtc.h" | ||||
| #include "hw/ide.h" | ||||
| @@ -104,14 +105,14 @@ static void clipper_init(MachineState *machine) | ||||
|     palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, | ||||
|                                 bios_name ? bios_name : "palcode-clipper"); | ||||
|     if (palcode_filename == NULL) { | ||||
|         hw_error("no palcode provided\n"); | ||||
|         error_report("no palcode provided"); | ||||
|         exit(1); | ||||
|     } | ||||
|     size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys, | ||||
|                     NULL, &palcode_entry, &palcode_low, &palcode_high, | ||||
|                     0, EM_ALPHA, 0); | ||||
|     if (size < 0) { | ||||
|         hw_error("could not load palcode '%s'\n", palcode_filename); | ||||
|         error_report("could not load palcode '%s'", palcode_filename); | ||||
|         exit(1); | ||||
|     } | ||||
|     g_free(palcode_filename); | ||||
| @@ -131,7 +132,7 @@ static void clipper_init(MachineState *machine) | ||||
|                         NULL, &kernel_entry, &kernel_low, &kernel_high, | ||||
|                         0, EM_ALPHA, 0); | ||||
|         if (size < 0) { | ||||
|             hw_error("could not load kernel '%s'\n", kernel_filename); | ||||
|             error_report("could not load kernel '%s'", kernel_filename); | ||||
|             exit(1); | ||||
|         } | ||||
|  | ||||
| @@ -148,7 +149,7 @@ static void clipper_init(MachineState *machine) | ||||
|  | ||||
|             initrd_size = get_image_size(initrd_filename); | ||||
|             if (initrd_size < 0) { | ||||
|                 hw_error("could not load initial ram disk '%s'\n", | ||||
|                 error_report("could not load initial ram disk '%s'", | ||||
|                              initrd_filename); | ||||
|                 exit(1); | ||||
|             } | ||||
|   | ||||
| @@ -920,7 +920,8 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, | ||||
|     { | ||||
|         qemu_irq *isa_irqs; | ||||
|  | ||||
|         *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io); | ||||
|         *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io, | ||||
|                                &error_abort); | ||||
|         isa_irqs = i8259_init(*isa_bus, | ||||
|                               qemu_allocate_irq(typhoon_set_isa_irq, s, 0)); | ||||
|         isa_bus_irqs(*isa_bus, isa_irqs); | ||||
|   | ||||
| @@ -39,27 +39,26 @@ static void cubieboard_init(MachineState *machine) | ||||
|  | ||||
|     object_property_set_int(OBJECT(&s->a10->emac), 1, "phy-addr", &err); | ||||
|     if (err != NULL) { | ||||
|         error_report("Couldn't set phy address: %s", error_get_pretty(err)); | ||||
|         error_reportf_err(err, "Couldn't set phy address: "); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     object_property_set_int(OBJECT(&s->a10->timer), 32768, "clk0-freq", &err); | ||||
|     if (err != NULL) { | ||||
|         error_report("Couldn't set clk0 frequency: %s", error_get_pretty(err)); | ||||
|         error_reportf_err(err, "Couldn't set clk0 frequency: "); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     object_property_set_int(OBJECT(&s->a10->timer), 24000000, "clk1-freq", | ||||
|                             &err); | ||||
|     if (err != NULL) { | ||||
|         error_report("Couldn't set clk1 frequency: %s", error_get_pretty(err)); | ||||
|         error_reportf_err(err, "Couldn't set clk1 frequency: "); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     object_property_set_bool(OBJECT(s->a10), true, "realized", &err); | ||||
|     if (err != NULL) { | ||||
|         error_report("Couldn't realize Allwinner A10: %s", | ||||
|                      error_get_pretty(err)); | ||||
|         error_reportf_err(err, "Couldn't realize Allwinner A10: "); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -64,8 +64,7 @@ static void digic4_board_init(DigicBoard *board) | ||||
|     s->digic = DIGIC(object_new(TYPE_DIGIC)); | ||||
|     object_property_set_bool(OBJECT(s->digic), true, "realized", &err); | ||||
|     if (err != NULL) { | ||||
|         error_report("Couldn't realize DIGIC SoC: %s", | ||||
|                      error_get_pretty(err)); | ||||
|         error_reportf_err(err, "Couldn't realize DIGIC SoC: "); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -150,27 +150,18 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, | ||||
|  | ||||
|     for (n = 0; n < EXYNOS4210_NCPUS; n++) { | ||||
|         Object *cpuobj = object_new(object_class_get_name(cpu_oc)); | ||||
|         Error *err = NULL; | ||||
|  | ||||
|         /* By default A9 CPUs have EL3 enabled.  This board does not currently | ||||
|          * support EL3 so the CPU EL3 property is disabled before realization. | ||||
|          */ | ||||
|         if (object_property_find(cpuobj, "has_el3", NULL)) { | ||||
|             object_property_set_bool(cpuobj, false, "has_el3", &err); | ||||
|             if (err) { | ||||
|                 error_report_err(err); | ||||
|                 exit(1); | ||||
|             } | ||||
|             object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); | ||||
|         } | ||||
|  | ||||
|         s->cpu[n] = ARM_CPU(cpuobj); | ||||
|         object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR, | ||||
|                                 "reset-cbar", &error_abort); | ||||
|         object_property_set_bool(cpuobj, true, "realized", &err); | ||||
|         if (err) { | ||||
|             error_report_err(err); | ||||
|             exit(1); | ||||
|         } | ||||
|         object_property_set_bool(cpuobj, true, "realized", &error_fatal); | ||||
|     } | ||||
|  | ||||
|     /*** IRQs ***/ | ||||
|   | ||||
| @@ -279,7 +279,6 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) | ||||
|         ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); | ||||
|         Object *cpuobj; | ||||
|         ARMCPU *cpu; | ||||
|         Error *err = NULL; | ||||
|  | ||||
|         cpuobj = object_new(object_class_get_name(oc)); | ||||
|         cpu = ARM_CPU(cpuobj); | ||||
| @@ -297,11 +296,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) | ||||
|             object_property_set_int(cpuobj, MPCORE_PERIPHBASE, | ||||
|                                     "reset-cbar", &error_abort); | ||||
|         } | ||||
|         object_property_set_bool(cpuobj, true, "realized", &err); | ||||
|         if (err) { | ||||
|             error_report_err(err); | ||||
|             exit(1); | ||||
|         } | ||||
|         object_property_set_bool(cpuobj, true, "realized", &error_fatal); | ||||
|         cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ); | ||||
|         cpu_fiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ); | ||||
|     } | ||||
| @@ -320,11 +315,13 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) | ||||
|         sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); | ||||
|         if (sysboot_filename != NULL) { | ||||
|             if (load_image_targphys(sysboot_filename, 0xfff88000, 0x8000) < 0) { | ||||
|                 hw_error("Unable to load %s\n", bios_name); | ||||
|                 error_report("Unable to load %s", bios_name); | ||||
|                 exit(1); | ||||
|             } | ||||
|             g_free(sysboot_filename); | ||||
|         } else { | ||||
|            hw_error("Unable to find %s\n", bios_name); | ||||
|             error_report("Unable to find %s", bios_name); | ||||
|             exit(1); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -75,7 +75,7 @@ static void imx25_pdk_init(MachineState *machine) | ||||
|  | ||||
|     object_property_set_bool(OBJECT(&s->soc), true, "realized", &err); | ||||
|     if (err != NULL) { | ||||
|         error_report("%s", error_get_pretty(err)); | ||||
|         error_report_err(err); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -533,7 +533,6 @@ static void integratorcp_init(MachineState *machine) | ||||
|     qemu_irq pic[32]; | ||||
|     DeviceState *dev, *sic, *icp; | ||||
|     int i; | ||||
|     Error *err = NULL; | ||||
|  | ||||
|     if (!cpu_model) { | ||||
|         cpu_model = "arm926"; | ||||
| @@ -552,18 +551,10 @@ static void integratorcp_init(MachineState *machine) | ||||
|      * realization. | ||||
|      */ | ||||
|     if (object_property_find(cpuobj, "has_el3", NULL)) { | ||||
|         object_property_set_bool(cpuobj, false, "has_el3", &err); | ||||
|         if (err) { | ||||
|             error_report_err(err); | ||||
|             exit(1); | ||||
|         } | ||||
|         object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); | ||||
|     } | ||||
|  | ||||
|     object_property_set_bool(cpuobj, true, "realized", &err); | ||||
|     if (err) { | ||||
|         error_report_err(err); | ||||
|         exit(1); | ||||
|     } | ||||
|     object_property_set_bool(cpuobj, true, "realized", &error_fatal); | ||||
|  | ||||
|     cpu = ARM_CPU(cpuobj); | ||||
|  | ||||
|   | ||||
| @@ -74,7 +74,7 @@ static void kzm_init(MachineState *machine) | ||||
|  | ||||
|     object_property_set_bool(OBJECT(&s->soc), true, "realized", &err); | ||||
|     if (err != NULL) { | ||||
|         error_report("%s", error_get_pretty(err)); | ||||
|         error_report_err(err); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -38,7 +38,7 @@ static void netduino2_init(MachineState *machine) | ||||
|     qdev_prop_set_string(dev, "cpu-model", "cortex-m3"); | ||||
|     object_property_set_bool(OBJECT(dev), true, "realized", &err); | ||||
|     if (err != NULL) { | ||||
|         error_report("%s", error_get_pretty(err)); | ||||
|         error_report_err(err); | ||||
|         exit(1); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -172,8 +172,8 @@ static void n8x0_nand_setup(struct n800_s *s) | ||||
|     qdev_prop_set_int32(s->nand, "shift", 1); | ||||
|     dinfo = drive_get(IF_MTD, 0, 0); | ||||
|     if (dinfo) { | ||||
|         qdev_prop_set_drive_nofail(s->nand, "drive", | ||||
|                                    blk_by_legacy_dinfo(dinfo)); | ||||
|         qdev_prop_set_drive(s->nand, "drive", blk_by_legacy_dinfo(dinfo), | ||||
|                             &error_fatal); | ||||
|     } | ||||
|     qdev_init_nofail(s->nand); | ||||
|     sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0, | ||||
|   | ||||
| @@ -99,33 +99,21 @@ static void realview_init(MachineState *machine, | ||||
|  | ||||
|     for (n = 0; n < smp_cpus; n++) { | ||||
|         Object *cpuobj = object_new(object_class_get_name(cpu_oc)); | ||||
|         Error *err = NULL; | ||||
|  | ||||
|         /* By default A9,A15 and ARM1176 CPUs have EL3 enabled.  This board | ||||
|          * does not currently support EL3 so the CPU EL3 property is disabled | ||||
|          * before realization. | ||||
|          */ | ||||
|         if (object_property_find(cpuobj, "has_el3", NULL)) { | ||||
|             object_property_set_bool(cpuobj, false, "has_el3", &err); | ||||
|             if (err) { | ||||
|                 error_report_err(err); | ||||
|                 exit(1); | ||||
|             } | ||||
|             object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); | ||||
|         } | ||||
|  | ||||
|         if (is_pb && is_mpcore) { | ||||
|             object_property_set_int(cpuobj, periphbase, "reset-cbar", &err); | ||||
|             if (err) { | ||||
|                 error_report_err(err); | ||||
|                 exit(1); | ||||
|             } | ||||
|             object_property_set_int(cpuobj, periphbase, "reset-cbar", | ||||
|                                     &error_fatal); | ||||
|         } | ||||
|  | ||||
|         object_property_set_bool(cpuobj, true, "realized", &err); | ||||
|         if (err) { | ||||
|             error_report_err(err); | ||||
|             exit(1); | ||||
|         } | ||||
|         object_property_set_bool(cpuobj, true, "realized", &error_fatal); | ||||
|  | ||||
|         cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpuobj), ARM_CPU_IRQ); | ||||
|     } | ||||
|   | ||||
| @@ -192,7 +192,6 @@ static void versatile_init(MachineState *machine, int board_id) | ||||
|     int n; | ||||
|     int done_smc = 0; | ||||
|     DriveInfo *dinfo; | ||||
|     Error *err = NULL; | ||||
|  | ||||
|     if (!machine->cpu_model) { | ||||
|         machine->cpu_model = "arm926"; | ||||
| @@ -211,18 +210,10 @@ static void versatile_init(MachineState *machine, int board_id) | ||||
|      * realization. | ||||
|      */ | ||||
|     if (object_property_find(cpuobj, "has_el3", NULL)) { | ||||
|         object_property_set_bool(cpuobj, false, "has_el3", &err); | ||||
|         if (err) { | ||||
|             error_report_err(err); | ||||
|             exit(1); | ||||
|         } | ||||
|         object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); | ||||
|     } | ||||
|  | ||||
|     object_property_set_bool(cpuobj, true, "realized", &err); | ||||
|     if (err) { | ||||
|         error_report_err(err); | ||||
|         exit(1); | ||||
|     } | ||||
|     object_property_set_bool(cpuobj, true, "realized", &error_fatal); | ||||
|  | ||||
|     cpu = ARM_CPU(cpuobj); | ||||
|  | ||||
|   | ||||
| @@ -211,7 +211,6 @@ static void init_cpus(const char *cpu_model, const char *privdev, | ||||
|     /* Create the actual CPUs */ | ||||
|     for (n = 0; n < smp_cpus; n++) { | ||||
|         Object *cpuobj = object_new(object_class_get_name(cpu_oc)); | ||||
|         Error *err = NULL; | ||||
|  | ||||
|         if (!secure) { | ||||
|             object_property_set_bool(cpuobj, false, "has_el3", NULL); | ||||
| @@ -221,11 +220,7 @@ static void init_cpus(const char *cpu_model, const char *privdev, | ||||
|             object_property_set_int(cpuobj, periphbase, | ||||
|                                     "reset-cbar", &error_abort); | ||||
|         } | ||||
|         object_property_set_bool(cpuobj, true, "realized", &err); | ||||
|         if (err) { | ||||
|             error_report_err(err); | ||||
|             exit(1); | ||||
|         } | ||||
|         object_property_set_bool(cpuobj, true, "realized", &error_fatal); | ||||
|     } | ||||
|  | ||||
|     /* Create the private peripheral devices (including the GIC); | ||||
|   | ||||
| @@ -94,23 +94,6 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, | ||||
|     aml_append(scope, dev); | ||||
| } | ||||
|  | ||||
| static void acpi_dsdt_add_rtc(Aml *scope, const MemMapEntry *rtc_memmap, | ||||
|                                           uint32_t rtc_irq) | ||||
| { | ||||
|     Aml *dev = aml_device("RTC0"); | ||||
|     aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0013"))); | ||||
|     aml_append(dev, aml_name_decl("_UID", aml_int(0))); | ||||
|  | ||||
|     Aml *crs = aml_resource_template(); | ||||
|     aml_append(crs, aml_memory32_fixed(rtc_memmap->base, | ||||
|                                        rtc_memmap->size, AML_READ_WRITE)); | ||||
|     aml_append(crs, | ||||
|                aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, | ||||
|                              AML_EXCLUSIVE, &rtc_irq, 1)); | ||||
|     aml_append(dev, aml_name_decl("_CRS", crs)); | ||||
|     aml_append(scope, dev); | ||||
| } | ||||
|  | ||||
| static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap) | ||||
| { | ||||
|     Aml *dev, *crs; | ||||
| @@ -571,12 +554,15 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) | ||||
|     /* Reserve space for header */ | ||||
|     acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader)); | ||||
|  | ||||
|     /* When booting the VM with UEFI, UEFI takes ownership of the RTC hardware. | ||||
|      * While UEFI can use libfdt to disable the RTC device node in the DTB that | ||||
|      * it passes to the OS, it cannot modify AML. Therefore, we won't generate | ||||
|      * the RTC ACPI device at all when using UEFI. | ||||
|      */ | ||||
|     scope = aml_scope("\\_SB"); | ||||
|     acpi_dsdt_add_cpus(scope, guest_info->smp_cpus); | ||||
|     acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], | ||||
|                        (irqmap[VIRT_UART] + ARM_SPI_BASE)); | ||||
|     acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC], | ||||
|                       (irqmap[VIRT_RTC] + ARM_SPI_BASE)); | ||||
|     acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); | ||||
|     acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], | ||||
|                     (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); | ||||
|   | ||||
| @@ -808,6 +808,7 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, | ||||
|     DeviceState *dev; | ||||
|     char *nodename; | ||||
|     int i; | ||||
|     PCIHostState *pci; | ||||
|  | ||||
|     dev = qdev_create(NULL, TYPE_GPEX_HOST); | ||||
|     qdev_init_nofail(dev); | ||||
| @@ -847,6 +848,19 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, | ||||
|         sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); | ||||
|     } | ||||
|  | ||||
|     pci = PCI_HOST_BRIDGE(dev); | ||||
|     if (pci->bus) { | ||||
|         for (i = 0; i < nb_nics; i++) { | ||||
|             NICInfo *nd = &nd_table[i]; | ||||
|  | ||||
|             if (!nd->model) { | ||||
|                 nd->model = g_strdup("virtio"); | ||||
|             } | ||||
|  | ||||
|             pci_nic_init_nofail(nd, pci->bus, nd->model, NULL); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     nodename = g_strdup_printf("/pcie@%" PRIx64, base); | ||||
|     qemu_fdt_add_subnode(vbi->fdt, nodename); | ||||
|     qemu_fdt_setprop_string(vbi->fdt, nodename, | ||||
| @@ -1186,9 +1200,8 @@ static void virt_set_gic_version(Object *obj, const char *value, Error **errp) | ||||
|     } else if (!strcmp(value, "host")) { | ||||
|         vms->gic_version = 0; /* Will probe later */ | ||||
|     } else { | ||||
|         error_report("Invalid gic-version option value"); | ||||
|         error_printf("Allowed gic-version values are: 3, 2, host\n"); | ||||
|         exit(1); | ||||
|         error_setg(errp, "Invalid gic-version value"); | ||||
|         error_append_hint(errp, "Valid values are 3, 2, host.\n"); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -156,7 +156,6 @@ static void zynq_init(MachineState *machine) | ||||
|     DeviceState *dev; | ||||
|     SysBusDevice *busdev; | ||||
|     qemu_irq pic[64]; | ||||
|     Error *err = NULL; | ||||
|     int n; | ||||
|  | ||||
|     if (!cpu_model) { | ||||
| @@ -171,29 +170,14 @@ static void zynq_init(MachineState *machine) | ||||
|      * realization. | ||||
|      */ | ||||
|     if (object_property_find(OBJECT(cpu), "has_el3", NULL)) { | ||||
|         object_property_set_bool(OBJECT(cpu), false, "has_el3", &err); | ||||
|         if (err) { | ||||
|             error_report_err(err); | ||||
|             exit(1); | ||||
|         } | ||||
|         object_property_set_bool(OBJECT(cpu), false, "has_el3", &error_fatal); | ||||
|     } | ||||
|  | ||||
|     object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", &err); | ||||
|     if (err) { | ||||
|         error_report_err(err); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar", &err); | ||||
|     if (err) { | ||||
|         error_report_err(err); | ||||
|         exit(1); | ||||
|     } | ||||
|     object_property_set_bool(OBJECT(cpu), true, "realized", &err); | ||||
|     if (err) { | ||||
|         error_report_err(err); | ||||
|         exit(1); | ||||
|     } | ||||
|     object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", | ||||
|                             &error_fatal); | ||||
|     object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar", | ||||
|                             &error_fatal); | ||||
|     object_property_set_bool(OBJECT(cpu), true, "realized", &error_fatal); | ||||
|  | ||||
|     /* max 2GB ram */ | ||||
|     if (ram_size > 0x80000000) { | ||||
|   | ||||
| @@ -25,42 +25,44 @@ typedef struct XlnxEP108 { | ||||
|     MemoryRegion ddr_ram; | ||||
| } XlnxEP108; | ||||
|  | ||||
| /* Max 2GB RAM */ | ||||
| #define EP108_MAX_RAM_SIZE 0x80000000ull | ||||
|  | ||||
| static struct arm_boot_info xlnx_ep108_binfo; | ||||
|  | ||||
| static void xlnx_ep108_init(MachineState *machine) | ||||
| { | ||||
|     XlnxEP108 *s = g_new0(XlnxEP108, 1); | ||||
|     Error *err = NULL; | ||||
|     uint64_t ram_size = machine->ram_size; | ||||
|  | ||||
|     /* Create the memory region to pass to the SoC */ | ||||
|     if (ram_size > XLNX_ZYNQMP_MAX_RAM_SIZE) { | ||||
|         error_report("ERROR: RAM size 0x%" PRIx64 " above max supported of " | ||||
|                      "0x%llx", ram_size, | ||||
|                      XLNX_ZYNQMP_MAX_RAM_SIZE); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     if (ram_size < 0x08000000) { | ||||
|         qemu_log("WARNING: RAM size 0x%" PRIx64 " is small for EP108", | ||||
|                  ram_size); | ||||
|     } | ||||
|  | ||||
|     memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram", | ||||
|                                          ram_size); | ||||
|  | ||||
|     object_initialize(&s->soc, sizeof(s->soc), TYPE_XLNX_ZYNQMP); | ||||
|     object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), | ||||
|                               &error_abort); | ||||
|  | ||||
|     object_property_set_link(OBJECT(&s->soc), OBJECT(&s->ddr_ram), | ||||
|                          "ddr-ram", &error_abort); | ||||
|  | ||||
|     object_property_set_bool(OBJECT(&s->soc), true, "realized", &err); | ||||
|     if (err) { | ||||
|         error_report("%s", error_get_pretty(err)); | ||||
|         error_report_err(err); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     if (machine->ram_size > EP108_MAX_RAM_SIZE) { | ||||
|         error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, " | ||||
|                      "reduced to %llx", machine->ram_size, EP108_MAX_RAM_SIZE); | ||||
|         machine->ram_size = EP108_MAX_RAM_SIZE; | ||||
|     } | ||||
|  | ||||
|     if (machine->ram_size < 0x08000000) { | ||||
|         qemu_log("WARNING: RAM size " RAM_ADDR_FMT " is small for EP108", | ||||
|                  machine->ram_size); | ||||
|     } | ||||
|  | ||||
|     memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram", | ||||
|                                          machine->ram_size); | ||||
|     memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram); | ||||
|  | ||||
|     xlnx_ep108_binfo.ram_size = machine->ram_size; | ||||
|     xlnx_ep108_binfo.ram_size = ram_size; | ||||
|     xlnx_ep108_binfo.kernel_filename = machine->kernel_filename; | ||||
|     xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline; | ||||
|     xlnx_ep108_binfo.initrd_filename = machine->initrd_filename; | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user