diff options
146 files changed, 2368 insertions, 2519 deletions
diff --git a/.gitmodules b/.gitmodules index 45e51e7..444c24a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,6 +13,9 @@ [submodule "roms/openbios"] path = roms/openbios url = git://git.qemu-project.org/openbios.git +[submodule "roms/openhackware"] + path = roms/openhackware + url = git://git.qemu-project.org/openhackware.git [submodule "roms/qemu-palcode"] path = roms/qemu-palcode url = git://github.com/rth7680/qemu-palcode.git diff --git a/Makefile.objs b/Makefile.objs index 5cd3d81..a6e0e2a 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -39,6 +39,7 @@ libcacard-y += libcacard/vcardt.o ifeq ($(CONFIG_SOFTMMU),y) common-obj-y = blockdev.o blockdev-nbd.o block/ +common-obj-y += iothread.o common-obj-y += net/ common-obj-y += qdev-monitor.o device-hotplug.o common-obj-$(CONFIG_WIN32) += os-win32.o @@ -214,6 +214,7 @@ aio_ctx_finalize(GSource *source) thread_pool_free(ctx->thread_pool); aio_set_event_notifier(ctx, &ctx->notifier, NULL); event_notifier_cleanup(&ctx->notifier); + rfifolock_destroy(&ctx->lock); qemu_mutex_destroy(&ctx->bh_lock); g_array_free(ctx->pollfds, TRUE); timerlistgroup_deinit(&ctx->tlg); @@ -250,6 +251,12 @@ static void aio_timerlist_notify(void *opaque) aio_notify(opaque); } +static void aio_rfifolock_cb(void *opaque) +{ + /* Kick owner thread in case they are blocked in aio_poll() */ + aio_notify(opaque); +} + AioContext *aio_context_new(void) { AioContext *ctx; @@ -257,6 +264,7 @@ AioContext *aio_context_new(void) ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD)); ctx->thread_pool = NULL; qemu_mutex_init(&ctx->bh_lock); + rfifolock_init(&ctx->lock, aio_rfifolock_cb, ctx); event_notifier_init(&ctx->notifier, false); aio_set_event_notifier(ctx, &ctx->notifier, (EventNotifierHandler *) @@ -275,3 +283,13 @@ void aio_context_unref(AioContext *ctx) { g_source_unref(&ctx->source); } + +void aio_context_acquire(AioContext *ctx) +{ + rfifolock_lock(&ctx->lock); +} + +void aio_context_release(AioContext *ctx) +{ + rfifolock_unlock(&ctx->lock); +} @@ -1321,7 +1321,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, bdrv_open_flags(bs, flags | BDRV_O_UNMAP) | BDRV_O_PROTOCOL, true, &local_err); if (ret < 0) { - goto fail; + goto unlink_and_fail; } /* Find the right image format driver */ @@ -4055,7 +4055,7 @@ int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag) int bdrv_debug_resume(BlockDriverState *bs, const char *tag) { - while (bs && bs->drv && !bs->drv->bdrv_debug_resume) { + while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) { bs = bs->file; } @@ -4776,9 +4776,17 @@ flush_parent: void bdrv_invalidate_cache(BlockDriverState *bs) { - if (bs->drv && bs->drv->bdrv_invalidate_cache) { + if (!bs->drv) { + return; + } + + if (bs->drv->bdrv_invalidate_cache) { bs->drv->bdrv_invalidate_cache(bs); + } else if (bs->file) { + bdrv_invalidate_cache(bs->file); } + + refresh_total_sectors(bs, bs->total_sectors); } void bdrv_invalidate_cache_all(void) @@ -5390,43 +5398,37 @@ int bdrv_amend_options(BlockDriverState *bs, QEMUOptionParameter *options) return bs->drv->bdrv_amend_options(bs, options); } -/* Used to recurse on single child block filters. - * Single child block filter will store their child in bs->file. +/* This function will be called by the bdrv_recurse_is_first_non_filter method + * of block filter and by bdrv_is_first_non_filter. + * It is used to test if the given bs is the candidate or recurse more in the + * node graph. */ -bool bdrv_generic_is_first_non_filter(BlockDriverState *bs, +bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs, BlockDriverState *candidate) { - if (!bs->drv) { - return false; - } - - if (!bs->drv->authorizations[BS_IS_A_FILTER]) { - if (bs == candidate) { - return true; - } else { - return false; - } - } - - if (!bs->drv->authorizations[BS_FILTER_PASS_DOWN]) { + /* return false if basic checks fails */ + if (!bs || !bs->drv) { return false; } - if (!bs->file) { - return false; + /* the code reached a non block filter driver -> check if the bs is + * the same as the candidate. It's the recursion termination condition. + */ + if (!bs->drv->is_filter) { + return bs == candidate; } + /* Down this path the driver is a block filter driver */ - return bdrv_recurse_is_first_non_filter(bs->file, candidate); -} - -bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs, - BlockDriverState *candidate) -{ - if (bs->drv && bs->drv->bdrv_recurse_is_first_non_filter) { + /* If the block filter recursion method is defined use it to recurse down + * the node graph. + */ + if (bs->drv->bdrv_recurse_is_first_non_filter) { return bs->drv->bdrv_recurse_is_first_non_filter(bs, candidate); } - return bdrv_generic_is_first_non_filter(bs, candidate); + /* the driver is a block filter but don't allow to recurse -> return false + */ + return false; } /* This function checks if the candidate is the first non filter bs down it's @@ -5441,6 +5443,7 @@ bool bdrv_is_first_non_filter(BlockDriverState *candidate) QTAILQ_FOREACH(bs, &bdrv_states, device_list) { bool perm; + /* try to recurse in this top level bs */ perm = bdrv_recurse_is_first_non_filter(bs, candidate); /* candidate is the first non filter */ diff --git a/block/blkverify.c b/block/blkverify.c index b98b08b..e1c3117 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -288,6 +288,20 @@ static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs, return bdrv_aio_flush(s->test_file, cb, opaque); } +static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs, + BlockDriverState *candidate) +{ + BDRVBlkverifyState *s = bs->opaque; + + bool perm = bdrv_recurse_is_first_non_filter(bs->file, candidate); + + if (perm) { + return true; + } + + return bdrv_recurse_is_first_non_filter(s->test_file, candidate); +} + static BlockDriver bdrv_blkverify = { .format_name = "blkverify", .protocol_name = "blkverify", @@ -302,7 +316,8 @@ static BlockDriver bdrv_blkverify = { .bdrv_aio_writev = blkverify_aio_writev, .bdrv_aio_flush = blkverify_aio_flush, - .authorizations = { true, false }, + .is_filter = true, + .bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter, }; static void bdrv_blkverify_init(void) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 36c1bed..9499df9 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -380,6 +380,10 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs, BLKDBG_EVENT(bs->file, BLKDBG_COW_READ); + if (!bs->drv) { + return -ENOMEDIUM; + } + /* Call .bdrv_co_readv() directly instead of using the public block-layer * interface. This avoids double I/O throttling and request tracking, * which can lead to deadlock when block layer copy-on-read is enabled. diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 8712d8b..6151148 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -96,7 +96,8 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index) refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); if (refcount_table_index >= s->refcount_table_size) return 0; - refcount_block_offset = s->refcount_table[refcount_table_index]; + refcount_block_offset = + s->refcount_table[refcount_table_index] & REFT_OFFSET_MASK; if (!refcount_block_offset) return 0; diff --git a/block/qcow2.c b/block/qcow2.c index cfe80be..945c9d6 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -644,7 +644,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, } /* Clear unknown autoclear feature bits */ - if (!bs->read_only && s->autoclear_features != 0) { + if (!bs->read_only && !(flags & BDRV_O_INCOMING) && s->autoclear_features) { s->autoclear_features = 0; ret = qcow2_update_header(bs); if (ret < 0) { @@ -657,7 +657,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, qemu_co_mutex_init(&s->lock); /* Repair image if dirty */ - if (!(flags & BDRV_O_CHECK) && !bs->read_only && + if (!(flags & (BDRV_O_CHECK | BDRV_O_INCOMING)) && !bs->read_only && (s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) { BdrvCheckResult result = {0}; @@ -1137,10 +1137,12 @@ static void qcow2_close(BlockDriverState *bs) /* else pre-write overlap checks in cache_destroy may crash */ s->l1_table = NULL; - qcow2_cache_flush(bs, s->l2_table_cache); - qcow2_cache_flush(bs, s->refcount_block_cache); + if (!(bs->open_flags & BDRV_O_INCOMING)) { + qcow2_cache_flush(bs, s->l2_table_cache); + qcow2_cache_flush(bs, s->refcount_block_cache); - qcow2_mark_clean(bs); + qcow2_mark_clean(bs); + } qcow2_cache_destroy(bs, s->l2_table_cache); qcow2_cache_destroy(bs, s->refcount_block_cache); @@ -1176,11 +1178,10 @@ static void qcow2_invalidate_cache(BlockDriverState *bs) qcow2_close(bs); - options = qdict_new(); - qdict_put(options, QCOW2_OPT_LAZY_REFCOUNTS, - qbool_from_int(s->use_lazy_refcounts)); + bdrv_invalidate_cache(bs->file); memset(s, 0, sizeof(BDRVQcowState)); + options = qdict_clone_shallow(bs->options); qcow2_open(bs, options, flags, NULL); QDECREF(options); diff --git a/block/qed.c b/block/qed.c index 8802ad3..837accd 100644 --- a/block/qed.c +++ b/block/qed.c @@ -1563,6 +1563,9 @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs) BDRVQEDState *s = bs->opaque; bdrv_qed_close(bs); + + bdrv_invalidate_cache(bs->file); + memset(s, 0, sizeof(BDRVQEDState)); bdrv_qed_open(bs, NULL, bs->open_flags, NULL); } diff --git a/block/quorum.c b/block/quorum.c index bd997b7..33bf2ae 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -852,8 +852,6 @@ static BlockDriver bdrv_quorum = { .bdrv_file_open = quorum_open, .bdrv_close = quorum_close, - .authorizations = { true, true }, - .bdrv_co_flush_to_disk = quorum_co_flush, .bdrv_getlength = quorum_getlength, @@ -862,6 +860,7 @@ static BlockDriver bdrv_quorum = { .bdrv_aio_writev = quorum_aio_writev, .bdrv_invalidate_cache = quorum_invalidate_cache, + .is_filter = true, .bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter, }; diff --git a/block/raw-posix.c b/block/raw-posix.c index e6b4c1f..1688e16 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -1561,6 +1561,15 @@ static int check_hdev_writable(BDRVRawState *s) return 0; } +static void hdev_parse_filename(const char *filename, QDict *options, + Error **errp) +{ + /* The prefix is optional, just as for "file". */ + strstart(filename, "host_device:", &filename); + + qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename))); +} + static int hdev_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { @@ -1767,6 +1776,18 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options, int ret = 0; struct stat stat_buf; int64_t total_size = 0; + bool has_prefix; + + /* This function is used by all three protocol block drivers and therefore + * any of these three prefixes may be given. + * The return value has to be stored somewhere, otherwise this is an error + * due to -Werror=unused-value. */ + has_prefix = + strstart(filename, "host_device:", &filename) || + strstart(filename, "host_cdrom:" , &filename) || + strstart(filename, "host_floppy:", &filename); + + (void)has_prefix; /* Read out options */ while (options && options->name) { @@ -1805,6 +1826,7 @@ static BlockDriver bdrv_host_device = { .instance_size = sizeof(BDRVRawState), .bdrv_needs_filename = true, .bdrv_probe_device = hdev_probe_device, + .bdrv_parse_filename = hdev_parse_filename, .bdrv_file_open = hdev_open, .bdrv_close = raw_close, .bdrv_reopen_prepare = raw_reopen_prepare, @@ -1834,6 +1856,15 @@ static BlockDriver bdrv_host_device = { }; #ifdef __linux__ +static void floppy_parse_filename(const char *filename, QDict *options, + Error **errp) +{ + /* The prefix is optional, just as for "file". */ + strstart(filename, "host_floppy:", &filename); + + qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename))); +} + static int floppy_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { @@ -1939,6 +1970,7 @@ static BlockDriver bdrv_host_floppy = { .instance_size = sizeof(BDRVRawState), .bdrv_needs_filename = true, .bdrv_probe_device = floppy_probe_device, + .bdrv_parse_filename = floppy_parse_filename, .bdrv_file_open = floppy_open, .bdrv_close = raw_close, .bdrv_reopen_prepare = raw_reopen_prepare, @@ -1963,7 +1995,20 @@ static BlockDriver bdrv_host_floppy = { .bdrv_media_changed = floppy_media_changed, .bdrv_eject = floppy_eject, }; +#endif + +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +static void cdrom_parse_filename(const char *filename, QDict *options, + Error **errp) +{ + /* The prefix is optional, just as for "file". */ + strstart(filename, "host_cdrom:", &filename); + qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename))); +} +#endif + +#ifdef __linux__ static int cdrom_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { @@ -2050,6 +2095,7 @@ static BlockDriver bdrv_host_cdrom = { .instance_size = sizeof(BDRVRawState), .bdrv_needs_filename = true, .bdrv_probe_device = cdrom_probe_device, + .bdrv_parse_filename = cdrom_parse_filename, .bdrv_file_open = cdrom_open, .bdrv_close = raw_close, .bdrv_reopen_prepare = raw_reopen_prepare, @@ -2180,6 +2226,7 @@ static BlockDriver bdrv_host_cdrom = { .instance_size = sizeof(BDRVRawState), .bdrv_needs_filename = true, .bdrv_probe_device = cdrom_probe_device, + .bdrv_parse_filename = cdrom_parse_filename, .bdrv_file_open = cdrom_open, .bdrv_close = raw_close, .bdrv_reopen_prepare = raw_reopen_prepare, diff --git a/block/raw-win32.c b/block/raw-win32.c index 9954748..48cb2c2 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -593,6 +593,15 @@ static int hdev_probe_device(const char *filename) return 0; } +static void hdev_parse_filename(const char *filename, QDict *options, + Error **errp) +{ + /* The prefix is optional, just as for "file". */ + strstart(filename, "host_device:", &filename); + + qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename))); +} + static int hdev_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { @@ -663,6 +672,7 @@ static BlockDriver bdrv_host_device = { .protocol_name = "host_device", .instance_size = sizeof(BDRVRawState), .bdrv_needs_filename = true, + .bdrv_parse_filename = hdev_parse_filename, .bdrv_probe_device = hdev_probe_device, .bdrv_file_open = hdev_open, .bdrv_close = raw_close, @@ -31,19 +31,6 @@ printf " '%s'" "$0" "$@" >> config.log echo >> config.log echo "#" >> config.log -# Save the configure command line for later reuse. -cat <<EOD >config.status -#!/bin/sh -# Generated by configure. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. -EOD -printf "exec" >>config.status -printf " '%s'" "$0" "$@" >>config.status -echo >>config.status -chmod +x config.status - error_exit() { echo echo "ERROR: $1" @@ -5146,3 +5133,17 @@ done if test "$docs" = "yes" ; then mkdir -p QMP fi + +# Save the configure command line for later reuse. +cat <<EOD >config.status +#!/bin/sh +# Generated by configure. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. +EOD +printf "exec" >>config.status +printf " '%s'" "$0" "$@" >>config.status +echo >>config.status +chmod +x config.status + diff --git a/device-hotplug.c b/device-hotplug.c index 103d34a..ebfa6b1 100644 --- a/device-hotplug.c +++ b/device-hotplug.c @@ -33,12 +33,14 @@ DriveInfo *add_init_drive(const char *optstr) { DriveInfo *dinfo; QemuOpts *opts; + MachineClass *mc; opts = drive_def(optstr); if (!opts) return NULL; - dinfo = drive_init(opts, current_machine->block_default_type); + mc = MACHINE_GET_CLASS(current_machine); + dinfo = drive_init(opts, mc->qemu_machine->block_default_type); if (!dinfo) { qemu_opts_del(opts); return NULL; diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 0728f36..d78921f 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -123,11 +123,12 @@ And it looks like this on the wire: Flat union types avoid the nesting on the wire. They are used whenever a specific field of the base type is declared as the discriminator ('type' is -then no longer generated). The discriminator must always be a string field. +then no longer generated). The discriminator must be of enumeration type. The above example can then be modified as follows: + { 'enum': 'BlockdevDriver', 'data': [ 'raw', 'qcow2' ] } { 'type': 'BlockdevCommonOptions', - 'data': { 'driver': 'str', 'readonly': 'bool' } } + 'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } } { 'union': 'BlockdevOptions', 'base': 'BlockdevCommonOptions', 'discriminator': 'driver', diff --git a/docs/qemupciserial.inf b/docs/qemupciserial.inf index 3474310..6f7eef4 100644 --- a/docs/qemupciserial.inf +++ b/docs/qemupciserial.inf @@ -11,99 +11,92 @@ ; (Com+Lpt)" from the list. Click "Have a disk". Select this file. ; Procedure may vary a bit depending on the windows version. -; FIXME: This file covers the single port version only. +; This file covers all options: pci-serial, pci-serial-2x, pci-serial-4x +; for both 32 and 64 bit platforms. [Version] -Signature="$CHICAGO$" -Class=Ports -ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Signature="$Windows NT$" +Class=MultiFunction +ClassGUID={4d36e971-e325-11ce-bfc1-08002be10318} Provider=%QEMU% -DriverVer=09/24/2012,1.3.0 - -[SourceDisksNames] -3426=windows cd - -[SourceDisksFiles] -serial.sys = 3426 -serenum.sys = 3426 - -[DestinationDirs] -DefaultDestDir = 11 ;LDID_SYS -ComPort.NT.Copy = 12 ;DIRID_DRIVERS -SerialEnumerator.NT.Copy=12 ;DIRID_DRIVERS - -; Drivers -;---------------------------------------------------------- +DriverVer=12/29/2013,1.3.0 +[ControlFlags] +ExcludeFromSelect=* [Manufacturer] -%QEMU%=QEMU,NTx86 +%QEMU%=QEMU,NTx86,NTAMD64 [QEMU.NTx86] -%QEMU-PCI_SERIAL.DeviceDesc% = ComPort, "PCI\VEN_1b36&DEV_0002&CC_0700" - -; COM sections -;---------------------------------------------------------- -[ComPort.AddReg] -HKR,,PortSubClass,1,01 - -[ComPort.NT] -AddReg=ComPort.AddReg, ComPort.NT.AddReg -LogConfig=caa -SyssetupPnPFlags = 1 - -[ComPort.NT.HW] -AddReg=ComPort.NT.HW.AddReg - -[ComPort.NT.AddReg] -HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" - -[ComPort.NT.HW.AddReg] -HKR,,"UpperFilters",0x00010000,"serenum" - -;-------------- Service installation -; Port Driver (function driver for this device) -[ComPort.NT.Services] -AddService = Serial, 0x00000002, Serial_Service_Inst, Serial_EventLog_Inst -AddService = Serenum,,Serenum_Service_Inst - -; -------------- Serial Port Driver install sections -[Serial_Service_Inst] -DisplayName = %Serial.SVCDESC% -ServiceType = 1 ; SERVICE_KERNEL_DRIVER -StartType = 1 ; SERVICE_SYSTEM_START (this driver may do detection) -ErrorControl = 0 ; SERVICE_ERROR_IGNORE -ServiceBinary = %12%\serial.sys -LoadOrderGroup = Extended base - -; -------------- Serenum Driver install section -[Serenum_Service_Inst] -DisplayName = %Serenum.SVCDESC% -ServiceType = 1 ; SERVICE_KERNEL_DRIVER -StartType = 3 ; SERVICE_DEMAND_START -ErrorControl = 1 ; SERVICE_ERROR_NORMAL -ServiceBinary = %12%\serenum.sys -LoadOrderGroup = PNP Filter - -[Serial_EventLog_Inst] -AddReg = Serial_EventLog_AddReg - -[Serial_EventLog_AddReg] -HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\serial.sys" -HKR,,TypesSupported,0x00010001,7 - -; The following sections are COM port resource configs. -; Section name format means: -; Char 1 = c (COM port) -; Char 2 = I/O config: 1 (3f8), 2 (2f8), 3 (3e8), 4 (2e8), a (any) -; Char 3 = IRQ config: #, a (any) - -[caa] ; Any base, any IRQ -ConfigPriority=HARDRECONFIG -IOConfig=8@100-ffff%fff8(3ff::) -IRQConfig=S:3,4,5,7,9,10,11,12,14,15 +%QEMU-PCI_SERIAL_1_PORT%=ComPort_inst1, PCI\VEN_1B36&DEV_0002 +%QEMU-PCI_SERIAL_2_PORT%=ComPort_inst2, PCI\VEN_1B36&DEV_0003 +%QEMU-PCI_SERIAL_4_PORT%=ComPort_inst4, PCI\VEN_1B36&DEV_0004 + +[QEMU.NTAMD64] +%QEMU-PCI_SERIAL_1_PORT%=ComPort_inst1, PCI\VEN_1B36&DEV_0002 +%QEMU-PCI_SERIAL_2_PORT%=ComPort_inst2, PCI\VEN_1B36&DEV_0003 +%QEMU-PCI_SERIAL_4_PORT%=ComPort_inst4, PCI\VEN_1B36&DEV_0004 + +[ComPort_inst1] +Include=mf.inf +Needs=MFINSTALL.mf + +[ComPort_inst2] +Include=mf.inf +Needs=MFINSTALL.mf + +[ComPort_inst4] +Include=mf.inf +Needs=MFINSTALL.mf + +[ComPort_inst1.HW] +AddReg=ComPort_inst1.RegHW + +[ComPort_inst2.HW] +AddReg=ComPort_inst2.RegHW + +[ComPort_inst4.HW] +AddReg=ComPort_inst4.RegHW + +[ComPort_inst1.Services] +Include=mf.inf +Needs=MFINSTALL.mf.Services + +[ComPort_inst2.Services] +Include=mf.inf +Needs=MFINSTALL.mf.Services + +[ComPort_inst4.Services] +Include=mf.inf +Needs=MFINSTALL.mf.Services + +[ComPort_inst1.RegHW] +HKR,Child0000,HardwareID,,*PNP0501 +HKR,Child0000,VaryingResourceMap,1,00, 00,00,00,00, 08,00,00,00 +HKR,Child0000,ResourceMap,1,02 + +[ComPort_inst2.RegHW] +HKR,Child0000,HardwareID,,*PNP0501 +HKR,Child0000,VaryingResourceMap,1,00, 00,00,00,00, 08,00,00,00 +HKR,Child0000,ResourceMap,1,02 +HKR,Child0001,HardwareID,,*PNP0501 +HKR,Child0001,VaryingResourceMap,1,00, 08,00,00,00, 08,00,00,00 +HKR,Child0001,ResourceMap,1,02 + +[ComPort_inst4.RegHW] +HKR,Child0000,HardwareID,,*PNP0501 +HKR,Child0000,VaryingResourceMap,1,00, 00,00,00,00, 08,00,00,00 +HKR,Child0000,ResourceMap,1,02 +HKR,Child0001,HardwareID,,*PNP0501 +HKR,Child0001,VaryingResourceMap,1,00, 08,00,00,00, 08,00,00,00 +HKR,Child0001,ResourceMap,1,02 +HKR,Child0002,HardwareID,,*PNP0501 +HKR,Child0002,VaryingResourceMap,1,00, 10,00,00,00, 08,00,00,00 +HKR,Child0002,ResourceMap,1,02 +HKR,Child0003,HardwareID,,*PNP0501 +HKR,Child0003,VaryingResourceMap,1,00, 18,00,00,00, 08,00,00,00 +HKR,Child0003,ResourceMap,1,02 [Strings] QEMU="QEMU" -QEMU-PCI_SERIAL.DeviceDesc="QEMU Serial PCI Card" - -Serial.SVCDESC = "Serial port driver" -Serenum.SVCDESC = "Serenum Filter Driver" +QEMU-PCI_SERIAL_1_PORT="1x QEMU PCI Serial Card" +QEMU-PCI_SERIAL_2_PORT="2x QEMU PCI Serial Card" +QEMU-PCI_SERIAL_4_PORT="4x QEMU PCI Serial Card" diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 2decff1..392ca84 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -658,14 +658,15 @@ static void spitz_adc_temp_on(void *opaque, int line, int level) max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); } -static int corgi_ssp_init(SSISlave *dev) +static int corgi_ssp_init(SSISlave *d) { - CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev); + DeviceState *dev = DEVICE(d); + CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d); - qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3); - s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0"); - s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1"); - s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2"); + qdev_init_gpio_in(dev, corgi_ssp_gpio_cs, 3); + s->bus[0] = ssi_create_bus(dev, "ssi0"); + s->bus[1] = ssi_create_bus(dev, "ssi1"); + s->bus[2] = ssi_create_bus(dev, "ssi2"); return 0; } diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index d1c7ad4..a5afc21 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -23,6 +23,7 @@ #include "virtio-blk.h" #include "block/aio.h" #include "hw/virtio/virtio-bus.h" +#include "monitor/monitor.h" /* for object_add() */ enum { SEG_MAX = 126, /* maximum number of I/O segments */ @@ -44,8 +45,6 @@ struct VirtIOBlockDataPlane { bool started; bool starting; bool stopping; - QEMUBH *start_bh; - QemuThread thread; VirtIOBlkConf *blk; int fd; /* image file descriptor */ @@ -59,12 +58,14 @@ struct VirtIOBlockDataPlane { * (because you don't own the file descriptor or handle; you just * use it). */ + IOThread *iothread; + bool internal_iothread; AioContext *ctx; EventNotifier io_notifier; /* Linux AIO completion */ EventNotifier host_notifier; /* doorbell */ IOQueue ioqueue; /* Linux AIO queue (should really be per - dataplane thread) */ + IOThread) */ VirtIOBlockRequest requests[REQ_MAX]; /* pool of requests, managed by the queue */ @@ -342,26 +343,7 @@ static void handle_io(EventNotifier *e) } } -static void *data_plane_thread(void *opaque) -{ - VirtIOBlockDataPlane *s = opaque; - - while (!s->stopping || s->num_reqs > 0) { - aio_poll(s->ctx, true); - } - return NULL; -} - -static void start_data_plane_bh(void *opaque) -{ - VirtIOBlockDataPlane *s = opaque; - - qemu_bh_delete(s->start_bh); - s->start_bh = NULL; - qemu_thread_create(&s->thread, "data_plane", data_plane_thread, - s, QEMU_THREAD_JOINABLE); -} - +/* Context: QEMU global mutex held */ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, VirtIOBlockDataPlane **dataplane, Error **errp) @@ -408,12 +390,33 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, s->fd = fd; s->blk = blk; + if (blk->iothread) { + s->internal_iothread = false; + s->iothread = blk->iothread; + object_ref(OBJECT(s->iothread)); + } else { + /* Create per-device IOThread if none specified */ + Error *local_err = NULL; + + s->internal_iothread = true; + object_add(TYPE_IOTHREAD, vdev->name, NULL, NULL, &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + g_free(s); + return; + } + s->iothread = iothread_find(vdev->name); + assert(s->iothread); + } + s->ctx = iothread_get_aio_context(s->iothread); + /* Prevent block operations that conflict with data plane thread */ bdrv_set_in_use(blk->conf.bs, 1); *dataplane = s; } +/* Context: QEMU global mutex held */ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) { if (!s) { @@ -422,9 +425,14 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) virtio_blk_data_plane_stop(s); bdrv_set_in_use(s->blk->conf.bs, 0); + object_unref(OBJECT(s->iothread)); + if (s->internal_iothread) { + object_unparent(OBJECT(s->iothread)); + } g_free(s); } +/* Context: QEMU global mutex held */ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev))); @@ -448,8 +456,6 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) return; } - s->ctx = aio_context_new(); - /* Set up guest notifier (irq) */ if (k->set_guest_notifiers(qbus->parent, 1, true) != 0) { fprintf(stderr, "virtio-blk failed to set guest notifier, " @@ -464,7 +470,6 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) exit(1); } s->host_notifier = *virtio_queue_get_host_notifier(vq); - aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify); /* Set up ioqueue */ ioq_init(&s->ioqueue, s->fd, REQ_MAX); @@ -472,7 +477,6 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) ioq_put_iocb(&s->ioqueue, &s->requests[i].iocb); } s->io_notifier = *ioq_get_notifier(&s->ioqueue); - aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io); s->starting = false; s->started = true; @@ -481,11 +485,14 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) /* Kick right away to begin processing requests already in vring */ event_notifier_set(virtio_queue_get_host_notifier(vq)); - /* Spawn thread in BH so it inherits iothread cpusets */ - s->start_bh = qemu_bh_new(start_data_plane_bh, s); - qemu_bh_schedule(s->start_bh); + /* Get this show started by hooking up our callbacks */ + aio_context_acquire(s->ctx); + aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify); + aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io); + aio_context_release(s->ctx); } +/* Context: QEMU global mutex held */ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev))); @@ -496,27 +503,32 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) s->stopping = true; trace_virtio_blk_data_plane_stop(s); - /* Stop thread or cancel pending thread creation BH */ - if (s->start_bh) { - qemu_bh_delete(s->start_bh); - s->start_bh = NULL; - } else { - aio_notify(s->ctx); - qemu_thread_join(&s->thread); + aio_context_acquire(s->ctx); + + /* Stop notifications for new requests from guest */ + aio_set_event_notifier(s->ctx, &s->host_notifier, NULL); + + /* Complete pending requests */ + while (s->num_reqs > 0) { + aio_poll(s->ctx, true); } + /* Stop ioq callbacks (there are no pending requests left) */ aio_set_event_notifier(s->ctx, &s->io_notifier, NULL); - ioq_cleanup(&s->ioqueue); - aio_set_event_notifier(s->ctx, &s->host_notifier, NULL); - k->set_host_notifier(qbus->parent, 0, false); + aio_context_release(s->ctx); - aio_context_unref(s->ctx); + /* Sync vring state back to virtqueue so that non-dataplane request + * processing can continue when we disable the host notifier below. + */ + vring_teardown(&s->vring, s->vdev, 0); + + ioq_cleanup(&s->ioqueue); + k->set_host_notifier(qbus->parent, 0, false); /* Clean up guest notifier (irq) */ k->set_guest_notifiers(qbus->parent, 1, false); - vring_teardown(&s->vring, s->vdev, 0); s->started = false; s->stopping = false; } diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 02a1544..e29a738 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -241,7 +241,8 @@ typedef enum { } CMDState; typedef struct Flash { - SSISlave ssidev; + SSISlave parent_obj; + uint32_t r; BlockDriverState *bdrv; @@ -545,7 +546,7 @@ static void decode_new_cmd(Flash *s, uint32_t value) static int m25p80_cs(SSISlave *ss, bool select) { - Flash *s = FROM_SSI_SLAVE(Flash, ss); + Flash *s = M25P80(ss); if (select) { s->len = 0; @@ -561,7 +562,7 @@ static int m25p80_cs(SSISlave *ss, bool select) static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) { - Flash *s = FROM_SSI_SLAVE(Flash, ss); + Flash *s = M25P80(ss); uint32_t r = 0; switch (s->state) { @@ -610,7 +611,7 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) static int m25p80_init(SSISlave *ss) { DriveInfo *dinfo; - Flash *s = FROM_SSI_SLAVE(Flash, ss); + Flash *s = M25P80(ss); M25P80Class *mc = M25P80_GET_CLASS(s); s->pi = mc->pi; diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index 2e00ad2..ffd29a8 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -15,8 +15,13 @@ #include "trace.h" #include "hw/virtio/virtio-serial.h" +#define TYPE_VIRTIO_CONSOLE "virtconsole" +#define VIRTIO_CONSOLE(obj) \ + OBJECT_CHECK(VirtConsole, (obj), TYPE_VIRTIO_CONSOLE) + typedef struct VirtConsole { - VirtIOSerialPort port; + VirtIOSerialPort parent_obj; + CharDriverState *chr; guint watch; } VirtConsole; @@ -31,7 +36,7 @@ static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond, VirtConsole *vcon = opaque; vcon->watch = 0; - virtio_serial_throttle_port(&vcon->port, false); + virtio_serial_throttle_port(VIRTIO_SERIAL_PORT(vcon), false); return FALSE; } @@ -39,7 +44,7 @@ static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond, static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, ssize_t len) { - VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); + VirtConsole *vcon = VIRTIO_CONSOLE(port); ssize_t ret; if (!vcon->chr) { @@ -75,7 +80,7 @@ static ssize_t flush_buf(VirtIOSerialPort *port, /* Callback function that's called when the guest opens/closes the port */ static void set_guest_connected(VirtIOSerialPort *port, int guest_connected) { - VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); + VirtConsole *vcon = VIRTIO_CONSOLE(port); if (!vcon->chr) { return; @@ -88,45 +93,49 @@ static int chr_can_read(void *opaque) { VirtConsole *vcon = opaque; - return virtio_serial_guest_ready(&vcon->port); + return virtio_serial_guest_ready(VIRTIO_SERIAL_PORT(vcon)); } /* Send data from a char device over to the guest */ static void chr_read(void *opaque, const uint8_t *buf, int size) { VirtConsole *vcon = opaque; + VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon); - trace_virtio_console_chr_read(vcon->port.id, size); - virtio_serial_write(&vcon->port, buf, size); + trace_virtio_console_chr_read(port->id, size); + virtio_serial_write(port, buf, size); } static void chr_event(void *opaque, int event) { VirtConsole *vcon = opaque; + VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon); - trace_virtio_console_chr_event(vcon->port.id, event); + trace_virtio_console_chr_event(port->id, event); switch (event) { case CHR_EVENT_OPENED: - virtio_serial_open(&vcon->port); + virtio_serial_open(port); break; case CHR_EVENT_CLOSED: if (vcon->watch) { g_source_remove(vcon->watch); vcon->watch = 0; } - virtio_serial_close(&vcon->port); + virtio_serial_close(port); break; } } -static int virtconsole_initfn(VirtIOSerialPort *port) +static void virtconsole_realize(DeviceState *dev, Error **errp) { - VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); - VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port); + VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); + VirtConsole *vcon = VIRTIO_CONSOLE(dev); + VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev); if (port->id == 0 && !k->is_console) { - error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility."); - return -1; + error_setg(errp, "Port number 0 on virtio-serial devices reserved " + "for virtconsole devices for backward compatibility."); + return; } if (vcon->chr) { @@ -134,19 +143,15 @@ static int virtconsole_initfn(VirtIOSerialPort *port) qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event, vcon); } - - return 0; } -static int virtconsole_exitfn(VirtIOSerialPort *port) +static void virtconsole_unrealize(DeviceState *dev, Error **errp) { - VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); + VirtConsole *vcon = VIRTIO_CONSOLE(dev); if (vcon->watch) { g_source_remove(vcon->watch); } - - return 0; } static Property virtconsole_properties[] = { @@ -160,15 +165,15 @@ static void virtconsole_class_init(ObjectClass *klass, void *data) VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass); k->is_console = true; - k->init = virtconsole_initfn; - k->exit = virtconsole_exitfn; + k->realize = virtconsole_realize; + k->unrealize = virtconsole_unrealize; k->have_data = flush_buf; k->set_guest_connected = set_guest_connected; dc->props = virtconsole_properties; } static const TypeInfo virtconsole_info = { - .name = "virtconsole", + .name = TYPE_VIRTIO_CONSOLE, .parent = TYPE_VIRTIO_SERIAL_PORT, .instance_size = sizeof(VirtConsole), .class_init = virtconsole_class_init, @@ -184,8 +189,8 @@ static void virtserialport_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass); - k->init = virtconsole_initfn; - k->exit = virtconsole_exitfn; + k->realize = virtconsole_realize; + k->unrealize = virtconsole_unrealize; k->have_data = flush_buf; k->set_guest_connected = set_guest_connected; dc->props = virtserialport_properties; diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 226e9f9..2b647b6 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -808,13 +808,14 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id) send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1); } -static int virtser_port_qdev_init(DeviceState *qdev) +static void virtser_port_device_realize(DeviceState *dev, Error **errp) { - VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev); + VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); - VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus); - int ret, max_nr_ports; + VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev)); + int max_nr_ports; bool plugging_port0; + Error *err = NULL; port->vser = bus->vser; port->bh = qemu_bh_new(flush_queued_data_bh, port); @@ -829,9 +830,9 @@ static int virtser_port_qdev_init(DeviceState *qdev) plugging_port0 = vsc->is_console && !find_port_by_id(port->vser, 0); if (find_port_by_id(port->vser, port->id)) { - error_report("virtio-serial-bus: A port already exists at id %u", - port->id); - return -1; + error_setg(errp, "virtio-serial-bus: A port already exists at id %u", + port->id); + return; } if (port->id == VIRTIO_CONSOLE_BAD_ID) { @@ -840,22 +841,24 @@ static int virtser_port_qdev_init(DeviceState *qdev) } else { port->id = find_free_port_id(port->vser); if (port->id == VIRTIO_CONSOLE_BAD_ID) { - error_report("virtio-serial-bus: Maximum port limit for this device reached"); - return -1; + error_setg(errp, "virtio-serial-bus: Maximum port limit for " + "this device reached"); + return; } } } max_nr_ports = tswap32(port->vser->config.max_nr_ports); if (port->id >= max_nr_ports) { - error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u", - max_nr_ports - 1); - return -1; + error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, " + "max. allowed: %u", max_nr_ports - 1); + return; } - ret = vsc->init(port); - if (ret) { - return ret; + vsc->realize(dev, &err); + if (err != NULL) { + error_propagate(errp, err); + return; } port->elem.out_num = 0; @@ -868,14 +871,12 @@ static int virtser_port_qdev_init(DeviceState *qdev) /* Send an update to the guest about this new port added */ virtio_notify_config(VIRTIO_DEVICE(port->vser)); - - return ret; } -static int virtser_port_qdev_exit(DeviceState *qdev) +static void virtser_port_device_unrealize(DeviceState *dev, Error **errp) { - VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev); - VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); + VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); + VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(dev); VirtIOSerial *vser = port->vser; qemu_bh_delete(port->bh); @@ -883,10 +884,9 @@ static int virtser_port_qdev_exit(DeviceState *qdev) QTAILQ_REMOVE(&vser->ports, port, next); - if (vsc->exit) { - vsc->exit(port); + if (vsc->unrealize) { + vsc->unrealize(dev, errp); } - return 0; } static void virtio_serial_device_realize(DeviceState *dev, Error **errp) @@ -971,10 +971,11 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp) static void virtio_serial_port_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); - k->init = virtser_port_qdev_init; + set_bit(DEVICE_CATEGORY_INPUT, k->categories); k->bus_type = TYPE_VIRTIO_SERIAL_BUS; - k->exit = virtser_port_qdev_exit; + k->realize = virtser_port_device_realize; + k->unrealize = virtser_port_device_unrealize; k->unplug = qdev_simple_unplug_cb; k->props = virtser_props; } diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 9e324be..981593c 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -8,7 +8,7 @@ common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o common-obj-$(CONFIG_XILINX_AXI) += stream.o common-obj-$(CONFIG_PTIMER) += ptimer.o common-obj-$(CONFIG_SOFTMMU) += sysbus.o +common-obj-$(CONFIG_SOFTMMU) += machine.o common-obj-$(CONFIG_SOFTMMU) += null-machine.o common-obj-$(CONFIG_SOFTMMU) += loader.o common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o - diff --git a/hw/core/loader.c b/hw/core/loader.c index b323c0c..2bf6b8f 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -54,7 +54,8 @@ #include <zlib.h> -bool rom_file_in_ram = true; +bool option_rom_has_mr = false; +bool rom_file_has_mr = true; static int roms_loaded; @@ -642,7 +643,8 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name) } int rom_add_file(const char *file, const char *fw_dir, - hwaddr addr, int32_t bootindex) + hwaddr addr, int32_t bootindex, + bool option_rom) { Rom *rom; int rc, fd = -1; @@ -694,7 +696,7 @@ int rom_add_file(const char *file, const char *fw_dir, basename); snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name); - if (rom_file_in_ram) { + if ((!option_rom || option_rom_has_mr) && rom_file_has_mr) { data = rom_set_mr(rom, OBJECT(fw_cfg), devpath); } else { data = rom->data; @@ -738,7 +740,7 @@ void *rom_add_blob(const char *name, const void *blob, size_t len, snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name); - if (rom_file_in_ram) { + if (rom_file_has_mr) { data = rom_set_mr(rom, OBJECT(fw_cfg), devpath); } else { data = rom->data; @@ -773,12 +775,12 @@ int rom_add_elf_program(const char *name, void *data, size_t datasize, int rom_add_vga(const char *file) { - return rom_add_file(file, "vgaroms", 0, -1); + return rom_add_file(file, "vgaroms", 0, -1, true); } int rom_add_option(const char *file, int32_t bootindex) { - return rom_add_file(file, "genroms", 0, bootindex); + return rom_add_file(file, "genroms", 0, bootindex, true); } static void rom_reset(void *unused) diff --git a/hw/core/machine.c b/hw/core/machine.c new file mode 100644 index 0000000..d3ffef7 --- /dev/null +++ b/hw/core/machine.c @@ -0,0 +1,28 @@ +/* + * QEMU Machine + * + * Copyright (C) 2014 Red Hat Inc + * + * Authors: + * Marcel Apfelbaum <marcel.a@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 "hw/boards.h" + +static const TypeInfo machine_info = { + .name = TYPE_MACHINE, + .parent = TYPE_OBJECT, + .abstract = true, + .class_size = sizeof(MachineClass), + .instance_size = sizeof(MachineState), +}; + +static void machine_register_types(void) +{ + type_register_static(&machine_info); +} + +type_init(machine_register_types) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 5f5957e..de83561 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -18,17 +18,19 @@ #include "net/hub.h" #include "qapi/visitor.h" #include "sysemu/char.h" +#include "sysemu/iothread.h" static void get_pointer(Object *obj, Visitor *v, Property *prop, - const char *(*print)(void *ptr), + char *(*print)(void *ptr), const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); void **ptr = qdev_get_prop_ptr(dev, prop); char *p; - p = (char *) (*ptr ? print(*ptr) : ""); + p = *ptr ? print(*ptr) : g_strdup(""); visit_type_str(v, &p, name, errp); + g_free(p); } static void set_pointer(Object *obj, Visitor *v, Property *prop, @@ -91,9 +93,9 @@ static void release_drive(Object *obj, const char *name, void *opaque) } } -static const char *print_drive(void *ptr) +static char *print_drive(void *ptr) { - return bdrv_get_device_name(ptr); + return g_strdup(bdrv_get_device_name(ptr)); } static void get_drive(Object *obj, Visitor *v, void *opaque, @@ -145,11 +147,12 @@ static void release_chr(Object *obj, const char *name, void *opaque) } -static const char *print_chr(void *ptr) +static char *print_chr(void *ptr) { CharDriverState *chr = ptr; + const char *val = chr->label ? chr->label : ""; - return chr->label ? chr->label : ""; + return g_strdup(val); } static void get_chr(Object *obj, Visitor *v, void *opaque, @@ -224,11 +227,12 @@ err: return ret; } -static const char *print_netdev(void *ptr) +static char *print_netdev(void *ptr) { NetClientState *netdev = ptr; + const char *val = netdev->name ? netdev->name : ""; - return netdev->name ? netdev->name : ""; + return g_strdup(val); } static void get_netdev(Object *obj, Visitor *v, void *opaque, @@ -382,6 +386,56 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) nd->instantiated = 1; } +/* --- iothread --- */ + +static char *print_iothread(void *ptr) +{ + return iothread_get_id(ptr); +} + +static int parse_iothread(DeviceState *dev, const char *str, void **ptr) +{ + IOThread *iothread; + + iothread = iothread_find(str); + if (!iothread) { + return -ENOENT; + } + object_ref(OBJECT(iothread)); + *ptr = iothread; + return 0; +} + +static void get_iothread(Object *obj, struct Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_iothread, name, errp); +} + +static void set_iothread(Object *obj, struct Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_iothread, name, errp); +} + +static void release_iothread(Object *obj, const char *name, void *opaque) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + IOThread **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { + object_unref(OBJECT(*ptr)); + } +} + +PropertyInfo qdev_prop_iothread = { + .name = "iothread", + .get = get_iothread, + .set = set_iothread, + .release = release_iothread, +}; + static int qdev_add_one_global(QemuOpts *opts, void *opaque) { GlobalProperty *g; diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 380976a..9f0a522 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -501,6 +501,45 @@ static void bus_unparent(Object *obj) } } +static bool bus_get_realized(Object *obj, Error **err) +{ + BusState *bus = BUS(obj); + + return bus->realized; +} + +static void bus_set_realized(Object *obj, bool value, Error **err) +{ + BusState *bus = BUS(obj); + BusClass *bc = BUS_GET_CLASS(bus); + Error *local_err = NULL; + + if (value && !bus->realized) { + if (bc->realize) { + bc->realize(bus, &local_err); + + if (local_err != NULL) { + goto error; + } + + } + } else if (!value && bus->realized) { + if (bc->unrealize) { + bc->unrealize(bus, &local_err); + + if (local_err != NULL) { + goto error; + } + } + } + + bus->realized = value; + return; + +error: + error_propagate(err, local_err); +} + void qbus_create_inplace(void *bus, size_t size, const char *typename, DeviceState *parent, const char *name) { @@ -677,6 +716,7 @@ static void device_set_realized(Object *obj, bool value, Error **err) { DeviceState *dev = DEVICE(obj); DeviceClass *dc = DEVICE_GET_CLASS(dev); + BusState *bus; Error *local_err = NULL; if (dev->hotplugged && !dc->hotpluggable) { @@ -710,14 +750,30 @@ static void device_set_realized(Object *obj, bool value, Error **err) dev->instance_id_alias, dev->alias_required_for_version); } + if (local_err == NULL) { + QLIST_FOREACH(bus, &dev->child_bus, sibling) { + object_property_set_bool(OBJECT(bus), true, "realized", + &local_err); + if (local_err != NULL) { + break; + } + } + } if (dev->hotplugged && local_err == NULL) { device_reset(dev); } } else if (!value && dev->realized) { - if (qdev_get_vmsd(dev)) { + QLIST_FOREACH(bus, &dev->child_bus, sibling) { + object_property_set_bool(OBJECT(bus), false, "realized", + &local_err); + if (local_err != NULL) { + break; + } + } + if (qdev_get_vmsd(dev) && local_err == NULL) { vmstate_unregister(dev, qdev_get_vmsd(dev), dev); } - if (dc->unrealize) { + if (dc->unrealize && local_err == NULL) { dc->unrealize(dev, &local_err); } } @@ -735,7 +791,8 @@ static bool device_get_hotpluggable(Object *obj, Error **err) DeviceClass *dc = DEVICE_GET_CLASS(obj); DeviceState *dev = DEVICE(obj); - return dc->hotpluggable && dev->parent_bus->allow_hotplug; + return dc->hotpluggable && (dev->parent_bus == NULL || + dev->parent_bus->allow_hotplug); } static void device_initfn(Object *obj) @@ -792,14 +849,6 @@ static void device_class_base_init(ObjectClass *class, void *data) * so do not propagate them to the subclasses. */ klass->props = NULL; - - /* by default all devices were considered as hotpluggable, - * so with intent to check it in generic qdev_unplug() / - * device_set_realized() functions make every device - * hotpluggable. Devices that shouldn't be hotpluggable, - * should override it in their class_init() - */ - klass->hotpluggable = true; } static void device_unparent(Object *obj) @@ -809,13 +858,13 @@ static void device_unparent(Object *obj) QObject *event_data; bool have_realized = dev->realized; + if (dev->realized) { + object_property_set_bool(obj, false, "realized", NULL); + } while (dev->num_child_bus) { bus = QLIST_FIRST(&dev->child_bus); object_unparent(OBJECT(bus)); } - if (dev->realized) { - object_property_set_bool(obj, false, "realized", NULL); - } if (dev->parent_bus) { bus_remove_child(dev->parent_bus, dev); object_unref(OBJECT(dev->parent_bus)); @@ -845,6 +894,14 @@ static void device_class_init(ObjectClass *class, void *data) class->unparent = device_unparent; dc->realize = device_realize; dc->unrealize = device_unrealize; + + /* by default all devices were considered as hotpluggable, + * so with intent to check it in generic qdev_unplug() / + * device_set_realized() functions make every device + * hotpluggable. Devices that shouldn't be hotpluggable, + * should override it in their class_init() + */ + dc->hotpluggable = true; } void device_reset(DeviceState *dev) @@ -888,6 +945,8 @@ static void qbus_initfn(Object *obj) object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY, TYPE_HOTPLUG_HANDLER, (Object **)&bus->hotplug_handler, NULL); + object_property_add_bool(obj, "realized", + bus_get_realized, bus_set_realized, NULL); } static char *default_bus_get_fw_dev_path(DeviceState *dev) diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c index 5da3dc5..85252a2 100644 --- a/hw/display/ads7846.c +++ b/hw/display/ads7846.c @@ -133,11 +133,12 @@ static const VMStateDescription vmstate_ads7846 = { } }; -static int ads7846_init(SSISlave *dev) +static int ads7846_init(SSISlave *d) { - ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev); + DeviceState *dev = DEVICE(d); + ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, d); - qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1); + qdev_init_gpio_out(dev, &s->interrupt, 1); s->input[0] = ADS_TEMP0; /* TEMP0 */ s->input[2] = ADS_VBAT; /* VBAT */ diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index 46c3b40..971152e 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -336,18 +336,19 @@ static const GraphicHwOps ssd0323_ops = { .gfx_update = ssd0323_update_display, }; -static int ssd0323_init(SSISlave *dev) +static int ssd0323_init(SSISlave *d) { - ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev); + DeviceState *dev = DEVICE(d); + ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, d); s->col_end = 63; s->row_end = 79; - s->con = graphic_console_init(DEVICE(dev), 0, &ssd0323_ops, s); + s->con = graphic_console_init(dev, 0, &ssd0323_ops, s); qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY); - qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1); + qdev_init_gpio_in(dev, ssd0323_cd, 1); - register_savevm(&dev->qdev, "ssd0323_oled", -1, 1, + register_savevm(dev, "ssd0323_oled", -1, 1, ssd0323_save, ssd0323_load, s); return 0; } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index b667d31..7ecfd70 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -466,9 +466,15 @@ static void acpi_align_size(GArray *blob, unsigned align) g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align)); } -/* Get pointer within table in a safe manner */ -#define ACPI_BUILD_PTR(table, size, off, type) \ - ((type *)(acpi_data_get_ptr(table, size, off, sizeof(type)))) +/* Set a value within table in a safe manner */ +#define ACPI_BUILD_SET_LE(table, size, off, bits, val) \ + do { \ + uint64_t ACPI_BUILD_SET_LE_val = cpu_to_le64(val); \ + memcpy(acpi_data_get_ptr(table, size, off, \ + (bits) / BITS_PER_BYTE), \ + &ACPI_BUILD_SET_LE_val, \ + (bits) / BITS_PER_BYTE); \ + } while (0) static inline void *acpi_data_get_ptr(uint8_t *table_data, unsigned table_size, unsigned off, unsigned size) @@ -974,22 +980,17 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state) static void patch_pci_windows(PcPciInfo *pci, uint8_t *start, unsigned size) { - *ACPI_BUILD_PTR(start, size, acpi_pci32_start[0], uint32_t) = - cpu_to_le32(pci->w32.begin); + ACPI_BUILD_SET_LE(start, size, acpi_pci32_start[0], 32, pci->w32.begin); - *ACPI_BUILD_PTR(start, size, acpi_pci32_end[0], uint32_t) = - cpu_to_le32(pci->w32.end - 1); + ACPI_BUILD_SET_LE(start, size, acpi_pci32_end[0], 32, pci->w32.end - 1); if (pci->w64.end || pci->w64.begin) { - *ACPI_BUILD_PTR(start, size, acpi_pci64_valid[0], uint8_t) = 1; - *ACPI_BUILD_PTR(start, size, acpi_pci64_start[0], uint64_t) = - cpu_to_le64(pci->w64.begin); - *ACPI_BUILD_PTR(start, size, acpi_pci64_end[0], uint64_t) = - cpu_to_le64(pci->w64.end - 1); - *ACPI_BUILD_PTR(start, size, acpi_pci64_length[0], uint64_t) = - cpu_to_le64(pci->w64.end - pci->w64.begin); + ACPI_BUILD_SET_LE(start, size, acpi_pci64_valid[0], 8, 1); + ACPI_BUILD_SET_LE(start, size, acpi_pci64_start[0], 64, pci->w64.begin); + ACPI_BUILD_SET_LE(start, size, acpi_pci64_end[0], 64, pci->w64.end - 1); + ACPI_BUILD_SET_LE(start, size, acpi_pci64_length[0], 64, pci->w64.end - pci->w64.begin); } else { - *ACPI_BUILD_PTR(start, size, acpi_pci64_valid[0], uint8_t) = 0; + ACPI_BUILD_SET_LE(start, size, acpi_pci64_valid[0], 8, 0); } } diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index ae1699d..5e1d2d3 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -266,13 +266,14 @@ static void pc_compat_1_7(QEMUMachineInitArgs *args) { smbios_type1_defaults = false; gigabyte_align = false; + option_rom_has_mr = true; } static void pc_compat_1_6(QEMUMachineInitArgs *args) { pc_compat_1_7(args); has_pci_info = false; - rom_file_in_ram = false; + rom_file_has_mr = false; has_acpi_build = false; } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index a7f6260..4b0456a 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -244,13 +244,14 @@ static void pc_compat_1_7(QEMUMachineInitArgs *args) { smbios_type1_defaults = false; gigabyte_align = false; + option_rom_has_mr = true; } static void pc_compat_1_6(QEMUMachineInitArgs *args) { pc_compat_1_7(args); has_pci_info = false; - rom_file_in_ram = false; + rom_file_has_mr = false; has_acpi_build = false; } diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index a5bbc24..c93dae0 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -269,7 +269,16 @@ static void ics_kvm_set_irq(void *opaque, int srcno, int val) static void ics_kvm_reset(DeviceState *dev) { - ics_set_kvm_state(ICS(dev), 1); + ICSState *ics = ICS(dev); + int i; + + memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs); + for (i = 0; i < ics->nr_irqs; i++) { + ics->irqs[i].priority = 0xff; + ics->irqs[i].saved_priority = 0xff; + } + + ics_set_kvm_state(ics, 1); } static void ics_kvm_realize(DeviceState *dev, Error **errp) diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c index d477ecd..bba87c2 100644 --- a/hw/misc/max111x.c +++ b/hw/misc/max111x.c @@ -13,7 +13,8 @@ #include "hw/ssi.h" typedef struct { - SSISlave ssidev; + SSISlave parent_obj; + qemu_irq interrupt; uint8_t tb1, rb2, rb3; int cycle; @@ -22,6 +23,14 @@ typedef struct { int inputs, com; } MAX111xState; +#define TYPE_MAX_111X "max111x" + +#define MAX_111X(obj) \ + OBJECT_CHECK(MAX111xState, (obj), TYPE_MAX_111X) + +#define TYPE_MAX_1110 "max1110" +#define TYPE_MAX_1111 "max1111" + /* Control-byte bitfields */ #define CB_PD0 (1 << 0) #define CB_PD1 (1 << 1) @@ -92,7 +101,7 @@ static void max111x_write(MAX111xState *s, uint32_t value) static uint32_t max111x_transfer(SSISlave *dev, uint32_t value) { - MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev); + MAX111xState *s = MAX_111X(dev); max111x_write(s, value); return max111x_read(s); } @@ -103,7 +112,7 @@ static const VMStateDescription vmstate_max111x = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_SSI_SLAVE(ssidev, MAX111xState), + VMSTATE_SSI_SLAVE(parent_obj, MAX111xState), VMSTATE_UINT8(tb1, MAX111xState), VMSTATE_UINT8(rb2, MAX111xState), VMSTATE_UINT8(rb3, MAX111xState), @@ -115,11 +124,12 @@ static const VMStateDescription vmstate_max111x = { } }; -static int max111x_init(SSISlave *dev, int inputs) +static int max111x_init(SSISlave *d, int inputs) { - MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev); + DeviceState *dev = DEVICE(d); + MAX111xState *s = MAX_111X(dev); - qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1); + qdev_init_gpio_out(dev, &s->interrupt, 1); s->inputs = inputs; /* TODO: add a user interface for setting these */ @@ -133,7 +143,7 @@ static int max111x_init(SSISlave *dev, int inputs) s->input[7] = 0x80; s->com = 0; - vmstate_register(&dev->qdev, -1, &vmstate_max111x, s); + vmstate_register(dev, -1, &vmstate_max111x, s); return 0; } @@ -149,23 +159,36 @@ static int max1111_init(SSISlave *dev) void max111x_set_input(DeviceState *dev, int line, uint8_t value) { - MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, SSI_SLAVE_FROM_QDEV(dev)); + MAX111xState *s = MAX_111X(dev); assert(line >= 0 && line < s->inputs); s->input[line] = value; } -static void max1110_class_init(ObjectClass *klass, void *data) +static void max111x_class_init(ObjectClass *klass, void *data) { SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - k->init = max1110_init; k->transfer = max111x_transfer; } -static const TypeInfo max1110_info = { - .name = "max1110", +static const TypeInfo max111x_info = { + .name = TYPE_MAX_111X, .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(MAX111xState), + .class_init = max111x_class_init, + .abstract = true, +}; + +static void max1110_class_init(ObjectClass *klass, void *data) +{ + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = max1110_init; +} + +static const TypeInfo max1110_info = { + .name = TYPE_MAX_1110, + .parent = TYPE_MAX_111X, .class_init = max1110_class_init, }; @@ -174,18 +197,17 @@ static void max1111_class_init(ObjectClass *klass, void *data) SSISlaveClass *k = SSI_SLAVE_CLASS(klass); k->init = max1111_init; - k->transfer = max111x_transfer; } static const TypeInfo max1111_info = { - .name = "max1111", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(MAX111xState), + .name = TYPE_MAX_1111, + .parent = TYPE_MAX_111X, .class_init = max1111_class_init, }; static void max111x_register_types(void) { + type_register_static(&max111x_info); type_register_static(&max1110_info); type_register_static(&max1111_info); } diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 4bc2e01..8b8cc4e 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -272,7 +272,7 @@ static void mch_update_smram(MCHPCIState *mch) PCIDevice *pd = PCI_DEVICE(mch); memory_region_transaction_begin(); - smram_update(&mch->smram_region, pd->config[MCH_HOST_BRDIGE_SMRAM], + smram_update(&mch->smram_region, pd->config[MCH_HOST_BRIDGE_SMRAM], mch->smm_enabled); memory_region_transaction_commit(); } @@ -283,7 +283,7 @@ static void mch_set_smm(int smm, void *arg) PCIDevice *pd = PCI_DEVICE(mch); memory_region_transaction_begin(); - smram_set_smm(&mch->smm_enabled, smm, pd->config[MCH_HOST_BRDIGE_SMRAM], + smram_set_smm(&mch->smm_enabled, smm, pd->config[MCH_HOST_BRIDGE_SMRAM], &mch->smram_region); memory_region_transaction_commit(); } @@ -306,8 +306,8 @@ static void mch_write_config(PCIDevice *d, mch_update_pciexbar(mch); } - if (ranges_overlap(address, len, MCH_HOST_BRDIGE_SMRAM, - MCH_HOST_BRDIGE_SMRAM_SIZE)) { + if (ranges_overlap(address, len, MCH_HOST_BRIDGE_SMRAM, + MCH_HOST_BRIDGE_SMRAM_SIZE)) { mch_update_smram(mch); } } @@ -347,7 +347,7 @@ static void mch_reset(DeviceState *qdev) pci_set_quad(d->config + MCH_HOST_BRIDGE_PCIEXBAR, MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT); - d->config[MCH_HOST_BRDIGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT; + d->config[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT; mch_update(mch); } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 4e0701d..8f722dd 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -48,7 +48,6 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *pcibus_get_dev_path(DeviceState *dev); static char *pcibus_get_fw_dev_path(DeviceState *dev); static void pcibus_reset(BusState *qbus); -static void pci_bus_finalize(Object *obj); static Property pci_props[] = { DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), @@ -61,6 +60,34 @@ static Property pci_props[] = { DEFINE_PROP_END_OF_LIST() }; +static const VMStateDescription vmstate_pcibus = { + .name = "PCIBUS", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32_EQUAL(nirq, PCIBus), + VMSTATE_VARRAY_INT32(irq_count, PCIBus, + nirq, 0, vmstate_info_int32, + int32_t), + VMSTATE_END_OF_LIST() + } +}; + +static void pci_bus_realize(BusState *qbus, Error **errp) +{ + PCIBus *bus = PCI_BUS(qbus); + + vmstate_register(NULL, -1, &vmstate_pcibus, bus); +} + +static void pci_bus_unrealize(BusState *qbus, Error **errp) +{ + PCIBus *bus = PCI_BUS(qbus); + + vmstate_unregister(NULL, &vmstate_pcibus, bus); +} + static void pci_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); @@ -68,6 +95,8 @@ static void pci_bus_class_init(ObjectClass *klass, void *data) k->print_dev = pcibus_dev_print; k->get_dev_path = pcibus_get_dev_path; k->get_fw_dev_path = pcibus_get_fw_dev_path; + k->realize = pci_bus_realize; + k->unrealize = pci_bus_unrealize; k->reset = pcibus_reset; } @@ -75,7 +104,6 @@ static const TypeInfo pci_bus_info = { .name = TYPE_PCI_BUS, .parent = TYPE_BUS, .instance_size = sizeof(PCIBus), - .instance_finalize = pci_bus_finalize, .class_init = pci_bus_class_init, }; @@ -95,17 +123,6 @@ static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU; static QLIST_HEAD(, PCIHostState) pci_host_bridges; -static const VMStateDescription vmstate_pcibus = { - .name = "PCIBUS", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_INT32_EQUAL(nirq, PCIBus), - VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32, int32_t), - VMSTATE_END_OF_LIST() - } -}; static int pci_bar(PCIDevice *d, int reg) { uint8_t type; @@ -299,8 +316,6 @@ static void pci_bus_init(PCIBus *bus, DeviceState *parent, QLIST_INIT(&bus->child); pci_host_bus_register(bus, parent); - - vmstate_register(NULL, -1, &vmstate_pcibus, bus); } bool pci_bus_is_express(PCIBus *bus) @@ -369,12 +384,6 @@ int pci_bus_num(PCIBus *s) return s->parent_dev->config[PCI_SECONDARY_BUS]; } -static void pci_bus_finalize(Object *obj) -{ - PCIBus *bus = PCI_BUS(obj); - vmstate_unregister(NULL, &vmstate_pcibus, bus); -} - static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) { PCIDevice *s = container_of(pv, PCIDevice, config); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index cea9469..cbef095 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -32,6 +32,7 @@ #include "exec/address-spaces.h" #include <libfdt.h> #include "trace.h" +#include "qemu/error-report.h" #include "hw/pci/pci_bus.h" @@ -292,7 +293,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, ret_intr_type = RTAS_TYPE_MSIX; break; default: - fprintf(stderr, "rtas_ibm_change_msi(%u) is not implemented\n", func); + error_report("rtas_ibm_change_msi(%u) is not implemented", func); rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } @@ -326,7 +327,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, /* Find a device number in the map to add or reuse the existing one */ ndev = spapr_msicfg_find(phb, config_addr, true); if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) { - fprintf(stderr, "No free entry for a new MSI device\n"); + error_report("No free entry for a new MSI device"); rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -335,7 +336,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, /* Check if there is an old config and MSI number has not changed */ if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) { /* Unexpected behaviour */ - fprintf(stderr, "Cannot reuse MSI config for device#%d", ndev); + error_report("Cannot reuse MSI config for device#%d", ndev); rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -345,7 +346,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, irq = spapr_allocate_irq_block(req_num, false, ret_intr_type == RTAS_TYPE_MSI); if (irq < 0) { - fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev); + error_report("Cannot allocate MSIs for device#%d", ndev); rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -505,12 +506,11 @@ static AddressSpace *spapr_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &phb->iommu_as; } -static int spapr_phb_init(SysBusDevice *s) +static void spapr_phb_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(s); + SysBusDevice *s = SYS_BUS_DEVICE(dev); sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); PCIHostState *phb = PCI_HOST_BRIDGE(s); - const char *busname; char *namebuf; int i; PCIBus *bus; @@ -521,9 +521,9 @@ static int spapr_phb_init(SysBusDevice *s) if ((sphb->buid != -1) || (sphb->dma_liobn != -1) || (sphb->mem_win_addr != -1) || (sphb->io_win_addr != -1)) { - fprintf(stderr, "Either \"index\" or other parameters must" - " be specified for PAPR PHB, not both\n"); - return -1; + error_setg(errp, "Either \"index\" or other parameters must" + " be specified for PAPR PHB, not both"); + return; } sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index; @@ -536,28 +536,28 @@ static int spapr_phb_init(SysBusDevice *s) } if (sphb->buid == -1) { - fprintf(stderr, "BUID not specified for PHB\n"); - return -1; + error_setg(errp, "BUID not specified for PHB"); + return; } if (sphb->dma_liobn == -1) { - fprintf(stderr, "LIOBN not specified for PHB\n"); - return -1; + error_setg(errp, "LIOBN not specified for PHB"); + return; } if (sphb->mem_win_addr == -1) { - fprintf(stderr, "Memory window address not specified for PHB\n"); - return -1; + error_setg(errp, "Memory window address not specified for PHB"); + return; } if (sphb->io_win_addr == -1) { - fprintf(stderr, "IO window address not specified for PHB\n"); - return -1; + error_setg(errp, "IO window address not specified for PHB"); + return; } if (find_phb(spapr, sphb->buid)) { - fprintf(stderr, "PCI host bridges must have unique BUIDs\n"); - return -1; + error_setg(errp, "PCI host bridges must have unique BUIDs"); + return; } sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid); @@ -594,26 +594,8 @@ static int spapr_phb_init(SysBusDevice *s) get_system_io(), 0, SPAPR_PCI_IO_WIN_SIZE); memory_region_add_subregion(get_system_memory(), sphb->io_win_addr, &sphb->iowindow); - /* - * Selecting a busname is more complex than you'd think, due to - * interacting constraints. If the user has specified an id - * explicitly for the phb , then we want to use the qdev default - * of naming the bus based on the bridge device (so the user can - * then assign devices to it in the way they expect). For the - * first / default PCI bus (index=0) we want to use just "pci" - * because libvirt expects there to be a bus called, simply, - * "pci". Otherwise, we use the same name as in the device tree, - * since it's unique by construction, and makes the guest visible - * BUID clear. - */ - if (dev->id) { - busname = NULL; - } else if (sphb->index == 0) { - busname = "pci"; - } else { - busname = sphb->dtbusname; - } - bus = pci_register_bus(dev, busname, + + bus = pci_register_bus(dev, NULL, pci_spapr_set_irq, pci_spapr_map_irq, sphb, &sphb->memspace, &sphb->iospace, PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS); @@ -624,8 +606,9 @@ static int spapr_phb_init(SysBusDevice *s) sphb->tcet = spapr_tce_new_table(dev, sphb->dma_liobn, sphb->dma_window_size); if (!sphb->tcet) { - fprintf(stderr, "Unable to create TCE table for %s\n", sphb->dtbusname); - return -1; + error_setg(errp, "Unable to create TCE table for %s", + sphb->dtbusname); + return; } address_space_init(&sphb->iommu_as, spapr_tce_get_iommu(sphb->tcet), sphb->dtbusname); @@ -642,13 +625,12 @@ static int spapr_phb_init(SysBusDevice *s) irq = spapr_allocate_lsi(0); if (!irq) { - return -1; + error_setg(errp, "spapr_allocate_lsi failed"); + return; } sphb->lsi_table[i].irq = irq; } - - return 0; } static void spapr_phb_reset(DeviceState *qdev) @@ -731,11 +713,10 @@ static const char *spapr_phb_root_bus_path(PCIHostState *host_bridge, static void spapr_phb_class_init(ObjectClass *klass, void *data) { PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); hc->root_bus_path = spapr_phb_root_bus_path; - sdc->init = spapr_phb_init; + dc->realize = spapr_phb_realize; dc->props = spapr_phb_properties; dc->reset = spapr_phb_reset; dc->vmsd = &vmstate_spapr_pci; diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 1bb56c4..3273c8a 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -238,9 +238,10 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static int ssi_sd_init(SSISlave *dev) +static int ssi_sd_init(SSISlave *d) { - ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev); + DeviceState *dev = DEVICE(d); + ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d); DriveInfo *dinfo; s->mode = SSI_SD_CMD; @@ -249,7 +250,7 @@ static int ssi_sd_init(SSISlave *dev) if (s->sd == NULL) { return -1; } - register_savevm(&dev->qdev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s); + register_savevm(dev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s); return 0; } diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 2c25260..017f022 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -15,7 +15,7 @@ #include "hw/ssi.h" struct SSIBus { - BusState qbus; + BusState parent_obj; }; #define TYPE_SSI_BUS "SSI" @@ -60,7 +60,7 @@ static int ssi_slave_init(DeviceState *dev) if (ssc->transfer_raw == ssi_transfer_raw_default && ssc->cs_polarity != SSI_CS_NONE) { - qdev_init_gpio_in(&s->qdev, ssi_cs_default, 1); + qdev_init_gpio_in(dev, ssi_cs_default, 1); } return ssc->init(s); @@ -88,7 +88,7 @@ static const TypeInfo ssi_slave_info = { DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name) { - return qdev_create(&bus->qbus, name); + return qdev_create(BUS(bus), name); } DeviceState *ssi_create_slave(SSIBus *bus, const char *name) @@ -108,11 +108,12 @@ SSIBus *ssi_create_bus(DeviceState *parent, const char *name) uint32_t ssi_transfer(SSIBus *bus, uint32_t val) { + BusState *b = BUS(bus); BusChild *kid; SSISlaveClass *ssc; uint32_t r = 0; - QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { + QTAILQ_FOREACH(kid, &b->children, sibling) { SSISlave *slave = SSI_SLAVE(kid->child); ssc = SSI_SLAVE_GET_CLASS(slave); r |= ssc->transfer_raw(slave, val); @@ -156,7 +157,7 @@ static int ssi_auto_connect_slave(Object *child, void *opaque) } cs_line = qdev_get_gpio_in(DEVICE(dev), 0); - qdev_set_parent_bus(DEVICE(dev), &arg->bus->qbus); + qdev_set_parent_bus(DEVICE(dev), BUS(arg->bus)); **arg->cs_linep = cs_line; (*arg->cs_linep)++; return 0; diff --git a/include/block/aio.h b/include/block/aio.h index 2efdf41..a92511b 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -19,6 +19,7 @@ #include "qemu/queue.h" #include "qemu/event_notifier.h" #include "qemu/thread.h" +#include "qemu/rfifolock.h" #include "qemu/timer.h" typedef struct BlockDriverAIOCB BlockDriverAIOCB; @@ -47,6 +48,9 @@ typedef void IOHandler(void *opaque); struct AioContext { GSource source; + /* Protects all fields from multi-threaded access */ + RFifoLock lock; + /* The list of registered AIO handlers */ QLIST_HEAD(, AioHandler) aio_handlers; @@ -104,6 +108,20 @@ void aio_context_ref(AioContext *ctx); */ void aio_context_unref(AioContext *ctx); +/* Take ownership of the AioContext. If the AioContext will be shared between + * threads, a thread must have ownership when calling aio_poll(). + * + * Note that multiple threads calling aio_poll() means timers, BHs, and + * callbacks may be invoked from a different thread than they were registered + * from. Therefore, code must use AioContext acquire/release or use + * fine-grained synchronization to protect shared state if other threads will + * be accessing it simultaneously. + */ +void aio_context_acquire(AioContext *ctx); + +/* Relinquish ownership of the AioContext. */ +void aio_context_release(AioContext *ctx); + /** * aio_bh_new: Allocate a new bottom half structure. * diff --git a/include/block/block.h b/include/block/block.h index 780f48b..bd34d14 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -286,15 +286,6 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); int bdrv_amend_options(BlockDriverState *bs_new, QEMUOptionParameter *options); /* external snapshots */ - -typedef enum { - BS_IS_A_FILTER, - BS_FILTER_PASS_DOWN, - BS_AUTHORIZATION_COUNT, -} BsAuthorization; - -bool bdrv_generic_is_first_non_filter(BlockDriverState *bs, - BlockDriverState *candidate); bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs, BlockDriverState *candidate); bool bdrv_is_first_non_filter(BlockDriverState *candidate); diff --git a/include/block/block_int.h b/include/block/block_int.h index 0bcf1c9..4fc5ea8 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -76,10 +76,10 @@ struct BlockDriver { const char *format_name; int instance_size; - /* this table of boolean contains authorizations for the block operations */ - bool authorizations[BS_AUTHORIZATION_COUNT]; - /* for snapshots complex block filter like Quorum can implement the - * following recursive callback instead of BS_IS_A_FILTER. + /* set to true if the BlockDriver is a block filter */ + bool is_filter; + /* for snapshots block filter like Quorum can implement the + * following recursive callback. * It's purpose is to recurse on the filter children while calling * bdrv_recurse_is_first_non_filter on them. * For a sample implementation look in the future Quorum block filter. diff --git a/include/hw/boards.h b/include/hw/boards.h index c2096e6..7bd2ea7 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -4,8 +4,8 @@ #define HW_BOARDS_H #include "sysemu/blockdev.h" -#include "sysemu/qemumachine.h" #include "hw/qdev.h" +#include "qom/object.h" typedef struct QEMUMachineInitArgs { const QEMUMachine *machine; @@ -50,9 +50,59 @@ struct QEMUMachine { const char *hw_version; }; +#define TYPE_MACHINE_SUFFIX "-machine" int qemu_register_machine(QEMUMachine *m); -QEMUMachine *find_default_machine(void); -extern QEMUMachine *current_machine; +#define TYPE_MACHINE "machine" +#define MACHINE(obj) \ + OBJECT_CHECK(MachineState, (obj), TYPE_MACHINE) +#define MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(MachineClass, (obj), TYPE_MACHINE) +#define MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(MachineClass, (klass), TYPE_MACHINE) + +typedef struct MachineState MachineState; +typedef struct MachineClass MachineClass; + +MachineClass *find_default_machine(void); +extern MachineState *current_machine; + +/** + * MachineClass: + * @qemu_machine: #QEMUMachine + */ +struct MachineClass { + /*< private >*/ + ObjectClass parent_class; + /*< public >*/ + + QEMUMachine *qemu_machine; +}; + +/** + * MachineState: + */ +struct MachineState { + /*< private >*/ + Object parent_obj; + /*< public >*/ + + char *accel; + bool kernel_irqchip; + int kvm_shadow_mem; + char *kernel; + char *initrd; + char *append; + char *dtb; + char *dumpdtb; + int phandle_start; + char *dt_compatible; + bool dump_guest_core; + bool mem_merge; + bool usb; + char *firmware; + + QEMUMachineInitArgs init_args; +}; #endif diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h index 9e4a0e4..e191435 100644 --- a/include/hw/i386/ich9.h +++ b/include/hw/i386/ich9.h @@ -102,7 +102,7 @@ Object *ich9_lpc_find(void); #define ICH9_USB_UHCI1_DEV 29 #define ICH9_USB_UHCI1_FUNC 0 -/* D30:F0 DMI-to-PCI brdige */ +/* D30:F0 DMI-to-PCI bridge */ #define ICH9_D2P_BRIDGE "ICH9 D2P BRIDGE" #define ICH9_D2P_BRIDGE_SAVEVM_VERSION 0 diff --git a/include/hw/loader.h b/include/hw/loader.h index aaf08c3..796cbf9 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -49,10 +49,12 @@ void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size, const char *source); -extern bool rom_file_in_ram; +extern bool option_rom_has_mr; +extern bool rom_file_has_mr; int rom_add_file(const char *file, const char *fw_dir, - hwaddr addr, int32_t bootindex); + hwaddr addr, int32_t bootindex, + bool option_rom); void *rom_add_blob(const char *name, const void *blob, size_t len, hwaddr addr, const char *fw_file_name, FWCfgReadCallback fw_callback, void *callback_opaque); @@ -66,7 +68,7 @@ void *rom_ptr(hwaddr addr); void do_info_roms(Monitor *mon, const QDict *qdict); #define rom_add_file_fixed(_f, _a, _i) \ - rom_add_file(_f, NULL, _a, _i) + rom_add_file(_f, NULL, _a, _i, false) #define rom_add_blob_fixed(_f, _b, _l, _a) \ rom_add_blob(_f, _b, _l, _a, NULL, NULL, NULL) diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index d0355b7..d9ee978 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -125,8 +125,8 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_PAM_RE ((uint8_t)0x1) #define MCH_HOST_BRIDGE_PAM_MASK ((uint8_t)0x3) -#define MCH_HOST_BRDIGE_SMRAM 0x9d -#define MCH_HOST_BRDIGE_SMRAM_SIZE 1 +#define MCH_HOST_BRIDGE_SMRAM 0x9d +#define MCH_HOST_BRIDGE_SMRAM_SIZE 1 #define MCH_HOST_BRIDGE_SMRAM_DEFAULT ((uint8_t)0x2) #define MCH_HOST_BRIDGE_SMRAM_D_OPEN ((uint8_t)(1 << 6)) #define MCH_HOST_BRIDGE_SMRAM_D_CLS ((uint8_t)(1 << 5)) @@ -140,16 +140,16 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END 0x100000 #define MCH_HOST_BRIDGE_ESMRAMC 0x9e -#define MCH_HOST_BRDIGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 6)) -#define MCH_HOST_BRDIGE_ESMRAMC_E_SMERR ((uint8_t)(1 << 5)) -#define MCH_HOST_BRDIGE_ESMRAMC_SM_CACHE ((uint8_t)(1 << 4)) -#define MCH_HOST_BRDIGE_ESMRAMC_SM_L1 ((uint8_t)(1 << 3)) -#define MCH_HOST_BRDIGE_ESMRAMC_SM_L2 ((uint8_t)(1 << 2)) -#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_MASK ((uint8_t)(0x3 << 1)) -#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_1MB ((uint8_t)(0x0 << 1)) -#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_2MB ((uint8_t)(0x1 << 1)) -#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_8MB ((uint8_t)(0x2 << 1)) -#define MCH_HOST_BRDIGE_ESMRAMC_T_EN ((uint8_t)1) +#define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 6)) +#define MCH_HOST_BRIDGE_ESMRAMC_E_SMERR ((uint8_t)(1 << 5)) +#define MCH_HOST_BRIDGE_ESMRAMC_SM_CACHE ((uint8_t)(1 << 4)) +#define MCH_HOST_BRIDGE_ESMRAMC_SM_L1 ((uint8_t)(1 << 3)) +#define MCH_HOST_BRIDGE_ESMRAMC_SM_L2 ((uint8_t)(1 << 2)) +#define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK ((uint8_t)(0x3 << 1)) +#define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB ((uint8_t)(0x0 << 1)) +#define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB ((uint8_t)(0x1 << 1)) +#define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB ((uint8_t)(0x2 << 1)) +#define MCH_HOST_BRIDGE_ESMRAMC_T_EN ((uint8_t)1) /* D1:F0 PCIE* port*/ #define MCH_PCIE_DEV 1 diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 1ed0691..dbe473c 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -36,6 +36,8 @@ typedef int (*qdev_event)(DeviceState *dev); typedef void (*qdev_resetfn)(DeviceState *dev); typedef void (*DeviceRealize)(DeviceState *dev, Error **errp); typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp); +typedef void (*BusRealize)(BusState *bus, Error **errp); +typedef void (*BusUnrealize)(BusState *bus, Error **errp); struct VMStateDescription; @@ -174,6 +176,9 @@ struct BusClass { */ char *(*get_fw_dev_path)(DeviceState *dev); void (*reset)(BusState *bus); + BusRealize realize; + BusUnrealize unrealize; + /* maximum devices allowed on the bus, 0: no limit. */ int max_dev; /* number of automatically allocated bus ids (e.g. ide.0) */ @@ -199,6 +204,7 @@ struct BusState { int allow_hotplug; HotplugHandler *hotplug_handler; int max_index; + bool realized; QTAILQ_HEAD(ChildrenHead, BusChild) children; QLIST_ENTRY(BusState) sibling; }; diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 0c0babf..3c000ee 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -22,6 +22,7 @@ extern PropertyInfo qdev_prop_bios_chs_trans; extern PropertyInfo qdev_prop_drive; extern PropertyInfo qdev_prop_netdev; extern PropertyInfo qdev_prop_vlan; +extern PropertyInfo qdev_prop_iothread; extern PropertyInfo qdev_prop_pci_devfn; extern PropertyInfo qdev_prop_blocksize; extern PropertyInfo qdev_prop_pci_host_devaddr; @@ -142,6 +143,8 @@ extern PropertyInfo qdev_prop_arraylen; DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NICPeers) #define DEFINE_PROP_DRIVE(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *) +#define DEFINE_PROP_IOTHREAD(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_iothread, IOThread *) #define DEFINE_PROP_MACADDR(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr) #define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \ diff --git a/include/hw/ssi.h b/include/hw/ssi.h index fdae317..6c13fb2 100644 --- a/include/hw/ssi.h +++ b/include/hw/ssi.h @@ -56,13 +56,12 @@ typedef struct SSISlaveClass { } SSISlaveClass; struct SSISlave { - DeviceState qdev; + DeviceState parent_obj; /* Chip select state */ bool cs; }; -#define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev) #define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev) extern const VMStateDescription vmstate_ssi_slave; diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 41885da..e4c41ff 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -16,6 +16,7 @@ #include "hw/virtio/virtio.h" #include "hw/block/block.h" +#include "sysemu/iothread.h" #define TYPE_VIRTIO_BLK "virtio-blk-device" #define VIRTIO_BLK(obj) \ @@ -106,6 +107,7 @@ struct virtio_scsi_inhdr struct VirtIOBlkConf { BlockConf conf; + IOThread *iothread; char *serial; uint32_t scsi; uint32_t config_wce; @@ -140,13 +142,15 @@ typedef struct VirtIOBlock { DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf), \ DEFINE_PROP_STRING("serial", _state, _field.serial), \ DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true), \ - DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true) + DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true), \ + DEFINE_PROP_IOTHREAD("x-iothread", _state, _field.iothread) #else #define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field) \ DEFINE_BLOCK_PROPERTIES(_state, _field.conf), \ DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf), \ DEFINE_PROP_STRING("serial", _state, _field.serial), \ - DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true) + DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true), \ + DEFINE_PROP_IOTHREAD("x-iothread", _state, _field.iothread) #endif /* __linux__ */ void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk); diff --git a/include/hw/virtio/virtio-serial.h b/include/hw/virtio/virtio-serial.h index 1d2040b..4746312 100644 --- a/include/hw/virtio/virtio-serial.h +++ b/include/hw/virtio/virtio-serial.h @@ -81,15 +81,15 @@ typedef struct VirtIOSerialPortClass { bool is_console; /* - * The per-port (or per-app) init function that's called when a + * The per-port (or per-app) realize function that's called when a * new device is found on the bus. */ - int (*init)(VirtIOSerialPort *port); + DeviceRealize realize; /* - * Per-port exit function that's called when a port gets + * Per-port unrealize function that's called when a port gets * hot-unplugged or removed. */ - int (*exit)(VirtIOSerialPort *port); + DeviceUnrealize unrealize; /* Callbacks for guest events */ /* Guest opened/closed device. */ diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index e181821..9d549fc 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -10,7 +10,6 @@ #include "hw/irq.h" #include "qemu-common.h" -#include "sysemu/qemumachine.h" /* xen-machine.c */ enum xen_mode { diff --git a/include/qapi/qmp/qerror.h b/include/qapi/qmp/qerror.h index 25193c9..da75abf 100644 --- a/include/qapi/qmp/qerror.h +++ b/include/qapi/qmp/qerror.h @@ -159,7 +159,7 @@ void qerror_report_err(Error *err); ERROR_CLASS_GENERIC_ERROR, "Invalid JSON syntax" #define QERR_KVM_MISSING_CAP \ - ERROR_CLASS_K_V_M_MISSING_CAP, "Using KVM without %s, %s unavailable" + ERROR_CLASS_KVM_MISSING_CAP, "Using KVM without %s, %s unavailable" #define QERR_MIGRATION_ACTIVE \ ERROR_CLASS_GENERIC_ERROR, "There's a migration process in progress" diff --git a/include/qemu-io.h b/include/qemu-io.h index 7e7c07c..5d6006f 100644 --- a/include/qemu-io.h +++ b/include/qemu-io.h @@ -38,6 +38,8 @@ typedef struct cmdinfo { helpfunc_t help; } cmdinfo_t; +extern bool qemuio_misalign; + bool qemuio_command(BlockDriverState *bs, const char *cmd); void qemuio_add_command(const cmdinfo_t *ci); diff --git a/include/qemu/rfifolock.h b/include/qemu/rfifolock.h new file mode 100644 index 0000000..b23ab53 --- /dev/null +++ b/include/qemu/rfifolock.h @@ -0,0 +1,54 @@ +/* + * Recursive FIFO lock + * + * Copyright Red Hat, Inc. 2013 + * + * Authors: + * Stefan Hajnoczi <stefanha@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. + * + */ + +#ifndef QEMU_RFIFOLOCK_H +#define QEMU_RFIFOLOCK_H + +#include "qemu/thread.h" + +/* Recursive FIFO lock + * + * This lock provides more features than a plain mutex: + * + * 1. Fairness - enforces FIFO order. + * 2. Nesting - can be taken recursively. + * 3. Contention callback - optional, called when thread must wait. + * + * The recursive FIFO lock is heavyweight so prefer other synchronization + * primitives if you do not need its features. + */ +typedef struct { + QemuMutex lock; /* protects all fields */ + + /* FIFO order */ + unsigned int head; /* active ticket number */ + unsigned int tail; /* waiting ticket number */ + QemuCond cond; /* used to wait for our ticket number */ + + /* Nesting */ + QemuThread owner_thread; /* thread that currently has ownership */ + unsigned int nesting; /* amount of nesting levels */ + + /* Contention callback */ + void (*cb)(void *); /* called when thread must wait, with ->lock + * held so it may not recursively lock/unlock + */ + void *cb_opaque; +} RFifoLock; + +void rfifolock_init(RFifoLock *r, void (*cb)(void *), void *opaque); +void rfifolock_destroy(RFifoLock *r); +void rfifolock_lock(RFifoLock *r); +void rfifolock_unlock(RFifoLock *r); + +#endif /* QEMU_RFIFOLOCK_H */ diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 83c9b16..bf8daac 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -30,6 +30,7 @@ typedef struct MemoryListener MemoryListener; typedef struct MemoryMappingList MemoryMappingList; +typedef struct QEMUMachine QEMUMachine; typedef struct NICInfo NICInfo; typedef struct HCIInfo HCIInfo; typedef struct AudioState AudioState; diff --git a/include/qom/object.h b/include/qom/object.h index 9c7c361..4cd7704 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -974,6 +974,14 @@ const char *object_property_get_type(Object *obj, const char *name, Object *object_get_root(void); /** + * object_get_canonical_path_component: + * + * Returns: The final component in the object's canonical path. The canonical + * path is the path within the composition tree starting from the root. + */ +gchar *object_get_canonical_path_component(Object *obj); + +/** * object_get_canonical_path: * * Returns: The canonical path for a object. This is the path within the diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h new file mode 100644 index 0000000..a32214a --- /dev/null +++ b/include/sysemu/iothread.h @@ -0,0 +1,30 @@ +/* + * Event loop thread + * + * Copyright Red Hat Inc., 2013 + * + * Authors: + * Stefan Hajnoczi <stefanha@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. + * + */ + +#ifndef IOTHREAD_H +#define IOTHREAD_H + +#include "block/aio.h" + +#define TYPE_IOTHREAD "iothread" + +typedef struct IOThread IOThread; + +#define IOTHREAD(obj) \ + OBJECT_CHECK(IOThread, obj, TYPE_IOTHREAD) + +IOThread *iothread_find(const char *id); +char *iothread_get_id(IOThread *iothread); +AioContext *iothread_get_aio_context(IOThread *iothread); + +#endif /* IOTHREAD_H */ diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index ed01998..0bee1e8 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -18,7 +18,6 @@ #include "config-host.h" #include "qemu/queue.h" #include "qom/cpu.h" -#include "sysemu/qemumachine.h" #ifdef CONFIG_KVM #include <linux/kvm.h> diff --git a/include/sysemu/qemumachine.h b/include/sysemu/qemumachine.h deleted file mode 100644 index 4cefd56..0000000 --- a/include/sysemu/qemumachine.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * QEMU Machine typedef - * - * Copyright Alexander Graf <agraf@suse.de> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#ifndef QEMUMACHINE_H -#define QEMUMACHINE_H - -typedef struct QEMUMachine QEMUMachine; - -#endif /* !QEMUMACHINE_H */ diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h index e62281d..224131f 100644 --- a/include/sysemu/qtest.h +++ b/include/sysemu/qtest.h @@ -16,7 +16,6 @@ #include "qemu-common.h" #include "qapi/error.h" -#include "sysemu/qemumachine.h" extern bool qtest_allowed; diff --git a/iothread.c b/iothread.c new file mode 100644 index 0000000..cb5986b --- /dev/null +++ b/iothread.c @@ -0,0 +1,178 @@ +/* + * Event loop thread + * + * Copyright Red Hat Inc., 2013 + * + * Authors: + * Stefan Hajnoczi <stefanha@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 "qom/object.h" +#include "qom/object_interfaces.h" +#include "qemu/module.h" +#include "qemu/thread.h" +#include "block/aio.h" +#include "sysemu/iothread.h" +#include "qmp-commands.h" + +#define IOTHREADS_PATH "/objects" + +typedef ObjectClass IOThreadClass; +struct IOThread { + Object parent_obj; + + QemuThread thread; + AioContext *ctx; + QemuMutex init_done_lock; + QemuCond init_done_cond; /* is thread initialization done? */ + bool stopping; + int thread_id; +}; + +#define IOTHREAD_GET_CLASS(obj) \ + OBJECT_GET_CLASS(IOThreadClass, obj, TYPE_IOTHREAD) +#define IOTHREAD_CLASS(klass) \ + OBJECT_CLASS_CHECK(IOThreadClass, klass, TYPE_IOTHREAD) + +static void *iothread_run(void *opaque) +{ + IOThread *iothread = opaque; + + qemu_mutex_lock(&iothread->init_done_lock); + iothread->thread_id = qemu_get_thread_id(); + qemu_cond_signal(&iothread->init_done_cond); + qemu_mutex_unlock(&iothread->init_done_lock); + + while (!iothread->stopping) { + aio_context_acquire(iothread->ctx); + while (!iothread->stopping && aio_poll(iothread->ctx, true)) { + /* Progress was made, keep going */ + } + aio_context_release(iothread->ctx); + } + return NULL; +} + +static void iothread_instance_finalize(Object *obj) +{ + IOThread *iothread = IOTHREAD(obj); + + iothread->stopping = true; + aio_notify(iothread->ctx); + qemu_thread_join(&iothread->thread); + qemu_cond_destroy(&iothread->init_done_cond); + qemu_mutex_destroy(&iothread->init_done_lock); + aio_context_unref(iothread->ctx); +} + +static void iothread_complete(UserCreatable *obj, Error **errp) +{ + IOThread *iothread = IOTHREAD(obj); + + iothread->stopping = false; + iothread->ctx = aio_context_new(); + iothread->thread_id = -1; + + qemu_mutex_init(&iothread->init_done_lock); + qemu_cond_init(&iothread->init_done_cond); + + /* This assumes we are called from a thread with useful CPU affinity for us + * to inherit. + */ + qemu_thread_create(&iothread->thread, "iothread", iothread_run, + iothread, QEMU_THREAD_JOINABLE); + + /* Wait for initialization to complete */ + qemu_mutex_lock(&iothread->init_done_lock); + while (iothread->thread_id == -1) { + qemu_cond_wait(&iothread->init_done_cond, + &iothread->init_done_lock); + } + qemu_mutex_unlock(&iothread->init_done_lock); +} + +static void iothread_class_init(ObjectClass *klass, void *class_data) +{ + UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); + ucc->complete = iothread_complete; +} + +static const TypeInfo iothread_info = { + .name = TYPE_IOTHREAD, + .parent = TYPE_OBJECT, + .class_init = iothread_class_init, + .instance_size = sizeof(IOThread), + .instance_finalize = iothread_instance_finalize, + .interfaces = (InterfaceInfo[]) { + {TYPE_USER_CREATABLE}, + {} + }, +}; + +static void iothread_register_types(void) +{ + type_register_static(&iothread_info); +} + +type_init(iothread_register_types) + +IOThread *iothread_find(const char *id) +{ + Object *container = container_get(object_get_root(), IOTHREADS_PATH); + Object *child; + + child = object_property_get_link(container, id, NULL); + if (!child) { + return NULL; + } + return (IOThread *)object_dynamic_cast(child, TYPE_IOTHREAD); +} + +char *iothread_get_id(IOThread *iothread) +{ + return object_get_canonical_path_component(OBJECT(iothread)); +} + +AioContext *iothread_get_aio_context(IOThread *iothread) +{ + return iothread->ctx; +} + +static int query_one_iothread(Object *object, void *opaque) +{ + IOThreadInfoList ***prev = opaque; + IOThreadInfoList *elem; + IOThreadInfo *info; + IOThread *iothread; + + iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD); + if (!iothread) { + return 0; + } + + info = g_new0(IOThreadInfo, 1); + info->id = iothread_get_id(iothread); + info->thread_id = iothread->thread_id; + + elem = g_new0(IOThreadInfoList, 1); + elem->value = info; + elem->next = NULL; + + **prev = elem; + *prev = &elem->next; + return 0; +} + +IOThreadInfoList *qmp_query_iothreads(Error **errp) +{ + IOThreadInfoList *head = NULL; + IOThreadInfoList **prev = &head; + Object *container = container_get(object_get_root(), IOTHREADS_PATH); + + object_child_foreach(container, query_one_iothread, &prev); + return head; +} @@ -14,7 +14,6 @@ #include "hw/hw.h" #include "cpu.h" #include "sysemu/kvm.h" -#include "sysemu/qemumachine.h" #ifndef CONFIG_USER_ONLY #include "hw/pci/msi.h" diff --git a/net/slirp.c b/net/slirp.c index 124e953..cce026b 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -529,7 +529,8 @@ static int slirp_smb(SlirpState* s, const char *exported_dir, "state directory=%s\n" "log file=%s/log.smbd\n" "smb passwd file=%s/smbpasswd\n" - "security = share\n" + "security = user\n" + "map to guest = Bad User\n" "[qemu]\n" "path=%s\n" "read only=no\n" @@ -549,7 +550,8 @@ static int slirp_smb(SlirpState* s, const char *exported_dir, snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", CONFIG_SMBD_COMMAND, smb_conf); - if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) { + if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0 || + slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 445) < 0) { slirp_smb_cleanup(s); error_report("conflicting/invalid smbserver address"); return -1; @@ -190,7 +190,7 @@ static void tap_send(void *opaque) TAPState *s = opaque; int size; - do { + while (qemu_can_send_packet(&s->nc)) { uint8_t *buf = s->buf; size = tap_read_packet(s->fd, s->buf, sizeof(s->buf)); @@ -206,8 +206,11 @@ static void tap_send(void *opaque) size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed); if (size == 0) { tap_read_poll(s, false); + break; + } else if (size < 0) { + break; } - } while (size > 0 && qemu_can_send_packet(&s->nc)); + } } static bool tap_has_ufo(NetClientState *nc) @@ -44,10 +44,6 @@ #include <sys/prctl.h> #endif -#ifdef __FreeBSD__ -#include <sys/sysctl.h> -#endif - static struct passwd *user_pwd; static const char *chroot_dir; static int daemonize; diff --git a/pc-bios/README b/pc-bios/README index 2bb6357..ef6008d 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -5,7 +5,7 @@ project (http://www.nongnu.org/vgabios/). - The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is - available at http://perso.magic.fr/l_indien/OpenHackWare/index.htm. + available at http://repo.or.cz/w/openhackware.git. - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20131015. + built from git tag qemu-slof-20140304. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/ohw.diff b/pc-bios/ohw.diff deleted file mode 100644 index c6b6623..0000000 --- a/pc-bios/ohw.diff +++ /dev/null @@ -1,1843 +0,0 @@ -diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/bios.h OpenHackWare-release-0.4/src/bios.h ---- OpenHackWare-release-0.4.org/src/bios.h 2005-04-06 23:20:22.000000000 +0200 -+++ OpenHackWare-release-0.4/src/bios.h 2005-07-07 01:10:20.000000000 +0200 -@@ -64,6 +64,7 @@ - ARCH_CHRP, - ARCH_MAC99, - ARCH_POP, -+ ARCH_HEATHROW, - }; - - /* Hardware definition(s) */ -@@ -174,6 +175,7 @@ - int bd_ioctl (bloc_device_t *bd, int func, void *args); - uint32_t bd_seclen (bloc_device_t *bd); - void bd_close (bloc_device_t *bd); -+void bd_reset_all(void); - uint32_t bd_seclen (bloc_device_t *bd); - uint32_t bd_maxbloc (bloc_device_t *bd); - void bd_sect2CHS (bloc_device_t *bd, uint32_t secnum, -@@ -183,12 +185,12 @@ - part_t *bd_probe (int boot_device); - bloc_device_t *bd_get (int device); - void bd_put (bloc_device_t *bd); --void bd_set_boot_part (bloc_device_t *bd, part_t *partition); -+void bd_set_boot_part (bloc_device_t *bd, part_t *partition, int partnum); - part_t **_bd_parts (bloc_device_t *bd); - - void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1, - uint32_t io_base2, uint32_t io_base3, -- void *OF_private); -+ void *OF_private0, void *OF_private1); - void ide_pci_pmac_register (uint32_t io_base0, uint32_t io_base1, - void *OF_private); - -@@ -399,17 +401,23 @@ - uint16_t min_grant, uint16_t max_latency); - void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses); - void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn, -- uint32_t *regions, uint32_t *sizes); -+ uint32_t *regions, uint32_t *sizes, -+ int irq_line); - void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size, - void *private_data); -+void OF_finalize_pci_ide (void *dev, -+ uint32_t io_base0, uint32_t io_base1, -+ uint32_t io_base2, uint32_t io_base3); - int OF_register_bus (const unsigned char *name, uint32_t address, - const unsigned char *type); - int OF_register_serial (const unsigned char *bus, const unsigned char *name, - uint32_t io_base, int irq); - int OF_register_stdio (const unsigned char *dev_in, - const unsigned char *dev_out); --void OF_vga_register (const unsigned char *name, uint32_t address, -- int width, int height, int depth); -+void OF_vga_register (const unsigned char *name, unused uint32_t address, -+ int width, int height, int depth, -+ unsigned long vga_bios_addr, -+ unsigned long vga_bios_size); - void *OF_blockdev_register (void *parent, void *private, - const unsigned char *type, - const unsigned char *name, int devnum, -diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/bloc.c OpenHackWare-release-0.4/src/bloc.c ---- OpenHackWare-release-0.4.org/src/bloc.c 2005-04-06 23:21:00.000000000 +0200 -+++ OpenHackWare-release-0.4/src/bloc.c 2005-07-08 00:28:26.000000000 +0200 -@@ -55,6 +55,7 @@ - /* Partitions */ - part_t *parts, *bparts; - part_t *boot_part; -+ int bpartnum; - /* Chain */ - bloc_device_t *next; - }; -@@ -66,6 +67,7 @@ - - static int ide_initialize (bloc_device_t *bd, int device); - static int ide_read_sector (bloc_device_t *bd, void *buffer, int secnum); -+static int ide_reset (bloc_device_t *bd); - - static int mem_initialize (bloc_device_t *bd, int device); - static int mem_read_sector (bloc_device_t *bd, void *buffer, int secnum); -@@ -212,6 +214,17 @@ - { - } - -+void bd_reset_all(void) -+{ -+ bloc_device_t *bd; -+ for (bd = bd_list; bd != NULL; bd = bd->next) { -+ if (bd->init == &ide_initialize) { -+ /* reset IDE drive because Darwin wants all IDE devices to be reset */ -+ ide_reset(bd); -+ } -+ } -+} -+ - uint32_t bd_seclen (bloc_device_t *bd) - { - return bd->seclen; -@@ -223,10 +236,12 @@ - } - - /* XXX: to be suppressed */ --void bd_set_boot_part (bloc_device_t *bd, part_t *partition) -+void bd_set_boot_part (bloc_device_t *bd, part_t *partition, int partnum) - { -+ dprintf("%s: part %p (%p) %d\n", __func__, partition, bd->boot_part, partnum); - if (bd->boot_part == NULL) { - bd->boot_part = partition; -+ bd->bpartnum = partnum; - } - } - -@@ -240,6 +255,13 @@ - return &bd->bparts; - } - -+void bd_set_boot_device (bloc_device_t *bd) -+{ -+#if defined (USE_OPENFIRMWARE) -+ OF_blockdev_set_boot_device(bd->OF_private, bd->bpartnum, "\\\\ofwboot"); -+#endif -+} -+ - part_t *bd_probe (int boot_device) - { - char devices[] = { /*'a', 'b',*/ 'c', 'd', 'e', 'f', 'm', '\0', }; -@@ -272,9 +294,7 @@ - tmp = part_probe(bd, force_raw); - if (boot_device == bd->device) { - boot_part = tmp; --#if defined (USE_OPENFIRMWARE) -- OF_blockdev_set_boot_device(bd->OF_private, 2, "\\\\ofwboot"); --#endif -+ bd_set_boot_device(bd); - } - } - -@@ -717,34 +737,29 @@ - /* IDE PCI access for pc */ - static uint8_t ide_pci_port_read (bloc_device_t *bd, int port) - { -- eieio(); -- -- return *(uint8_t *)(bd->io_base + port); -+ uint8_t value; -+ value = inb(bd->io_base + port); -+ return value; - } - - static void ide_pci_port_write (bloc_device_t *bd, int port, uint8_t value) - { -- *(uint8_t *)(bd->io_base + port) = value; -- eieio(); -+ outb(bd->io_base + port, value); - } - - static uint32_t ide_pci_data_readl (bloc_device_t *bd) - { -- eieio(); -- -- return *((uint32_t *)bd->io_base); -+ return inl(bd->io_base); - } - - static void ide_pci_data_writel (bloc_device_t *bd, uint32_t val) - { -- *(uint32_t *)(bd->io_base) = val; -- eieio(); -+ outl(bd->io_base, val); - } - - static void ide_pci_control_write (bloc_device_t *bd, uint32_t val) - { -- *((uint8_t *)bd->tmp) = val; -- eieio(); -+ outb(bd->tmp + 2, val); - } - - static ide_ops_t ide_pci_pc_ops = { -@@ -761,7 +776,7 @@ - - void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1, - uint32_t io_base2, uint32_t io_base3, -- unused void *OF_private) -+ void *OF_private0, void *OF_private1) - { - if (ide_pci_ops == NULL) { - ide_pci_ops = malloc(sizeof(ide_ops_t)); -@@ -770,19 +785,19 @@ - memcpy(ide_pci_ops, &ide_pci_pc_ops, sizeof(ide_ops_t)); - } - if ((io_base0 != 0 || io_base1 != 0) && -- ide_pci_ops->base[0] == 0 && ide_pci_ops->base[1] == 0) { -+ ide_pci_ops->base[0] == 0 && ide_pci_ops->base[2] == 0) { - ide_pci_ops->base[0] = io_base0; -- ide_pci_ops->base[1] = io_base1; -+ ide_pci_ops->base[2] = io_base1; - #ifdef USE_OPENFIRMWARE -- ide_pci_ops->OF_private[0] = OF_private; -+ ide_pci_ops->OF_private[0] = OF_private0; - #endif - } - if ((io_base2 != 0 || io_base3 != 0) && -- ide_pci_ops->base[2] == 0 && ide_pci_ops->base[3] == 0) { -- ide_pci_ops->base[2] = io_base2; -+ ide_pci_ops->base[1] == 0 && ide_pci_ops->base[3] == 0) { -+ ide_pci_ops->base[1] = io_base2; - ide_pci_ops->base[3] = io_base3; - #ifdef USE_OPENFIRMWARE -- ide_pci_ops->OF_private[1] = OF_private; -+ ide_pci_ops->OF_private[1] = OF_private1; - #endif - } - } -@@ -935,6 +950,8 @@ - } - - static void atapi_pad_req (void *buffer, int len); -+static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer, -+ int maxlen); - static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum); - - static int ide_initialize (bloc_device_t *bd, int device) -@@ -1035,9 +1052,7 @@ - DPRINTF("INQUIRY\n"); - len = spc_inquiry_req(&atapi_buffer, 36); - atapi_pad_req(&atapi_buffer, len); -- ide_port_write(bd, 0x07, 0xA0); -- for (i = 0; i < 3; i++) -- ide_data_writel(bd, ldswap32(&atapi_buffer[i])); -+ atapi_make_req(bd, atapi_buffer, 36); - status = ide_port_read(bd, 0x07); - if (status != 0x48) { - ERROR("ATAPI INQUIRY : status %0x != 0x48\n", status); -@@ -1053,9 +1068,7 @@ - DPRINTF("READ_CAPACITY\n"); - len = mmc_read_capacity_req(&atapi_buffer); - atapi_pad_req(&atapi_buffer, len); -- ide_port_write(bd, 0x07, 0xA0); -- for (i = 0; i < 3; i++) -- ide_data_writel(bd, ldswap32(&atapi_buffer[i])); -+ atapi_make_req(bd, atapi_buffer, 8); - status = ide_port_read(bd, 0x07); - if (status != 0x48) { - ERROR("ATAPI READ_CAPACITY : status %0x != 0x48\n", status); -@@ -1105,6 +1118,22 @@ - memset(p + len, 0, 12 - len); - } - -+static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer, -+ int maxlen) -+{ -+ int i; -+ /* select drive */ -+ if (bd->drv == 0) -+ ide_port_write(bd, 0x06, 0x40); -+ else -+ ide_port_write(bd, 0x06, 0x50); -+ ide_port_write(bd, 0x04, maxlen & 0xff); -+ ide_port_write(bd, 0x05, (maxlen >> 8) & 0xff); -+ ide_port_write(bd, 0x07, 0xA0); -+ for (i = 0; i < 3; i++) -+ ide_data_writel(bd, ldswap32(&buffer[i])); -+} -+ - static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum) - { - uint32_t atapi_buffer[4]; -@@ -1112,16 +1141,9 @@ - uint32_t status, value; - int i, len; - -- /* select drive */ -- if (bd->drv == 0) -- ide_port_write(bd, 0x06, 0x40); -- else -- ide_port_write(bd, 0x06, 0x50); - len = mmc_read12_req(atapi_buffer, secnum, 1); - atapi_pad_req(&atapi_buffer, len); -- ide_port_write(bd, 0x07, 0xA0); -- for (i = 0; i < 3; i++) -- ide_data_writel(bd, ldswap32(&atapi_buffer[i])); -+ atapi_make_req(bd, atapi_buffer, bd->seclen); - status = ide_port_read(bd, 0x07); - if (status != 0x48) { - ERROR("ATAPI READ12 : status %0x != 0x48\n", status); -diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/apple.c OpenHackWare-release-0.4/src/libpart/apple.c ---- OpenHackWare-release-0.4.org/src/libpart/apple.c 2005-03-31 09:23:33.000000000 +0200 -+++ OpenHackWare-release-0.4/src/libpart/apple.c 2005-07-03 16:17:41.000000000 +0200 -@@ -199,14 +199,18 @@ - if (len == 0) { - /* Place holder. Skip it */ - DPRINTF("%s placeholder part\t%d\n", __func__, i); -+ part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; -+ part_register(bd, part, name, i); - } else if (strncmp("Apple_Void", type, 32) == 0) { - /* Void partition. Skip it */ - DPRINTF("%s Void part\t%d [%s]\n", __func__, i, type); -+ part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; -+ part_register(bd, part, name, i); - } else if (strncmp("Apple_Free", type, 32) == 0) { - /* Free space. Skip it */ - DPRINTF("%s Free part (%d)\n", __func__, i); - part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; -- part_register(bd, part, name); -+ part_register(bd, part, name, i); - } else if (strncmp("Apple_partition_map", type, 32) == 0 || - strncmp("Apple_Partition_Map", type, 32) == 0 - #if 0 // Is this really used or is it just a mistake ? -@@ -226,7 +230,7 @@ - */ - } - part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; -- part_register(bd, part, name); -+ part_register(bd, part, name, i); - } else if (strncmp("Apple_Driver", type, 32) == 0 || - strncmp("Apple_Driver43", type, 32) == 0 || - strncmp("Apple_Driver43_CD", type, 32) == 0 || -@@ -236,8 +240,12 @@ - strncmp("Apple_Driver_IOKit", type, 32) == 0) { - /* Drivers. don't care for now */ - DPRINTF("%s Drivers part\t%d [%s]\n", __func__, i, type); -+ part->flags = PART_TYPE_APPLE | PART_FLAG_DRIVER; -+ part_register(bd, part, name, i); - } else if (strncmp("Apple_Patches", type, 32) == 0) { - /* Patches: don't care for now */ -+ part->flags = PART_TYPE_APPLE | PART_FLAG_PATCH; -+ part_register(bd, part, name, i); - DPRINTF("%s Patches part\t%d [%s]\n", __func__, i, type); - } else if (strncmp("Apple_HFS", type, 32) == 0 || - strncmp("Apple_MFS", type, 32) == 0 || -@@ -256,9 +264,8 @@ - count = partmap->bloc_cnt * HFS_BLOCSIZE; - if (partmap->boot_size == 0 || partmap->boot_load == 0) { - printf("Not a bootable partition %d %d (%p %p)\n", -- partmap->boot_size, partmap->boot_load,boot_part, part); -- if (boot_part == NULL) -- boot_part = part; -+ partmap->boot_size, partmap->boot_load, -+ boot_part, part); - part->flags = PART_TYPE_APPLE | PART_FLAG_FS; - } else { - part->boot_start.bloc = partmap->boot_start; -@@ -278,8 +285,8 @@ - boot_part = part; - part->flags = PART_TYPE_APPLE | PART_FLAG_FS | PART_FLAG_BOOT; - } -- printf("Partition: %d %s st %0x size %0x", -- i, name, partmap->start_bloc, partmap->bloc_cnt); -+ printf("Partition: %d '%s' '%s' st %0x size %0x", -+ i, name, type, partmap->start_bloc, partmap->bloc_cnt); - #ifndef DEBUG - printf("\n"); - #endif -@@ -290,11 +297,13 @@ - part->boot_load, part->boot_entry); - DPRINTF(" load %0x entry %0x %0x\n", - partmap->boot_load2, partmap->boot_entry2, HFS_BLOCSIZE); -- part_register(bd, part, name); -+ part_register(bd, part, name, i); - } else { - memcpy(tmp, type, 32); - tmp[32] = '\0'; - ERROR("Unknown partition type [%s]\n", tmp); -+ part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; -+ part_register(bd, part, name, i); - } - } - error: -diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/core.c OpenHackWare-release-0.4/src/libpart/core.c ---- OpenHackWare-release-0.4.org/src/libpart/core.c 2005-03-31 09:23:33.000000000 +0200 -+++ OpenHackWare-release-0.4/src/libpart/core.c 2005-07-03 16:17:41.000000000 +0200 -@@ -126,7 +126,7 @@ - } - - int part_register (bloc_device_t *bd, part_t *partition, -- const unsigned char *name) -+ const unsigned char *name, int partnum) - { - part_t **cur; - -@@ -134,6 +134,7 @@ - partition->bd = bd; - partition->next = NULL; - partition->name = strdup(name); -+ partition->partnum = partnum; - for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next) - continue; - *cur = partition; -@@ -141,29 +142,15 @@ - return 0; - } - --static inline int set_boot_part (bloc_device_t *bd, int partnum) --{ -- part_t *cur; -- -- cur = part_get(bd, partnum); -- if (cur == NULL) -- return -1; -- bd_set_boot_part(bd, cur); -- -- return 0; --} -- - part_t *part_get (bloc_device_t *bd, int partnum) - { - part_t **listp, *cur; -- int i; - - listp = _bd_parts(bd); -- cur = *listp; -- for (i = 0; i != partnum; i++) { -- if (cur == NULL) -+ -+ for (cur = *listp; cur != NULL; cur = cur->next) { -+ if (cur->partnum == partnum) - break; -- cur = cur->next; - } - - return cur; -@@ -192,17 +179,20 @@ - part_set_blocsize(bd, part, 512); - part->bd = bd; - part->flags = PART_TYPE_RAW | PART_FLAG_BOOT; -- part_register(bd, part, "Raw"); -+ part_register(bd, part, "Raw", 0); - - return part; - } - -+bloc_device_t *part_get_bd (part_t *part) -+{ -+ return part->bd; -+} -+ - part_t *part_probe (bloc_device_t *bd, int set_raw) - { -- part_t *part0, *boot_part, **cur; -+ part_t *part0 = NULL, *boot_part, **cur; - -- /* Register the 0 partition: raw partition containing the whole disk */ -- part0 = part_get_raw(bd); - /* Try to find a valid boot partition */ - boot_part = Apple_probe_partitions(bd); - if (boot_part == NULL) { -@@ -210,10 +200,13 @@ - if (boot_part == NULL && arch == ARCH_PREP) - boot_part = PREP_find_partition(bd); - if (boot_part == NULL && set_raw != 0) { -- boot_part = part0; -- set_boot_part(bd, 0); -+ dprintf("Use bloc device as raw partition\n"); - } - } -+ if (_bd_parts(bd) == NULL) { -+ /* Register the 0 partition: raw partition containing the whole disk */ -+ part0 = part_get_raw(bd); -+ } - /* Probe filesystem on each found partition */ - for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next) { - const unsigned char *map, *type; -@@ -248,23 +241,28 @@ - type = "unknown"; - break; - } -- DPRINTF("Probe filesystem on %s %s partition '%s' %s\n", -+ dprintf("Probe filesystem on %s %s partition '%s' %s %p\n", - type, map, (*cur)->name, -- ((*cur)->flags) & PART_FLAG_BOOT ? "(bootable)" : ""); -+ ((*cur)->flags) & PART_FLAG_BOOT ? "(bootable)" : "", *cur); - if (((*cur)->flags) & PART_FLAG_FS) { - if (((*cur)->flags) & PART_FLAG_BOOT) - (*cur)->fs = fs_probe(*cur, 1); - else - (*cur)->fs = fs_probe(*cur, 0); -+ } else if (((*cur)->flags) & PART_TYPE_RAW) { -+ (*cur)->fs = fs_probe(*cur, 2); - } else { - (*cur)->fs = fs_probe(*cur, 2); - } -- if (((*cur)->flags) & PART_FLAG_BOOT) { -- bd_set_boot_part(bd, *cur); - fs_get_bootfile((*cur)->fs); -+ if (((*cur)->flags) & PART_FLAG_BOOT) { -+ dprintf("Partition is bootable (%d)\n", (*cur)->partnum); -+ bd_set_boot_part(bd, *cur, (*cur)->partnum); -+ if (boot_part == NULL) -+ boot_part = *cur; - } - } -- DPRINTF("Boot partition: %p %p %p %p\n", boot_part, boot_part->fs, -+ dprintf("Boot partition: %p %p %p %p\n", boot_part, boot_part->fs, - part_fs(boot_part), part0); - - return boot_part; -@@ -279,6 +277,7 @@ - part->boot_size.offset = 0; - part->boot_load = 0; - part->boot_entry = 0; -+ part->flags |= PART_FLAG_BOOT; - - return 0; - } -diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/isofs.c OpenHackWare-release-0.4/src/libpart/isofs.c ---- OpenHackWare-release-0.4.org/src/libpart/isofs.c 2005-03-31 09:23:33.000000000 +0200 -+++ OpenHackWare-release-0.4/src/libpart/isofs.c 2005-07-03 16:17:41.000000000 +0200 -@@ -242,7 +242,7 @@ - part->boot_start.bloc, part->boot_size.bloc, - part->boot_load, part->boot_entry); - part->flags = PART_TYPE_ISO9660 | PART_FLAG_BOOT; -- part_register(bd, part, name); -+ part_register(bd, part, name, i + 1); - fs_raw_set_bootfile(part, part->boot_start.bloc, - part->boot_start.offset, - part->boot_size.bloc, -diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/libpart.h OpenHackWare-release-0.4/src/libpart/libpart.h ---- OpenHackWare-release-0.4.org/src/libpart/libpart.h 2005-03-31 09:23:33.000000000 +0200 -+++ OpenHackWare-release-0.4/src/libpart/libpart.h 2005-07-03 16:17:41.000000000 +0200 -@@ -30,6 +30,7 @@ - - struct part_t { - bloc_device_t *bd; -+ int partnum; - uint32_t start; /* Partition first bloc */ - uint32_t size; /* Partition size, in blocs */ - uint32_t spb; -@@ -54,7 +55,7 @@ - }; - - int part_register (bloc_device_t *bd, part_t *partition, -- const unsigned char *name); -+ const unsigned char *name, int partnum); - void part_set_blocsize (bloc_device_t *bd, part_t *part, uint32_t blocsize); - void part_private_set (part_t *part, void *private); - void *part_private_get (part_t *part); -diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/prep.c OpenHackWare-release-0.4/src/libpart/prep.c ---- OpenHackWare-release-0.4.org/src/libpart/prep.c 2005-03-31 09:23:33.000000000 +0200 -+++ OpenHackWare-release-0.4/src/libpart/prep.c 2005-07-03 16:17:41.000000000 +0200 -@@ -164,7 +164,7 @@ - part->boot_load = 0; - part->boot_entry = boot_offset - part->bloc_size; - part->flags = PART_TYPE_PREP | PART_FLAG_BOOT; -- part_register(bd, part, "PREP boot"); -+ part_register(bd, part, "PREP boot", i); - fs_raw_set_bootfile(part, part->boot_start.bloc, - part->boot_start.offset, - part->boot_size.bloc, -diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/main.c OpenHackWare-release-0.4/src/main.c ---- OpenHackWare-release-0.4.org/src/main.c 2005-03-31 09:23:33.000000000 +0200 -+++ OpenHackWare-release-0.4/src/main.c 2005-06-07 23:48:39.000000000 +0200 -@@ -364,20 +364,24 @@ - void *load_base, *load_entry, *last_alloc, *load_end; - uint32_t memsize, boot_image_size, cmdline_size, ramdisk_size; - uint32_t boot_base, boot_nb; -- int boot_device; -+ int boot_device, i; -+ static const uint32_t isa_base_tab[3] = { -+ 0x80000000, /* PREP */ -+ 0xFE000000, /* Grackle (Heathrow) */ -+ 0xF2000000, /* UniNorth (Mac99) */ -+ }; - - /* Retrieve NVRAM configuration */ -- nvram_retry: -+ for(i = 0; i < 3; i++) { -+ isa_io_base = isa_base_tab[i]; - nvram = NVRAM_get_config(&memsize, &boot_device, - &boot_image, &boot_image_size, - &cmdline, &cmdline_size, - &ramdisk, &ramdisk_size); -- if (nvram == NULL) { -- /* Retry with another isa_io_base */ -- if (isa_io_base == 0x80000000) { -- isa_io_base = 0xF2000000; -- goto nvram_retry; -+ if (nvram) -+ break; - } -+ if (i == 3) { - ERROR("Unable to load configuration from NVRAM. Aborting...\n"); - return -1; - } -@@ -402,7 +406,7 @@ - cpu_name = CPU_get_name(pvr); - OF_register_cpu(cpu_name, 0, pvr, - 200 * 1000 * 1000, 200 * 1000 * 1000, -- 100 * 1000 * 1000, 10 * 1000 * 1000, -+ 100 * 1000 * 1000, 100 * 1000 * 1000, - 0x0092); - } - OF_register_memory(memsize, 512 * 1024 /* TOFIX */); -@@ -433,9 +437,12 @@ - vga_puts(copyright); - vga_puts("\n"); - -+#if 0 - /* QEMU is quite incoherent: d is cdrom, not second drive */ -+ /* XXX: should probe CD-ROM position */ - if (boot_device == 'd') - boot_device = 'e'; -+#endif - /* Open boot device */ - boot_part = bd_probe(boot_device); - if (boot_device == 'm') { -diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/nvram.c OpenHackWare-release-0.4/src/nvram.c ---- OpenHackWare-release-0.4.org/src/nvram.c 2005-03-31 09:23:33.000000000 +0200 -+++ OpenHackWare-release-0.4/src/nvram.c 2005-06-04 23:44:03.000000000 +0200 -@@ -334,6 +334,7 @@ - ret = NVRAM_chrp_format(nvram); - break; - case ARCH_MAC99: -+ case ARCH_HEATHROW: /* XXX: may be incorrect */ - ret = NVRAM_mac99_format(nvram); - break; - case ARCH_POP: -@@ -409,13 +410,12 @@ - arch = ARCH_MAC99; - } else if (strcmp(sign, "POP") == 0) { - arch = ARCH_POP; -+ } else if (strcmp(sign, "HEATHROW") == 0) { -+ arch = ARCH_HEATHROW; - } else { - ERROR("Unknown PPC architecture: '%s'\n", sign); - return NULL; - } -- /* HACK */ -- if (arch == ARCH_CHRP) -- arch = ARCH_MAC99; - lword = NVRAM_get_lword(nvram, 0x30); - *RAM_size = lword; - byte = NVRAM_get_byte(nvram, 0x34); -diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/of.c OpenHackWare-release-0.4/src/of.c ---- OpenHackWare-release-0.4.org/src/of.c 2005-04-06 23:17:26.000000000 +0200 -+++ OpenHackWare-release-0.4/src/of.c 2005-07-07 23:30:08.000000000 +0200 -@@ -489,7 +489,7 @@ - ERROR("%s can't alloc new node '%s' name\n", __func__, name); - return NULL; - } -- new->prop_address = OF_prop_int_new(env, new, "address", address); -+ new->prop_address = OF_prop_int_new(env, new, "unit-address", address); - if (new->prop_address == NULL) { - free(new->prop_name->value); - free(new->prop_name); -@@ -1017,6 +1017,33 @@ - string, strlen(string) + 1); - } - -+/* convert '\1' char to '\0' */ -+static OF_prop_t *OF_prop_string_new1 (OF_env_t *env, OF_node_t *node, -+ const unsigned char *name, -+ const unsigned char *string) -+{ -+ int len, i; -+ OF_prop_t *ret; -+ unsigned char *str; -+ -+ if (strchr(string, '\1') == NULL) { -+ return OF_prop_string_new(env, node, name, string); -+ } else { -+ len = strlen(string) + 1; -+ str = malloc(len); -+ if (!str) -+ return NULL; -+ memcpy(str, string, len); -+ for(i = 0; i < len; i++) -+ if (str[i] == '\1') -+ str[i] = '\0'; -+ ret = OF_property_new(env, node, name, -+ str, len); -+ free(str); -+ return ret; -+ } -+} -+ - __attribute__ (( section (".OpenFirmware") )) - static OF_prop_t *OF_prop_int_new (OF_env_t *env, OF_node_t *node, - const unsigned char *name, uint32_t value) -@@ -1421,15 +1448,12 @@ - __attribute__ (( section (".OpenFirmware") )) - int OF_init (void) - { -- const unsigned char compat_str[] = - #if 0 - "PowerMac3,1\0MacRISC\0Power Macintosh\0"; - "PowerMac1,2\0MacRISC\0Power Macintosh\0"; - "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0"; - "AAPL,PowerMac3,0\0MacRISC\0Power Macintosh\0"; - "AAPL,Gossamer\0MacRISC\0Power Macintosh\0"; --#else -- "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0"; - #endif - OF_env_t *OF_env; - OF_node_t *als, *opt, *chs, *pks; -@@ -1455,15 +1479,21 @@ - return -1; - } - OF_prop_string_new(OF_env, OF_node_root, "device_type", "bootrom"); --#if 0 -- OF_prop_string_new(OF_env, OF_node_root, -- "model", "PPC Open Hack'Ware " BIOS_VERSION); --#else -+ if (arch == ARCH_HEATHROW) { -+ const unsigned char compat_str[] = -+ "PowerMac1,1\0MacRISC\0Power Macintosh"; -+ OF_property_new(OF_env, OF_node_root, "compatible", -+ compat_str, sizeof(compat_str)); - OF_prop_string_new(OF_env, OF_node_root, -- "model", compat_str); --#endif -+ "model", "Power Macintosh"); -+ } else { -+ const unsigned char compat_str[] = -+ "PowerMac3,1\0MacRISC\0Power Macintosh"; - OF_property_new(OF_env, OF_node_root, "compatible", - compat_str, sizeof(compat_str)); -+ OF_prop_string_new(OF_env, OF_node_root, -+ "model", "PowerMac3,1"); -+ } - #if 0 - OF_prop_string_new(OF_env, OF_node_root, "copyright", copyright); - #else -@@ -1561,14 +1591,15 @@ - range.size = 0x00800000; - OF_property_new(OF_env, rom, "ranges", &range, sizeof(OF_range_t)); - OF_prop_int_new(OF_env, rom, "#address-cells", 1); -+ - /* "/rom/boot-rom@fff00000" node */ -- brom = OF_node_new(OF_env, OF_node_root, "boot-rom", 0xfff00000); -+ brom = OF_node_new(OF_env, rom, "boot-rom", 0xfff00000); - if (brom == NULL) { - ERROR("Cannot create 'boot-rom'\n"); - return -1; - } - regs.address = 0xFFF00000; -- regs.size = 0x00010000; -+ regs.size = 0x00100000; - OF_property_new(OF_env, brom, "reg", ®s, sizeof(OF_regprop_t)); - OF_prop_string_new(OF_env, brom, "write-characteristic", "flash"); - OF_prop_string_new(OF_env, brom, "BootROM-build-date", -@@ -1577,7 +1608,7 @@ - OF_prop_string_new(OF_env, brom, "copyright", copyright); - OF_prop_string_new(OF_env, brom, "model", BIOS_str); - OF_prop_int_new(OF_env, brom, "result", 0); --#if 0 -+#if 1 - { - /* Hack taken 'as-is' from PearPC */ - unsigned char info[] = { -@@ -1596,7 +1627,9 @@ - OF_node_put(OF_env, brom); - OF_node_put(OF_env, rom); - } -+#if 0 - /* From here, hardcoded hacks to get a Mac-like machine */ -+ /* XXX: Core99 does not seem to like this NVRAM tree */ - /* "/nvram@fff04000" node */ - { - OF_regprop_t regs; -@@ -1617,6 +1650,7 @@ - OF_prop_int_new(OF_env, chs, "nvram", OF_pack_handle(OF_env, nvr)); - OF_node_put(OF_env, nvr); - } -+#endif - /* "/pseudo-hid" : hid emulation as Apple does */ - { - OF_node_t *hid; -@@ -1663,7 +1697,27 @@ - } - OF_node_put(OF_env, hid); - } -+ if (arch == ARCH_MAC99) { -+ OF_node_t *unin; -+ OF_regprop_t regs; - -+ unin = OF_node_new(OF_env, OF_node_root, -+ "uni-n", 0xf8000000); -+ if (unin == NULL) { -+ ERROR("Cannot create 'uni-n'\n"); -+ return -1; -+ } -+ OF_prop_string_new(OF_env, unin, "device-type", "memory-controller"); -+ OF_prop_string_new(OF_env, unin, "model", "AAPL,UniNorth"); -+ OF_prop_string_new(OF_env, unin, "compatible", "uni-north"); -+ regs.address = 0xf8000000; -+ regs.size = 0x01000000; -+ OF_property_new(OF_env, unin, "reg", ®s, sizeof(regs)); -+ OF_prop_int_new(OF_env, unin, "#address-cells", 1); -+ OF_prop_int_new(OF_env, unin, "#size-cells", 1); -+ OF_prop_int_new(OF_env, unin, "device-rev", 3); -+ OF_node_put(OF_env, unin); -+ } - - #if 1 /* This is mandatory for claim to work - * but I don't know where it should really be (in cpu ?) -@@ -1693,7 +1747,9 @@ - - /* "/options/boot-args" node */ - { -- const unsigned char *args = "-v rootdev cdrom"; -+ // const unsigned char *args = "-v rootdev cdrom"; -+ //const unsigned char *args = "-v io=0xffffffff"; -+ const unsigned char *args = "-v"; - /* Ask MacOS X to print debug messages */ - // OF_prop_string_new(OF_env, chs, "machargs", args); - // OF_prop_string_new(OF_env, opt, "boot-command", args); -@@ -2013,17 +2069,17 @@ - OF_prop_int_new(OF_env, node, "min-grant", min_grant); - OF_prop_int_new(OF_env, node, "max-latency", max_latency); - if (dev->type != NULL) -- OF_prop_string_new(OF_env, node, "device_type", dev->type); -+ OF_prop_string_new1(OF_env, node, "device_type", dev->type); - if (dev->compat != NULL) -- OF_prop_string_new(OF_env, node, "compatible", dev->compat); -+ OF_prop_string_new1(OF_env, node, "compatible", dev->compat); - if (dev->model != NULL) -- OF_prop_string_new(OF_env, node, "model", dev->model); -+ OF_prop_string_new1(OF_env, node, "model", dev->model); - if (dev->acells != 0) - OF_prop_int_new(OF_env, node, "#address-cells", dev->acells); - if (dev->scells != 0) -- OF_prop_int_new(OF_env, node, "#interrupt-cells", dev->acells); -+ OF_prop_int_new(OF_env, node, "#size-cells", dev->scells); - if (dev->icells != 0) -- OF_prop_int_new(OF_env, node, "#size-cells", dev->acells); -+ OF_prop_int_new(OF_env, node, "#interrupt-cells", dev->icells); - dprintf("Done %p %p\n", parent, node); - - return node; -@@ -2040,8 +2096,9 @@ - OF_env_t *OF_env; - pci_range_t ranges[3]; - OF_regprop_t regs[1]; -- OF_node_t *pci_host; -+ OF_node_t *pci_host, *als; - int nranges; -+ unsigned char buffer[OF_NAMELEN_MAX]; - - OF_env = OF_env_main; - dprintf("register PCI host '%s' '%s' '%s' '%s'\n", -@@ -2052,6 +2109,17 @@ - ERROR("Cannot create pci host\n"); - return NULL; - } -+ -+ als = OF_node_get(OF_env, "aliases"); -+ if (als == NULL) { -+ ERROR("Cannot get 'aliases'\n"); -+ return NULL; -+ } -+ sprintf(buffer, "/%s", dev->name); -+ OF_prop_string_set(OF_env, als, "pci", buffer); -+ OF_node_put(OF_env, als); -+ -+ - regs[0].address = cfg_base; - regs[0].size = cfg_len; - OF_property_new(OF_env, pci_host, "reg", regs, sizeof(OF_regprop_t)); -@@ -2136,6 +2204,11 @@ - return pci_dev; - } - -+/* XXX: suppress that, used for interrupt map init */ -+OF_node_t *pci_host_node; -+uint32_t pci_host_interrupt_map[7 * 32]; -+int pci_host_interrupt_map_len = 0; -+ - void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses) - { - OF_env_t *OF_env; -@@ -2145,10 +2218,12 @@ - regs[0].address = first_bus; - regs[0].size = nb_busses; - OF_property_new(OF_env, dev, "bus-range", regs, sizeof(OF_regprop_t)); -+ pci_host_node = dev; - } - - void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn, -- uint32_t *regions, uint32_t *sizes) -+ uint32_t *regions, uint32_t *sizes, -+ int irq_line) - { - OF_env_t *OF_env; - pci_reg_prop_t pregs[6], rregs[6]; -@@ -2156,6 +2231,7 @@ - int i, j, k; - - OF_env = OF_env_main; -+ /* XXX: only useful for VGA card in fact */ - if (regions[0] != 0x00000000) - OF_prop_int_set(OF_env, dev, "address", regions[0] & ~0x0000000F); - for (i = 0, j = 0, k = 0; i < 6; i++) { -@@ -2222,7 +2298,22 @@ - } else { - OF_property_new(OF_env, dev, "assigned-addresses", NULL, 0); - } --#if 0 -+ if (irq_line >= 0) { -+ int i; -+ OF_prop_int_new(OF_env, dev, "interrupts", 1); -+ i = pci_host_interrupt_map_len; -+ pci_host_interrupt_map[i++] = (devfn << 8) & 0xf800; -+ pci_host_interrupt_map[i++] = 0; -+ pci_host_interrupt_map[i++] = 0; -+ pci_host_interrupt_map[i++] = 0; -+ pci_host_interrupt_map[i++] = 0; /* pic handle will be patched later */ -+ pci_host_interrupt_map[i++] = irq_line; -+ if (arch != ARCH_HEATHROW) { -+ pci_host_interrupt_map[i++] = 1; -+ } -+ pci_host_interrupt_map_len = i; -+ } -+#if 1 - { - OF_prop_t *prop_name = ((OF_node_t *)dev)->prop_name; - -@@ -2390,6 +2481,54 @@ - return 0; - } - -+static void keylargo_ata(OF_node_t *mio, uint32_t base_address, -+ uint32_t base, int irq1, int irq2, -+ uint16_t pic_phandle) -+{ -+ OF_env_t *OF_env = OF_env_main; -+ OF_node_t *ata; -+ OF_regprop_t regs[2]; -+ -+ ata = OF_node_new(OF_env, mio, "ata-4", base); -+ if (ata == NULL) { -+ ERROR("Cannot create 'ata-4'\n"); -+ return; -+ } -+ OF_prop_string_new(OF_env, ata, "device_type", "ata"); -+#if 1 -+ OF_prop_string_new(OF_env, ata, "compatible", "key2largo-ata"); -+ OF_prop_string_new(OF_env, ata, "model", "ata-4"); -+ OF_prop_string_new(OF_env, ata, "cable-type", "80-conductor"); -+#else -+ OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata"); -+ OF_prop_string_new(OF_env, ata, "model", "ata-4"); -+#endif -+ OF_prop_int_new(OF_env, ata, "#address-cells", 1); -+ OF_prop_int_new(OF_env, ata, "#size-cells", 0); -+ regs[0].address = base; -+ regs[0].size = 0x00001000; -+#if 0 // HACK: Don't set up DMA registers -+ regs[1].address = 0x00008A00; -+ regs[1].size = 0x00001000; -+ OF_property_new(OF_env, ata, "reg", -+ regs, 2 * sizeof(OF_regprop_t)); -+#else -+ OF_property_new(OF_env, ata, "reg", -+ regs, sizeof(OF_regprop_t)); -+#endif -+ OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle); -+ regs[0].address = irq1; -+ regs[0].size = 0x00000001; -+ regs[1].address = irq2; -+ regs[1].size = 0x00000000; -+ OF_property_new(OF_env, ata, "interrupts", -+ regs, 2 * sizeof(OF_regprop_t)); -+ if (base == 0x1f000) -+ ide_pci_pmac_register(base_address + base, 0x00000000, ata); -+ else -+ ide_pci_pmac_register(0x00000000, base_address + base, ata); -+} -+ - void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size, - void *private_data) - { -@@ -2398,6 +2537,8 @@ - pci_reg_prop_t pregs[2]; - OF_node_t *mio, *chs, *als; - uint16_t pic_phandle; -+ int rec_len; -+ OF_prop_t *mio_reg; - - OF_DPRINTF("mac-io: %p\n", dev); - OF_env = OF_env_main; -@@ -2416,10 +2557,14 @@ - mio = dev; - mio->private_data = private_data; - pregs[0].addr.hi = 0x00000000; -- pregs[0].addr.mid = 0x82013810; -+ pregs[0].addr.mid = 0x00000000; - pregs[0].addr.lo = 0x00000000; - pregs[0].size_hi = base_address; - pregs[0].size_lo = size; -+ mio_reg = OF_property_get(OF_env, mio, "reg"); -+ if (mio_reg && mio_reg->vlen >= 5 * 4) { -+ pregs[0].addr.mid = ((pci_reg_prop_t *)mio_reg->value)->addr.hi; -+ } - OF_property_new(OF_env, mio, "ranges", - &pregs, sizeof(pci_reg_prop_t)); - #if 0 -@@ -2431,8 +2576,32 @@ - OF_property_new(OF_env, mio, "assigned-addresses", - &pregs, sizeof(pci_reg_prop_t)); - #endif -+ -+ if (arch == ARCH_HEATHROW) { -+ /* Heathrow PIC */ -+ OF_regprop_t regs; -+ OF_node_t *mpic; -+ const char compat_str[] = "heathrow\0mac-risc"; -+ -+ mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x10); -+ if (mpic == NULL) { -+ ERROR("Cannot create 'mpic'\n"); -+ goto out; -+ } -+ OF_prop_string_new(OF_env, mpic, "device_type", "interrupt-controller"); -+ OF_property_new(OF_env, mpic, "compatible", compat_str, sizeof(compat_str)); -+ OF_prop_int_new(OF_env, mpic, "#interrupt-cells", 1); -+ regs.address = 0x10; -+ regs.size = 0x20; -+ OF_property_new(OF_env, mpic, "reg", -+ ®s, sizeof(regs)); -+ OF_property_new(OF_env, mpic, "interrupt-controller", NULL, 0); -+ pic_phandle = OF_pack_handle(OF_env, mpic); -+ OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle); -+ OF_node_put(OF_env, mpic); -+ rec_len = 6; -+ } else { - /* OpenPIC */ -- { - OF_regprop_t regs[4]; - OF_node_t *mpic; - mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x40000); -@@ -2455,8 +2624,37 @@ - pic_phandle = OF_pack_handle(OF_env, mpic); - OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle); - OF_node_put(OF_env, mpic); -+ rec_len = 7; - } --#if 1 -+ -+ /* patch pci host table */ -+ /* XXX: do it after the PCI init */ -+ { -+ int i; -+ uint32_t tab[4]; -+ -+ for(i = 0; i < pci_host_interrupt_map_len; i += rec_len) -+ pci_host_interrupt_map[i + 4] = pic_phandle; -+#if 0 -+ dprintf("interrupt-map:\n"); -+ for(i = 0; i < pci_host_interrupt_map_len; i++) { -+ dprintf(" %08x", pci_host_interrupt_map[i]); -+ if ((i % rec_len) == (rec_len - 1)) -+ dprintf("\n"); -+ } -+ dprintf("\n"); -+#endif -+ OF_property_new(OF_env, pci_host_node, "interrupt-map", -+ pci_host_interrupt_map, -+ pci_host_interrupt_map_len * sizeof(uint32_t)); -+ tab[0] = 0xf800; -+ tab[1] = 0; -+ tab[2] = 0; -+ tab[3] = 0; -+ OF_property_new(OF_env, pci_host_node, "interrupt-map-mask", -+ tab, 4 * sizeof(uint32_t)); -+ } -+#if 0 - /* escc is useful to get MacOS X debug messages */ - { - OF_regprop_t regs[8]; -@@ -2645,85 +2843,12 @@ - OF_node_put(OF_env, scc); - } - #endif -- /* IDE controller */ -- { -- OF_node_t *ata; -- OF_regprop_t regs[2]; -- ata = OF_node_new(OF_env, mio, "ata-4", 0x1f000); -- if (ata == NULL) { -- ERROR("Cannot create 'ata-4'\n"); -- goto out; -- } -- OF_prop_string_new(OF_env, ata, "device_type", "ata"); --#if 1 -- OF_prop_string_new(OF_env, ata, "compatible", "keylargo-ata"); -- OF_prop_string_new(OF_env, ata, "model", "ata-4"); --#else -- OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata"); -- OF_prop_string_new(OF_env, ata, "model", "ata-4"); --#endif -- OF_prop_int_new(OF_env, ata, "#address-cells", 1); -- OF_prop_int_new(OF_env, ata, "#size-cells", 0); -- regs[0].address = 0x0001F000; -- regs[0].size = 0x00001000; --#if 0 // HACK: Don't set up DMA registers -- regs[1].address = 0x00008A00; -- regs[1].size = 0x00001000; -- OF_property_new(OF_env, ata, "reg", -- regs, 2 * sizeof(OF_regprop_t)); --#else -- OF_property_new(OF_env, ata, "reg", -- regs, sizeof(OF_regprop_t)); --#endif -- OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle); -- regs[0].address = 0x00000013; -- regs[0].size = 0x00000001; -- regs[1].address = 0x0000000B; -- regs[1].size = 0x00000000; -- OF_property_new(OF_env, ata, "interrupts", -- regs, 2 * sizeof(OF_regprop_t)); -- ide_pci_pmac_register(base_address + 0x1f000, 0x00000000, ata); -- -- } -- { -- OF_node_t *ata; -- OF_regprop_t regs[2]; -- ata = OF_node_new(OF_env, mio, "ata-4", 0x20000); -- if (ata == NULL) { -- ERROR("Cannot create 'ata-4'\n"); -- goto out; -- } -- OF_prop_string_new(OF_env, ata, "device_type", "ata"); --#if 1 -- OF_prop_string_new(OF_env, ata, "compatible", "keylargo-ata"); -- OF_prop_string_new(OF_env, ata, "model", "ata-4"); --#else -- OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata"); -- OF_prop_string_new(OF_env, ata, "model", "ata-4"); --#endif -- OF_prop_int_new(OF_env, ata, "#address-cells", 1); -- OF_prop_int_new(OF_env, ata, "#size-cells", 0); -- regs[0].address = 0x00020000; -- regs[0].size = 0x00001000; --#if 0 // HACK: Don't set up DMA registers -- regs[1].address = 0x00008A00; -- regs[1].size = 0x00001000; -- OF_property_new(OF_env, ata, "reg", -- regs, 2 * sizeof(OF_regprop_t)); --#else -- OF_property_new(OF_env, ata, "reg", -- regs, sizeof(OF_regprop_t)); --#endif -- OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle); -- regs[0].address = 0x00000014; -- regs[0].size = 0x00000001; -- regs[1].address = 0x0000000B; -- regs[1].size = 0x00000000; -- OF_property_new(OF_env, ata, "interrupts", -- regs, 2 * sizeof(OF_regprop_t)); -- ide_pci_pmac_register(0x00000000, base_address + 0x20000, ata); -- -+ /* Keylargo IDE controller: need some work (DMA problem ?) */ -+ if (arch == ARCH_MAC99) { -+ keylargo_ata(mio, base_address, 0x1f000, 0x13, 0xb, pic_phandle); -+ keylargo_ata(mio, base_address, 0x20000, 0x14, 0xb, pic_phandle); - } -+#if 0 - /* Timer */ - { - OF_node_t *tmr; -@@ -2746,10 +2871,11 @@ - regs, sizeof(OF_regprop_t)); - OF_node_put(OF_env, tmr); - } -+#endif - /* VIA-PMU */ - { - /* Controls adb, RTC and power-mgt (forget it !) */ -- OF_node_t *via, *adb, *rtc; -+ OF_node_t *via, *adb; - OF_regprop_t regs[1]; - #if 0 // THIS IS A HACK AND IS COMPLETELY ABSURD ! - // (but needed has Qemu doesn't emulate via-pmu). -@@ -2773,14 +2899,21 @@ - regs[0].size = 0x00002000; - OF_property_new(OF_env, via, "reg", regs, sizeof(OF_regprop_t)); - OF_prop_int_new(OF_env, via, "interrupt-parent", pic_phandle); -+ if (arch == ARCH_HEATHROW) { -+ OF_prop_int_new(OF_env, via, "interrupts", 0x12); -+ } else { - regs[0].address = 0x00000019; - regs[0].size = 0x00000001; - OF_property_new(OF_env, via, "interrupts", - regs, sizeof(OF_regprop_t)); -+ } -+ /* force usage of OF bus speeds */ -+ OF_prop_int_new(OF_env, via, "BusSpeedCorrect", 1); - #if 0 - OF_prop_int_new(OF_env, via, "pmu-version", 0x00D0740C); - #endif --#if 1 -+ { -+ OF_node_t *kbd, *mouse; - /* ADB pseudo-device */ - adb = OF_node_new(OF_env, via, "adb", OF_ADDRESS_NONE); - if (adb == NULL) { -@@ -2797,9 +2930,26 @@ - OF_prop_int_new(OF_env, adb, "#size-cells", 0); - OF_pack_get_path(OF_env, tmp, 512, adb); - OF_prop_string_new(OF_env, als, "adb", tmp); -- /* XXX: add "keyboard@2" and "mouse@3" */ -- OF_node_put(OF_env, adb); --#endif -+ -+ kbd = OF_node_new(OF_env, adb, "keyboard", 2); -+ if (kbd == NULL) { -+ ERROR("Cannot create 'kbd'\n"); -+ goto out; -+ } -+ OF_prop_string_new(OF_env, kbd, "device_type", "keyboard"); -+ OF_prop_int_new(OF_env, kbd, "reg", 2); -+ -+ mouse = OF_node_new(OF_env, adb, "mouse", 3); -+ if (mouse == NULL) { -+ ERROR("Cannot create 'mouse'\n"); -+ goto out; -+ } -+ OF_prop_string_new(OF_env, mouse, "device_type", "mouse"); -+ OF_prop_int_new(OF_env, mouse, "reg", 3); -+ OF_prop_int_new(OF_env, mouse, "#buttons", 3); -+ } -+ { -+ OF_node_t *rtc; - - rtc = OF_node_new(OF_env, via, "rtc", OF_ADDRESS_NONE); - if (rtc == NULL) { -@@ -2813,14 +2963,68 @@ - OF_prop_string_new(OF_env, rtc, "compatible", "rtc"); - #endif - OF_node_put(OF_env, rtc); -- OF_node_put(OF_env, via); - } -+ // OF_node_put(OF_env, via); -+ } -+ { -+ OF_node_t *pmgt; -+ pmgt = OF_node_new(OF_env, mio, "power-mgt", OF_ADDRESS_NONE); -+ OF_prop_string_new(OF_env, pmgt, "device_type", "power-mgt"); -+ OF_prop_string_new(OF_env, pmgt, "compatible", "cuda"); -+ OF_prop_string_new(OF_env, pmgt, "mgt-kind", "min-consumption-pwm-led"); -+ OF_node_put(OF_env, pmgt); -+ } -+ -+ if (arch == ARCH_HEATHROW) { -+ /* NVRAM */ -+ OF_node_t *nvr; -+ OF_regprop_t regs; -+ nvr = OF_node_new(OF_env, mio, "nvram", 0x60000); -+ OF_prop_string_new(OF_env, nvr, "device_type", "nvram"); -+ regs.address = 0x60000; -+ regs.size = 0x00020000; -+ OF_property_new(OF_env, nvr, "reg", ®s, sizeof(regs)); -+ OF_prop_int_new(OF_env, nvr, "#bytes", 0x2000); -+ OF_node_put(OF_env, nvr); -+ } -+ - out: - // OF_node_put(OF_env, mio); - OF_node_put(OF_env, chs); - OF_node_put(OF_env, als); - } - -+void OF_finalize_pci_ide (void *dev, -+ uint32_t io_base0, uint32_t io_base1, -+ uint32_t io_base2, uint32_t io_base3) -+{ -+ OF_env_t *OF_env = OF_env_main; -+ OF_node_t *pci_ata = dev; -+ OF_node_t *ata, *atas[2]; -+ int i; -+ -+ OF_prop_int_new(OF_env, pci_ata, "#address-cells", 1); -+ OF_prop_int_new(OF_env, pci_ata, "#size-cells", 0); -+ -+ /* XXX: Darwin handles only one device */ -+ for(i = 0; i < 1; i++) { -+ ata = OF_node_new(OF_env, pci_ata, "ata-4", i); -+ if (ata == NULL) { -+ ERROR("Cannot create 'ata-4'\n"); -+ return; -+ } -+ OF_prop_string_new(OF_env, ata, "device_type", "ata"); -+ OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata"); -+ OF_prop_string_new(OF_env, ata, "model", "ata-4"); -+ OF_prop_int_new(OF_env, ata, "#address-cells", 1); -+ OF_prop_int_new(OF_env, ata, "#size-cells", 0); -+ OF_prop_int_new(OF_env, ata, "reg", i); -+ atas[i] = ata; -+ } -+ ide_pci_pc_register(io_base0, io_base1, io_base2, io_base3, -+ atas[0], atas[1]); -+} -+ - /*****************************************************************************/ - /* Fake package */ - static void OF_method_fake (OF_env_t *OF_env) -@@ -2862,11 +3066,11 @@ - /* As we get a 1:1 mapping, do nothing */ - ihandle = popd(OF_env); - args = (void *)popd(OF_env); -- address = popd(OF_env); -- virt = popd(OF_env); -- size = popd(OF_env); - popd(OF_env); -- OF_DPRINTF("Translate address %0x %0x %0x %0x\n", ihandle, address, -+ size = popd(OF_env); -+ virt = popd(OF_env); -+ address = popd(OF_env); -+ OF_DPRINTF("Map %0x %0x %0x %0x\n", ihandle, address, - virt, size); - pushd(OF_env, 0); - } -@@ -3270,7 +3474,7 @@ - OF_prop_string_new(OF_env, dsk, "device_type", "block"); - OF_prop_string_new(OF_env, dsk, "category", type); - OF_prop_int_new(OF_env, dsk, "device_id", devnum); -- OF_prop_int_new(OF_env, dsk, "reg", 0); -+ OF_prop_int_new(OF_env, dsk, "reg", devnum); - OF_method_new(OF_env, dsk, "open", &OF_blockdev_open); - OF_method_new(OF_env, dsk, "seek", &OF_blockdev_seek); - OF_method_new(OF_env, dsk, "read", &OF_blockdev_read); -@@ -3432,7 +3636,8 @@ - } - - void OF_vga_register (const unsigned char *name, unused uint32_t address, -- int width, int height, int depth) -+ int width, int height, int depth, -+ unsigned long vga_bios_addr, unsigned long vga_bios_size) - { - OF_env_t *OF_env; - unsigned char tmp[OF_NAMELEN_MAX]; -@@ -3504,6 +3709,18 @@ - OF_prop_string_new(OF_env, als, "display", tmp); - OF_node_put(OF_env, als); - /* XXX: may also need read-rectangle */ -+ -+ if (vga_bios_size >= 8) { -+ const uint8_t *p; -+ int size; -+ /* check the QEMU VGA BIOS header */ -+ p = (const uint8_t *)vga_bios_addr; -+ if (p[0] == 'N' && p[1] == 'D' && p[2] == 'R' && p[3] == 'V') { -+ size = *(uint32_t *)(p + 4); -+ OF_property_new(OF_env, disp, "driver,AAPL,MacOS,PowerPC", -+ p + 8, size); -+ } -+ } - out: - OF_node_put(OF_env, disp); - } -@@ -4451,7 +4668,10 @@ - break; - case 0x233441d3: /* MacOS X 10.2 and OpenDarwin 1.41 */ - /* Create "memory-map" pseudo device */ -- popd(OF_env); -+ { -+ OF_node_t *map; -+ uint32_t phandle; -+ - /* Find "/packages" */ - chs = OF_pack_find_by_name(OF_env, OF_node_root, "/chosen"); - if (chs == NULL) { -@@ -4459,10 +4679,6 @@ - ERROR("Cannot get '/chosen'\n"); - break; - } -- { --#if 1 -- OF_node_t *map; -- uint32_t phandle; - map = OF_node_new(OF_env, chs, "memory-map", OF_ADDRESS_NONE); - if (map == NULL) { - pushd(OF_env, -1); -@@ -4473,11 +4689,8 @@ - OF_node_put(OF_env, map); - OF_node_put(OF_env, chs); - pushd(OF_env, phandle); -- } --#else -- pushd(OF_env, 0); --#endif - pushd(OF_env, 0); -+ } - break; - case 0x32a2d18e: /* MacOS X 10.2 and OpenDarwin 6.02 */ - /* Return screen ihandle */ -@@ -4540,9 +4753,10 @@ - case 0x4ad41f2d: - /* Yaboot: wait 10 ms: sure ! */ - break; -+ - default: - /* ERROR */ -- printf("Script:\n%s\n", FString); -+ printf("Script: len=%d\n%s\n", (int)strlen(FString), FString); - printf("Call %0x NOT IMPLEMENTED !\n", crc); - bug(); - break; -@@ -4581,6 +4795,7 @@ - { - OF_CHECK_NBARGS(OF_env, 0); - /* Should free all OF resources */ -+ bd_reset_all(); - #if defined (DEBUG_BIOS) - { - uint16_t loglevel = 0x02 | 0x10 | 0x80; -diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/pci.c OpenHackWare-release-0.4/src/pci.c ---- OpenHackWare-release-0.4.org/src/pci.c 2005-03-31 09:23:33.000000000 +0200 -+++ OpenHackWare-release-0.4/src/pci.c 2005-07-07 23:27:37.000000000 +0200 -@@ -99,8 +99,8 @@ - uint16_t min_grant; - uint16_t max_latency; - uint8_t irq_line; -- uint32_t regions[6]; -- uint32_t sizes[6]; -+ uint32_t regions[7]; /* the region 6 is the PCI ROM */ -+ uint32_t sizes[7]; - pci_device_t *next; - }; - -@@ -158,6 +158,7 @@ - - /* IRQ numbers assigned to PCI IRQs */ - static uint8_t prep_pci_irqs[4] = { 9, 11, 9, 11 }; -+static uint8_t heathrow_pci_irqs[4] = { 0x15, 0x16, 0x17, 0x18 }; - static uint8_t pmac_pci_irqs[4] = { 8, 9, 10, 11 }; - - /* PREP PCI host */ -@@ -399,6 +400,79 @@ - &uninorth_config_readl, &uninorth_config_writel, - }; - -+/* Grackle PCI host */ -+ -+static uint32_t grackle_cfg_address (pci_bridge_t *bridge, -+ uint8_t bus, uint8_t devfn, -+ uint8_t offset) -+{ -+ uint32_t addr; -+ addr = 0x80000000 | (bus << 16) | (devfn << 8) | (offset & 0xfc); -+ stswap32((uint32_t *)bridge->cfg_addr, addr); -+ return bridge->cfg_data + (offset & 3); -+} -+ -+static uint8_t grackle_config_readb (pci_bridge_t *bridge, -+ uint8_t bus, uint8_t devfn, -+ uint8_t offset) -+{ -+ uint32_t addr; -+ addr = grackle_cfg_address(bridge, bus, devfn, offset); -+ return *((uint8_t *)addr); -+} -+ -+static void grackle_config_writeb (pci_bridge_t *bridge, -+ uint8_t bus, uint8_t devfn, -+ uint8_t offset, uint8_t val) -+{ -+ uint32_t addr; -+ addr = grackle_cfg_address(bridge, bus, devfn, offset); -+ *((uint8_t *)addr) = val; -+} -+ -+static uint16_t grackle_config_readw (pci_bridge_t *bridge, -+ uint8_t bus, uint8_t devfn, -+ uint8_t offset) -+{ -+ uint32_t addr; -+ addr = grackle_cfg_address(bridge, bus, devfn, offset); -+ return ldswap16((uint16_t *)addr); -+} -+ -+static void grackle_config_writew (pci_bridge_t *bridge, -+ uint8_t bus, uint8_t devfn, -+ uint8_t offset, uint16_t val) -+{ -+ uint32_t addr; -+ addr = grackle_cfg_address(bridge, bus, devfn, offset); -+ stswap16((uint16_t *)addr, val); -+} -+ -+static uint32_t grackle_config_readl (pci_bridge_t *bridge, -+ uint8_t bus, uint8_t devfn, -+ uint8_t offset) -+{ -+ uint32_t addr; -+ addr = grackle_cfg_address(bridge, bus, devfn, offset); -+ return ldswap32((uint32_t *)addr); -+} -+ -+static void grackle_config_writel (pci_bridge_t *bridge, -+ uint8_t bus, uint8_t devfn, -+ uint8_t offset, uint32_t val) -+{ -+ uint32_t addr; -+ -+ addr = grackle_cfg_address(bridge, bus, devfn, offset); -+ stswap32((uint32_t *)addr, val); -+} -+ -+static pci_ops_t grackle_pci_ops = { -+ &grackle_config_readb, &grackle_config_writeb, -+ &grackle_config_readw, &grackle_config_writew, -+ &grackle_config_readl, &grackle_config_writel, -+}; -+ - static inline uint8_t pci_config_readb (pci_bridge_t *bridge, - uint8_t bus, uint8_t devfn, - uint8_t offset) -@@ -466,12 +540,22 @@ - }, - }; - -+static int ide_config_cb2 (pci_device_t *device) -+{ -+ OF_finalize_pci_ide(device->common.OF_private, -+ device->regions[0] & ~0x0000000F, -+ device->regions[1] & ~0x0000000F, -+ device->regions[2] & ~0x0000000F, -+ device->regions[3] & ~0x0000000F); -+ return 0; -+} -+ - static pci_dev_t ide_devices[] = { - { -- 0x8086, 0x0100, -- NULL, "Qemu IDE", "Qemu IDE", "ide", -+ 0x1095, 0x0646, /* CMD646 IDE controller */ -+ "pci-ide", "pci-ata", NULL, NULL, - 0, 0, 0, -- NULL, NULL, -+ ide_config_cb2, NULL, - }, - { - 0xFFFF, 0xFFFF, -@@ -481,7 +565,9 @@ - }, - }; - --static int ide_config_cb (pci_device_t *device) -+#if 0 -+/* should base it on PCI ID, not on arch */ -+static int ide_config_cb (unused pci_device_t *device) - { - printf("Register IDE controller\n"); - switch (arch) { -@@ -491,14 +577,8 @@ - device->common.OF_private); - break; - default: -- ide_pci_pc_register(device->regions[0] & ~0x0000000F, -- device->regions[1] & ~0x0000000F, -- device->regions[2] & ~0x0000000F, -- device->regions[3] & ~0x0000000F, -- device->common.OF_private); - break; - } -- - return 0; - } - -@@ -512,16 +592,12 @@ - device->common.OF_private); - break; - default: -- ide_pci_pc_register(device->regions[0] & ~0x0000000F, -- device->regions[1] & ~0x0000000F, -- device->regions[2] & ~0x0000000F, -- device->regions[3] & ~0x0000000F, -- device->common.OF_private); - break; - } - - return 0; - } -+#endif - - static pci_subclass_t mass_subclass[] = { - { -@@ -530,7 +606,7 @@ - }, - { - 0x01, "IDE controller", "ide", ide_devices, NULL, -- &ide_config_cb, NULL, -+ NULL, NULL, - }, - { - 0x02, "Floppy disk controller", NULL, NULL, NULL, -@@ -546,7 +622,7 @@ - }, - { - 0x05, "ATA controller", "ata", NULL, NULL, -- &ata_config_cb, NULL, -+ NULL, NULL, - }, - { - 0x80, "misc mass-storage controller", NULL, NULL, NULL, -@@ -646,7 +722,9 @@ - /* VGA 640x480x16 */ - OF_vga_register(device->common.device->name, - device->regions[0] & ~0x0000000F, -- vga_width, vga_height, vga_depth); -+ vga_width, vga_height, vga_depth, -+ device->regions[6] & ~0x0000000F, -+ device->sizes[6]); - } - vga_console_register(); - -@@ -750,6 +828,13 @@ - NULL, &PREP_pci_ops, - }; - -+pci_dev_t grackle_fake_bridge = { -+ 0xFFFF, 0xFFFF, -+ "pci", "pci-bridge", "DEC,21154", "DEC,21154.pci-bridge", -+ -1, -1, -1, -+ NULL, &grackle_pci_ops, -+}; -+ - static pci_dev_t hbrg_devices[] = { - { - 0x106B, 0x0020, NULL, -@@ -758,8 +843,8 @@ - NULL, &uninorth_agp_fake_bridge, - }, - { -- 0x106B, 0x001F, -- NULL, "pci", "AAPL,UniNorth", "uni-north", -+ 0x106B, 0x001F, NULL, -+ "pci", "AAPL,UniNorth", "uni-north", - 3, 2, 1, - NULL, &uninorth_fake_bridge, - }, -@@ -770,10 +855,10 @@ - NULL, &uninorth_fake_bridge, - }, - { -- 0x1011, 0x0026, NULL, -- "pci-bridge", NULL, NULL, -+ 0x1057, 0x0002, "pci", -+ "pci", "MOT,MPC106", "grackle", - 3, 2, 1, -- NULL, &PREP_pci_ops, -+ NULL, &grackle_fake_bridge, - }, - { - 0x1057, 0x4801, NULL, -@@ -1443,7 +1528,14 @@ - } - - static const pci_dev_t misc_pci[] = { -- /* Apple Mac-io controller */ -+ /* Paddington Mac I/O */ -+ { -+ 0x106B, 0x0017, -+ "mac-io", "mac-io", "AAPL,343S1211", "paddington\1heathrow", -+ 1, 1, 1, -+ &macio_config_cb, NULL, -+ }, -+ /* KeyLargo Mac I/O */ - { - 0x106B, 0x0022, - "mac-io", "mac-io", "AAPL,Keylargo", "Keylargo", -@@ -1599,7 +1691,7 @@ - uint8_t min_grant, uint8_t max_latency, - int irq_line) - { -- uint32_t cmd; -+ uint32_t cmd, addr; - int i; - - device->min_grant = min_grant; -@@ -1611,22 +1703,28 @@ - printf("MAP PCI device %d:%d to IRQ %d\n", - device->bus, device->devfn, irq_line); - } -- for (i = 0; i < 6; i++) { -+ for (i = 0; i < 7; i++) { - if ((device->regions[i] & ~0xF) != 0x00000000 && - (device->regions[i] & ~0xF) != 0xFFFFFFF0) { - printf("Map PCI device %d:%d %d to %0x %0x (%s)\n", - device->bus, device->devfn, i, - device->regions[i], device->sizes[i], -- device->regions[i] & 0x00000001 ? "I/O" : "memory"); -+ (device->regions[i] & 0x00000001) && i != 6 ? "I/O" : -+ "memory"); -+ if (i != 6) { - cmd = pci_config_readl(bridge, device->bus, device->devfn, 0x04); - if (device->regions[i] & 0x00000001) - cmd |= 0x00000001; - else - cmd |= 0x00000002; - pci_config_writel(bridge, device->bus, device->devfn, 0x04, cmd); -+ } -+ if (i == 6) -+ addr = 0x30; /* PCI ROM */ -+ else -+ addr = 0x10 + (i * sizeof(uint32_t)); - pci_config_writel(bridge, device->bus, device->devfn, -- 0x10 + (i * sizeof(uint32_t)), -- device->regions[i]); -+ addr, device->regions[i]); - } - } - } -@@ -1900,7 +1998,7 @@ - goto out; - } - ret = (pci_u_t *)newd; -- max_areas = 6; -+ max_areas = 7; - /* register PCI device in OF tree */ - if (bridge->dev.common.type == PCI_FAKE_BRIDGE) { - newd->common.OF_private = -@@ -1927,6 +2025,9 @@ - /* Handle 64 bits memory mapping */ - continue; - } -+ if (i == 6) -+ addr = 0x30; /* PCI ROM */ -+ else - addr = 0x10 + (i * sizeof(uint32_t)); - /* Get region size - * Note: we assume it's always a power of 2 -@@ -1935,7 +2036,7 @@ - smask = pci_config_readl(bridge, bus, devfn, addr); - if (smask == 0x00000000 || smask == 0xFFFFFFFF) - continue; -- if (smask & 0x00000001) { -+ if ((smask & 0x00000001) != 0 && i != 6) { - /* I/O space */ - base = io_base; - /* Align to a minimum of 256 bytes (arbitrary) */ -@@ -1947,6 +2048,8 @@ - /* Align to a minimum of 64 kB (arbitrary) */ - min_align = 1 << 16; - amask = 0x0000000F; -+ if (i == 6) -+ smask |= 1; /* PCI ROM enable */ - } - omask = smask & amask; - smask &= ~amask; -@@ -1980,7 +2083,10 @@ - if (irq_pin > 0) { - /* assign the IRQ */ - irq_pin = ((devfn >> 3) + irq_pin - 1) & 3; -- if (arch == ARCH_PREP) { -+ /* XXX: should base it on the PCI bridge type, not the arch */ -+ switch(arch) { -+ case ARCH_PREP: -+ { - int elcr_port, val; - irq_line = prep_pci_irqs[irq_pin]; - /* set the IRQ to level-sensitive */ -@@ -1988,14 +2094,22 @@ - val = inb(elcr_port); - val |= 1 << (irq_line & 7); - outb(elcr_port, val); -- } else { -+ } -+ break; -+ case ARCH_MAC99: - irq_line = pmac_pci_irqs[irq_pin]; -+ break; -+ case ARCH_HEATHROW: -+ irq_line = heathrow_pci_irqs[irq_pin]; -+ break; -+ default: -+ break; - } - } - update_device: - pci_update_device(bridge, newd, min_grant, max_latency, irq_line); - OF_finalize_pci_device(newd->common.OF_private, bus, devfn, -- newd->regions, newd->sizes); -+ newd->regions, newd->sizes, irq_line); - /* Call special inits if needed */ - if (dev->config_cb != NULL) - (*dev->config_cb)(newd); -@@ -2049,6 +2163,32 @@ - case ARCH_CHRP: - /* TODO */ - break; -+ case ARCH_HEATHROW: -+ dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp); -+ if (dev == NULL) -+ return -1; -+ fake_host = pci_add_host(hostp, dev, -+ (0x06 << 24) | (0x00 << 16) | (0xFF << 8)); -+ if (fake_host == NULL) -+ return -1; -+ fake_host->dev.common.type = PCI_FAKE_HOST; -+ dev = &grackle_fake_bridge; -+ if (dev == NULL) -+ goto free_fake_host; -+ fake_bridge = pci_add_bridge(fake_host, 0, 0, dev, -+ (0x06 << 24) | (0x04 << 16) | (0xFF << 8), -+ cfg_base, cfg_len, -+ cfg_base + 0x7ec00000, -+ cfg_base + 0x7ee00000, -+ mem_base, mem_len, -+ io_base, io_len, -+ rbase, rlen, -+ 0, -+ &grackle_pci_ops); -+ if (fake_bridge == NULL) -+ goto free_fake_host; -+ fake_bridge->dev.common.type = PCI_FAKE_BRIDGE; -+ break; - case ARCH_MAC99: - dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp); - if (dev == NULL) -@@ -2167,6 +2307,30 @@ - case ARCH_CHRP: - /* TODO */ - break; -+ case ARCH_HEATHROW: -+ cfg_base = 0x80000000; -+ cfg_len = 0x7f000000; -+ mem_base = 0x80000000; -+ mem_len = 0x01000000; -+ io_base = 0xfe000000; -+ io_len = 0x00800000; -+#if 1 -+ rbase = 0xfd000000; -+ rlen = 0x01000000; -+#else -+ rbase = 0x00000000; -+ rlen = 0x01000000; -+#endif -+ if (pci_check_host(&pci_main, cfg_base, cfg_len, -+ mem_base, mem_len, io_base, io_len, rbase, rlen, -+ 0x1057, 0x0002) == 0) { -+ isa_io_base = io_base; -+ busnum++; -+ } -+ for (curh = pci_main; curh->next != NULL; curh = curh->next) -+ continue; -+ pci_check_devices(curh); -+ break; - case ARCH_MAC99: - /* We are supposed to have 3 host bridges: - * - the uninorth AGP bridge at 0xF0000000 diff --git a/pc-bios/ppc_rom.bin b/pc-bios/ppc_rom.bin Binary files differindex 0ad0282..d378d9a 100644 --- a/pc-bios/ppc_rom.bin +++ b/pc-bios/ppc_rom.bin diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin Binary files differindex 92a9831..a742bff 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin diff --git a/qapi-schema.json b/qapi-schema.json index 6c381b7..b68cd44 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -883,6 +883,35 @@ { 'command': 'query-cpus', 'returns': ['CpuInfo'] } ## +# @IOThreadInfo: +# +# Information about an iothread +# +# @id: the identifier of the iothread +# +# @thread-id: ID of the underlying host thread +# +# Since: 2.0 +## +{ 'type': 'IOThreadInfo', + 'data': {'id': 'str', 'thread-id': 'int'} } + +## +# @query-iothreads: +# +# Returns a list of information about each iothread. +# +# Note this list excludes the QEMU main loop thread, which is not declared +# using the -object iothread command-line option. It is always the main thread +# of the process. +# +# Returns: a list of @IOThreadInfo for each iothread +# +# Since: 2.0 +## +{ 'command': 'query-iothreads', 'returns': ['IOThreadInfo'] } + +## # @BlockDeviceInfo: # # Information about the backing device for a block device. @@ -4249,6 +4278,18 @@ '*no-flush': 'bool' } } ## +# @BlockdevDriver +# +# Drivers that are supported in block device operations. +# +# Since: 2.0 +## +{ 'enum': 'BlockdevDriver', + 'data': [ 'file', 'http', 'https', 'ftp', 'ftps', 'tftp', 'vvfat', 'blkdebug', + 'blkverify', 'bochs', 'cloop', 'cow', 'dmg', 'parallels', 'qcow', + 'qcow2', 'qed', 'raw', 'vdi', 'vhdx', 'vmdk', 'vpc', 'quorum' ] } + +## # @BlockdevOptionsBase # # Options that are available for all block devices, independent of the block @@ -4272,7 +4313,7 @@ # Since: 1.7 ## { 'type': 'BlockdevOptionsBase', - 'data': { 'driver': 'str', + 'data': { 'driver': 'BlockdevDriver', '*id': 'str', '*node-name': 'str', '*discard': 'BlockdevDiscardOptions', diff --git a/qdev-monitor.c b/qdev-monitor.c index 6673e3c..9268c87 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -522,7 +522,7 @@ DeviceState *qdev_device_add(QemuOpts *opts) return NULL; } - /* create device, set properties */ + /* create device */ dev = DEVICE(object_new(driver)); if (bus) { @@ -533,11 +533,7 @@ DeviceState *qdev_device_add(QemuOpts *opts) if (id) { dev->id = id; } - if (qemu_opt_foreach(opts, set_property, dev, 1) != 0) { - object_unparent(OBJECT(dev)); - object_unref(OBJECT(dev)); - return NULL; - } + if (dev->id) { object_property_add_child(qdev_get_peripheral(), dev->id, OBJECT(dev), NULL); @@ -549,6 +545,13 @@ DeviceState *qdev_device_add(QemuOpts *opts) g_free(name); } + /* set properties */ + if (qemu_opt_foreach(opts, set_property, dev, 1) != 0) { + object_unparent(OBJECT(dev)); + object_unref(OBJECT(dev)); + return NULL; + } + dev->opts = opts; object_property_set_bool(OBJECT(dev), true, "realized", &err); if (err != NULL) { diff --git a/qemu-char.c b/qemu-char.c index 4d50838..54ed244 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -213,7 +213,7 @@ void qemu_chr_add_handlers(CharDriverState *s, s->chr_read = fd_read; s->chr_event = fd_event; s->handler_opaque = opaque; - if (s->chr_update_read_handler) + if (fe_open && s->chr_update_read_handler) s->chr_update_read_handler(s); if (!s->explicit_fe_open) { @@ -1136,13 +1136,14 @@ static void pty_chr_state(CharDriverState *chr, int connected) if (!s->connected) { s->connected = 1; qemu_chr_be_generic_open(chr); + } + if (!chr->fd_in_tag) { chr->fd_in_tag = io_add_watch_poll(s->fd, pty_chr_read_poll, pty_chr_read, chr); } } } - static void pty_chr_close(struct CharDriverState *chr) { PtyCharDriver *s = chr->opaque; @@ -2509,6 +2510,17 @@ static void tcp_chr_connect(void *opaque) qemu_chr_be_generic_open(chr); } +static void tcp_chr_update_read_handler(CharDriverState *chr) +{ + TCPCharDriver *s = chr->opaque; + + remove_fd_in_watch(chr); + if (s->chan) { + chr->fd_in_tag = io_add_watch_poll(s->chan, tcp_chr_read_poll, + tcp_chr_read, chr); + } +} + #define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c; static void tcp_chr_telnet_init(int fd) { @@ -2664,6 +2676,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, chr->get_msgfd = tcp_get_msgfd; chr->chr_add_client = tcp_chr_add_client; chr->chr_add_watch = tcp_chr_add_watch; + chr->chr_update_read_handler = tcp_chr_update_read_handler; /* be isn't opened until we get a connection */ chr->explicit_be_open = true; diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index f1de24c..fb1db53 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -16,7 +16,7 @@ #define CMD_NOFILE_OK 0x01 -int qemuio_misalign; +bool qemuio_misalign; static cmdinfo_t *cmdtab; static int ncmds; @@ -24,10 +24,9 @@ #define CMD_NOFILE_OK 0x01 -char *progname; +static char *progname; -BlockDriverState *qemuio_bs; -extern int qemuio_misalign; +static BlockDriverState *qemuio_bs; /* qemu-io commands passed using -c */ static int ncmdline; @@ -408,7 +407,7 @@ int main(int argc, char **argv) readonly = 1; break; case 'm': - qemuio_misalign = 1; + qemuio_misalign = true; break; case 'g': growable = 1; diff --git a/qmp-commands.hx b/qmp-commands.hx index d982cd6..a22621f 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2327,6 +2327,45 @@ EQMP }, SQMP +query-iothreads +--------------- + +Returns a list of information about each iothread. + +Note this list excludes the QEMU main loop thread, which is not declared +using the -object iothread command-line option. It is always the main thread +of the process. + +Return a json-array. Each iothread is represented by a json-object, which contains: + +- "id": name of iothread (json-str) +- "thread-id": ID of the underlying host thread (json-int) + +Example: + +-> { "execute": "query-iothreads" } +<- { + "return":[ + { + "id":"iothread0", + "thread-id":3134 + }, + { + "id":"iothread1", + "thread-id":3135 + } + ] + } + +EQMP + + { + .name = "query-iothreads", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_iothreads, + }, + +SQMP query-pci --------- @@ -114,8 +114,11 @@ void qmp_cpu(int64_t index, Error **errp) void qmp_cpu_add(int64_t id, Error **errp) { - if (current_machine->hot_add_cpu) { - current_machine->hot_add_cpu(id, errp); + MachineClass *mc; + + mc = MACHINE_GET_CLASS(current_machine); + if (mc->qemu_machine->hot_add_cpu) { + mc->qemu_machine->hot_add_cpu(id, errp); } else { error_setg(errp, "Not supported"); } diff --git a/qom/object.c b/qom/object.c index 660859c..a2a1ffa 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1102,39 +1102,49 @@ void object_property_add_link(Object *obj, const char *name, g_free(full_type); } +gchar *object_get_canonical_path_component(Object *obj) +{ + ObjectProperty *prop = NULL; + + g_assert(obj); + g_assert(obj->parent != NULL); + + QTAILQ_FOREACH(prop, &obj->parent->properties, node) { + if (!object_property_is_child(prop)) { + continue; + } + + if (prop->opaque == obj) { + return g_strdup(prop->name); + } + } + + /* obj had a parent but was not a child, should never happen */ + g_assert_not_reached(); + return NULL; +} + gchar *object_get_canonical_path(Object *obj) { Object *root = object_get_root(); - char *newpath = NULL, *path = NULL; + char *newpath, *path = NULL; while (obj != root) { - ObjectProperty *prop = NULL; - - g_assert(obj->parent != NULL); - - QTAILQ_FOREACH(prop, &obj->parent->properties, node) { - if (!object_property_is_child(prop)) { - continue; - } + char *component = object_get_canonical_path_component(obj); - if (prop->opaque == obj) { - if (path) { - newpath = g_strdup_printf("%s/%s", prop->name, path); - g_free(path); - path = newpath; - } else { - path = g_strdup(prop->name); - } - break; - } + if (path) { + newpath = g_strdup_printf("%s/%s", component, path); + g_free(component); + g_free(path); + path = newpath; + } else { + path = component; } - g_assert(prop != NULL); - obj = obj->parent; } - newpath = g_strdup_printf("/%s", path); + newpath = g_strdup_printf("/%s", path ? path : ""); g_free(path); return newpath; @@ -1293,6 +1303,7 @@ void object_property_add_str(Object *obj, const char *name, void (*set)(Object *, const char *, Error **), Error **errp) { + Error *local_err = NULL; StringProperty *prop = g_malloc0(sizeof(*prop)); prop->get = get; @@ -1302,7 +1313,11 @@ void object_property_add_str(Object *obj, const char *name, get ? property_get_str : NULL, set ? property_set_str : NULL, property_release_str, - prop, errp); + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } } typedef struct BoolProperty @@ -1349,6 +1364,7 @@ void object_property_add_bool(Object *obj, const char *name, void (*set)(Object *, bool, Error **), Error **errp) { + Error *local_err = NULL; BoolProperty *prop = g_malloc0(sizeof(*prop)); prop->get = get; @@ -1358,7 +1374,11 @@ void object_property_add_bool(Object *obj, const char *name, get ? property_get_bool : NULL, set ? property_set_bool : NULL, property_release_bool, - prop, errp); + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } } static char *qdev_get_type(Object *obj, Error **errp) diff --git a/roms/SLOF b/roms/SLOF -Subproject e2e8ac901e617573ea383f9cffd136146d0675a +Subproject af6b7bf5879b6cd6825de2a107cb0e3219fb1df diff --git a/roms/openhackware b/roms/openhackware new file mode 160000 +Subproject e9829b5584169ad14df2ca8776b87f4985aa9f0 diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 2c6e0dc..10864ef 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -127,16 +127,6 @@ const char *%(name)s_lookup[] = { ''') return ret -def generate_enum_name(name): - if name.isupper(): - return c_fun(name, False) - new_name = '' - for c in c_fun(name, False): - if c.isupper(): - new_name += '_' - new_name += c - return new_name.lstrip('_').upper() - def generate_enum(name, values): lookup_decl = mcgen(''' extern const char *%(name)s_lookup[]; @@ -154,11 +144,11 @@ typedef enum %(name)s i = 0 for value in enum_values: + enum_full_value = generate_enum_full_value(name, value) enum_decl += mcgen(''' - %(abbrev)s_%(value)s = %(i)d, + %(enum_full_value)s = %(i)d, ''', - abbrev=de_camel_case(name).upper(), - value=generate_enum_name(value), + enum_full_value = enum_full_value, i=i) i += 1 @@ -211,14 +201,21 @@ def generate_union(expr): base = expr.get('base') discriminator = expr.get('discriminator') + enum_define = discriminator_find_enum_define(expr) + if enum_define: + discriminator_type_name = enum_define['enum_name'] + else: + discriminator_type_name = '%sKind' % (name) + ret = mcgen(''' struct %(name)s { - %(name)sKind kind; + %(discriminator_type_name)s kind; union { void *data; ''', - name=name) + name=name, + discriminator_type_name=discriminator_type_name) for key in typeinfo: ret += mcgen(''' @@ -399,8 +396,11 @@ for expr in exprs: fdef.write(generate_enum_lookup(expr['enum'], expr['data'])) elif expr.has_key('union'): ret += generate_fwd_struct(expr['union'], expr['data']) + "\n" - ret += generate_enum('%sKind' % expr['union'], expr['data'].keys()) - fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys())) + enum_define = discriminator_find_enum_define(expr) + if not enum_define: + ret += generate_enum('%sKind' % expr['union'], expr['data'].keys()) + fdef.write(generate_enum_lookup('%sKind' % expr['union'], + expr['data'].keys())) if expr.get('discriminator') == {}: fdef.write(generate_anon_union_qtypes(expr)) else: diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index c6de9ae..45ce3a9 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -214,18 +214,22 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** ''', name=name) + # For anon union, always use the default enum type automatically generated + # as "'%sKind' % (name)" + disc_type = '%sKind' % (name) + for key in members: assert (members[key] in builtin_types or find_struct(members[key]) or find_union(members[key])), "Invalid anonymous union member" + enum_full_value = generate_enum_full_value(disc_type, key) ret += mcgen(''' - case %(abbrev)s_KIND_%(enum)s: + case %(enum_full_value)s: visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); break; ''', - abbrev = de_camel_case(name).upper(), - enum = c_fun(de_camel_case(key),False).upper(), + enum_full_value = enum_full_value, c_type = type_name(members[key]), c_name = c_fun(key)) @@ -255,7 +259,16 @@ def generate_visit_union(expr): assert not base return generate_visit_anon_union(name, members) - ret = generate_visit_enum('%sKind' % name, members.keys()) + enum_define = discriminator_find_enum_define(expr) + if enum_define: + # Use the enum type as discriminator + ret = "" + disc_type = enum_define['enum_name'] + else: + # There will always be a discriminator in the C switch code, by default it + # is an enum type generated silently as "'%sKind' % (name)" + ret = generate_visit_enum('%sKind' % name, members.keys()) + disc_type = '%sKind' % (name) if base: base_fields = find_struct(base)['data'] @@ -291,15 +304,16 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** pop_indent() if not discriminator: - desc_type = "type" + disc_key = "type" else: - desc_type = discriminator + disc_key = discriminator ret += mcgen(''' - visit_type_%(name)sKind(m, &(*obj)->kind, "%(type)s", &err); + visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err); if (!err) { switch ((*obj)->kind) { ''', - name=name, type=desc_type) + disc_type = disc_type, + disc_key = disc_key) for key in members: if not discriminator: @@ -313,13 +327,13 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** visit_end_implicit_struct(m, &err); }''' + enum_full_value = generate_enum_full_value(disc_type, key) ret += mcgen(''' - case %(abbrev)s_KIND_%(enum)s: + case %(enum_full_value)s: ''' + fmt + ''' break; ''', - abbrev = de_camel_case(name).upper(), - enum = c_fun(de_camel_case(key),False).upper(), + enum_full_value = enum_full_value, c_type=type_name(members[key]), c_name=c_fun(key)) @@ -510,7 +524,11 @@ for expr in exprs: ret += generate_visit_list(expr['union'], expr['data']) fdef.write(ret) - ret = generate_decl_enum('%sKind' % expr['union'], expr['data'].keys()) + enum_define = discriminator_find_enum_define(expr) + ret = "" + if not enum_define: + ret = generate_decl_enum('%sKind' % expr['union'], + expr['data'].keys()) ret += generate_declaration(expr['union'], expr['data']) fdecl.write(ret) elif expr.has_key('enum'): diff --git a/scripts/qapi.py b/scripts/qapi.py index f3c2a20..b474c39 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -39,12 +39,10 @@ class QAPISchemaError(Exception): def __init__(self, schema, msg): self.fp = schema.fp self.msg = msg - self.line = self.col = 1 - for ch in schema.src[0:schema.pos]: - if ch == '\n': - self.line += 1 - self.col = 1 - elif ch == '\t': + self.col = 1 + self.line = schema.line + for ch in schema.src[schema.line_pos:schema.pos]: + if ch == '\t': self.col = (self.col + 7) % 8 + 1 else: self.col += 1 @@ -52,6 +50,15 @@ class QAPISchemaError(Exception): def __str__(self): return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg) +class QAPIExprError(Exception): + def __init__(self, expr_info, msg): + self.fp = expr_info['fp'] + self.line = expr_info['line'] + self.msg = msg + + def __str__(self): + return "%s:%s: %s" % (self.fp.name, self.line, self.msg) + class QAPISchema: def __init__(self, fp): @@ -60,11 +67,16 @@ class QAPISchema: if self.src == '' or self.src[-1] != '\n': self.src += '\n' self.cursor = 0 + self.line = 1 + self.line_pos = 0 self.exprs = [] self.accept() while self.tok != None: - self.exprs.append(self.get_expr(False)) + expr_info = {'fp': fp, 'line': self.line} + expr_elem = {'expr': self.get_expr(False), + 'info': expr_info} + self.exprs.append(expr_elem) def accept(self): while True: @@ -100,6 +112,8 @@ class QAPISchema: if self.cursor == len(self.src): self.tok = None return + self.line += 1 + self.line_pos = self.cursor elif not self.tok.isspace(): raise QAPISchemaError(self, 'Stray "%s"' % self.tok) @@ -116,6 +130,8 @@ class QAPISchema: if self.tok != ':': raise QAPISchemaError(self, 'Expected ":"') self.accept() + if key in expr: + raise QAPISchemaError(self, 'Duplicate key "%s"' % key) expr[key] = self.get_expr(True) if self.tok == '}': self.accept() @@ -158,6 +174,95 @@ class QAPISchema: raise QAPISchemaError(self, 'Expected "{", "[" or string') return expr +def find_base_fields(base): + base_struct_define = find_struct(base) + if not base_struct_define: + return None + return base_struct_define['data'] + +# Return the discriminator enum define if discriminator is specified as an +# enum type, otherwise return None. +def discriminator_find_enum_define(expr): + base = expr.get('base') + discriminator = expr.get('discriminator') + + if not (discriminator and base): + return None + + base_fields = find_base_fields(base) + if not base_fields: + return None + + discriminator_type = base_fields.get(discriminator) + if not discriminator_type: + return None + + return find_enum(discriminator_type) + +def check_union(expr, expr_info): + name = expr['union'] + base = expr.get('base') + discriminator = expr.get('discriminator') + members = expr['data'] + + # If the object has a member 'base', its value must name a complex type. + if base: + base_fields = find_base_fields(base) + if not base_fields: + raise QAPIExprError(expr_info, + "Base '%s' is not a valid type" + % base) + + # If the union object has no member 'discriminator', it's an + # ordinary union. + if not discriminator: + enum_define = None + + # Else if the value of member 'discriminator' is {}, it's an + # anonymous union. + elif discriminator == {}: + enum_define = None + + # Else, it's a flat union. + else: + # The object must have a member 'base'. + if not base: + raise QAPIExprError(expr_info, + "Flat union '%s' must have a base field" + % name) + # The value of member 'discriminator' must name a member of the + # base type. + discriminator_type = base_fields.get(discriminator) + if not discriminator_type: + raise QAPIExprError(expr_info, + "Discriminator '%s' is not a member of base " + "type '%s'" + % (discriminator, base)) + enum_define = find_enum(discriminator_type) + # Do not allow string discriminator + if not enum_define: + raise QAPIExprError(expr_info, + "Discriminator '%s' must be of enumeration " + "type" % discriminator) + + # Check every branch + for (key, value) in members.items(): + # If this named member's value names an enum type, then all members + # of 'data' must also be members of the enum type. + if enum_define and not key in enum_define['enum_values']: + raise QAPIExprError(expr_info, + "Discriminator value '%s' is not found in " + "enum '%s'" % + (key, enum_define["enum_name"])) + # Todo: add checking for values. Key is checked as above, value can be + # also checked here, but we need more functions to handle array case. + +def check_exprs(schema): + for expr_elem in schema.exprs: + expr = expr_elem['expr'] + if expr.has_key('union'): + check_union(expr, expr_elem['info']) + def parse_schema(fp): try: schema = QAPISchema(fp) @@ -167,16 +272,29 @@ def parse_schema(fp): exprs = [] - for expr in schema.exprs: + for expr_elem in schema.exprs: + expr = expr_elem['expr'] if expr.has_key('enum'): - add_enum(expr['enum']) + add_enum(expr['enum'], expr['data']) elif expr.has_key('union'): add_union(expr) - add_enum('%sKind' % expr['union']) elif expr.has_key('type'): add_struct(expr) exprs.append(expr) + # Try again for hidden UnionKind enum + for expr_elem in schema.exprs: + expr = expr_elem['expr'] + if expr.has_key('union'): + if not discriminator_find_enum_define(expr): + add_enum('%sKind' % expr['union']) + + try: + check_exprs(schema) + except QAPIExprError, e: + print >>sys.stderr, e + exit(1) + return exprs def parse_args(typeinfo): @@ -289,13 +407,19 @@ def find_union(name): return union return None -def add_enum(name): +def add_enum(name, enum_values = None): global enum_types - enum_types.append(name) + enum_types.append({"enum_name": name, "enum_values": enum_values}) -def is_enum(name): +def find_enum(name): global enum_types - return (name in enum_types) + for enum in enum_types: + if enum['enum_name'] == name: + return enum + return None + +def is_enum(name): + return find_enum(name) != None def c_type(name): if name == 'str': @@ -373,3 +497,30 @@ def guardend(name): ''', name=guardname(name)) + +# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1 +# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2 +# ENUM24_Name -> ENUM24_NAME +def _generate_enum_string(value): + c_fun_str = c_fun(value, False) + if value.isupper(): + return c_fun_str + + new_name = '' + l = len(c_fun_str) + for i in range(l): + c = c_fun_str[i] + # When c is upper and no "_" appears before, do more checks + if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_": + # Case 1: next string is lower + # Case 2: previous string is digit + if (i < (l - 1) and c_fun_str[i + 1].islower()) or \ + c_fun_str[i - 1].isdigit(): + new_name += '_' + new_name += c + return new_name.lstrip('_').upper() + +def generate_enum_full_value(enum_name, enum_value): + abbrev_string = _generate_enum_string(enum_name) + value_string = _generate_enum_string(enum_value) + return "%s_%s" % (abbrev_string, value_string) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 9f69d7e..5cfe450 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -315,7 +315,7 @@ typedef struct X86RegisterInfo32 { } X86RegisterInfo32; #define REGISTER(reg) \ - [R_##reg] = { .name = #reg, .qapi_enum = X86_C_P_U_REGISTER32_##reg } + [R_##reg] = { .name = #reg, .qapi_enum = X86_CPU_REGISTER32_##reg } X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { REGISTER(EAX), REGISTER(ECX), diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index e7f878e..5806e59 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -458,7 +458,8 @@ static const sparc_def_t sparc_defs[] = { .mmu_trcr_mask = 0xffffffff, .nwindows = 8, .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN | - CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL | CPU_FEATURE_POWERDOWN, + CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL | CPU_FEATURE_POWERDOWN | + CPU_FEATURE_CASA, }, #endif }; diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index c519063..ed6d2d1 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -271,6 +271,7 @@ typedef struct sparc_def_t { #define CPU_FEATURE_ASR17 (1 << 15) #define CPU_FEATURE_CACHE_CTRL (1 << 16) #define CPU_FEATURE_POWERDOWN (1 << 17) +#define CPU_FEATURE_CASA (1 << 18) #ifndef TARGET_SPARC64 #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \ @@ -282,7 +283,8 @@ typedef struct sparc_def_t { CPU_FEATURE_MUL | CPU_FEATURE_DIV | \ CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | \ CPU_FEATURE_FMUL | CPU_FEATURE_VIS1 | \ - CPU_FEATURE_VIS2 | CPU_FEATURE_FSMULD) + CPU_FEATURE_VIS2 | CPU_FEATURE_FSMULD | \ + CPU_FEATURE_CASA) enum { mmu_us_12, // Ultrasparc < III (64 entry TLB) mmu_us_3, // Ultrasparc III (512 entry TLB) diff --git a/target-sparc/helper.h b/target-sparc/helper.h index 2a771b2..cd8d3fa 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -22,7 +22,6 @@ DEF_HELPER_1(popc, tl, tl) DEF_HELPER_4(ldda_asi, void, env, tl, int, int) DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int) DEF_HELPER_5(stf_asi, void, env, tl, int, int, int) -DEF_HELPER_5(cas_asi, tl, env, tl, tl, tl, i32) DEF_HELPER_5(casx_asi, tl, env, tl, tl, tl, i32) DEF_HELPER_2(set_softint, void, env, i64) DEF_HELPER_2(clear_softint, void, env, i64) @@ -31,6 +30,9 @@ DEF_HELPER_2(tick_set_count, void, ptr, i64) DEF_HELPER_1(tick_get_count, i64, ptr) DEF_HELPER_2(tick_set_limit, void, ptr, i64) #endif +#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) +DEF_HELPER_5(cas_asi, tl, env, tl, tl, tl, i32) +#endif DEF_HELPER_3(check_align, void, env, tl, i32) DEF_HELPER_1(debug, void, env) DEF_HELPER_1(save, void, env) diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c index 92761ad..32491b4 100644 --- a/target-sparc/ldst_helper.c +++ b/target-sparc/ldst_helper.c @@ -584,6 +584,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, } break; case 0xb: /* Supervisor data access */ + case 0x80: switch (size) { case 1: ret = cpu_ldub_kernel(env, addr); @@ -955,6 +956,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi, } break; case 0xb: /* Supervisor data access */ + case 0x80: switch (size) { case 1: cpu_stb_kernel(env, addr, val); @@ -2232,33 +2234,35 @@ void helper_stf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, } } -target_ulong helper_cas_asi(CPUSPARCState *env, target_ulong addr, - target_ulong val1, target_ulong val2, uint32_t asi) +target_ulong helper_casx_asi(CPUSPARCState *env, target_ulong addr, + target_ulong val1, target_ulong val2, + uint32_t asi) { target_ulong ret; - val2 &= 0xffffffffUL; - ret = helper_ld_asi(env, addr, asi, 4, 0); - ret &= 0xffffffffUL; + ret = helper_ld_asi(env, addr, asi, 8, 0); if (val2 == ret) { - helper_st_asi(env, addr, val1 & 0xffffffffUL, asi, 4); + helper_st_asi(env, addr, val1, asi, 8); } return ret; } +#endif /* TARGET_SPARC64 */ -target_ulong helper_casx_asi(CPUSPARCState *env, target_ulong addr, - target_ulong val1, target_ulong val2, - uint32_t asi) +#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) +target_ulong helper_cas_asi(CPUSPARCState *env, target_ulong addr, + target_ulong val1, target_ulong val2, uint32_t asi) { target_ulong ret; - ret = helper_ld_asi(env, addr, asi, 8, 0); + val2 &= 0xffffffffUL; + ret = helper_ld_asi(env, addr, asi, 4, 0); + ret &= 0xffffffffUL; if (val2 == ret) { - helper_st_asi(env, addr, val1, asi, 8); + helper_st_asi(env, addr, val1 & 0xffffffffUL, asi, 4); } return ret; } -#endif /* TARGET_SPARC64 */ +#endif /* !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) */ void helper_ldqf(CPUSPARCState *env, target_ulong addr, int mem_idx) { diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 6150b22..46d7859 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2107,18 +2107,6 @@ static inline void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, tcg_temp_free_i64(t64); } -static inline void gen_cas_asi(DisasContext *dc, TCGv addr, - TCGv val2, int insn, int rd) -{ - TCGv val1 = gen_load_gpr(dc, rd); - TCGv dst = gen_dest_gpr(dc, rd); - TCGv_i32 r_asi = gen_get_asi(insn, addr); - - gen_helper_cas_asi(dst, cpu_env, addr, val1, val2, r_asi); - tcg_temp_free_i32(r_asi); - gen_store_gpr(dc, rd, dst); -} - static inline void gen_casx_asi(DisasContext *dc, TCGv addr, TCGv val2, int insn, int rd) { @@ -2229,6 +2217,22 @@ static inline void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, #endif #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) +static inline void gen_cas_asi(DisasContext *dc, TCGv addr, + TCGv val2, int insn, int rd) +{ + TCGv val1 = gen_load_gpr(dc, rd); + TCGv dst = gen_dest_gpr(dc, rd); +#ifdef TARGET_SPARC64 + TCGv_i32 r_asi = gen_get_asi(insn, addr); +#else + TCGv_i32 r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); +#endif + + gen_helper_cas_asi(dst, cpu_env, addr, val1, val2, r_asi); + tcg_temp_free_i32(r_asi); + gen_store_gpr(dc, rd, dst); +} + static inline void gen_ldstub_asi(TCGv dst, TCGv addr, int insn) { TCGv_i64 r_val; @@ -5103,11 +5107,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd)); break; - case 0x3c: /* V9 casa */ - rs2 = GET_FIELD(insn, 27, 31); - cpu_src2 = gen_load_gpr(dc, rs2); - gen_cas_asi(dc, cpu_addr, cpu_src2, insn, rd); - break; case 0x3e: /* V9 casxa */ rs2 = GET_FIELD(insn, 27, 31); cpu_src2 = gen_load_gpr(dc, rs2); @@ -5120,6 +5119,22 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x37: /* stdc */ goto ncp_insn; #endif +#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) + case 0x3c: /* V9 or LEON3 casa */ +#ifndef TARGET_SPARC64 + CHECK_IU_FEATURE(dc, CASA); + if (IS_IMM) { + goto illegal_insn; + } + if (!supervisor(dc)) { + goto priv_insn; + } +#endif + rs2 = GET_FIELD(insn, 27, 31); + cpu_src2 = gen_load_gpr(dc, rs2); + gen_cas_asi(dc, cpu_addr, cpu_src2, insn, rd); + break; +#endif default: goto illegal_insn; } diff --git a/tests/Makefile b/tests/Makefile index b17d41e..471b4c8 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -35,6 +35,7 @@ check-unit-y += tests/test-visitor-serialization$(EXESUF) check-unit-y += tests/test-iov$(EXESUF) gcov-files-test-iov-y = util/iov.c check-unit-y += tests/test-aio$(EXESUF) +check-unit-y += tests/test-rfifolock$(EXESUF) check-unit-y += tests/test-throttle$(EXESUF) gcov-files-test-aio-$(CONFIG_WIN32) = aio-win32.c gcov-files-test-aio-$(CONFIG_POSIX) = aio-posix.c @@ -69,9 +70,24 @@ gcov-files-ipack-y += hw/ipack/ipack.c check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF) gcov-files-ipack-y += hw/char/ipoctal232.c +check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF) +gcov-files-virtioserial-y += hw/char/virtio-console.c + gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio.c check-qtest-virtio-y += tests/virtio-net-test$(EXESUF) gcov-files-virtio-y += i386-softmmu/hw/net/virtio-net.c +check-qtest-virtio-y += tests/virtio-balloon-test$(EXESUF) +gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio-balloon.c +check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF) +gcov-files-virtio-y += i386-softmmu/hw/block/virtio-blk.c +check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF) +gcov-files-virtio-y += hw/virtio/virtio-rng.c +check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF) +gcov-files-virtio-y += i386-softmmu/hw/scsi/virtio-scsi.c +check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF) +gcov-files-virtio-y += i386-softmmu/hw/char/virtio-serial-bus.c +check-qtest-virtio-y += $(check-qtest-virtioserial-y) +gcov-files-virtio-y += $(gcov-files-virtioserial-y) check-qtest-pci-y += tests/e1000-test$(EXESUF) gcov-files-pci-y += hw/net/e1000.c @@ -87,9 +103,9 @@ gcov-files-pci-y += hw/net/ne2000.c check-qtest-pci-y += $(check-qtest-virtio-y) gcov-files-pci-y += $(gcov-files-virtio-y) hw/virtio/virtio-pci.c check-qtest-pci-y += tests/tpci200-test$(EXESUF) -gcov-files-pci-y += hw/char/tpci200.c +gcov-files-pci-y += hw/ipack/tpci200.c check-qtest-pci-y += $(check-qtest-ipack-y) -gcov-files-pci-y += $(gcov-files-ipack-y) hw/ipack/tpci200.c +gcov-files-pci-y += $(gcov-files-ipack-y) check-qtest-i386-y = tests/endianness-test$(EXESUF) check-qtest-i386-y += tests/fdc-test$(EXESUF) @@ -129,6 +145,8 @@ check-qtest-arm-y = tests/tmp105-test$(EXESUF) gcov-files-arm-y += hw/misc/tmp105.c check-qtest-ppc-y += tests/boot-order-test$(EXESUF) check-qtest-ppc64-y += tests/boot-order-test$(EXESUF) +check-qtest-ppc64-y += tests/spapr-phb-test$(EXESUF) +gcov-files-ppc64-y += ppc64-softmmu/hw/ppc/spapr_pci.c check-qtest-microblazeel-y = $(check-qtest-microblaze-y) check-qtest-xtensaeb-y = $(check-qtest-xtensa-y) @@ -142,7 +160,11 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \ missing-comma-object.json non-objects.json \ qapi-schema-test.json quoted-structural-chars.json \ trailing-comma-list.json trailing-comma-object.json \ - unclosed-list.json unclosed-object.json unclosed-string.json) + unclosed-list.json unclosed-object.json unclosed-string.json \ + duplicate-key.json union-invalid-base.json flat-union-no-base.json \ + flat-union-invalid-discriminator.json \ + flat-union-invalid-branch-key.json flat-union-reverse-define.json \ + flat-union-string-discriminator.json) GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h @@ -172,6 +194,7 @@ tests/check-qjson$(EXESUF): tests/check-qjson.o libqemuutil.a libqemustub.a tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(qom-core-obj) libqemuutil.a libqemustub.a tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(block-obj-y) libqemuutil.a libqemustub.a tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a +tests/test-rfifolock$(EXESUF): tests/test-rfifolock.o libqemuutil.a libqemustub.a tests/test-throttle$(EXESUF): tests/test-throttle.o $(block-obj-y) libqemuutil.a libqemustub.a tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a @@ -221,6 +244,7 @@ libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o tests/rtc-test$(EXESUF): tests/rtc-test.o tests/m48t59-test$(EXESUF): tests/m48t59-test.o tests/endianness-test$(EXESUF): tests/endianness-test.o +tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o @@ -235,7 +259,13 @@ tests/pcnet-test$(EXESUF): tests/pcnet-test.o tests/eepro100-test$(EXESUF): tests/eepro100-test.o tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o tests/ne2000-test$(EXESUF): tests/ne2000-test.o +tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o +tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o +tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o +tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o +tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o +tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o tests/tpci200-test$(EXESUF): tests/tpci200-test.o tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o tests/qom-test$(EXESUF): tests/qom-test.o diff --git a/tests/acpi-test-data/pc/SSDT b/tests/acpi-test-data/pc/SSDT Binary files differindex c1a4589..ae5a9a5 100644 --- a/tests/acpi-test-data/pc/SSDT +++ b/tests/acpi-test-data/pc/SSDT diff --git a/tests/acpi-test-data/q35/SSDT b/tests/acpi-test-data/q35/SSDT Binary files differindex 9915dbe..634b481 100644 --- a/tests/acpi-test-data/q35/SSDT +++ b/tests/acpi-test-data/q35/SSDT diff --git a/tests/libqtest.c b/tests/libqtest.c index f587d36..2b90e4a 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -34,6 +34,7 @@ #include "qapi/qmp/json-parser.h" #define MAX_IRQ 256 +#define SOCKET_TIMEOUT 5 QTestState *global_qtest; @@ -78,12 +79,16 @@ static int socket_accept(int sock) struct sockaddr_un addr; socklen_t addrlen; int ret; + struct timeval timeout = { .tv_sec = SOCKET_TIMEOUT, + .tv_usec = 0 }; + + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, + sizeof(timeout)); addrlen = sizeof(addr); do { ret = accept(sock, (struct sockaddr *)&addr, &addrlen); } while (ret == -1 && errno == EINTR); - g_assert_no_errno(ret); close(sock); return ret; @@ -147,12 +152,16 @@ QTestState *qtest_init(const char *extra_args) } s->fd = socket_accept(sock); - s->qmp_fd = socket_accept(qmpsock); + if (s->fd >= 0) { + s->qmp_fd = socket_accept(qmpsock); + } unlink(socket_path); unlink(qmp_socket_path); g_free(socket_path); g_free(qmp_socket_path); + g_assert(s->fd >= 0 && s->qmp_fd >= 0); + s->rx = g_string_new(""); for (i = 0; i < MAX_IRQ; i++) { s->irq_level[i] = false; @@ -581,3 +590,23 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size) qtest_sendf(s, "\n"); qtest_rsp(s, 0); } + +QDict *qmp(const char *fmt, ...) +{ + va_list ap; + QDict *response; + + va_start(ap, fmt); + response = qtest_qmpv(global_qtest, fmt, ap); + va_end(ap); + return response; +} + +void qmp_discard_response(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + qtest_qmpv_discard_response(global_qtest, fmt, ap); + va_end(ap); +} diff --git a/tests/libqtest.h b/tests/libqtest.h index 9deebdc..8268c09 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -356,16 +356,7 @@ static inline void qtest_end(void) * * Sends a QMP message to QEMU and returns the response. */ -static inline QDict *qmp(const char *fmt, ...) -{ - va_list ap; - QDict *response; - - va_start(ap, fmt); - response = qtest_qmpv(global_qtest, fmt, ap); - va_end(ap); - return response; -} +QDict *qmp(const char *fmt, ...); /** * qmp_discard_response: @@ -373,14 +364,7 @@ static inline QDict *qmp(const char *fmt, ...) * * Sends a QMP message to QEMU and consumes the response. */ -static inline void qmp_discard_response(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - qtest_qmpv_discard_response(global_qtest, fmt, ap); - va_end(ap); -} +void qmp_discard_response(const char *fmt, ...); /** * get_irq: diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out index e3bd904..4ce3dcf 100644 --- a/tests/qapi-schema/comments.out +++ b/tests/qapi-schema/comments.out @@ -1,3 +1,3 @@ [OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] -['Status'] +[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}] [] diff --git a/tests/qapi-schema/duplicate-key.err b/tests/qapi-schema/duplicate-key.err new file mode 100644 index 0000000..0801c6a --- /dev/null +++ b/tests/qapi-schema/duplicate-key.err @@ -0,0 +1 @@ +<stdin>:2:10: Duplicate key "key" diff --git a/tests/qapi-schema/duplicate-key.exit b/tests/qapi-schema/duplicate-key.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/duplicate-key.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/duplicate-key.json b/tests/qapi-schema/duplicate-key.json new file mode 100644 index 0000000..1b55d88 --- /dev/null +++ b/tests/qapi-schema/duplicate-key.json @@ -0,0 +1,2 @@ +{ 'key': 'value', + 'key': 'value' } diff --git a/tests/qapi-schema/duplicate-key.out b/tests/qapi-schema/duplicate-key.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/duplicate-key.out diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.err b/tests/qapi-schema/flat-union-invalid-branch-key.err new file mode 100644 index 0000000..1125caf --- /dev/null +++ b/tests/qapi-schema/flat-union-invalid-branch-key.err @@ -0,0 +1 @@ +<stdin>:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum' diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.exit b/tests/qapi-schema/flat-union-invalid-branch-key.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/flat-union-invalid-branch-key.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.json b/tests/qapi-schema/flat-union-invalid-branch-key.json new file mode 100644 index 0000000..a624282 --- /dev/null +++ b/tests/qapi-schema/flat-union-invalid-branch-key.json @@ -0,0 +1,17 @@ +{ 'enum': 'TestEnum', + 'data': [ 'value1', 'value2' ] } + +{ 'type': 'TestBase', + 'data': { 'enum1': 'TestEnum' } } + +{ 'type': 'TestTypeA', + 'data': { 'string': 'str' } } + +{ 'type': 'TestTypeB', + 'data': { 'integer': 'int' } } + +{ 'union': 'TestUnion', + 'base': 'TestBase', + 'discriminator': 'enum1', + 'data': { 'value_wrong': 'TestTypeA', + 'value2': 'TestTypeB' } } diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.out b/tests/qapi-schema/flat-union-invalid-branch-key.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/flat-union-invalid-branch-key.out diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.err b/tests/qapi-schema/flat-union-invalid-discriminator.err new file mode 100644 index 0000000..cad9dbf --- /dev/null +++ b/tests/qapi-schema/flat-union-invalid-discriminator.err @@ -0,0 +1 @@ +<stdin>:13: Discriminator 'enum_wrong' is not a member of base type 'TestBase' diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.exit b/tests/qapi-schema/flat-union-invalid-discriminator.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/flat-union-invalid-discriminator.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.json b/tests/qapi-schema/flat-union-invalid-discriminator.json new file mode 100644 index 0000000..887157e --- /dev/null +++ b/tests/qapi-schema/flat-union-invalid-discriminator.json @@ -0,0 +1,17 @@ +{ 'enum': 'TestEnum', + 'data': [ 'value1', 'value2' ] } + +{ 'type': 'TestBase', + 'data': { 'enum1': 'TestEnum' } } + +{ 'type': 'TestTypeA', + 'data': { 'string': 'str' } } + +{ 'type': 'TestTypeB', + 'data': { 'integer': 'int' } } + +{ 'union': 'TestUnion', + 'base': 'TestBase', + 'discriminator': 'enum_wrong', + 'data': { 'value1': 'TestTypeA', + 'value2': 'TestTypeB' } } diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.out b/tests/qapi-schema/flat-union-invalid-discriminator.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/flat-union-invalid-discriminator.out diff --git a/tests/qapi-schema/flat-union-no-base.err b/tests/qapi-schema/flat-union-no-base.err new file mode 100644 index 0000000..e2d7443 --- /dev/null +++ b/tests/qapi-schema/flat-union-no-base.err @@ -0,0 +1 @@ +<stdin>:7: Flat union 'TestUnion' must have a base field diff --git a/tests/qapi-schema/flat-union-no-base.exit b/tests/qapi-schema/flat-union-no-base.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/flat-union-no-base.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/flat-union-no-base.json b/tests/qapi-schema/flat-union-no-base.json new file mode 100644 index 0000000..50f2673 --- /dev/null +++ b/tests/qapi-schema/flat-union-no-base.json @@ -0,0 +1,10 @@ +{ 'type': 'TestTypeA', + 'data': { 'string': 'str' } } + +{ 'type': 'TestTypeB', + 'data': { 'integer': 'int' } } + +{ 'union': 'TestUnion', + 'discriminator': 'enum1', + 'data': { 'value1': 'TestTypeA', + 'value2': 'TestTypeB' } } diff --git a/tests/qapi-schema/flat-union-no-base.out b/tests/qapi-schema/flat-union-no-base.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/flat-union-no-base.out diff --git a/tests/qapi-schema/flat-union-reverse-define.err b/tests/qapi-schema/flat-union-reverse-define.err new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/flat-union-reverse-define.err diff --git a/tests/qapi-schema/flat-union-reverse-define.exit b/tests/qapi-schema/flat-union-reverse-define.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/qapi-schema/flat-union-reverse-define.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/flat-union-reverse-define.json b/tests/qapi-schema/flat-union-reverse-define.json new file mode 100644 index 0000000..9ea7e72 --- /dev/null +++ b/tests/qapi-schema/flat-union-reverse-define.json @@ -0,0 +1,17 @@ +{ 'union': 'TestUnion', + 'base': 'TestBase', + 'discriminator': 'enum1', + 'data': { 'value1': 'TestTypeA', + 'value2': 'TestTypeB' } } + +{ 'type': 'TestBase', + 'data': { 'enum1': 'TestEnum' } } + +{ 'enum': 'TestEnum', + 'data': [ 'value1', 'value2' ] } + +{ 'type': 'TestTypeA', + 'data': { 'string': 'str' } } + +{ 'type': 'TestTypeB', + 'data': { 'integer': 'int' } } diff --git a/tests/qapi-schema/flat-union-reverse-define.out b/tests/qapi-schema/flat-union-reverse-define.out new file mode 100644 index 0000000..03c952e --- /dev/null +++ b/tests/qapi-schema/flat-union-reverse-define.out @@ -0,0 +1,9 @@ +[OrderedDict([('union', 'TestUnion'), ('base', 'TestBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'TestTypeA'), ('value2', 'TestTypeB')]))]), + OrderedDict([('type', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]), + OrderedDict([('enum', 'TestEnum'), ('data', ['value1', 'value2'])]), + OrderedDict([('type', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]), + OrderedDict([('type', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])] +[{'enum_name': 'TestEnum', 'enum_values': ['value1', 'value2']}] +[OrderedDict([('type', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]), + OrderedDict([('type', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]), + OrderedDict([('type', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])] diff --git a/tests/qapi-schema/flat-union-string-discriminator.err b/tests/qapi-schema/flat-union-string-discriminator.err new file mode 100644 index 0000000..8748270 --- /dev/null +++ b/tests/qapi-schema/flat-union-string-discriminator.err @@ -0,0 +1 @@ +<stdin>:13: Discriminator 'kind' must be of enumeration type diff --git a/tests/qapi-schema/flat-union-string-discriminator.exit b/tests/qapi-schema/flat-union-string-discriminator.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/flat-union-string-discriminator.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/flat-union-string-discriminator.json b/tests/qapi-schema/flat-union-string-discriminator.json new file mode 100644 index 0000000..e966aeb --- /dev/null +++ b/tests/qapi-schema/flat-union-string-discriminator.json @@ -0,0 +1,17 @@ +{ 'enum': 'TestEnum', + 'data': [ 'value1', 'value2' ] } + +{ 'type': 'TestBase', + 'data': { 'enum1': 'TestEnum', 'kind': 'str' } } + +{ 'type': 'TestTypeA', + 'data': { 'string': 'str' } } + +{ 'type': 'TestTypeB', + 'data': { 'integer': 'int' } } + +{ 'union': 'TestUnion', + 'base': 'TestBase', + 'discriminator': 'kind', + 'data': { 'kind1': 'TestTypeA', + 'kind2': 'TestTypeB' } } diff --git a/tests/qapi-schema/flat-union-string-discriminator.out b/tests/qapi-schema/flat-union-string-discriminator.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/flat-union-string-discriminator.out diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 471ba47..818c06d 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -37,10 +37,13 @@ 'base': 'UserDefZero', 'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } } +{ 'type': 'UserDefUnionBase', + 'data': { 'string': 'str', 'enum1': 'EnumOne' } } + { 'union': 'UserDefFlatUnion', - 'base': 'UserDefOne', - 'discriminator': 'string', - 'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } } + 'base': 'UserDefUnionBase', + 'discriminator': 'enum1', + 'data': { 'value1' : 'UserDefA', 'value2' : 'UserDefB', 'value3' : 'UserDefB' } } # FIXME generated struct UserDefFlatUnion has members for direct base # UserDefOne, but lacks members for indirect base UserDefZero diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 89b53d4..6cd03f3 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -7,7 +7,8 @@ OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('union', 'UserDefUnion'), ('base', 'UserDefZero'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]), - OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefOne'), ('discriminator', 'string'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]), + OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]), + OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]), OrderedDict([('union', 'UserDefAnonUnion'), ('discriminator', OrderedDict()), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]), OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str'])]))]), OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]), @@ -15,11 +16,10 @@ OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('*ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]), OrderedDict([('command', 'user_def_cmd3'), ('data', OrderedDict([('a', 'int'), ('*b', 'int')])), ('returns', 'int')]), OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])] -['EnumOne', - 'UserDefUnionKind', - 'UserDefFlatUnionKind', - 'UserDefAnonUnionKind', - 'UserDefNativeListUnionKind'] +[{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, + {'enum_name': 'UserDefUnionKind', 'enum_values': None}, + {'enum_name': 'UserDefAnonUnionKind', 'enum_values': None}, + {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None}] [OrderedDict([('type', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), OrderedDict([('type', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('type', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]), @@ -27,4 +27,5 @@ OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]), OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), + OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]), OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])] diff --git a/tests/qapi-schema/union-invalid-base.err b/tests/qapi-schema/union-invalid-base.err new file mode 100644 index 0000000..dd8e3d1 --- /dev/null +++ b/tests/qapi-schema/union-invalid-base.err @@ -0,0 +1 @@ +<stdin>:7: Base 'TestBaseWrong' is not a valid type diff --git a/tests/qapi-schema/union-invalid-base.exit b/tests/qapi-schema/union-invalid-base.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/union-invalid-base.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/union-invalid-base.json b/tests/qapi-schema/union-invalid-base.json new file mode 100644 index 0000000..1fa4930 --- /dev/null +++ b/tests/qapi-schema/union-invalid-base.json @@ -0,0 +1,10 @@ +{ 'type': 'TestTypeA', + 'data': { 'string': 'str' } } + +{ 'type': 'TestTypeB', + 'data': { 'integer': 'int' } } + +{ 'union': 'TestUnion', + 'base': 'TestBaseWrong', + 'data': { 'value1': 'TestTypeA', + 'value2': 'TestTypeB' } } diff --git a/tests/qapi-schema/union-invalid-base.out b/tests/qapi-schema/union-invalid-base.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/union-invalid-base.out diff --git a/tests/qdev-monitor-test.c b/tests/qdev-monitor-test.c index ba7f9cc..e20ffd6 100644 --- a/tests/qdev-monitor-test.c +++ b/tests/qdev-monitor-test.c @@ -32,8 +32,7 @@ static void test_device_add(void) "}}"); g_assert(response); error = qdict_get_qdict(response, "error"); - g_assert(!strcmp(qdict_get_try_str(error, "desc") ?: "", - "Device needs media, but drive is empty")); + g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, "GenericError"); QDECREF(response); /* Delete the drive */ @@ -42,7 +41,7 @@ static void test_device_add(void) " \"command-line\": \"drive_del drive0\"" "}}"); g_assert(response); - g_assert(!strcmp(qdict_get_try_str(response, "return") ?: "(null)", "")); + g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, ""); QDECREF(response); /* Try to re-add the drive. This fails with duplicate IDs if a leaked @@ -53,8 +52,7 @@ static void test_device_add(void) " \"command-line\": \"drive_add pci-addr=auto if=none,id=drive0\"" "}}"); g_assert(response); - g_assert(!strcmp(qdict_get_try_str(response, "return") ?: "", - "OK\r\n")); + g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "OK\r\n"); QDECREF(response); qtest_end(); diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index af8ed9f..f0116aa 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -138,6 +138,32 @@ $QEMU_IMG snapshot -a foo "$TEST_IMG" _check_test_img $QEMU_IO -c "$OPEN_RO" -c "read -P 1 0 512" | _filter_qemu_io +echo +echo "=== Testing overlap while COW is in flight ===" +echo +# compat=0.10 is required in order to make the following discard actually +# unallocate the sector rather than make it a zero sector - we want COW, after +# all. +IMGOPTS='compat=0.10' _make_test_img 1G +# Write two clusters, the second one enforces creation of an L2 table after +# the first data cluster. +$QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io +# Discard the first cluster. This cluster will soon enough be reallocated and +# used for COW. +$QEMU_IO -c 'discard 0k 64k' "$TEST_IMG" | _filter_qemu_io +# Now, corrupt the image by marking the second L2 table cluster as free. +poke_file "$TEST_IMG" '131084' "\x00\x00" # 0x2000c +# Start a write operation requiring COW on the image stopping it right before +# doing the read; then, trigger the corruption prevention by writing anything to +# any unallocated cluster, leading to an attempt to overwrite the second L2 +# table. Finally, resume the COW write and see it fail (but not crash). +echo "open -o file.driver=blkdebug $TEST_IMG +break cow_read 0 +aio_write 0k 1k +wait_break 0 +write 64k 64k +resume 0" | $QEMU_IO | _filter_qemu_io + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index 6c7bdbb..a517948 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -78,4 +78,19 @@ read 512/512 bytes at offset 0 No errors were found on the image. read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +=== Testing overlap while COW is in flight === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 536870912 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qcow2: Preventing invalid write on metadata (overlaps with active L2 table); image marked as corrupt. +blkdebug: Suspended request '0' +write failed: Input/output error +blkdebug: Resuming request '0' +aio_write failed: No medium found *** done diff --git a/tests/qom-test.c b/tests/qom-test.c index b6671fb..6d9a00b 100644 --- a/tests/qom-test.c +++ b/tests/qom-test.c @@ -10,6 +10,7 @@ #include <glib.h> #include <string.h> +#include "qemu-common.h" #include "libqtest.h" #include "qemu/osdep.h" #include "qapi/qmp/types.h" @@ -43,6 +44,40 @@ static bool is_blacklisted(const char *arch, const char *mach) return false; } +static void test_properties(const char *path) +{ + char *child_path; + QDict *response, *tuple; + QList *list; + QListEntry *entry; + + g_test_message("Obtaining properties of %s", path); + response = qmp("{ 'execute': 'qom-list'," + " 'arguments': { 'path': '%s' } }", path); + g_assert(response); + + g_assert(qdict_haskey(response, "return")); + list = qobject_to_qlist(qdict_get(response, "return")); + QLIST_FOREACH_ENTRY(list, entry) { + tuple = qobject_to_qdict(qlist_entry_obj(entry)); + if (strstart(qdict_get_str(tuple, "type"), "child<", NULL)) { + child_path = g_strdup_printf("%s/%s", + path, qdict_get_str(tuple, "name")); + test_properties(child_path); + g_free(child_path); + } else { + const char *prop = qdict_get_str(tuple, "name"); + g_test_message("Testing property %s.%s", path, prop); + response = qmp("{ 'execute': 'qom-get'," + " 'arguments': { 'path': '%s'," + " 'property': '%s' } }", + path, prop); + /* qom-get may fail but should not, e.g., segfault. */ + g_assert(response); + } + } +} + static void test_machine(gconstpointer data) { const char *machine = data; @@ -51,8 +86,12 @@ static void test_machine(gconstpointer data) args = g_strdup_printf("-machine %s", machine); qtest_start(args); + + test_properties("/machine"); + response = qmp("{ 'execute': 'quit' }"); g_assert(qdict_haskey(response, "return")); + qtest_end(); g_free(args); } diff --git a/tests/spapr-phb-test.c b/tests/spapr-phb-test.c new file mode 100644 index 0000000..b629de4 --- /dev/null +++ b/tests/spapr-phb-test.c @@ -0,0 +1,35 @@ +/* + * QTest testcase for SPAPR PHB + * + * Authors: + * Alexey Kardashevskiy <aik@ozlabs.ru> + * + * 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 <glib.h> + +#include "libqtest.h" + +#define TYPE_SPAPR_PCI_HOST_BRIDGE "spapr-pci-host-bridge" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void test_phb_device(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/spapr-phb/device", test_phb_device); + + qtest_start("-device " TYPE_SPAPR_PCI_HOST_BRIDGE ",index=100"); + + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/test-aio.c b/tests/test-aio.c index 592721e..56f4288 100644 --- a/tests/test-aio.c +++ b/tests/test-aio.c @@ -112,6 +112,64 @@ static void test_notify(void) g_assert(!aio_poll(ctx, false)); } +typedef struct { + QemuMutex start_lock; + bool thread_acquired; +} AcquireTestData; + +static void *test_acquire_thread(void *opaque) +{ + AcquireTestData *data = opaque; + + /* Wait for other thread to let us start */ + qemu_mutex_lock(&data->start_lock); + qemu_mutex_unlock(&data->start_lock); + + aio_context_acquire(ctx); + aio_context_release(ctx); + + data->thread_acquired = true; /* success, we got here */ + + return NULL; +} + +static void dummy_notifier_read(EventNotifier *unused) +{ + g_assert(false); /* should never be invoked */ +} + +static void test_acquire(void) +{ + QemuThread thread; + EventNotifier notifier; + AcquireTestData data; + + /* Dummy event notifier ensures aio_poll() will block */ + event_notifier_init(¬ifier, false); + aio_set_event_notifier(ctx, ¬ifier, dummy_notifier_read); + g_assert(!aio_poll(ctx, false)); /* consume aio_notify() */ + + qemu_mutex_init(&data.start_lock); + qemu_mutex_lock(&data.start_lock); + data.thread_acquired = false; + + qemu_thread_create(&thread, "test_acquire_thread", + test_acquire_thread, + &data, QEMU_THREAD_JOINABLE); + + /* Block in aio_poll(), let other thread kick us and acquire context */ + aio_context_acquire(ctx); + qemu_mutex_unlock(&data.start_lock); /* let the thread run */ + g_assert(!aio_poll(ctx, true)); + aio_context_release(ctx); + + qemu_thread_join(&thread); + aio_set_event_notifier(ctx, ¬ifier, NULL); + event_notifier_cleanup(¬ifier); + + g_assert(data.thread_acquired); +} + static void test_bh_schedule(void) { BHTestData data = { .n = 0 }; @@ -775,6 +833,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); g_test_add_func("/aio/notify", test_notify); + g_test_add_func("/aio/acquire", test_acquire); g_test_add_func("/aio/bh/schedule", test_bh_schedule); g_test_add_func("/aio/bh/schedule10", test_bh_schedule10); g_test_add_func("/aio/bh/cancel", test_bh_cancel); diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c index 8e62c2d..554e222 100644 --- a/tests/test-qmp-commands.c +++ b/tests/test-qmp-commands.c @@ -141,7 +141,7 @@ static void test_dispatch_cmd_io(void) ret3 = qobject_to_qint(test_qmp_dispatch(req)); assert(qint_get_int(ret3) == 66); - QDECREF(ret); + QDECREF(ret3); QDECREF(req); } diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c index 64d72f6..38b5e95 100644 --- a/tests/test-qmp-input-strict.c +++ b/tests/test-qmp-input-strict.c @@ -146,7 +146,10 @@ static void test_validate_union_flat(TestInputVisitorData *data, Visitor *v; Error *errp = NULL; - v = validate_test_init(data, "{ 'string': 'a', 'boolean': true }"); + v = validate_test_init(data, + "{ 'enum1': 'value1', " + "'string': 'str', " + "'boolean': true }"); /* TODO when generator bug is fixed, add 'integer': 41 */ visit_type_UserDefFlatUnion(v, &tmp, NULL, &errp); diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c index 2dffafc..1729667 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qmp-input-visitor.c @@ -310,14 +310,18 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data, Error *err = NULL; UserDefFlatUnion *tmp; - v = visitor_input_test_init(data, "{ 'string': 'a', 'boolean': true }"); + v = visitor_input_test_init(data, + "{ 'enum1': 'value1', " + "'string': 'str', " + "'boolean': true }"); /* TODO when generator bug is fixed, add 'integer': 41 */ visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); g_assert(err == NULL); - g_assert_cmpint(tmp->kind, ==, USER_DEF_UNION_KIND_A); + g_assert_cmpint(tmp->kind, ==, ENUM_ONE_VALUE1); + g_assert_cmpstr(tmp->string, ==, "str"); /* TODO g_assert_cmpint(tmp->integer, ==, 41); */ - g_assert_cmpint(tmp->a->boolean, ==, true); + g_assert_cmpint(tmp->value1->boolean, ==, true); qapi_free_UserDefFlatUnion(tmp); } diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c index 105f4cf..da27971 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qmp-output-visitor.c @@ -449,10 +449,11 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data, Error *err = NULL; UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion)); - tmp->kind = USER_DEF_UNION_KIND_A; - tmp->a = g_malloc0(sizeof(UserDefA)); + tmp->kind = ENUM_ONE_VALUE1; + tmp->string = g_strdup("str"); + tmp->value1 = g_malloc0(sizeof(UserDefA)); /* TODO when generator bug is fixed: tmp->integer = 41; */ - tmp->a->boolean = true; + tmp->value1->boolean = true; visit_type_UserDefFlatUnion(data->ov, &tmp, NULL, &err); g_assert(err == NULL); @@ -461,7 +462,8 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data, g_assert(qobject_type(arg) == QTYPE_QDICT); qdict = qobject_to_qdict(arg); - g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "a"); + g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1"); + g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str"); /* TODO g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 41); */ g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true); diff --git a/tests/test-rfifolock.c b/tests/test-rfifolock.c new file mode 100644 index 0000000..0572ebb --- /dev/null +++ b/tests/test-rfifolock.c @@ -0,0 +1,91 @@ +/* + * RFifoLock tests + * + * Copyright Red Hat, Inc. 2013 + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include <glib.h> +#include "qemu-common.h" +#include "qemu/rfifolock.h" + +static void test_nesting(void) +{ + RFifoLock lock; + + /* Trivial test, ensure the lock is recursive */ + rfifolock_init(&lock, NULL, NULL); + rfifolock_lock(&lock); + rfifolock_lock(&lock); + rfifolock_lock(&lock); + rfifolock_unlock(&lock); + rfifolock_unlock(&lock); + rfifolock_unlock(&lock); + rfifolock_destroy(&lock); +} + +typedef struct { + RFifoLock lock; + int fd[2]; +} CallbackTestData; + +static void rfifolock_cb(void *opaque) +{ + CallbackTestData *data = opaque; + int ret; + char c = 0; + + ret = write(data->fd[1], &c, sizeof(c)); + g_assert(ret == 1); +} + +static void *callback_thread(void *opaque) +{ + CallbackTestData *data = opaque; + + /* The other thread holds the lock so the contention callback will be + * invoked... + */ + rfifolock_lock(&data->lock); + rfifolock_unlock(&data->lock); + return NULL; +} + +static void test_callback(void) +{ + CallbackTestData data; + QemuThread thread; + int ret; + char c; + + rfifolock_init(&data.lock, rfifolock_cb, &data); + ret = qemu_pipe(data.fd); + g_assert(ret == 0); + + /* Hold lock but allow the callback to kick us by writing to the pipe */ + rfifolock_lock(&data.lock); + qemu_thread_create(&thread, "callback_thread", + callback_thread, &data, QEMU_THREAD_JOINABLE); + ret = read(data.fd[0], &c, sizeof(c)); + g_assert(ret == 1); + rfifolock_unlock(&data.lock); + /* If we got here then the callback was invoked, as expected */ + + qemu_thread_join(&thread); + close(data.fd[0]); + close(data.fd[1]); + rfifolock_destroy(&data.lock); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/nesting", test_nesting); + g_test_add_func("/callback", test_callback); + return g_test_run(); +} diff --git a/tests/virtio-balloon-test.c b/tests/virtio-balloon-test.c new file mode 100644 index 0000000..becebb5 --- /dev/null +++ b/tests/virtio-balloon-test.c @@ -0,0 +1,33 @@ +/* + * QTest testcase for VirtIO Balloon + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/balloon/pci/nop", pci_nop); + + qtest_start("-device virtio-balloon-pci"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c new file mode 100644 index 0000000..d53f875 --- /dev/null +++ b/tests/virtio-blk-test.c @@ -0,0 +1,34 @@ +/* + * QTest testcase for VirtIO Block Device + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/blk/pci/nop", pci_nop); + + qtest_start("-drive id=drv0,if=none,file=/dev/null " + "-device virtio-blk-pci,drive=drv0"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/virtio-console-test.c b/tests/virtio-console-test.c new file mode 100644 index 0000000..f98f5af2 --- /dev/null +++ b/tests/virtio-console-test.c @@ -0,0 +1,34 @@ +/* + * QTest testcase for VirtIO Console + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/console/pci/nop", pci_nop); + + qtest_start("-device virtio-serial-pci,id=vser0 " + "-device virtconsole,bus=vser0.0"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/virtio-rng-test.c b/tests/virtio-rng-test.c new file mode 100644 index 0000000..402c206 --- /dev/null +++ b/tests/virtio-rng-test.c @@ -0,0 +1,33 @@ +/* + * QTest testcase for VirtIO RNG + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/rng/pci/nop", pci_nop); + + qtest_start("-device virtio-rng-pci"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c new file mode 100644 index 0000000..3230908 --- /dev/null +++ b/tests/virtio-scsi-test.c @@ -0,0 +1,35 @@ +/* + * QTest testcase for VirtIO SCSI + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/scsi/pci/nop", pci_nop); + + qtest_start("-drive id=drv0,if=none,file=/dev/null " + "-device virtio-scsi-pci,id=vscsi0 " + "-device scsi-hd,bus=vscsi0.0,drive=drv0"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/virtio-serial-test.c b/tests/virtio-serial-test.c new file mode 100644 index 0000000..e743875 --- /dev/null +++ b/tests/virtio-serial-test.c @@ -0,0 +1,33 @@ +/* + * QTest testcase for VirtIO Serial + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/serial/pci/nop", pci_nop); + + qtest_start("-device virtio-serial-pci"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/trace/control-internal.h b/trace/control-internal.h index cce2da4..b3f587e 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -16,15 +16,15 @@ extern TraceEvent trace_events[]; -static inline TraceEvent *trace_event_id(TraceEventID id) +static inline TraceEventID trace_event_count(void) { - assert(id < trace_event_count()); - return &trace_events[id]; + return TRACE_EVENT_COUNT; } -static inline TraceEventID trace_event_count(void) +static inline TraceEvent *trace_event_id(TraceEventID id) { - return TRACE_EVENT_COUNT; + assert(id < trace_event_count()); + return &trace_events[id]; } static inline bool trace_event_is_pattern(const char *str) diff --git a/util/Makefile.objs b/util/Makefile.objs index 937376b..df83b62 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -14,3 +14,4 @@ util-obj-y += crc32c.o util-obj-y += throttle.o util-obj-y += getauxval.o util-obj-y += readline.o +util-obj-y += rfifolock.o diff --git a/util/oslib-posix.c b/util/oslib-posix.c index c2eeb4f..8e9c770 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -63,6 +63,10 @@ extern int daemon(int, int); #include <sys/syscall.h> #endif +#ifdef __FreeBSD__ +#include <sys/sysctl.h> +#endif + int qemu_get_thread_id(void) { #if defined(__linux__) diff --git a/util/rfifolock.c b/util/rfifolock.c new file mode 100644 index 0000000..afbf748 --- /dev/null +++ b/util/rfifolock.c @@ -0,0 +1,78 @@ +/* + * Recursive FIFO lock + * + * Copyright Red Hat, Inc. 2013 + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include <assert.h> +#include "qemu/rfifolock.h" + +void rfifolock_init(RFifoLock *r, void (*cb)(void *), void *opaque) +{ + qemu_mutex_init(&r->lock); + r->head = 0; + r->tail = 0; + qemu_cond_init(&r->cond); + r->nesting = 0; + r->cb = cb; + r->cb_opaque = opaque; +} + +void rfifolock_destroy(RFifoLock *r) +{ + qemu_cond_destroy(&r->cond); + qemu_mutex_destroy(&r->lock); +} + +/* + * Theory of operation: + * + * In order to ensure FIFO ordering, implement a ticketlock. Threads acquiring + * the lock enqueue themselves by incrementing the tail index. When the lock + * is unlocked, the head is incremented and waiting threads are notified. + * + * Recursive locking does not take a ticket since the head is only incremented + * when the outermost recursive caller unlocks. + */ +void rfifolock_lock(RFifoLock *r) +{ + qemu_mutex_lock(&r->lock); + + /* Take a ticket */ + unsigned int ticket = r->tail++; + + if (r->nesting > 0 && qemu_thread_is_self(&r->owner_thread)) { + r->tail--; /* put ticket back, we're nesting */ + } else { + while (ticket != r->head) { + /* Invoke optional contention callback */ + if (r->cb) { + r->cb(r->cb_opaque); + } + qemu_cond_wait(&r->cond, &r->lock); + } + } + + qemu_thread_get_self(&r->owner_thread); + r->nesting++; + qemu_mutex_unlock(&r->lock); +} + +void rfifolock_unlock(RFifoLock *r) +{ + qemu_mutex_lock(&r->lock); + assert(r->nesting > 0); + assert(qemu_thread_is_self(&r->owner_thread)); + if (--r->nesting == 0) { + r->head++; + qemu_cond_broadcast(&r->cond); + } + qemu_mutex_unlock(&r->lock); +} @@ -1571,54 +1571,82 @@ void pcmcia_info(Monitor *mon, const QDict *qdict) /***********************************************************/ /* machine registration */ -static QEMUMachine *first_machine = NULL; -QEMUMachine *current_machine = NULL; +MachineState *current_machine; + +static void machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->qemu_machine = data; +} int qemu_register_machine(QEMUMachine *m) { - QEMUMachine **pm; - pm = &first_machine; - while (*pm != NULL) - pm = &(*pm)->next; - m->next = NULL; - *pm = m; + TypeInfo ti = { + .name = g_strconcat(m->name, TYPE_MACHINE_SUFFIX, NULL), + .parent = TYPE_MACHINE, + .class_init = machine_class_init, + .class_data = (void *)m, + }; + + type_register(&ti); + return 0; } -static QEMUMachine *find_machine(const char *name) +static MachineClass *find_machine(const char *name) { - QEMUMachine *m; + GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); + MachineClass *mc = NULL; + + for (el = machines; el; el = el->next) { + MachineClass *temp = el->data; - for(m = first_machine; m != NULL; m = m->next) { - if (!strcmp(m->name, name)) - return m; - if (m->alias && !strcmp(m->alias, name)) - return m; + if (!strcmp(temp->qemu_machine->name, name)) { + mc = temp; + break; + } + if (temp->qemu_machine->alias && + !strcmp(temp->qemu_machine->alias, name)) { + mc = temp; + break; + } } - return NULL; + + g_slist_free(machines); + return mc; } -QEMUMachine *find_default_machine(void) +MachineClass *find_default_machine(void) { - QEMUMachine *m; + GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); + MachineClass *mc = NULL; - for(m = first_machine; m != NULL; m = m->next) { - if (m->is_default) { - return m; + for (el = machines; el; el = el->next) { + MachineClass *temp = el->data; + + if (temp->qemu_machine->is_default) { + mc = temp; + break; } } - return NULL; + + g_slist_free(machines); + return mc; } MachineInfoList *qmp_query_machines(Error **errp) { + GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); MachineInfoList *mach_list = NULL; QEMUMachine *m; - for (m = first_machine; m; m = m->next) { + for (el = machines; el; el = el->next) { + MachineClass *mc = el->data; MachineInfoList *entry; MachineInfo *info; + m = mc->qemu_machine; info = g_malloc0(sizeof(*info)); if (m->is_default) { info->has_is_default = true; @@ -1639,6 +1667,7 @@ MachineInfoList *qmp_query_machines(Error **errp) mach_list = entry; } + g_slist_free(machines); return mach_list; } @@ -1832,8 +1861,12 @@ void qemu_devices_reset(void) void qemu_system_reset(bool report) { - if (current_machine && current_machine->reset) { - current_machine->reset(); + MachineClass *mc; + + mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; + + if (mc && mc->qemu_machine->reset) { + mc->qemu_machine->reset(); } else { qemu_devices_reset(); } @@ -2605,24 +2638,29 @@ static int debugcon_parse(const char *devname) return 0; } -static QEMUMachine *machine_parse(const char *name) +static MachineClass *machine_parse(const char *name) { - QEMUMachine *m, *machine = NULL; + MachineClass *mc = NULL; + GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); if (name) { - machine = find_machine(name); + mc = find_machine(name); } - if (machine) { - return machine; + if (mc) { + return mc; } printf("Supported machines are:\n"); - for (m = first_machine; m != NULL; m = m->next) { + for (el = machines; el; el = el->next) { + MachineClass *mc = el->data; + QEMUMachine *m = mc->qemu_machine; if (m->alias) { printf("%-20s %s (alias of %s)\n", m->alias, m->desc, m->name); } printf("%-20s %s%s\n", m->name, m->desc, m->is_default ? " (default)" : ""); } + + g_slist_free(machines); exit(!name || !is_help_option(name)); } @@ -2871,6 +2909,7 @@ int main(int argc, char **argv, char **envp) int optind; const char *optarg; const char *loadvm = NULL; + MachineClass *machine_class; QEMUMachine *machine; const char *cpu_model; const char *vga_model = "none"; @@ -2945,7 +2984,7 @@ int main(int argc, char **argv, char **envp) os_setup_early_signal_handling(); module_call_init(MODULE_INIT_MACHINE); - machine = find_default_machine(); + machine_class = find_default_machine(); cpu_model = NULL; ram_size = 0; snapshot = 0; @@ -3011,7 +3050,7 @@ int main(int argc, char **argv, char **envp) } switch(popt->index) { case QEMU_OPTION_M: - machine = machine_parse(optarg); + machine_class = machine_parse(optarg); break; case QEMU_OPTION_no_kvm_irqchip: { olist = qemu_find_opts("machine"); @@ -3567,7 +3606,7 @@ int main(int argc, char **argv, char **envp) } optarg = qemu_opt_get(opts, "type"); if (optarg) { - machine = machine_parse(optarg); + machine_class = machine_parse(optarg); } break; case QEMU_OPTION_no_kvm: @@ -3873,11 +3912,17 @@ int main(int argc, char **argv, char **envp) } #endif - if (machine == NULL) { + if (machine_class == NULL) { fprintf(stderr, "No machine found.\n"); exit(1); } + current_machine = MACHINE(object_new(object_class_get_name( + OBJECT_CLASS(machine_class)))); + object_property_add_child(object_get_root(), "machine", + OBJECT(current_machine), &error_abort); + + machine = machine_class->qemu_machine; if (machine->hw_version) { qemu_set_version(machine->hw_version); } @@ -4306,7 +4351,9 @@ int main(int argc, char **argv, char **envp) .kernel_cmdline = kernel_cmdline, .initrd_filename = initrd_filename, .cpu_model = cpu_model }; - machine->init(&args); + + current_machine->init_args = args; + machine->init(¤t_machine->init_args); audio_init(); @@ -4314,8 +4361,6 @@ int main(int argc, char **argv, char **envp) set_numa_modes(); - current_machine = machine; - /* init USB devices */ if (usb_enabled(false)) { if (foreach_device_config(DEV_USB, usb_parse) < 0) |