Re: [Qemu-devel] [PATCH RFC v7 7/7] qemu-iotests-s390x-fix-test-130
Hi Kevin: On 04/28/2015 04:23 PM, Kevin Wolf wrote: Am 28.04.2015 um 04:59 hat tu bo geschrieben: Hi Kevin: On 04/27/2015 07:34 PM, Kevin Wolf wrote: Am 27.04.2015 um 13:24 hat Max Reitz geschrieben: On 27.04.2015 09:15, tu bo wrote: Hi Max: On 04/24/2015 01:07 AM, Max Reitz wrote: Well, that's a peculiar commit title. :-) I guess it's supposed to be qemu-iotests: s390x: fix test 130? You're right. I will change it in the next version :-) On 23.04.2015 04:42, Xiao Guang Chen wrote: From: Bo Tu t...@linux.vnet.ibm.com The tests for device type ide_cd should only be tested for the pc platform. The default device id of hard disk on the s390 platform differs to that of the x86 platform. A new variable device_id is defined and virtio0 set for the s390 platform. A x86 platform specific output file is also needed. Signed-off-by: Bo Tu t...@linux.vnet.ibm.com --- tests/qemu-iotests/130| 13 +++-- tests/qemu-iotests/130.out| 4 ++-- tests/qemu-iotests/130.pc.out | 43 +++ 3 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 tests/qemu-iotests/130.pc.out diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130 index bc26247..de40c7b 100755 --- a/tests/qemu-iotests/130 +++ b/tests/qemu-iotests/130 @@ -58,9 +58,18 @@ echo === HMP commit === echo # bdrv_make_empty() involves a header update for qcow2 +case $QEMU_DEFAULT_MACHINE in +pc) +device_id=ide0-hd0 +;; +s390) +device_id=virtio0 +;; I think I mentioned before that I don't really like not taking the fact into account that there are other machine types, too. I'm still accepting it based on the fact that I think those machine types won't pass the tests right now anyway, so not caring for them in these case blocks won't break any tests, but it still feels like something we can avoid (like defaulting to virtio0 for any non-pc platform). Anyway, because I seem to remember I accepted it before: With the commit title fixed: Reviewed-by: Max Reitz mre...@redhat.com I guess you discussed with Xiao Guang Chen and accepted it in [PATCH RFC v5 6/7] qemu-iotests s390x fix test-051, because test 130 and 051 are using the same fix solution, and test 051 was fixed in v5. Seeing section of v5 in cover letter as below: Indeed we discussed it. Just for clarification, I disliked having only cases for pc and s390 -- there are other platforms, too, which will simply break by not including them in these case statements. We could try to avoid this by defaulting to virtio0 for every non-pc platform, and it will probably work for most without having to do further work here. However, I did accept it because all those non-PC (and non-s390) platforms won't pass the tests before this patch set either (because these test cases try to use IDE devices which will not be available there). So the series will not break them because they didn't work before either. Bottom line: I'm fine with this solution as it is. Maybe I'm missing the obvious, but why don't you just specify an explicit ID instead of guessing the default ID that qemu will use depending on the platform? Please forgive me that I'm very sure about the meaning of default ID you mentioned. Maybe you mean default device ID? If I'm wrong, please correct me :-) The default device id of hard disk on the s390 platform differs to the device id on the x86 platform, so we need to use different device id for different platform. For instance, using virtio0 for s390x, and using ide0-hd0 for x86 as below: +_send_qemu_cmd $QEMU_HANDLE commit virtio0 (qemu) +_send_qemu_cmd $QEMU_HANDLE commit ide0-hd0 (qemu) Any why not use this? qemu -drive id=testdisk,... (qemu) commit testdisk I tried and it works fine, which is a more easier solution for test 130. I'll use your solution in patch v8.
Re: [Qemu-devel] [PATCH RFC 19/19] qapi: New QMP command query-schema for QMP schema introspection
Eric Blake ebl...@redhat.com writes: On 04/02/2015 11:29 AM, Markus Armbruster wrote: * Implicit type definitions are made explicit, and given auto-generated names. These names start with ':' so they don't clash with the user's names. Example: a simple union implicitly defines an enumeration type for its discriminator. Given that I just tripped over a bug in my series where I failed to consider that '*name' and 'name' should be considered the same, I'm wondering if we should first update the parse engine to flatten shorthand into a canonical form (that is, get to a point where we have a list of all names and their C counterparts), rather than having to tweak lots of places in the backends to repeatedly make the same translations over and over again (stripping off leading '*', converting qapi 'default' into C 'q_default', converting qapi 'a-b' into C 'a_b', etc.). I bet some of the backend generator gets simpler if the front end reuses your work to get into a canonical form on initial parse. Agree: The schema generation proper is pretty trivial. Much of the qapi-introspect.py's code actually does something else: convert the output of parse_schema() into a more usable data structure, lowering away uninteresting stuff. This should really be done in qapi.py, so the other generators can use it, too. However, we can't simply rebase your series onto mine, because mine is already based on yours. I really, really want to base on your tests, simplifications and bug fixes. Rearranging everything now doesn't sound appealing to me. Let's get our combined work in, except for this PATCH 19, which isn't ready, yet. +++ b/scripts/qapi-introspect.py @@ -0,0 +1,430 @@ + +def make_implicit_enum_type(name, role, values): +name = ':enum-%s-%s' % (name, role) Evidence of my python newbie-ness: Here, you are using string formatting (as in 'pattern' % arguments), in other patches, I've seen you use concatenation (would look like ':enum-' + name + '-' + role). Is there any rhyme or reason why one form should be considered over the other? I'm no Pythonista, either. I use whatever feels more readable.
Re: [Qemu-devel] [PATCH v7 25/39] qapi: Require valid names
Eric Blake ebl...@redhat.com writes: On 04/29/2015 07:06 AM, Eric Blake wrote: Previous commits demonstrated that the generator overlooked various bad naming situations: - types, commands, and events need a valid name - enum members must be valid names, when combined with prefix - union and alternate branches cannot be marked optional regex, this patch just uses a broader combination that allows both upstream and downstream names, as well as a small hack that realizes that any enum name is merely a suffix to an already valid name prefix (that is, any enum name is valid if prepending _ fits the normal rules). +# Enum members can start with a digit, because the generated C +# code always prefixes it with the enum name +if enum_member: +membername = _%s %membername +if not valid_name.match(membername): +raise QAPIExprError(expr_info, Python question: Would it be any simpler to write: membername = '_' + membername and if so, do I need to squash anything in? I find + easier to read here, even when compare to a correctly spaced _%s % membername. I think we have enough squash candidates to justify a quick v8. I'd prefer that, as I I haven't checked v7 anyway :)
Re: [Qemu-devel] [PATCH v7 36/39] qapi: Drop support for inline nested types
Eric Blake ebl...@redhat.com writes: On 04/29/2015 07:06 AM, Eric Blake wrote: A future patch will be using a 'name':{dictionary} entry in the QAPI schema to specify a default value for an optional argument (see previous commit messages for more details why); but existing use of inline nested structs conflicts with that goal. Now that all commands have been changed to avoid inline nested structs, nuke support for them, and turn it into a hard error. Update the testsuite to reflect tighter parsing rules. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- scripts/qapi-commands.py | 8 +++--- scripts/qapi-event.py| 4 +-- scripts/qapi-types.py| 9 ++- scripts/qapi-visit.py| 37 scripts/qapi.py | 20 ++- +++ b/scripts/qapi-visit.py @@ -51,27 +51,6 @@ def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = else: full_name = %s_%s % (name, fn_prefix) -for argname, argentry, optional, structured in parse_args(members): -if structured: -if not fn_prefix: -nested_fn_prefix = argname -else: -nested_fn_prefix = %s_%s % (fn_prefix, argname) - -nested_field_prefix = %s%s. % (field_prefix, argname) -ret += generate_visit_struct_fields(name, nested_field_prefix, -nested_fn_prefix, argentry) This is the only place that calls generate_visit_struct_fields with a non-empty string for prefix arguments; I've got a cleanup patch that we can either squash into this patch or leave as standalone. Squash vs. separate patch: your choice.
Re: [Qemu-devel] [PATCH] hw/sd: Don't pass BlockBackend to sd_reset()
Peter Maydell peter.mayd...@linaro.org writes: The only valid BlockBackend to pass to sd_reset() is the one for the SD card, which is sd-blk. Drop the second argument from this function in favour of having it just use sd-blk. Signed-off-by: Peter Maydell peter.mayd...@linaro.org --- A minor cleanup that was lurking in the omap3 tree (where it's used to allow SD card controllers to reset the card, which is something I haven't yet figured out the legitimacy of...) Reviewed-by: Markus Armbruster arm...@redhat.com
Re: [Qemu-devel] driver enhancement for Intel IGD passthrough
From: Alex Williamson [mailto:alex.william...@redhat.com] Sent: Tuesday, April 21, 2015 2:13 AM On Thu, 2015-04-16 at 17:24 +, Tian, Kevin wrote: ping... From: Tian, Kevin Sent: Friday, April 10, 2015 10:33 AM Hi, We are working on Linux/Windows graphics driver enhancement to remove those non-standard PCI resource accesses, e.g. to PCH/MCH registers, in parallel with the ongoing effort from Tiejun on current driver support. When the goal is to make IGD passthrough like a standard PCI passthrough w/o IGD specific patches, there is one open about VBT table which contains important display information (resolution, timing, etc.) for embedded panels (e.g. on laptop) which may not be detected through normal EDID query interface. Lacking of VBT may lead to a suboptimal display quality and other tricky issues. So we want to hear your opinions whether it makes sense to you to only maintain one IGD specific logic by exposing VBT through OpRegion to the guest. Except it all current IGD specific tweaks will not be required in the future w/ planned driver enhancements. Hi Kevin, I found the VBT in chapter 4 here: https://01.org/linuxgraphics/sites/default/files/documentation/acpi_igd_opre gion_spec.pdf How ASL/Driver use it: The system BIOS during, POST, decompresses (if necessary) the video BIOS image to physical RAM, scans VBIOS image, and copies ONLY the VBT block (all of the VBT data including its header) to OpRegion memory. This must be done whether IGD is primary or secondary VGA, and after VBIOS POST. The driver, during initialization, reads this data, validates it, and uses it. So this sounds like a simple extension required in SeaBIOS and OVMF to perform this additional operation to create this opregion in guest memory, right? I'm not really seeing why this needs to be anything special beyond some guest BIOS code and maybe some procedure to extract the VBIOS from the host or expose it through sysfs. I'd expect we need a VBIOS to initialize the card in the guest anyway. There isn't really any requirement to pass through the host VBT, is there? Seems like we can recreate it ourselves once we have the VBIOS. If that's the case, it seems fairly agreeable to me, especially if it's more of an optimization than a requirement. Thanks, Alex either presenting VBT in guest BIOS or in guest OpRegion is OK because guest driver will try another if one is lacking. You can even create a new VBT with filtered information. Here the background of this ask, is that we initially plan to make IGD passthru exactly same as normal PCI passthru w/o IGD specific patches, by providing driver enhancements, however w/o a valid VBT presented there will be feature/quality impact on some platforms. So we want to know whether keeping this very IGD specific logic only for VBT is acceptable to the community, after removing other hacks on MCH/ICH, etc. Looks from your feedback it should be fine. :-) Thanks Kevin
Re: [Qemu-devel] Patch for 64 bit mingw compilation
Hi The changes appear to be necessary. I was building Windows QEMU GA on Fedora 21, MINGW cross-compiler v. 4.9.2, build 20141030, Fedora MinGW 4.9.2-1.fc21 and before the changes, linking failed. Below is the building log for qga-vss.dll before the changes: - $ make qga/vss-win32/qga-vss.dll CHK version_gen.h CXX qga/vss-win32/requester.o qga/vss-win32/requester.cpp:1:0: warning: -fPIC ignored for target (all code is position independent) /* ^ qga/vss-win32/requester.cpp:1:0: warning: -fPIC ignored for target (all code is position independent) /* ^ In file included from qga/vss-win32/requester.cpp:17:0: ./inc/win2003/vswriter.h:39:2: warning: 'typedef' was ignored in this declaration }; ^ ./inc/win2003/vswriter.h:47:2: warning: 'typedef' was ignored in this declaration }; ^ ./inc/win2003/vswriter.h:59:2: warning: 'typedef' was ignored in this declaration }; ^ ./inc/win2003/vswriter.h:67:2: warning: 'typedef' was ignored in this declaration }; ^ ./inc/win2003/vswriter.h:75:2: warning: 'typedef' was ignored in this declaration }; ^ ./inc/win2003/vswriter.h:83:5: warning: 'typedef' was ignored in this declaration }; ^ ./inc/win2003/vswriter.h:93:5: warning: 'typedef' was ignored in this declaration }; ^ ./inc/win2003/vswriter.h:103:2: warning: 'typedef' was ignored in this declaration }; ^ ./inc/win2003/vswriter.h:112:2: warning: 'typedef' was ignored in this declaration }; ^ ./inc/win2003/vswriter.h:119:2: warning: 'typedef' was ignored in this declaration }; ^ CXX qga/vss-win32/provider.o qga/vss-win32/provider.cpp:1:0: warning: -fPIC ignored for target (all code is position independent) /* ^ qga/vss-win32/provider.cpp:1:0: warning: -fPIC ignored for target (all code is position independent) /* ^ CXX qga/vss-win32/install.o qga/vss-win32/install.cpp:1:0: warning: -fPIC ignored for target (all code is position independent) /* ^ qga/vss-win32/install.cpp:1:0: warning: -fPIC ignored for target (all code is position independent) /* ^ LINK qga/vss-win32/qga-vss.dll qga/vss-win32/requester.o: In function `WaitForAsync': /home/jhindin/development/qemu_upstream/qga/vss-win32/requester.cpp:148: undefined reference to `__stack_chk_fail' qga/vss-win32/requester.o: In function `requester_freeze': /home/jhindin/development/qemu_upstream/qga/vss-win32/requester.cpp:435: undefined reference to `__stack_chk_fail' qga/vss-win32/requester.o: In function `requester_thaw': /home/jhindin/development/qemu_upstream/qga/vss-win32/requester.cpp:503: undefined reference to `__stack_chk_fail' qga/vss-win32/requester.o: In function `fprintf(_iobuf*, char const*, ...)': /usr/x86_64-w64-mingw32/sys-root/mingw/include/stdio.h:292: undefined reference to `__stack_chk_fail' qga/vss-win32/requester.o:requester.cpp:(.rdata$.refptr.__stack_chk_guard[.refptr.__stack_chk_guard]+0x0): undefined reference to `__stack_chk_guard' qga/vss-win32/install.o: In function `errmsg_dialog': /home/jhindin/development/qemu_upstream/qga/vss-win32/install.cpp:65: undefined reference to `__stack_chk_fail' qga/vss-win32/install.o: In function `CreateRegistryKey': /home/jhindin/development/qemu_upstream/qga/vss-win32/install.cpp:349: undefined reference to `__stack_chk_fail' qga/vss-win32/install.o: In function `errmsg(unsigned long, char const*)': /home/jhindin/development/qemu_upstream/qga/vss-win32/install.cpp:52: undefined reference to `__stack_chk_fail' qga/vss-win32/install.o: In function `QGAProviderFind': /home/jhindin/development/qemu_upstream/qga/vss-win32/install.cpp:175: undefined reference to `__stack_chk_fail' qga/vss-win32/install.o: In function `DllUnregisterServer': /home/jhindin/development/qemu_upstream/qga/vss-win32/install.cpp:445: undefined reference to `__stack_chk_fail' qga/vss-win32/install.o:/home/jhindin/development/qemu_upstream/qga/vss-win32/install.cpp:422: more undefined references to `__stack_chk_fail' follow collect2: error: ld returned 1 exit status /home/jhindin/development/qemu_upstream/qga/vss-win32/Makefile.objs:10: recipe for target 'qga/vss-win32/qga-vss.dll' failed make: *** [qga/vss-win32/qga-vss.dll] Error 1 -- Regards, Joseph Hindin On Sun, May 3, 2015 at 11:33 AM, Olga Krishtal okrish...@parallels.com wrote: On 11/03/15 17:51, Joseph Hindin wrote: Hi When compiling the QEMU Guest Agent with 64-bit MinGW toolchain version 4.9.2, I run into the following problem: qga-vss.dll linking failed as linker reported a lot of unresolved symbol __stack_chk_fail errors stemming from the stack protection. The attached patch solves the problem by adding libssp to the qga-vss.dll libraries list. Regards, Joseph Hindin Are you sure that it is necessary? I worked with VSS-provider in order to check it on 64 bit platform (Win Server 2008) , and I did not have such problems.
Re: [Qemu-devel] [PATCH 4/4] qemu-ga: Building Windows MSI installation with configure/Makefile
On 26/04/2015 09:04, Yossi Hindin wrote: +ifdef QEMU_GA_MSI_WITH_VSS +${QEMU_GA_MSI}: qga/vss-win32/qga-vss.dll qemu-ga.exe Shouldn't the qemu-ga.exe dependency be unconditional? +endif + +${QEMU_GA_MSI}: config-host.mak + +${QEMU_GA_MSI}: qga/installer/qemu-ga.wxs + $(call quiet-command,QEMU_GA_VERSION=$(QEMU_GA_VERSION) QEMU_GA_MANUFACTURER=$(QEMU_GA_MANUFACTURER) QEMU_GA_DISTRO=$(QEMU_GA_DISTRO) \ + wixl -o $@ ${QEMU_GA_MSI_ARCH} ${QEMU_GA_MSI_WITH_VSS} ${QEMU_GA_MSI_MINGW_DLL_PATH} $, WIXL $@) Please use $(...) instead of ${...} for consistency. + clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h rm -f qemu-options.def + rm -f *.msi find . \( -name '*.l[oa]' -o -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} + rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ rm -f fsdev/*.pod diff --git a/configure b/configure index 6969f6f..0aa79bb 100755 --- a/configure +++ b/configure @@ -316,6 +316,7 @@ snappy= bzip2= guest_agent= guest_agent_with_vss=no +guest_msi= vss_win32_sdk= win_sdk=no want_tools=yes @@ -1069,6 +1070,10 @@ for opt do ;; --disable-guest-agent) guest_agent=no ;; + --enable-guest-msi) guest_msi=yes + ;; + --disable-guest-msi) guest_msi=no + ;; --with-vss-sdk) vss_win32_sdk= ;; --with-vss-sdk=*) vss_win32_sdk=$optarg @@ -1407,6 +1412,8 @@ Advanced options (experts only): --enable-quorum enable quorum block filter support --disable-numa disable libnuma support --enable-numaenable libnuma support + --enable-guest-msi enable building guest agent Windows MSI installation package + --disable-guest-msi disable building guest agent Windows MSI installation package --enable-guest-agent-msi? Also, please keep the guest agent options together. NOTE: The object files are built at the place where configure is launched EOF @@ -3832,6 +3839,54 @@ if test $mingw32 = yes -a $guest_agent != no -a $guest_agent_with_vss fi ## +# Guest agent Window MSI package + +if test $guest_msi = yes; then Since building the MSI is on-demand anyway (make msi), we might as well treat it similar to other configure options: - --enable-foo causes an error if the feature is not available - --disable-foo forcibly disable the feature - the default is to configure the feature if available, otherwise disable it This would be something like this: if test $guest_agent != yes; then if test $guest_msi = yes; then error_exit MSI guest agent package requires guest agent enabled fi guest_msi=no elif test $mingw32 != yes; then if test $guest_msi = yes; then error_exit MSI guest agent package is available only for MinGW Windows cross-compilation fi guest_msi=no elif test ! has_wixl; then if test $guest_msi = yes; then error_exit wixl not found, required for building MSI guest agent package fi guest_msi=no fi if test $guest_msi != no; then ... fi + + + if test $guest_agent_with_vss = yes; then +QEMU_GA_MSI_WITH_VSS=-D InstallVss + fi + + if test $QEMU_GA_MANUFACTURER = ; then +QEMU_GA_MANUFACTURER=QEMU + fi + + if test $QEMU_GA_DISTRO = ; then +QEMU_GA_DISTRO=Linux + fi + + if test $QEMU_GA_VERSION = ; then + QEMU_GA_VERSION=`cat $source_path/VERSION` + fi + + case $cpu in + x86_64) +QEMU_GA_MSI_ARCH=-a x64 -D Arch=64 +;; + i386) +QEMU_GA_MSI_ARCH=-D Arch=32 +;; + *) +error_exit CPU $cpu not supported for building installation package +;; + esac + +fi + +## ## # check if we have fdatasync @@ -4500,6 +4555,14 @@ if test $mingw32 = yes ; then echo CONFIG_QGA_VSS=y $config_host_mak echo WIN_SDK=\$win_sdk\ $config_host_mak fi + if test $guest_msi = yes; then Similarly, != no here. +echo QEMU_GA_MSI_MINGW_DLL_PATH=-D Mingw_dlls=`$pkg_config --variable=prefix glib-2.0`/bin $config_host_mak Why not set up the variable above? Paolo +echo QEMU_GA_MSI_WITH_VSS=${QEMU_GA_MSI_WITH_VSS} $config_host_mak +echo QEMU_GA_MSI_ARCH=${QEMU_GA_MSI_ARCH} $config_host_mak +echo QEMU_GA_MANUFACTURER=${QEMU_GA_MANUFACTURER} $config_host_mak +echo QEMU_GA_DISTRO=${QEMU_GA_DISTRO} $config_host_mak +echo QEMU_GA_VERSION=${QEMU_GA_VERSION} $config_host_mak + fi else echo CONFIG_POSIX=y $config_host_mak fi
Re: [Qemu-devel] [PATCH 3/4] qemu-ga: Introduce Windows MSI script
On 26/04/2015 09:04, Yossi Hindin wrote: + ?ifndef env.QEMU_GA_VERSION ? +?error Environemtn variable QEMU_GA_VERSION undefined? + ?endif? + Environment Ironically, msitools was started exactly to build an installer with qemu-ga (the idea was to do it with raw tables, that was a few months before Marc-Andre wrote wixl). It only took 2.5 years... Paolo
Re: [Qemu-devel] [PATCH 0/5] Extend TPM support with a QEMU-external TPM
On Wed, 29 Apr 2015 12:42:21 -0400 Stefan Berger stef...@linux.vnet.ibm.com wrote: On 04/29/2015 05:06 AM, Igor Mammedov wrote: On Wed, 22 Apr 2015 14:18:55 -0400 Stefan Berger stef...@linux.vnet.ibm.com wrote: On 04/22/2015 03:00 AM, Igor Mammedov wrote: On Thu, 16 Apr 2015 10:05:35 -0400 Stefan Berger stef...@linux.vnet.ibm.com wrote: On 04/16/2015 09:35 AM, Igor Mammedov wrote: On Wed, 15 Apr 2015 18:38:43 -0400 [...] Is it possible to use MMIO region instead of allocating tpm_ppi_anchor and tpm_ppi in BIOS memory? MMIO region of what? Of the TIS? The TIS doesn't have memory locations 'just to keep bytes' and they would be cleared upon machine reset / reboot. The purpose of the PPI interface is to leave an opcode for the BIOS to act upon after a reset. So we have to write it into memory that doesn't get cleared upon reboot. Also, the BIOS leaves a result in memory so we can read the result code in the OS via sysfs entry. it doesn't matter where opcodes are stored though, they could be stored on QEMU's TPM device (i.e. inside TPM owned MMIO region). That way QEMU will know in advance where opcodes are stored and build ACPI tables with correct address without any need for scanning memory. It only matters that these opcodes survive a machine reboot. Some devices get reset on the way and the choices of suitable NVRAM are limited. Ok, so we could extend the TPM TIS model with a buffer that can hold these opcodes. At the moment I think I need 3 bytes. Future specifications may require more. We can make room for this in the TIS from offset 0xf90-0xfff where we can put vendor specific extensions. Maybe we just stick it into locality 4 - 0xfed4 4f90 to 0xfed4 4fff and don't reset that memory area ? yep So we can do it this way ... The only thing that speaks against this is that this would not work if SeaBIOS was not running on QEMU but on bare metal -- if that was to be a concern at all. The current solution tried to address this as well, but it would require coreboot support and the last time I tested this on my Chromebook it looks like an anchor created but SeaBIOS is not found after a reboot anymore, so it would require some form of cooperation from coreboot to enable this. So if we ditch this, we can go with a buffer in the MMIO. Coreboot would probably require different ACPI buffer read/write functions, the rest could stay the same. Yes, understood. Although it's just another workaround around split brain problem where QEMU owned ACPI tables have to know about guest (BIOS) provided address. I had previously tried using NVRAM of the TPM to leave that opcode (and result) , but this doesn't work well due to protection restrictions of the TPM's NVRAM locations and using the Linux TSS for example non-root users could then write an opcode into the NVRAM of the TPM (there are TPM commands to write to the TPM's NVRAM locations and tpm-tools has tools to write to these locations) that the machine then ends up acting upon without the admin of the machine wanting that. So, that's not a choice, either. That would simplify BIOS part a bit and significantly simplify ACPI code as most of it is dealing with figuring out address of tpm_ppi. Wished it would, but I don't see a way to make it easier. Since ACPI implementation for handling opcodes doesn't interface/depend on TPM device and interfaces only with BIOS it should also be BIOS owned. Cleaner way could be installing an additional BIOS generated table (with correct ADDR) to QEMU provided ACPI tables set. Would that be a custom table? Do we need changes for this in the OS or can that table be found via ACPI? It would be just additional SSDT, no OS changes are required. what you'll need to do is to extend QEMU supplied RSDT to include pointer to additional SSDT. I'm not sure where ACPI tables come from in case of coreboot though. That also would be reusable with coreboot since you will have shared ACPI impl. in SeaBIOS without need to duplicate it in QEMU/coreboot. Can you sketch the ACPI code necessary to convey the SeaBIOS / coreboot allocated memory address ? How do we write the SeaBIOS allocated address into the ACPI code? grep for acpi_pci64_start in SeaBIOS code, it should give rough idea how to do it. [...] ... or we can do it this way. Which way now ? My preference is the TIS path, because it seems easier. Now what I am seeing in SeaBIOS is that another SSDT is being built. Would this then be an additional SSDT or would it replace the TPM's SSDT that we're now supplying from QEMU. perhaps an additional SSDT that has only Seabios specific AML which doesn't interact with TIS device. 2 choices now -- which one to take? I'd try installing extra SSDT table first as a cleanest way (seabios only) and if it fails fallback to TIS path. Stefan
Re: [Qemu-devel] [PATCH v5 13/20] hw/acpi/aml-build: Add ToUUID macro
On Wed, 29 Apr 2015 21:41:39 +0800 Shannon Zhao shannon.z...@linaro.org wrote: On 2015/4/28 17:48, Shannon Zhao wrote: On 2015/4/28 17:35, Igor Mammedov wrote: On Tue, 28 Apr 2015 16:52:19 +0800 Shannon Zhao zhaoshengl...@huawei.com wrote: On 2015/4/28 16:15, Igor Mammedov wrote: btw: whole thing might be simpler if an intermediate conversion is avoided, just pack buffer as in spec byte by byte: /* format: aabbccdd-eeff-gghh-iijj-kkllmmnnoopp */ assert(strlen(uuid) == ...); build_append_byte(var-buf, HEX2BYTE(uuid[3]); /* dd */ use build_append_byte(var-buf, HEX2BYTE(uuid + 7); ? build_append_byte(var-buf, HEX2BYTE(uuid[2]); /* cc */ use build_append_byte(var-buf, HEX2BYTE(uuid + 5); ? if you mean hyphens /-/ then they are not encoded, but you surely can add checks for them to make sure that UUID format is as expected. I mean uuid[3] points to b not dd. Maybe use following way: static uint8_t Hex2Byte(char *src) or even better: Hex2Byte(char *src, byte_idx) and do pointer arithmetic inside [...] build_append_byte(var-buf, Hex2Byte(uuid + (3 * 2))); /* dd */ build_append_byte(var-buf, Hex2Byte(uuid, 3)); /* dd - at offset 00 */ build_append_byte(var-buf, Hex2Byte(uuid, 2)); /* cc - at offset 01 */ ... Yes, it's better to first four bytes. But there are hyphens /-/, for offset 04, 05 and etc it doesn't work. We can't use following expression: build_append_byte(var-buf, Hex2Byte(uuid, 5)); /* ff - at offset 04 */ build_append_byte(var-buf, Hex2Byte(uuid, 4)); /* ee - at offset 05 */ ... So about the implementation of this macro, I think I'd like to use following approach. This lets Hex2Byte do what it should only do and still has a clear look of UUID. What do you think about? static uint8_t Hex2Byte(char *src) { int hi = Hex2Digit(*src++); int lo = Hex2Digit(*src); if ((hi 0) || (lo 0)) return -1; just make Hex2Digit() assert on wrong input. return (hi 4) | lo; } g_assert((strlen(uuid) == 36) (uuid[8] == '-') (uuid[13] == '-') (uuid[18] == '-') (uuid[23] == '-')); build_append_byte(var-buf, Hex2Byte(uuid + (3 * 2))); /* dd */ ^ I'd make it one number, instead of forcing reader to do math every time he/she looks at this code. build_append_byte(var-buf, Hex2Byte(uuid + (2 * 2))); /* cc */ build_append_byte(var-buf, Hex2Byte(uuid + (1 * 2))); /* bb */ build_append_byte(var-buf, Hex2Byte(uuid + (0 * 2))); /* aa */ build_append_byte(var-buf, Hex2Byte(uuid + (5 * 2 + 1))); /* ff */ build_append_byte(var-buf, Hex2Byte(uuid + (4 * 2 + 1))); /* ee */ build_append_byte(var-buf, Hex2Byte(uuid + (7 * 2 + 2))); /* hh */ build_append_byte(var-buf, Hex2Byte(uuid + (6 * 2 + 2))); /* gg */ build_append_byte(var-buf, Hex2Byte(uuid + (8 * 2 + 3))); /* ii */ build_append_byte(var-buf, Hex2Byte(uuid + (9 * 2 + 3))); /* jj */ build_append_byte(var-buf, Hex2Byte(uuid + (10 * 2 + 4))); /* kk */ build_append_byte(var-buf, Hex2Byte(uuid + (11 * 2 + 4))); /* ll */ build_append_byte(var-buf, Hex2Byte(uuid + (12 * 2 + 4))); /* mm */ build_append_byte(var-buf, Hex2Byte(uuid + (13 * 2 + 4))); /* nn */ build_append_byte(var-buf, Hex2Byte(uuid + (14 * 2 + 4))); /* oo */ build_append_byte(var-buf, Hex2Byte(uuid + (15 * 2 + 4))); /* pp */
Re: [Qemu-devel] [PATCH v1 1/1] hw/ptimer: Do not artificially limit timers when using icount
On 04/05/2015 05:18, Edgar E. Iglesias wrote: From: Edgar E. Iglesias edgar.igles...@xilinx.com Signed-off-by: Edgar E. Iglesias edgar.igles...@xilinx.com --- hw/core/ptimer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 2abad1f..8437bd6 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -189,7 +189,7 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) * on the current generation of host machines. */ -if (limit * s-period 1 s-period) { +if (!use_icount limit * s-period 1 s-period) { limit = 1 / s-period; } Reviewed-by: Paolo Bonzini pbonz...@redhat.com
Re: [Qemu-devel] [RFC PATCH 05/15] spapr_pci: add PHB unrealize
On 01/05/2015 03:18, Michael Roth wrote: Sorry, I mixed up memory regions with memory region alias. Memory region aliases do a memory_region_ref() on the original MR, similar to memory_region_add_subregion(), so that's what ends up creating the reference to the owner/PHB. So I think I do need to object_unparent() the 2 MR aliases in realize (otherwise the PHB doesn't get finalized), but everything else can get moved to instance_finalize() as you suggested and that seems to do the trick. Yes, unparenting the aliases in unrealize is okay and in fact may be required to avoid a leak. Patching docs/memory.txt to point it out would be great. :) Paolo
Re: [Qemu-devel] [PATCH v5 13/20] hw/acpi/aml-build: Add ToUUID macro
On 2015/5/4 17:22, Igor Mammedov wrote: On Wed, 29 Apr 2015 21:41:39 +0800 Shannon Zhao shannon.z...@linaro.org wrote: On 2015/4/28 17:48, Shannon Zhao wrote: On 2015/4/28 17:35, Igor Mammedov wrote: On Tue, 28 Apr 2015 16:52:19 +0800 Shannon Zhao zhaoshengl...@huawei.com wrote: On 2015/4/28 16:15, Igor Mammedov wrote: btw: whole thing might be simpler if an intermediate conversion is avoided, just pack buffer as in spec byte by byte: /* format: aabbccdd-eeff-gghh-iijj-kkllmmnnoopp */ assert(strlen(uuid) == ...); build_append_byte(var-buf, HEX2BYTE(uuid[3]); /* dd */ use build_append_byte(var-buf, HEX2BYTE(uuid + 7); ? build_append_byte(var-buf, HEX2BYTE(uuid[2]); /* cc */ use build_append_byte(var-buf, HEX2BYTE(uuid + 5); ? if you mean hyphens /-/ then they are not encoded, but you surely can add checks for them to make sure that UUID format is as expected. I mean uuid[3] points to b not dd. Maybe use following way: static uint8_t Hex2Byte(char *src) or even better: Hex2Byte(char *src, byte_idx) and do pointer arithmetic inside [...] build_append_byte(var-buf, Hex2Byte(uuid + (3 * 2))); /* dd */ build_append_byte(var-buf, Hex2Byte(uuid, 3)); /* dd - at offset 00 */ build_append_byte(var-buf, Hex2Byte(uuid, 2)); /* cc - at offset 01 */ ... Yes, it's better to first four bytes. But there are hyphens /-/, for offset 04, 05 and etc it doesn't work. We can't use following expression: build_append_byte(var-buf, Hex2Byte(uuid, 5)); /* ff - at offset 04 */ build_append_byte(var-buf, Hex2Byte(uuid, 4)); /* ee - at offset 05 */ ... So about the implementation of this macro, I think I'd like to use following approach. This lets Hex2Byte do what it should only do and still has a clear look of UUID. What do you think about? static uint8_t Hex2Byte(char *src) { int hi = Hex2Digit(*src++); int lo = Hex2Digit(*src); if ((hi 0) || (lo 0)) return -1; just make Hex2Digit() assert on wrong input. Ok. return (hi 4) | lo; } g_assert((strlen(uuid) == 36) (uuid[8] == '-') (uuid[13] == '-') (uuid[18] == '-') (uuid[23] == '-')); build_append_byte(var-buf, Hex2Byte(uuid + (3 * 2))); /* dd */ ^ I'd make it one number, instead of forcing reader to do math every time he/she looks at this code. Ok, will do this. And about other patches in this series could you offer your comments? Thanks, Shannon build_append_byte(var-buf, Hex2Byte(uuid + (2 * 2))); /* cc */ build_append_byte(var-buf, Hex2Byte(uuid + (1 * 2))); /* bb */ build_append_byte(var-buf, Hex2Byte(uuid + (0 * 2))); /* aa */ build_append_byte(var-buf, Hex2Byte(uuid + (5 * 2 + 1))); /* ff */ build_append_byte(var-buf, Hex2Byte(uuid + (4 * 2 + 1))); /* ee */ build_append_byte(var-buf, Hex2Byte(uuid + (7 * 2 + 2))); /* hh */ build_append_byte(var-buf, Hex2Byte(uuid + (6 * 2 + 2))); /* gg */ build_append_byte(var-buf, Hex2Byte(uuid + (8 * 2 + 3))); /* ii */ build_append_byte(var-buf, Hex2Byte(uuid + (9 * 2 + 3))); /* jj */ build_append_byte(var-buf, Hex2Byte(uuid + (10 * 2 + 4))); /* kk */ build_append_byte(var-buf, Hex2Byte(uuid + (11 * 2 + 4))); /* ll */ build_append_byte(var-buf, Hex2Byte(uuid + (12 * 2 + 4))); /* mm */ build_append_byte(var-buf, Hex2Byte(uuid + (13 * 2 + 4))); /* nn */ build_append_byte(var-buf, Hex2Byte(uuid + (14 * 2 + 4))); /* oo */ build_append_byte(var-buf, Hex2Byte(uuid + (15 * 2 + 4))); /* pp */
Re: [Qemu-devel] [PATCH 2/2] spice-char: notify the server when chardev is writable
Hi Gerd, On (Mon) 27 Oct 2014 [12:57:57], Gerd Hoffmann wrote: On Mo, 2014-10-27 at 12:45 +0100, Marc-André Lureau wrote: Hi On Mon, Oct 27, 2014 at 9:08 AM, Gerd Hoffmann kra...@redhat.com wrote: +static void spice_chr_accept_input(struct CharDriverState *chr) +{ +SpiceCharDriver *s = chr-opaque; + +spice_server_char_device_wakeup(s-sin); Does this build on older spice versions? I'd suspect this needs #if SPICE_SERVER_VERSION too ... There is already a spice_server_char_device_wakeup() call there. On older servers, this additional call will trigger just a read try. With the proposed patch in Spice server, it will do read write try (I didn't see the need to create a new function to do only read or write, both should be fine) Ok then. Added to spice queue. Fails to build, but that looks like just being the dependency on amits patch and should go away once that one is upstream. The dependency patch is now in tree, please pick this series up. Thanks, Amit
Re: [Qemu-devel] [RFC PATCH 02/15] qdev: store DeviceState's canonical path to use when unparenting
On 02/05/2015 00:54, Michael Roth wrote: What about unparenting children devices in the device's unrealize callback? It sucks that you have to do it manually, but using stale canonical paths isn't the nicest thing either. That does seems to do the trick. It felt wrong when I first looked at it because in some cases the children attach themselves to the parent without making making the parent aware, Can you point to an example? The parent owns its property namespace, so it would be wrong for a child to attach itself unbeknownst to the parent. There are a couple cases where an object adds a property to another object, e.g. the rtc-time property of /machine, but in that case the property is a well-known name whose setting is outsourced by /machine to the device. Paolo
Re: [Qemu-devel] [PATCH v2 3/3] TPM2 ACPI table support
On Thu, 30 Apr 2015 22:44:08 -0400 Stefan Berger stef...@linux.vnet.ibm.com wrote: Add a TPM2 ACPI table if a TPM 2 is used in the backend. Rename tpm_find() to tpm_get_version() and have this function return the version of the TPM found, TPMVersion_Unspec if no TPM is found. Use the version number to build version specific ACPI tables. Signed-off-by: Stefan Berger stef...@linux.vnet.ibm.com --- hw/i386/acpi-build.c | 34 ++ hw/i386/acpi-defs.h | 18 ++ hw/tpm/tpm_tis.c | 11 +++ include/hw/acpi/tpm.h | 5 + include/sysemu/tpm.h | 11 +-- 5 files changed, 73 insertions(+), 6 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index e761005..fa64646 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -42,6 +42,7 @@ #include hw/acpi/memory_hotplug.h #include sysemu/tpm.h #include hw/acpi/tpm.h +#include sysemu/tpm_backend.h /* Supported chipsets: */ #include hw/acpi/piix4.h @@ -111,7 +112,7 @@ typedef struct AcpiPmInfo { typedef struct AcpiMiscInfo { bool has_hpet; -bool has_tpm; +TPMVersion tpm_version; const unsigned char *dsdt_code; unsigned dsdt_size; uint16_t pvpanic_port; @@ -239,7 +240,7 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) static void acpi_get_misc_info(AcpiMiscInfo *info) { info-has_hpet = hpet_find(); -info-has_tpm = tpm_find(); +info-tpm_version = tpm_get_version(); info-pvpanic_port = pvpanic_port(); info-applesmc_io_base = applesmc_port(); } @@ -1065,6 +1066,21 @@ build_tpm_ssdt(GArray *table_data, GArray *linker) memcpy(tpm_ptr, ssdt_tpm_aml, sizeof(ssdt_tpm_aml)); } +static void +build_tpm2(GArray *table_data, GArray *linker) +{ +Acpi20TPM2 *tpm2_ptr; + +tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr); + +tpm2_ptr-platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT); +tpm2_ptr-control_area_address = cpu_to_le64(0); +tpm2_ptr-start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); + +build_header(linker, table_data, + (void *)tpm2_ptr, TPM2, sizeof(*tpm2_ptr), 4); +} + typedef enum { MEM_AFFINITY_NOFLAGS = 0, MEM_AFFINITY_ENABLED = (1 0), @@ -1428,12 +1444,22 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_hpet(tables_blob, tables-linker); } -if (misc.has_tpm) { +if (misc.tpm_version != TPM_VERSION_UNSPEC) { acpi_add_table(table_offsets, tables_blob); build_tpm_tcpa(tables_blob, tables-linker, tables-tcpalog); acpi_add_table(table_offsets, tables_blob); -build_tpm_ssdt(tables_blob, tables-linker); +switch (misc.tpm_version) { +case TPM_VERSION_1_2: +build_tpm_ssdt(tables_blob, tables-linker); +break; +case TPM_VERSION_2_0: +build_tpm2(tables_blob, tables-linker); +break; +case TPM_VERSION_UNSPEC: +/* not possible */ +break; s/case TPM_VERSION_UNSPEC/default: +assert()/ +} } if (guest_info-numa_nodes) { acpi_add_table(table_offsets, tables_blob); diff --git a/hw/i386/acpi-defs.h b/hw/i386/acpi-defs.h index c4468f8..79ee9b1 100644 --- a/hw/i386/acpi-defs.h +++ b/hw/i386/acpi-defs.h @@ -316,6 +316,9 @@ typedef struct AcpiTableMcfg AcpiTableMcfg; /* * TCPA Description Table + * + * Following Level 00, Rev 00.37 of specs: + * http://www.trustedcomputinggroup.org/resources/tcg_acpi_specification */ struct Acpi20Tcpa { ACPI_TABLE_HEADER_DEF/* ACPI common table header */ @@ -325,6 +328,21 @@ struct Acpi20Tcpa { } QEMU_PACKED; typedef struct Acpi20Tcpa Acpi20Tcpa; +/* + * TPM2 + * + * Following Level 00, Rev 00.37 of specs: + * http://www.trustedcomputinggroup.org/resources/tcg_acpi_specification + */ +struct Acpi20TPM2 { +ACPI_TABLE_HEADER_DEF +uint16_t platform_class; +uint16_t reserved; +uint64_t control_area_address; +uint32_t start_method; +} QEMU_PACKED; +typedef struct Acpi20TPM2 Acpi20TPM2; + /* DMAR - DMA Remapping table r2.2 */ struct AcpiTableDmar { ACPI_TABLE_HEADER_DEF diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 636e6d3..be7e61f 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -32,6 +32,7 @@ #include tpm_tis.h #include qemu-common.h #include qemu/main-loop.h +#include sysemu/tpm_backend.h #define DEBUG_TIS 0 @@ -963,6 +964,16 @@ static int tpm_tis_do_startup_tpm(TPMState *s) } /* + * Get the TPMVersion of the backend device being used + */ +TPMVersion tpm_tis_get_tpm_version(Object *obj) +{ +TPMState *s = TPM(obj); + +return tpm_backend_get_tpm_version(s-be_driver); +} + +/* * This function is called when the
Re: [Qemu-devel] [PATCH] cpu: Register QOM links at /machine/cpus/index
On Thu, 30 Apr 2015 16:19:07 -0300 Eduardo Habkost ehabk...@redhat.com wrote: This will provide a predictable path for the CPU objects, and a more powerful alternative for the query-cpus QMP command, as now every QOM property on CPU objects can be easily queried. provided the way cpu_index is generated, path won't be predictable/stable with CPU unplug. I'd rather use DEVICE-id instead of cpu_index. Signed-off-by: Eduardo Habkost ehabk...@redhat.com --- Note that this doesn't replace any future topology enumeration mechanisms we may choose to implement. It just replaces the existing topology-unaware VCPU enumeration mechanism that is query-cpus. Reference to previous discussion: Date: Thu, 23 Apr 2015 10:17:36 -0300 From: Eduardo Habkost ehabk...@redhat.com Subject: Re: [Qemu-devel] cpu modelling and hotplug (was: [PATCH RFC 0/4] target-i386: PC socket/core/thread modeling, part 1) Message-ID: 20150423131736.ga17...@thinpad.lan.raisama.net --- exec.c| 16 include/qom/cpu.h | 3 +++ 2 files changed, 19 insertions(+) diff --git a/exec.c b/exec.c index ae37b98..8bdfa65 100644 --- a/exec.c +++ b/exec.c @@ -519,6 +519,20 @@ void tcg_cpu_address_space_init(CPUState *cpu, AddressSpace *as) } #endif +static void cpu_add_qom_link(CPUState *cpu) +{ +#if !defined(CONFIG_USER_ONLY) +Object *cobj = OBJECT(cpu); +Object *cpu_container = container_get(OBJECT(current_machine), /cpus); +char *path = g_strdup_printf(%d, cpu-cpu_index); + +cpu-self = cobj; +object_property_add_link(cpu_container, path, TYPE_CPU, cpu-self, NULL, + OBJ_PROP_LINK_UNREF_ON_RELEASE, error_abort); +g_free(path); +#endif +} + void cpu_exec_init(CPUArchState *env) { CPUState *cpu = ENV_GET_CPU(env); @@ -558,6 +572,8 @@ void cpu_exec_init(CPUArchState *env) if (cc-vmsd != NULL) { vmstate_register(NULL, cpu_index, cc-vmsd, cpu); } + +cpu_add_qom_link(cpu); } #if defined(CONFIG_USER_ONLY) diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 39f0f19..c253420 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -246,6 +246,9 @@ struct CPUState { DeviceState parent_obj; /* public */ +/* Needed for the /machine/cpus/index link */ +Object *self; + int nr_cores; int nr_threads; int numa_node;
Re: [Qemu-devel] [PATCH 2/2] balloon: add a feature bit to let Guest OS deflate balloon on oom
On 01/04/15 13:18, Michael S. Tsirkin wrote: On Wed, Apr 01, 2015 at 12:51:42PM +0300, James Bottomley wrote: On Wed, 2015-04-01 at 11:50 +0200, Michael S. Tsirkin wrote: On Wed, Apr 01, 2015 at 12:44:28PM +0300, James Bottomley wrote: On Fri, 2015-02-27 at 09:57 +0300, Denis V. Lunev wrote: Excessive virtio_balloon inflation can cause invocation of OOM-killer, when Linux is under severe memory pressure. Various mechanisms are responsible for correct virtio_balloon memory management. Nevertheless it is often the case that these control tools does not have enough time to react on fast changing memory load. As a result OS runs out of memory and invokes OOM-killer. The balancing of memory by use of the virtio balloon should not cause the termination of processes while there are pages in the balloon. Now there is no way for virtio balloon driver to free memory at the last moment before some process get killed by OOM-killer. This does not provide a security breach as balloon itself is running inside Guest OS and is working in the cooperation with the host. Thus some improvements from Guest side should be considered as normal. To solve the problem, introduce a virtio_balloon callback which is expected to be called from the oom notifier call chain in out_of_memory() function. If virtio balloon could release some memory, it will make the system return and retry the allocation that forced the out of memory killer to run. This behavior should be enabled if and only if appropriate feature bit is set on the device. It is off by default. This functionality was recently merged into vanilla Linux. commit 5a10b7dbf904bfe01bb9fcc6298f7df09eed77d5 Author: Raushaniya Maksudova rmaksud...@parallels.com Date: Mon Nov 10 09:36:29 2014 +1030 This patch adds respective control bits into QEMU. It introduces deflate-on-oom option for balloon device which does the trick. What's the status on this, please? It's been over a month since this was posted with no further review feedback, so I think it's ready. Getting this into qemu is blocking our next step which would be adding the feature bit to the virtio spec. James This was posted after soft feature freeze for 2.3, so it'll have to go into 2.4. I don't see why would this block your work on the spec: you should make progress on this meanwhile. I can do that ... I just thought the spec was trailing edge, so I was waiting to have the patch accepted, which confirms the implementation. I didn't want to write it into the spec and have the actual implementation changed by review later. James It's up to you really, I would just like to point out two things: - spec process is a long one, assuming we accept a spec change, we go though a public review period, multiple votes etc. About half a year to release a spec revision with new features. So time enough to make minor changes. - oasis process works like this (roughly): spec is written spec goes through a public review process community standard is published 3 implementations are reported spec becomes an oasis standard so implementations aren't required at early stages 2.3 is done, 2.4 window is opened The patch is applicable for both git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git and vanilla qemu. How can we proceed?
Re: [Qemu-devel] [RFC 5/5] arm: Simplify cycle counter
On 01/05/2015 00:02, Peter Maydell wrote: On 30 April 2015 at 22:33, Christopher Covington christopher.coving...@linaro.org wrote: On Apr 30, 2015 2:28 PM, Peter Maydell peter.mayd...@linaro.org wrote: Are you really really sure the _raw function is the correct one? Nowhere else in the codebase calls it except the other wrappers in cpu.c which provide a sane view of the instruction count... (I suspect cpu_get_icount_raw() should really be static.) I thought it wasn't being used because it was new, having been introduced by Pavel Dovgalyuk's determinism patches. When you talk about sanity, what would this patch make insane? The right function is cpu_get_ticks(). This one works without icount as well. At the top there is: if (use_icount) { return cpu_get_icount(); } and perhaps it would be correct to use cpu_get_icount_raw() if you do not want the cycle counter to increase in halted state. But at least x86 wants it to increase. Paolo The instructions per second and cycles per second that would result? If so, what if seconds/timer ticks were changed in the same patch to be derived from the instruction count. All of this could potentially only apply with -icount specified. I don't really know for certain how the code here works, but it makes me very dubious when I see a function that is being used literally nowhere else in any other target CPU, and where every other code path to it goes via taking a lock. Paolo: can you suggest what the right function to call to implement a cycle counter is? thanks -- PMM
Re: [Qemu-devel] [PATCH v5 06/20] hw/arm/virt-acpi-build: Generation of DSDT table for virt devices
On Wed, 15 Apr 2015 21:24:55 +0800 Shannon Zhao zhaoshengl...@huawei.com wrote: From: Shannon Zhao shannon.z...@linaro.org DSDT consists of the usual common table header plus a definition block in AML encoding which describes all devices in the platform. After initializing DSDT with header information the namespace is created which is followed by the device encodings. The devices are described using the Resource Template for the 32-Bit Fixed Memory Range and the Extended Interrupt Descriptors. Signed-off-by: Shannon Zhao zhaoshengl...@huawei.com Signed-off-by: Shannon Zhao shannon.z...@linaro.org --- hw/arm/virt-acpi-build.c | 128 +++ 1 file changed, 128 insertions(+) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index c5a3cf9..d044880 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -50,6 +50,130 @@ #include qom/qom-qobject.h #include exec/ram_addr.h +static void acpi_dsdt_add_cpus(Aml *scope, int max_cpus) +{ +uint16_t i; + +for (i = 0; i max_cpus; i++) { +Aml *dev = aml_device(C%03x, i); +aml_append(dev, aml_name_decl(_HID, aml_string(ACPI0007))); +aml_append(dev, aml_name_decl(_UID, aml_int(i))); +Aml *crs = aml_resource_template(); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} +} Is maxcpus a correct here? Usually maxcpus includes non present CPUs as well but there is no STA method that tells whether it's present or not. + +static void acpi_dsdt_add_uart(Aml *scope, const MemMap *uart_memmap, + const int *uart_irq) +{ +Aml *dev = aml_device(COM0); +aml_append(dev, aml_name_decl(_HID, aml_string(ARMH0011))); +aml_append(dev, aml_name_decl(_UID, aml_int(0))); + +Aml *crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(uart_memmap-addr, + uart_memmap-size, aml_ReadWrite)); +aml_append(crs, + aml_interrupt(aml_consumer, aml_level, aml_active_high, + aml_exclusive, aml_not_wake_capable, *uart_irq + 32)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} + +static void acpi_dsdt_add_rtc(Aml *scope, const MemMap *rtc_memmap, + const int *rtc_irq) +{ +Aml *dev = aml_device(RTC0); +aml_append(dev, aml_name_decl(_HID, aml_string(LNRO0013))); +aml_append(dev, aml_name_decl(_UID, aml_int(0))); + +Aml *crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(rtc_memmap-addr, + rtc_memmap-size, aml_ReadWrite)); +aml_append(crs, + aml_interrupt(aml_consumer, aml_level, aml_active_high, + aml_exclusive, aml_not_wake_capable, *rtc_irq + 32)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} + +static void acpi_dsdt_add_flash(Aml *scope, const MemMap *flash_memmap) +{ +Aml *dev, *crs; +hwaddr base = flash_memmap-addr; +hwaddr size = flash_memmap-size; + +dev = aml_device(FLS0); +aml_append(dev, aml_name_decl(_HID, aml_string(LNRO0015))); +aml_append(dev, aml_name_decl(_UID, aml_int(0))); + +crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(base, size, aml_ReadWrite)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); + +dev = aml_device(FLS1); +aml_append(dev, aml_name_decl(_HID, aml_string(LNRO0015))); +aml_append(dev, aml_name_decl(_UID, aml_int(1))); +crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(base + size, size, aml_ReadWrite)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} + +static void acpi_dsdt_add_virtio(Aml *scope, const MemMap *virtio_mmio_memmap, + const int *mmio_irq, int num) +{ +hwaddr base = virtio_mmio_memmap-addr; +hwaddr size = virtio_mmio_memmap-size; +int irq = *mmio_irq + 32; +int i; + +for (i = 0; i num; i++) { +Aml *dev = aml_device(VR%02u, i); +aml_append(dev, aml_name_decl(_HID, aml_string(LNRO0005))); +aml_append(dev, aml_name_decl(_UID, aml_int(i))); + +Aml *crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(base, size, aml_ReadWrite)); +aml_append(crs, + aml_interrupt(aml_consumer, aml_level, aml_active_high, + aml_exclusive, aml_not_wake_capable, irq + i)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +base += size; +} +} + +/* DSDT */ +static void +build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) +{ +Aml *scope, *dsdt; +AcpiDsdtInfo *info =
Re: [Qemu-devel] [PATCH] cpu: Register QOM links at /machine/cpus/index
On 04/05/2015 11:47, Igor Mammedov wrote: On Thu, 30 Apr 2015 16:19:07 -0300 Eduardo Habkost ehabk...@redhat.com wrote: This will provide a predictable path for the CPU objects, and a more powerful alternative for the query-cpus QMP command, as now every QOM property on CPU objects can be easily queried. provided the way cpu_index is generated, path won't be predictable/stable with CPU unplug. I'd rather use DEVICE-id instead of cpu_index. Can we use the APIC id then? Perhaps wrapped with a CPUState-level method get_stable_processor_id()? Paolo
[Qemu-devel] .gitignore contains .c and .h ?
Hello. The .gitignore in the master branch contains the following lines : /qapi-types.[ch] /qapi-visit.[ch] /qapi-event.[ch] Why is it so ? Are they generated automatically each time I compile the project ? I am modifying qapi-types.h and qapi-types.c , am I doing wrong ? regards, Guillaume
Re: [Qemu-devel] [PATCH v5 08/20] hw/arm/virt-acpi-build: Generate MADT table
On Wed, 15 Apr 2015 21:24:57 +0800 Shannon Zhao zhaoshengl...@huawei.com wrote: From: Shannon Zhao shannon.z...@linaro.org MADT describes GIC enabled ARM platforms. The GICC and GICD subtables are used to define the GIC regions. Signed-off-by: Shannon Zhao zhaoshengl...@huawei.com Signed-off-by: Shannon Zhao shannon.z...@linaro.org Reviewed-by: Alex Bennée alex.ben...@linaro.org --- hw/arm/virt-acpi-build.c | 61 include/hw/acpi/acpi-defs.h | 38 - include/hw/arm/virt-acpi-build.h | 2 ++ 3 files changed, 100 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index c72a9c8..94cced0 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -50,6 +50,20 @@ #include qom/qom-qobject.h #include exec/ram_addr.h +typedef struct VirtAcpiCpuInfo { +DECLARE_BITMAP(found_cpus, VIRT_ACPI_CPU_ID_LIMIT); +} VirtAcpiCpuInfo; + +static void virt_acpi_get_cpu_info(VirtAcpiCpuInfo *cpuinfo) +{ +CPUState *cpu; + +memset(cpuinfo-found_cpus, 0, sizeof cpuinfo-found_cpus); +CPU_FOREACH(cpu) { +set_bit(cpu-cpu_index, cpuinfo-found_cpus); +} +} + static void acpi_dsdt_add_cpus(Aml *scope, int max_cpus) { uint16_t i; @@ -146,6 +160,47 @@ static void acpi_dsdt_add_virtio(Aml *scope, const MemMap *virtio_mmio_memmap, } } +/* MADT */ +static void +build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info, + VirtAcpiCpuInfo *cpuinfo) +{ +int madt_start = table_data-len; +const struct AcpiMadtInfo *info = guest_info-madt_info; +AcpiMultipleApicTable *madt; +AcpiMadtGenericDistributor *gicd; +int i; + +madt = acpi_data_push(table_data, sizeof *madt); +madt-local_apic_address = info-gic_cpu_memmap-addr; should be safe to drop this since OSPM must ignore this field if gicc provides base_address. +madt-flags = cpu_to_le32(1); is it correct? Looking at 5.1 spec it's x86 specific PCAT_COMPAT flag, why do you use it for ARM? + +for (i = 0; i guest_info-max_cpus; i++) { +AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data, + sizeof *gicc); +gicc-type = ACPI_APIC_GENERIC_INTERRUPT; +gicc-length = sizeof(*gicc); +gicc-base_address = info-gic_cpu_memmap-addr; +gicc-cpu_interface_number = i; +gicc-arm_mpidr = i; +gicc-uid = i; +if (test_bit(i, cpuinfo-found_cpus)) { +gicc-flags = cpu_to_le32(1); #define ACPI_GICC_ENABLED 1 +} else { +gicc-flags = cpu_to_le32(0); +} not necessary else clause, field is zeroed by default. +} + +gicd = acpi_data_push(table_data, sizeof *gicd); +gicd-type = ACPI_APIC_GENERIC_DISTRIBUTOR; +gicd-length = sizeof(*gicd); +gicd-base_address = info-gic_dist_memmap-addr; + +build_header(linker, table_data, + (void *)(table_data-data + madt_start), APIC, + table_data-len - madt_start, 1); wrong revision? +} + /* FADT */ static void build_fadt(GArray *table_data, GArray *linker, unsigned dsdt) @@ -215,8 +270,11 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) { GArray *table_offsets; unsigned dsdt; +VirtAcpiCpuInfo cpuinfo; GArray *tables_blob = tables-table_data; +virt_acpi_get_cpu_info(cpuinfo); + table_offsets = g_array_new(false, true /* clear */, sizeof(uint32_t)); @@ -241,6 +299,9 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_fadt(tables_blob, tables-linker, dsdt); +acpi_add_table(table_offsets, tables_blob); +build_madt(tables_blob, tables-linker, guest_info, cpuinfo); + /* Cleanup memory that's no longer used. */ g_array_free(table_offsets, true); } diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index bac981d..4092dc3 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -236,7 +236,13 @@ typedef struct AcpiMultipleApicTable AcpiMultipleApicTable; #define ACPI_APIC_IO_SAPIC 6 #define ACPI_APIC_LOCAL_SAPIC7 #define ACPI_APIC_XRUPT_SOURCE 8 -#define ACPI_APIC_RESERVED 9 /* 9 and greater are reserved */ +#define ACPI_APIC_LOCAL_X2APIC 9 +#define ACPI_APIC_LOCAL_X2APIC_NMI 10 +#define ACPI_APIC_GENERIC_INTERRUPT 11 +#define ACPI_APIC_GENERIC_DISTRIBUTOR 12 +#define ACPI_APIC_GENERIC_MSI_FRAME 13 +#define ACPI_APIC_GENERIC_REDISTRIBUTOR 14 +#define ACPI_APIC_RESERVED 15 /* 15 and greater are reserved */ /* * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) @@
Re: [Qemu-devel] [PATCH v5 13/20] hw/acpi/aml-build: Add ToUUID macro
On Mon, 04 May 2015 17:30:20 +0800 Shannon Zhao shannon.z...@linaro.org wrote: On 2015/5/4 17:22, Igor Mammedov wrote: On Wed, 29 Apr 2015 21:41:39 +0800 Shannon Zhao shannon.z...@linaro.org wrote: On 2015/4/28 17:48, Shannon Zhao wrote: On 2015/4/28 17:35, Igor Mammedov wrote: On Tue, 28 Apr 2015 16:52:19 +0800 Shannon Zhao zhaoshengl...@huawei.com wrote: On 2015/4/28 16:15, Igor Mammedov wrote: btw: whole thing might be simpler if an intermediate conversion is avoided, just pack buffer as in spec byte by byte: /* format: aabbccdd-eeff-gghh-iijj-kkllmmnnoopp */ assert(strlen(uuid) == ...); build_append_byte(var-buf, HEX2BYTE(uuid[3]); /* dd */ use build_append_byte(var-buf, HEX2BYTE(uuid + 7); ? build_append_byte(var-buf, HEX2BYTE(uuid[2]); /* cc */ use build_append_byte(var-buf, HEX2BYTE(uuid + 5); ? if you mean hyphens /-/ then they are not encoded, but you surely can add checks for them to make sure that UUID format is as expected. I mean uuid[3] points to b not dd. Maybe use following way: static uint8_t Hex2Byte(char *src) or even better: Hex2Byte(char *src, byte_idx) and do pointer arithmetic inside [...] build_append_byte(var-buf, Hex2Byte(uuid + (3 * 2))); /* dd */ build_append_byte(var-buf, Hex2Byte(uuid, 3)); /* dd - at offset 00 */ build_append_byte(var-buf, Hex2Byte(uuid, 2)); /* cc - at offset 01 */ ... Yes, it's better to first four bytes. But there are hyphens /-/, for offset 04, 05 and etc it doesn't work. We can't use following expression: build_append_byte(var-buf, Hex2Byte(uuid, 5)); /* ff - at offset 04 */ build_append_byte(var-buf, Hex2Byte(uuid, 4)); /* ee - at offset 05 */ ... So about the implementation of this macro, I think I'd like to use following approach. This lets Hex2Byte do what it should only do and still has a clear look of UUID. What do you think about? static uint8_t Hex2Byte(char *src) { int hi = Hex2Digit(*src++); int lo = Hex2Digit(*src); if ((hi 0) || (lo 0)) return -1; just make Hex2Digit() assert on wrong input. Ok. return (hi 4) | lo; } g_assert((strlen(uuid) == 36) (uuid[8] == '-') (uuid[13] == '-') (uuid[18] == '-') (uuid[23] == '-')); build_append_byte(var-buf, Hex2Byte(uuid + (3 * 2))); /* dd */ ^ I'd make it one number, instead of forcing reader to do math every time he/she looks at this code. Ok, will do this. And about other patches in this series could you offer your comments? the rest of AML patches looks good, I'll give them RB on next respin. Thanks, Shannon build_append_byte(var-buf, Hex2Byte(uuid + (2 * 2))); /* cc */ build_append_byte(var-buf, Hex2Byte(uuid + (1 * 2))); /* bb */ build_append_byte(var-buf, Hex2Byte(uuid + (0 * 2))); /* aa */ build_append_byte(var-buf, Hex2Byte(uuid + (5 * 2 + 1))); /* ff */ build_append_byte(var-buf, Hex2Byte(uuid + (4 * 2 + 1))); /* ee */ build_append_byte(var-buf, Hex2Byte(uuid + (7 * 2 + 2))); /* hh */ build_append_byte(var-buf, Hex2Byte(uuid + (6 * 2 + 2))); /* gg */ build_append_byte(var-buf, Hex2Byte(uuid + (8 * 2 + 3))); /* ii */ build_append_byte(var-buf, Hex2Byte(uuid + (9 * 2 + 3))); /* jj */ build_append_byte(var-buf, Hex2Byte(uuid + (10 * 2 + 4))); /* kk */ build_append_byte(var-buf, Hex2Byte(uuid + (11 * 2 + 4))); /* ll */ build_append_byte(var-buf, Hex2Byte(uuid + (12 * 2 + 4))); /* mm */ build_append_byte(var-buf, Hex2Byte(uuid + (13 * 2 + 4))); /* nn */ build_append_byte(var-buf, Hex2Byte(uuid + (14 * 2 + 4))); /* oo */ build_append_byte(var-buf, Hex2Byte(uuid + (15 * 2 + 4))); /* pp */
Re: [Qemu-devel] [Qemu-block] [PATCH 1/6] qcow2: use one single memory block for the L2/refcount cache tables
Am 01.05.2015 um 16:23 hat Stefan Hajnoczi geschrieben: On Thu, Apr 30, 2015 at 01:11:40PM +0300, Alberto Garcia wrote: Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables) { BDRVQcowState *s = bs-opaque; Qcow2Cache *c; -int i; c = g_new0(Qcow2Cache, 1); c-size = num_tables; +c-table_size = s-cluster_size; This assumes c-table_size meets bs' memory alignment requirements. The following would be safer: c-table_size = QEMU_ALIGN_UP(c-table_size, bdrv_opt_mem_align(bs-file)); You can't just access more than one cluster. You might be caching data and later write it back when it's stale. If you can't do I/O in chunks as small as the cluster size (which is rather unlikely), relying on bdrv_pwrite(), like Berto's patch does, is the correct solution. Kevin pgpj5Wnce450q.pgp Description: PGP signature
Re: [Qemu-devel] .gitignore contains .c and .h ?
On Mon, 04 May 2015 09:47:11 +0200 Guillaume Le Louët guillaume.lelo...@gmail.com wrote: Hello. The .gitignore in the master branch contains the following lines : /qapi-types.[ch] /qapi-visit.[ch] /qapi-event.[ch] Why is it so ? Are they generated automatically each time I compile the project ? I am modifying qapi-types.h and qapi-types.c , am I doing wrong ? Yes, they are created automatically and you should not edit them manually. Just have a look at the main Makefile: qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \ $(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \ $(SRC_PATH)/qapi/event.json qapi-types.c qapi-types.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ $(gen-out-type) -o . -b -i $, \ GEN $@) So if you want to change something in this area, you likely have to touch the *.json files instead. Thomas
Re: [Qemu-devel] [PATCH 1/1] vl.c: Since the help says that 'disk_image' is a raw hard disk image, pass format=raw
Am 01.05.2015 um 01:28 hat Don Slutz geschrieben: On 04/30/15 16:15, Kevin Wolf wrote: Am 30.04.2015 um 21:15 hat Eric Blake geschrieben: [adding qemu-block] On 04/30/2015 12:23 PM, Don Slutz wrote: ~/qemu/out/master/x86_64-softmmu/qemu-system-x86_64 -h | head QEMU emulator version 2.3.50, Copyright (c) 2003-2008 Fabrice Bellard usage: qemu-system-x86_64 [options] [disk_image] 'disk_image' is a raw hard disk image for IDE hard disk 0 Standard options: ... Signed-off-by: Don Slutz dsl...@verizon.com --- vl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) Reviewed-by: Eric Blake ebl...@redhat.com Without this, qemu will try to probe formats. It is arguably is more convenient when using the shorthand of supplying a disk image to let qemu pick the format; but as the --help text says the image is raw, it's better to be explicit and avoid probing. Besides, we can always use longhand to specify actual format and/or probing if we don't like the shorthand. I don't think you can take an outdated help text as a justification for breaking backwards compatibility. Is this a hard no, soft no, or TBD? The following is what prompted this: WARNING: Image format was not specified for '/dev/etherd/e500.1' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. Specify the 'raw' format explicitly to remove the restrictions. which I would say also breaks backwards compatibility. It doesn't, except if you consider an additional warning as breakage. Only some corner cases that you probably wouldn't ever hit intentionally changed their failure mode from 'image is opened in the wrong format when restarting qemu' to 'write to sector 0 failed'. If you don't hit the restrictions and you never specify the format explicitly, you can just ignore the warning. However I do agree that this is the right change to have done. However there currently is no way to specify that the 'disk_image' is raw. Also the old options (-hda, -hdb, -hdc, and -hdd) all have similar issues. Yes, you need to use -drive for that currently. So do you want a more complex patch that allows the format to be specified? Only for 'disk_image'? Include -hd* ? I'm afraid that there is no nice way to improve the plain 'disk_image' case. You would have to add another option, and then it's not any better than -hda and friends any more. -hda in turn could be extended to take additional options (i.e. it becomes something like -drive with implied index=0), but then there's little reason not to use -drive. We might actually want to extent -hd* at some point, but we would probably use this as a chance to clean up the interface and remove legacy options that -drive has to maintain for compatibility. Change the help message also? Yes, this definitely. If the help message states that it's a raw image, the help text is wrong. Kevin
Re: [Qemu-devel] [PATCH v5 06/20] hw/arm/virt-acpi-build: Generation of DSDT table for virt devices
On 2015/5/4 17:58, Igor Mammedov wrote: On Wed, 15 Apr 2015 21:24:55 +0800 Shannon Zhao zhaoshengl...@huawei.com wrote: From: Shannon Zhao shannon.z...@linaro.org DSDT consists of the usual common table header plus a definition block in AML encoding which describes all devices in the platform. After initializing DSDT with header information the namespace is created which is followed by the device encodings. The devices are described using the Resource Template for the 32-Bit Fixed Memory Range and the Extended Interrupt Descriptors. Signed-off-by: Shannon Zhao zhaoshengl...@huawei.com Signed-off-by: Shannon Zhao shannon.z...@linaro.org --- hw/arm/virt-acpi-build.c | 128 +++ 1 file changed, 128 insertions(+) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index c5a3cf9..d044880 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -50,6 +50,130 @@ #include qom/qom-qobject.h #include exec/ram_addr.h +static void acpi_dsdt_add_cpus(Aml *scope, int max_cpus) +{ +uint16_t i; + +for (i = 0; i max_cpus; i++) { +Aml *dev = aml_device(C%03x, i); +aml_append(dev, aml_name_decl(_HID, aml_string(ACPI0007))); +aml_append(dev, aml_name_decl(_UID, aml_int(i))); +Aml *crs = aml_resource_template(); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} +} Is maxcpus a correct here? Usually maxcpus includes non present CPUs as well but there is no STA method that tells whether it's present or not. 5.2.12.14 GICC Structure In the GICC interrupt model, logical processors are required to have a Processor Device object in the DSDT Here we create Processor Device object for all possible CPUs and in MADT the gicc-flags tells whether it's present or not. And this flags is for kernel booting initialization, not for dynamic configuration. BTW, ARM doesn't support vCPU hotplug now. If we want to support hotplug later, we should add _STA method for each Processor. + +static void acpi_dsdt_add_uart(Aml *scope, const MemMap *uart_memmap, + const int *uart_irq) +{ +Aml *dev = aml_device(COM0); +aml_append(dev, aml_name_decl(_HID, aml_string(ARMH0011))); +aml_append(dev, aml_name_decl(_UID, aml_int(0))); + +Aml *crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(uart_memmap-addr, + uart_memmap-size, aml_ReadWrite)); +aml_append(crs, + aml_interrupt(aml_consumer, aml_level, aml_active_high, + aml_exclusive, aml_not_wake_capable, *uart_irq + 32)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} + +static void acpi_dsdt_add_rtc(Aml *scope, const MemMap *rtc_memmap, + const int *rtc_irq) +{ +Aml *dev = aml_device(RTC0); +aml_append(dev, aml_name_decl(_HID, aml_string(LNRO0013))); +aml_append(dev, aml_name_decl(_UID, aml_int(0))); + +Aml *crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(rtc_memmap-addr, + rtc_memmap-size, aml_ReadWrite)); +aml_append(crs, + aml_interrupt(aml_consumer, aml_level, aml_active_high, + aml_exclusive, aml_not_wake_capable, *rtc_irq + 32)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} + +static void acpi_dsdt_add_flash(Aml *scope, const MemMap *flash_memmap) +{ +Aml *dev, *crs; +hwaddr base = flash_memmap-addr; +hwaddr size = flash_memmap-size; + +dev = aml_device(FLS0); +aml_append(dev, aml_name_decl(_HID, aml_string(LNRO0015))); +aml_append(dev, aml_name_decl(_UID, aml_int(0))); + +crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(base, size, aml_ReadWrite)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); + +dev = aml_device(FLS1); +aml_append(dev, aml_name_decl(_HID, aml_string(LNRO0015))); +aml_append(dev, aml_name_decl(_UID, aml_int(1))); +crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(base + size, size, aml_ReadWrite)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} + +static void acpi_dsdt_add_virtio(Aml *scope, const MemMap *virtio_mmio_memmap, + const int *mmio_irq, int num) +{ +hwaddr base = virtio_mmio_memmap-addr; +hwaddr size = virtio_mmio_memmap-size; +int irq = *mmio_irq + 32; +int i; + +for (i = 0; i num; i++) { +Aml *dev = aml_device(VR%02u, i); +aml_append(dev, aml_name_decl(_HID, aml_string(LNRO0005))); +aml_append(dev, aml_name_decl(_UID, aml_int(i))); + +Aml *crs = aml_resource_template(); +
Re: [Qemu-devel] Comparison of virtual disks?
On 03.05.2015 10:16, Erik Rull wrote: Hi all, is there a comparison chart of the different disk formats supported by QEMU? Especially throughput, latencies and robustness against unexpected power loss on the host would be interesting. Thanks a lot. Best regards, Erik Hi Erik, I'm sorry, but I don't know whether such a chart exists (the closest thing I know is http://en.wikipedia.org/wiki/Category:Disk_images - which is not very close...). However, the general assumption we as developers are working with is that if the user's top priority is performance, they should use raw; and if they want to use all of the features qemu's block layer provides, they should use qcow2. All other formats are implemented merely for compatibility and ideally they should not be used for running VMs, but only for converting them to qcow2 using qemu-img convert. Especially considering performance (throughput and latency), qcow2 will probably be the only format that we are really willing to work on. For the other drivers, the general idea is that reasonably fast is enough, but we probably won't go out of our way to make the implementations as fast as possible. On the other hand, other formats may support special raw-like operating modes (e.g. vpc does), making them potentially automatically as fast as raw is, if configured appropriately. Finally, there is robustness: raw will be as robust as it gets, because it should behave just like a real disk. For qcow2, we took special care to make sure the image will not be corrupted if qemu or the host crash. There are options like cache=unsafe and lazy-refcounts=on, which may corrupt the image in case of a crash, but at least the latter results in a special flag being set which makes qemu check and, if need be, repair the image the next time it is used. Speaking of checking and repairing, that's something that is only really implemented for qcow2, too. From what I can see, qed supports it, too; vdi and vmdk only support checking (I don't know how thorough it is); and vhdx has a journal which I guess means it is pretty safe against unexpected crashes, too. We are trying to make all formats resistent against unexpected crashes (by flushing metadata whenever necessary), but I think it is safe to say here too we are paying special attention to qcow2. So, all in all, raw is the format of choice if all you need is performance; if you do need features not offered by raw, qcow2 (the QEMU image format) is the recommended choice. Or, to quote qemu-img's manpage: For running VMs, it is recommended to convert the disk images to either raw or qcow2 in order to achieve good performance. Again, sorry I don't have a full chart to present to you. Max Konsole output
Re: [Qemu-devel] [PATCH v5 08/20] hw/arm/virt-acpi-build: Generate MADT table
On 2015/5/4 18:21, Igor Mammedov wrote: On Wed, 15 Apr 2015 21:24:57 +0800 Shannon Zhao zhaoshengl...@huawei.com wrote: From: Shannon Zhao shannon.z...@linaro.org MADT describes GIC enabled ARM platforms. The GICC and GICD subtables are used to define the GIC regions. Signed-off-by: Shannon Zhao zhaoshengl...@huawei.com Signed-off-by: Shannon Zhao shannon.z...@linaro.org Reviewed-by: Alex Bennée alex.ben...@linaro.org --- hw/arm/virt-acpi-build.c | 61 include/hw/acpi/acpi-defs.h | 38 - include/hw/arm/virt-acpi-build.h | 2 ++ 3 files changed, 100 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index c72a9c8..94cced0 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -50,6 +50,20 @@ #include qom/qom-qobject.h #include exec/ram_addr.h +typedef struct VirtAcpiCpuInfo { +DECLARE_BITMAP(found_cpus, VIRT_ACPI_CPU_ID_LIMIT); +} VirtAcpiCpuInfo; + +static void virt_acpi_get_cpu_info(VirtAcpiCpuInfo *cpuinfo) +{ +CPUState *cpu; + +memset(cpuinfo-found_cpus, 0, sizeof cpuinfo-found_cpus); +CPU_FOREACH(cpu) { +set_bit(cpu-cpu_index, cpuinfo-found_cpus); +} +} + static void acpi_dsdt_add_cpus(Aml *scope, int max_cpus) { uint16_t i; @@ -146,6 +160,47 @@ static void acpi_dsdt_add_virtio(Aml *scope, const MemMap *virtio_mmio_memmap, } } +/* MADT */ +static void +build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info, + VirtAcpiCpuInfo *cpuinfo) +{ +int madt_start = table_data-len; +const struct AcpiMadtInfo *info = guest_info-madt_info; +AcpiMultipleApicTable *madt; +AcpiMadtGenericDistributor *gicd; +int i; + +madt = acpi_data_push(table_data, sizeof *madt); +madt-local_apic_address = info-gic_cpu_memmap-addr; should be safe to drop this since OSPM must ignore this field if gicc provides base_address. Ok. +madt-flags = cpu_to_le32(1); is it correct? Looking at 5.1 spec it's x86 specific PCAT_COMPAT flag, why do you use it for ARM? Oh, will fix. Thanks. + +for (i = 0; i guest_info-max_cpus; i++) { +AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data, + sizeof *gicc); +gicc-type = ACPI_APIC_GENERIC_INTERRUPT; +gicc-length = sizeof(*gicc); +gicc-base_address = info-gic_cpu_memmap-addr; +gicc-cpu_interface_number = i; +gicc-arm_mpidr = i; +gicc-uid = i; +if (test_bit(i, cpuinfo-found_cpus)) { +gicc-flags = cpu_to_le32(1); #define ACPI_GICC_ENABLED 1 +} else { +gicc-flags = cpu_to_le32(0); +} not necessary else clause, field is zeroed by default. Ok, will remove. +} + +gicd = acpi_data_push(table_data, sizeof *gicd); +gicd-type = ACPI_APIC_GENERIC_DISTRIBUTOR; +gicd-length = sizeof(*gicd); +gicd-base_address = info-gic_dist_memmap-addr; + +build_header(linker, table_data, + (void *)(table_data-data + madt_start), APIC, + table_data-len - madt_start, 1); wrong revision? Thanks, will fix this including other patches. +} + /* FADT */ static void build_fadt(GArray *table_data, GArray *linker, unsigned dsdt) @@ -215,8 +270,11 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) { GArray *table_offsets; unsigned dsdt; +VirtAcpiCpuInfo cpuinfo; GArray *tables_blob = tables-table_data; +virt_acpi_get_cpu_info(cpuinfo); + table_offsets = g_array_new(false, true /* clear */, sizeof(uint32_t)); @@ -241,6 +299,9 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_fadt(tables_blob, tables-linker, dsdt); +acpi_add_table(table_offsets, tables_blob); +build_madt(tables_blob, tables-linker, guest_info, cpuinfo); + /* Cleanup memory that's no longer used. */ g_array_free(table_offsets, true); } diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index bac981d..4092dc3 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -236,7 +236,13 @@ typedef struct AcpiMultipleApicTable AcpiMultipleApicTable; #define ACPI_APIC_IO_SAPIC 6 #define ACPI_APIC_LOCAL_SAPIC7 #define ACPI_APIC_XRUPT_SOURCE 8 -#define ACPI_APIC_RESERVED 9 /* 9 and greater are reserved */ +#define ACPI_APIC_LOCAL_X2APIC 9 +#define ACPI_APIC_LOCAL_X2APIC_NMI 10 +#define ACPI_APIC_GENERIC_INTERRUPT 11 +#define ACPI_APIC_GENERIC_DISTRIBUTOR 12 +#define ACPI_APIC_GENERIC_MSI_FRAME 13 +#define ACPI_APIC_GENERIC_REDISTRIBUTOR 14 +#define
[Qemu-devel] [Bug 1450891] Re: VM will not resume on GlusterFS
We can't just reopen files, we don't know what state they are in. Any data that has been written to the image between the last flush and the point where gluster made the fd invalid may be there or may be missing. If any data is missing, we can't continue the guest or you'll get data corruption. The correct fix for resuming after I/O errors is on gluster. As long as it invalidates the fd, without a way to resume, there is no way for qemu to correctly continue after an error. -- You received this bug notification because you are a member of qemu- devel-ml, which is subscribed to QEMU. https://bugs.launchpad.net/bugs/1450891 Title: VM will not resume on GlusterFS Status in QEMU: New Bug description: oVirt uses libvirt to run QEMU. Images are passed to QEMU as files, not file descriptors. When running images from a GlusterFS, the file descriptors may get invalidated because of network problems or the glusterfs process being restarted. In this case, the VM goes into paused state. When trying to resume the VM ('cont' command), QEMU uses the same invalidated file descriptors throwing a: block I/O error in device 'drive-virtio-disk0': Transport endpoint is not connected (107). Please check file-descriptors and reopen image file on 'cont' event in QEMU. Thanks. References: [1] http://lists.nongnu.org/archive/html/qemu-devel/2015-03/msg01269.html [2] https://bugzilla.redhat.com/show_bug.cgi?id=1058300 To manage notifications about this bug go to: https://bugs.launchpad.net/qemu/+bug/1450891/+subscriptions
Re: [Qemu-devel] .gitignore contains .c and .h ?
You're right, I noticed that compiling with make was removing my modifications. I ended up modifying the qapi-schema.json . May I advise to move the generated .c and .h files into a generated/ folder ? Thank you Thomas. Le 04/05/2015 13:01, Thomas Huth a écrit : On Mon, 04 May 2015 09:47:11 +0200 Guillaume Le Louët guillaume.lelo...@gmail.com wrote: Hello. The .gitignore in the master branch contains the following lines : /qapi-types.[ch] /qapi-visit.[ch] /qapi-event.[ch] Why is it so ? Are they generated automatically each time I compile the project ? I am modifying qapi-types.h and qapi-types.c , am I doing wrong ? Yes, they are created automatically and you should not edit them manually. Just have a look at the main Makefile: qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \ $(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \ $(SRC_PATH)/qapi/event.json qapi-types.c qapi-types.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ $(gen-out-type) -o . -b -i $, \ GEN $@) So if you want to change something in this area, you likely have to touch the *.json files instead. Thomas
Re: [Qemu-devel] .gitignore contains .c and .h ?
On 4 May 2015 at 12:37, Guillaume Le Louët guillaume.lelo...@gmail.com wrote: You're right, I noticed that compiling with make was removing my modifications. I ended up modifying the qapi-schema.json . May I advise to move the generated .c and .h files into a generated/ folder ? If you want to keep generated files out of your source tree I would recommend using a separate build tree: mkdir build/whatever (cd build/whatever ../../configure [args here]) make -C build/whatever (You'll need to distclean your tree first if you've been doing in-source-tree builds.) -- PMM
Re: [Qemu-devel] [Qemu-block] [PATCH v3 3/9] libqos: Add migration helpers
Am 30.04.2015 um 20:07 hat John Snow geschrieben: libqos.c: -set_context for addressing which commands go where -migrate performs the actual migration malloc.c: - Structure of the allocator is adjusted slightly with a second-tier malloc to make swapping around the allocators easy when we migrate the lists from the source to the destination. Signed-off-by: John Snow js...@redhat.com --- tests/libqos/libqos.c | 84 +++ tests/libqos/libqos.h | 2 ++ tests/libqos/malloc.c | 74 ++--- tests/libqos/malloc.h | 1 + 4 files changed, 144 insertions(+), 17 deletions(-) diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index 7e72078..ac1bae1 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -1,5 +1,6 @@ #include stdio.h #include stdlib.h +#include string.h #include glib.h #include unistd.h #include fcntl.h @@ -62,6 +63,89 @@ void qtest_shutdown(QOSState *qs) g_free(qs); } +void set_context(QOSState *s) +{ +global_qtest = s-qts; +} + +static QDict *qmp_execute(const char *command) +{ +char *fmt; +QDict *rsp; + +fmt = g_strdup_printf({ 'execute': '%s' }, command); +rsp = qmp(fmt); +g_free(fmt); + +return rsp; +} + +void migrate(QOSState *from, QOSState *to, const char *uri) +{ +const char *st; +char *s; +QDict *rsp, *sub; +bool running; + +set_context(from); + +/* Is the machine currently running? */ +rsp = qmp_execute(query-status); +g_assert(qdict_haskey(rsp, return)); +sub = qdict_get_qdict(rsp, return); +g_assert(qdict_haskey(sub, running)); +running = qdict_get_bool(sub, running); +QDECREF(rsp); + +/* Issue the migrate command. */ +s = g_strdup_printf({ 'execute': 'migrate', +'arguments': { 'uri': '%s' } }, +uri); +rsp = qmp(s); +g_free(s); +g_assert(qdict_haskey(rsp, return)); +QDECREF(rsp); + +/* Wait for STOP event, but only if we were running: */ +if (running) { +qmp_eventwait(STOP); +} + +/* If we were running, we can wait for an event. */ +if (running) { +migrate_allocator(from-alloc, to-alloc); +set_context(to); +qmp_eventwait(RESUME); +return; +} + +/* Otherwise, we need to wait: poll until migration is completed. */ +while (1) { +rsp = qmp_execute(query-migrate); +g_assert(qdict_haskey(rsp, return)); +sub = qdict_get_qdict(rsp, return); +g_assert(qdict_haskey(sub, status)); +st = qdict_get_str(sub, status); + +/* setup, active, completed, failed, cancelled */ +if (strcmp(st, completed) == 0) { +QDECREF(rsp); +break; +} + +if ((strcmp(st, setup) == 0) || (strcmp(st, active) == 0)) { +QDECREF(rsp); +continue; Wouldn't it be nicer to sleep a bit before retrying? +} + +fprintf(stderr, Migration did not complete, status: %s\n, st); +g_assert_not_reached(); +} + +migrate_allocator(from-alloc, to-alloc); +set_context(to); +} Kevin
[Qemu-devel] [PATCH] coverity: fix address_space_rw model
If the is_write argument is true, address_space_rw writes to memory and thus reads from the buffer. The opposite holds if is_write is false. Fix the model. Cc: Markus Armbruster arm...@redhat.com Signed-off-by: Paolo Bonzini pbonz...@redhat.com --- scripts/coverity-model.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/coverity-model.c b/scripts/coverity-model.c index 224d2d1..617f67d 100644 --- a/scripts/coverity-model.c +++ b/scripts/coverity-model.c @@ -49,7 +49,7 @@ typedef uint64_t hwaddr; typedef uint32_t MemTxResult; typedef uint64_t MemTxAttrs; -static void __write(uint8_t *buf, ssize_t len) +static void __bufwrite(uint8_t *buf, ssize_t len) { int first, last; __coverity_negative_sink__(len); @@ -59,7 +59,7 @@ static void __write(uint8_t *buf, ssize_t len) __coverity_writeall__(buf); } -static void __read(uint8_t *buf, ssize_t len) +static void __bufread(uint8_t *buf, ssize_t len) { __coverity_negative_sink__(len); if (len == 0) return; @@ -74,7 +74,7 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, // TODO: investigate impact of treating reads as producing // tainted data, with __coverity_tainted_data_argument__(buf). -if (is_write) __write(buf, len); else __read(buf, len); +if (is_write) __bufread(buf, len); else __bufwrite(buf, len); return result; } -- 2.3.5
[Qemu-devel] [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options
Signed-off-by: Quan Xu quan...@intel.com --Changes in v6: -Remove stray insertion. --- configure| 14 ++ hmp.c| 2 ++ qapi-schema.json | 16 ++-- qemu-options.hx | 13 +++-- tpm.c| 7 ++- 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 09c9225..8c9411d 100755 --- a/configure +++ b/configure @@ -3010,6 +3010,16 @@ else fi ## +# TPM xenstubdoms is only on x86 Linux + +if test $targetos = Linux test $cpu = i386 -o $cpu = x86_64 \ + test $xen = yes; then + tpm_xenstubdoms=$tpm +else + tpm_xenstubdoms=no +fi + +## # attr probe if test $attr != no ; then @@ -4432,6 +4442,7 @@ echo gcov $gcov_tool echo gcov enabled $gcov echo TPM support $tpm echo libssh2 support $libssh2 +echo TPM xenstubdoms $tpm_xenstubdoms echo TPM passthrough $tpm_passthrough echo QOM debugging $qom_cast_debug echo vhdx $vhdx @@ -4919,6 +4930,9 @@ if test $tpm = yes; then if test $tpm_passthrough = yes; then echo CONFIG_TPM_PASSTHROUGH=y $config_host_mak fi + if test $tpm_xenstubdoms = yes; then +echo CONFIG_TPM_XENSTUBDOMS=y $config_host_mak + fi fi echo TRACE_BACKENDS=$trace_backends $config_host_mak diff --git a/hmp.c b/hmp.c index f31ae27..c10b6f7 100644 --- a/hmp.c +++ b/hmp.c @@ -813,6 +813,8 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) tpo-has_cancel_path ? ,cancel-path= : , tpo-has_cancel_path ? tpo-cancel_path : ); break; +case TPM_TYPE_OPTIONS_KIND_XENSTUBDOMS: +break; case TPM_TYPE_OPTIONS_KIND_MAX: break; } diff --git a/qapi-schema.json b/qapi-schema.json index ac9594d..9bdb15e 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2975,9 +2975,11 @@ # # @passthrough: TPM passthrough type # +# @xenstubdoms: TPM xenstubdoms type (since 2.4) +# # Since: 1.5 ## -{ 'enum': 'TpmType', 'data': [ 'passthrough' ] } +{ 'enum': 'TpmType', 'data': [ 'passthrough', 'xenstubdoms' ] } ## # @query-tpm-types: @@ -3006,6 +3008,15 @@ '*cancel-path' : 'str'} } ## +# @TPMXenstubdomsOptions: +# +# Information about the TPM xenstubdoms type +# +# Since: 2.4 +## +{ 'type': 'TPMXenstubdomsOptions', 'data': { } } + +## # @TpmTypeOptions: # # A union referencing different TPM backend types' configuration options @@ -3015,7 +3026,8 @@ # Since: 1.5 ## { 'union': 'TpmTypeOptions', - 'data': { 'passthrough' : 'TPMPassthroughOptions' } } + 'data': { 'passthrough' : 'TPMPassthroughOptions', +'xenstubdoms' : 'TPMXenstubdomsOptions' } } ## # @TpmInfo: diff --git a/qemu-options.hx b/qemu-options.hx index 319d971..9254902 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2539,7 +2539,8 @@ DEF(tpmdev, HAS_ARG, QEMU_OPTION_tpmdev, \ -tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n use path to provide path to a character device; default is /dev/tpm0\n use cancel-path to provide path to TPM's cancel sysfs entry; if\n -not provided it will be searched for in /sys/class/misc/tpm?/device\n, +not provided it will be searched for in /sys/class/misc/tpm?/device\n +-tpmdev xenstubdoms,id=id\n, QEMU_ARCH_ALL) STEXI @@ -2549,7 +2550,8 @@ The general form of a TPM device option is: @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}] @findex -tpmdev Backend type must be: -@option{passthrough}. +@option{passthrough}, or +@option{xenstubdoms}. The specific backend type will determine the applicable options. The @code{-tpmdev} option creates the TPM backend and requires a @@ -2599,6 +2601,13 @@ To create a passthrough TPM use the following two options: Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by @code{tpmdev=tpm0} in the device option. +To create a xenstubdoms TPM use the following two options: +@example +-tpmdev xenstubdoms,id=tpm0 -device tpm-tis,tpmdev=tpm0 +@end example +Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by +@code{tpmdev=tpm0} in the device option. + @end table ETEXI diff --git a/tpm.c b/tpm.c index 963b7ee..30643fd 100644 --- a/tpm.c +++ b/tpm.c @@ -25,7 +25,7 @@ static QLIST_HEAD(, TPMBackend) tpm_backends = #define TPM_MAX_MODELS 1 -#define TPM_MAX_DRIVERS 1 +#define TPM_MAX_DRIVERS 2 static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = { NULL, @@ -254,6 +254,7 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv) { TPMInfo *res = g_new0(TPMInfo, 1); TPMPassthroughOptions *tpo; +TPMXenstubdomsOptions *txo; res-id = g_strdup(drv-id); res-model = drv-fe_model; @@ -273,6 +274,10 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
[Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part)
*INTRODUCTION* The goal of virtual Trusted Platform Module (vTPM) is to provide a TPM functionality to virtual machines (Fedora, Ubuntu, Redhat, Windows .etc). This allows programs to interact with a TPM in a virtual machine the same way they interact with a TPM on the physical system. Each virtual machine gets its own unique, emulated, software TPM. Each major component of vTPM is implemented as a stubdom, providing secure separation guaranteed by the hypervisor. The vTPM stubdom is a Xen mini-OS domain that emulates a TPM for the virtual machine to use. It is a small wrapper around the Berlios TPM emulator. TPM commands are passed from mini-os TPM backend driver. *ARCHITECTURE* The architecture of stubdom vTPM for HVM virtual machine: ++ | Windows/Linux DomU | ... || ^| |v || | Qemu tpm1.2 Tis | || ^| |v || | XenStubdoms backend| ++ | ^ v | ++ | XenDevOps | ++ | ^ v | ++ | mini-os/tpmback | || ^| |v || | vtpm-stubdom | ... || ^| |v || | mini-os/tpmfront | ++ | ^ v | ++ | mini-os/tpmback | || ^| |v || | vtpmmgr-stubdom | || ^| |v || | mini-os/tpm_tis | ++ | ^ v | ++ |Hardware TPM| ++ * Windows/Linux DomU: The HVM based guest that wants to use a vTPM. There may be more than one of these. * Qemu tpm1.2 Tis: Implementation of the tpm1.2 Tis interface for HVM virtual machines. It is Qemu emulation device. * vTPM xenstubdoms driver: Qemu vTPM driver. This driver provides vtpm initialization and sending data and commends to a para-virtualized vtpm stubdom. * XenDevOps: Register Xen stubdom vTPM frontend driver, and transfer any request/repond between TPM xenstubdoms driver and Xen vTPM stubdom. Facilitate communications between Xen vTPM stubdom and vTPM xenstubdoms driver. * mini-os/tpmback: Mini-os TPM backend driver. The Linux frontend driver connects to this backend driver to facilitate communications between the Linux DomU and its vTPM. This driver is also used by vtpmmgr stubdom to communicate with vtpm-stubdom. * vtpm-stubdom: A mini-os stub domain that implements a vTPM. There is a one to one mapping between running vtpm-stubdom instances and logical vtpms on the system. The vTPM Platform Configuration Registers (PCRs) are all initialized to zero. * mini-os/tpmfront: Mini-os TPM frontend driver. The vTPM mini-os domain vtpm stubdom uses this driver to communicate with vtpmmgr-stubdom. This driver could also be used separately to implement a mini-os domain that wishes to use a vTPM of its own. * vtpmmgr-stubdom: A mini-os domain that implements the vTPM manager. There is only one vTPM manager and it should be running during the entire lifetime of the machine. vtpmmgr domain securely stores encryption keys for each of the vtpms and accesses to the hardware TPM to get the root of trust for the entire system. * mini-os/tpm_tis: Mini-os TPM version 1.2 TPM Interface Specification (TIS) driver. This driver used by vtpmmgr-stubdom to talk directly to the hardware TPM. Communication is facilitated by mapping hardware memory pages into vtpmmgr stubdom. * Hardware TPM: The physical TPM 1.2 that is soldered onto the motherboard. --Changes in v6: -Add a parameter indicating whether the command that was a selftest, and whether it completed successfully. -Remove the redundant copy right. -Reduce the includes to its minimum. -Replace buf_size with PAGE_SIZE and use length rather than shr-length. -Remove stray insertion. Quan Xu (6): Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options Qemu-Xen-vTPM: Xen frontend driver infrastructure Qemu-Xen-vTPM: Xen frontend driver infrastructure Qemu-Xen-vTPM: Move tpm_passthrough_is_selftest() into tpm_util.c Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen. Qemu-Xen-vTPM: QEMU machine class is initialized before tpm_init() configure| 14 ++ hmp.c
[Qemu-devel] [PATCH v6 4/6] Qemu-Xen-vTPM: Move tpm_passthrough_is_selftest() into tpm_util.c
and rename it to tpm_util_is_selftest(). Signed-off-by: Quan Xu quan...@intel.com --Changes in v6: -Remove the redundant copy right. -Reduce the includes to its minimum. --- hw/tpm/Makefile.objs | 2 +- hw/tpm/tpm_passthrough.c | 13 + hw/tpm/tpm_util.c| 39 +++ include/sysemu/tpm_backend_int.h | 1 + 4 files changed, 42 insertions(+), 13 deletions(-) create mode 100644 hw/tpm/tpm_util.c diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index 57919fa..e8fca65 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,3 +1,3 @@ -common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o +common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o tpm_util.o common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 2a45071..ff08e15 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -112,17 +112,6 @@ static void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len) } } -static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t in_len) -{ -struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in; - -if (in_len = sizeof(*hdr)) { -return (be32_to_cpu(hdr-ordinal) == TPM_ORD_ContinueSelfTest); -} - -return false; -} - static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt, const uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t out_len, @@ -136,7 +125,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt, tpm_pt-tpm_executing = true; *selftest_done = false; -is_selftest = tpm_passthrough_is_selftest(in, in_len); +is_selftest = tpm_util_is_selftest(in, in_len); ret = tpm_passthrough_unix_write(tpm_pt-tpm_fd, in, in_len); if (ret != in_len) { diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c new file mode 100644 index 000..73be8c5 --- /dev/null +++ b/hw/tpm/tpm_util.c @@ -0,0 +1,39 @@ +/* + * TPM util functions + * + * * Copyright (c) 2015 Intel Corporation + * Authors: + *Quan Xu quan...@intel.com + * + * Copyright (c) 2010 - 2013 IBM Corporation + * Authors: + *Stefan Berger stef...@us.ibm.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see http://www.gnu.org/licenses/ + */ + +#include sysemu/tpm_backend.h +#include tpm_int.h +#include sysemu/tpm_backend_int.h + +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len) +{ +struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in; + +if (in_len = sizeof(*hdr)) { +return (be32_to_cpu(hdr-ordinal) == TPM_ORD_ContinueSelfTest); +} + +return false; +} diff --git a/include/sysemu/tpm_backend_int.h b/include/sysemu/tpm_backend_int.h index 05d94d0..e18acab 100644 --- a/include/sysemu/tpm_backend_int.h +++ b/include/sysemu/tpm_backend_int.h @@ -34,6 +34,7 @@ void tpm_backend_thread_create(TPMBackendThread *tbt, void tpm_backend_thread_end(TPMBackendThread *tbt); void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt, GFunc func, gpointer user_data); +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len); typedef enum TPMBackendCmd { TPM_BACKEND_CMD_INIT = 1, -- 1.8.3.2
[Qemu-devel] [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen.
This Patch provides the glue for the TPM_TIS(Qemu frontend) to Xen stubdom vTPM domain that provides the actual TPM functionality. It sends data and TPM commends with xen_vtpm_frontend. It is similar as another two vTPM backens: *vTPM passthrough backen Since QEMU 1.5. *vTPM libtpms-based backen. Some details: This part of the patch provides support for the spawning of a thread that will interact with stubdom vTPM domain by the xen_vtpm_frontend. It expects a signal from the frontend to wake and pick up the TPM command that is supposed to be processed and delivers the response packet using a callback function provided by the frontend. The backend connects itself to the frontend by filling out an interface structure with pointers to the function implementing support for various operations. (QEMU) vTPM XenStubdoms backen is initialized by Qemu command line options, -tpmdev xenstubdoms,id=xenvtpm0 -device tpm-tis,tpmdev=xenvtpm0 Signed-off-by: Quan Xu quan...@intel.com --Changes in v6: -Add a parameter indicating whether the command that was a selftest, and whether it completed successfully. --- hw/tpm/Makefile.objs | 2 +- hw/tpm/tpm_xenstubdoms.c | 277 +++ 2 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 hw/tpm/tpm_xenstubdoms.c diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index e8fca65..698b9e6 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,3 +1,3 @@ common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o tpm_util.o common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o -common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o tpm_xenstubdoms.o diff --git a/hw/tpm/tpm_xenstubdoms.c b/hw/tpm/tpm_xenstubdoms.c new file mode 100644 index 000..f461323 --- /dev/null +++ b/hw/tpm/tpm_xenstubdoms.c @@ -0,0 +1,277 @@ +/* + * Xen Stubdom vTPM driver + * + * Copyright (c) 2015 Intel Corporation + * Authors: + *Quan Xu quan...@intel.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see http://www.gnu.org/licenses/ + */ + +#include dirent.h +#include qemu-common.h +#include qapi/error.h +#include qemu/sockets.h +#include qemu/log.h +#include sysemu/tpm_backend.h +#include tpm_int.h +#include hw/hw.h +#include hw/i386/pc.h +#include hw/xen/xen_backend.h +#include sysemu/tpm_backend_int.h +#include tpm_tis.h + +#ifdef DEBUG_TPM +#define DPRINTF(fmt, ...) \ +do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ +do { } while (0) +#endif + +#define TYPE_TPM_XENSTUBDOMS tpm-xenstubdoms +#define TPM_XENSTUBDOMS(obj) \ +OBJECT_CHECK(TPMXenstubdomsState, (obj), TYPE_TPM_XENSTUBDOMS) + +static const TPMDriverOps tpm_xenstubdoms_driver; + +/* Data structures */ +typedef struct TPMXenstubdomsThreadParams { +TPMState *tpm_state; +TPMRecvDataCB *recv_data_callback; +TPMBackend *tb; +} TPMXenstubdomsThreadParams; + +struct TPMXenstubdomsState { +TPMBackend parent; +TPMBackendThread tbt; +TPMXenstubdomsThreadParams tpm_thread_params; +bool had_startup_error; +}; + +typedef struct TPMXenstubdomsState TPMXenstubdomsState; + +/* Functions */ +static void tpm_xenstubdoms_cancel_cmd(TPMBackend *tb); + +static int tpm_xenstubdoms_unix_transfer(const TPMLocality *locty_data, + bool *selftest_done) +{ +size_t rlen; +struct XenDevice *xendev; +int ret; +bool is_selftest; +const struct tpm_resp_hdr *hdr; + +is_selftest = tpm_util_is_selftest(locty_data-w_buffer.buffer, + locty_data-w_buffer.size); + +xendev = xen_find_xendev(vtpm, xen_domid, xenstore_dev); +if (xendev == NULL) { +xen_be_printf(xendev, 0, Can not find vtpm device.\n); +return -1; +} + +ret = vtpm_send(xendev, locty_data-w_buffer.buffer, +locty_data-w_offset); +if (ret 0) { +xen_be_printf(xendev, 0, Can not send vtpm command.\n); +goto err_exit; +} + +ret = vtpm_recv(xendev, locty_data-r_buffer.buffer, rlen); +if (ret 0) { +xen_be_printf(xendev, 0, vtpm reception command error.\n); +goto err_exit; +} + +if (is_selftest (ret = sizeof(struct tpm_resp_hdr))) { +hdr = (struct tpm_resp_hdr
[Qemu-devel] [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
This patch adds infrastructure for xen front drivers living in qemu, so drivers don't need to implement common stuff on their own. It's mostly xenbus management stuff: some functions to access XenStore, setting up XenStore watches, callbacks on device discovery and state changes, and handle event channel between the virtual machines. Call xen_fe_register() function to register XenDevOps, and make sure, XenDevOps's flags is DEVOPS_FLAG_FE, which is flag bit to point out the XenDevOps is Xen frontend. Create a new file xen_pvdev.c for some common part of xen frontend and backend, such as xendevs queue and xenstore update functions. Signed-off-by: Quan Xu quan...@intel.com --- hw/display/xenfb.c | 4 +- hw/xen/Makefile.objs | 2 +- hw/xen/xen_backend.c | 353 --- hw/xen/xen_frontend.c| 345 +++ hw/xen/xen_pvdev.c | 481 +++ include/hw/xen/xen_backend.h | 22 +- 6 files changed, 850 insertions(+), 357 deletions(-) create mode 100644 hw/xen/xen_frontend.c create mode 100644 hw/xen/xen_pvdev.c diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 5e324ef..10751df 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -988,8 +988,8 @@ void xen_init_display(int domid) wait_more: i++; main_loop_wait(true); -xfb = xen_be_find_xendev(vfb, domid, 0); -xin = xen_be_find_xendev(vkbd, domid, 0); +xfb = xen_find_xendev(vfb, domid, 0); +xin = xen_find_xendev(vkbd, domid, 0); if (!xfb || !xin) { if (i 256) { usleep(1); diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index a0ca0aa..95eb9d0 100644 --- a/hw/xen/Makefile.objs +++ b/hw/xen/Makefile.objs @@ -1,5 +1,5 @@ # xen backend driver support -common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o +common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o xen_frontend.o xen_pvdev.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c index b2cb22b..844f918 100644 --- a/hw/xen/xen_backend.c +++ b/hw/xen/xen_backend.c @@ -44,86 +44,11 @@ /* - */ /* public */ -XenXC xen_xc = XC_HANDLER_INITIAL_VALUE; -struct xs_handle *xenstore = NULL; const char *xen_protocol; /* private */ -static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs); static int debug = 0; -/* - */ - -int xenstore_write_str(const char *base, const char *node, const char *val) -{ -char abspath[XEN_BUFSIZE]; - -snprintf(abspath, sizeof(abspath), %s/%s, base, node); -if (!xs_write(xenstore, 0, abspath, val, strlen(val))) { -return -1; -} -return 0; -} - -char *xenstore_read_str(const char *base, const char *node) -{ -char abspath[XEN_BUFSIZE]; -unsigned int len; -char *str, *ret = NULL; - -snprintf(abspath, sizeof(abspath), %s/%s, base, node); -str = xs_read(xenstore, 0, abspath, len); -if (str != NULL) { -/* move to qemu-allocated memory to make sure - * callers can savely g_free() stuff. */ -ret = g_strdup(str); -free(str); -} -return ret; -} - -int xenstore_write_int(const char *base, const char *node, int ival) -{ -char val[12]; - -snprintf(val, sizeof(val), %d, ival); -return xenstore_write_str(base, node, val); -} - -int xenstore_write_int64(const char *base, const char *node, int64_t ival) -{ -char val[21]; - -snprintf(val, sizeof(val), %PRId64, ival); -return xenstore_write_str(base, node, val); -} - -int xenstore_read_int(const char *base, const char *node, int *ival) -{ -char *val; -int rc = -1; - -val = xenstore_read_str(base, node); -if (val 1 == sscanf(val, %d, ival)) { -rc = 0; -} -g_free(val); -return rc; -} - -int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval) -{ -char *val; -int rc = -1; - -val = xenstore_read_str(base, node); -if (val 1 == sscanf(val, %SCNu64, uval)) { -rc = 0; -} -g_free(val); -return rc; -} - int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val) { return xenstore_write_str(xendev-be, node, val); @@ -195,183 +120,6 @@ int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state) } /* - */ - -struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev) -{ -struct XenDevice *xendev; - -QTAILQ_FOREACH(xendev, xendevs, next) { -if (xendev-dom != dom) { -continue; -} -if (xendev-dev != dev) { -continue; -} -if
[Qemu-devel] [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
This patch adds infrastructure for xen front drivers living in qemu, so drivers don't need to implement common stuff on their own. It's mostly xenbus management stuff: some functions to access XenStore, setting up XenStore watches, callbacks on device discovery and state changes, and handle event channel between the virtual machines. Call xen_fe_register() function to register XenDevOps, and make sure, [...] 3 = [...] device = (frontend device, the backend is running in QEMU/.etc) vkbd = [...] vif = [...] .. (QEMU) xen_vtpmdev_ops is initialized with the following process: xen_hvm_init() [...] --xen_fe_register(vtpm, ...) --xenstore_fe_scan() --xen_fe_try_init(ops) -- XenDevOps.init() --xen_fe_get_xendev() -- XenDevOps.alloc() --xen_fe_check() --xen_fe_try_initialise() -- XenDevOps.initialise() --xen_fe_try_connected() -- XenDevOps.connected() --xs_watch() [...] Signed-off-by: Quan Xu quan...@intel.com --Changes in v6: -Replace buf_size with PAGE_SIZE and use length rather than shr-length. --- hw/tpm/Makefile.objs | 1 + hw/tpm/xen_vtpm_frontend.c | 315 +++ hw/xen/xen_frontend.c| 20 +++ include/hw/xen/xen_backend.h | 5 + include/hw/xen/xen_common.h | 6 + xen-hvm.c| 5 + 6 files changed, 352 insertions(+) create mode 100644 hw/tpm/xen_vtpm_frontend.c diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index 99f5983..57919fa 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,2 +1,3 @@ common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c new file mode 100644 index 000..d6e7cc6 --- /dev/null +++ b/hw/tpm/xen_vtpm_frontend.c @@ -0,0 +1,315 @@ +/* + * Connect to Xen vTPM stubdom domain + * + * Copyright (c) 2015 Intel Corporation + * Authors: + *Quan Xu quan...@intel.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see http://www.gnu.org/licenses/ + */ + +#include stdio.h +#include stdlib.h +#include stdarg.h +#include string.h +#include unistd.h +#include signal.h +#include inttypes.h +#include time.h +#include fcntl.h +#include errno.h +#include sys/ioctl.h +#include sys/types.h +#include sys/stat.h +#include sys/mman.h +#include sys/uio.h + +#include hw/hw.h +#include block/aio.h +#include hw/xen/xen_backend.h + +#ifndef XS_STUBDOM_VTPM_ENABLE +#define XS_STUBDOM_VTPM_ENABLE1 +#endif + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +enum tpmif_state { +/* No contents, vTPM idle, cancel complete */ +TPMIF_STATE_IDLE, +/* Request ready or vTPM working */ +TPMIF_STATE_SUBMIT, +/* Response ready or vTPM idle */ +TPMIF_STATE_FINISH, +/* Cancel requested or vTPM working */ +TPMIF_STATE_CANCEL, +}; + +static AioContext *vtpm_aio_ctx; + +enum status_bits { +VTPM_STATUS_RUNNING = 0x1, +VTPM_STATUS_IDLE = 0x2, +VTPM_STATUS_RESULT = 0x4, +VTPM_STATUS_CANCELED = 0x8, +}; + +struct tpmif_shared_page { +/* Request and response length in bytes */ +uint32_t length; +/* Enum tpmif_state */ +uint8_t state; +/* For the current request */ +uint8_t locality; +/* Should be zero */ +uint8_t pad; +/* Extra pages for long packets; may be zero */ +uint8_t nr_extra_pages; +/* + * Grant IDs, the length is actually nr_extra_pages. + * beyond the extra_pages entries is the actual request + * and response. + */ +uint32_t extra_pages[0]; +}; + +struct xen_vtpm_dev { +struct XenDevice xendev; /* must be first */ +struct tpmif_shared_page *shr; +xc_gntshr*xen_xcs; +int ring_ref; +int bedomid; +QEMUBH *sr_bh; +}; + +static uint8_t vtpm_status(struct xen_vtpm_dev *vtpmdev) +{ +switch (vtpmdev-shr-state) { +case TPMIF_STATE_IDLE: +case TPMIF_STATE_FINISH: +return VTPM_STATUS_IDLE; +case TPMIF_STATE_SUBMIT: +case TPMIF_STATE_CANCEL: +return VTPM_STATUS_RUNNING; +default: +return 0; +} +} + +static bool
[Qemu-devel] [PATCH v6 6/6] Qemu-Xen-vTPM: QEMU machine class is initialized before tpm_init()
make sure QEMU machine class is initialized and QEMU has registered Xen stubdom vTPM driver when call tpm_init() Signed-off-by: Quan Xu quan...@intel.com Reviewed-by: Stefan Berger stef...@linux.vnet.ibm.com --- vl.c | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/vl.c b/vl.c index 74c2681..7bc87f1 100644 --- a/vl.c +++ b/vl.c @@ -4131,12 +4131,6 @@ int main(int argc, char **argv, char **envp) exit(1); } -#ifdef CONFIG_TPM -if (tpm_init() 0) { -exit(1); -} -#endif - /* init the bluetooth world */ if (foreach_device_config(DEV_BT, bt_parse)) exit(1); @@ -4239,6 +4233,17 @@ int main(int argc, char **argv, char **envp) exit(1); } +/* + * For compatible with Xen stubdom vTPM driver, make + * sure QEMU machine class is initialized and QEMU has + * registered Xen stubdom vTPM driver. + */ +#ifdef CONFIG_TPM +if (tpm_init() 0) { +exit(1); +} +#endif + /* init generic devices */ if (qemu_opts_foreach(qemu_find_opts(device), device_init_func, NULL, 1) != 0) exit(1); -- 1.8.3.2
Re: [Qemu-devel] Comparison of virtual disks?
On 04/05/2015 13:14, Max Reitz wrote: I'm sorry, but I don't know whether such a chart exists (the closest thing I know is http://en.wikipedia.org/wiki/Category:Disk_images - which is not very close...). However, the general assumption we as developers are working with is that if the user's top priority is performance, they should use raw; and if they want to use all of the features qemu's block layer provides, they should use qcow2. All other formats are implemented merely for compatibility and ideally they should not be used for running VMs, but only for converting them to qcow2 using qemu-img convert. In addition to this, there are a bunch of image formats that have good read performance: I can think of vhdx, vmdk, vdi. These can be used as backing images for qcow2, for example the virt-v2v tool uses this trick to convert Hyper-V and VMware images without copying them first. Paolo
Re: [Qemu-devel] [Qemu-block] [PATCH v3 0/9] ahci: enable migration
Am 30.04.2015 um 20:07 hat John Snow geschrieben: The day we all feared is here, and I am proposing we allow the migration of the AHCI device tentatively for the 2.4 development window. There are some more NCQ migration tests are needed, but I felt that it was important to get migration enabled as close to the start of the 2.4 development window as possible. If the NCQ patches don't pan out by the time the 2.4 freeze occurs, we can revert the migration boolean and add a conditional around the ahci tests that rely on the migration feature being enabled. I am justifying this checkin based on a series of ping-pong migration tests I ran under heavy load (using google's stressapptest) and saw over 300 successful migrations without a single failure. This series does a few things: (1) Add migration facilities to libqos (2) Enable AHCI and ICH9 migration (3) Add a series of migration tests to ahci-test Reviewed-by: Kevin Wolf kw...@redhat.com I think besides the NCQ tests, we'll definitely also want to test migration with READ DMA in flight (this series tests only WRITE DMA and FLUSH CACHE). Probably also discard. Nice to have, but less important, would be the other variants that exist, like the EXT version of each command, and READ/WRITE SECTOR. But all of that can be added in a follow-up series, it's not a reason to hold up what's already there. Kevin
[Qemu-devel] [RFC v2 0/4] VFIO Platform device featuring IRQ forwarding
This series adds IRQ forwarding support in the VFIO platform device. The VFIO platform device uses the KVM-VFIO device to enable IRQ forwarding. Dependency List: - QEMU KVM platform device passthrough and its dependencies see https://lists.gnu.org/archive/html/qemu-devel/2015-04/msg04379.html - kernel forwarding series: see (https://www.mail-archive.com/kvm@vger.kernel.org/msg115253.html) Repos: - QEMU pieces can be found at: http://git.linaro.org/people/eric.auger/qemu.git (branch vfio_integ_v15_fwd) - kernel pieces can be found at: http://git.linaro.org/people/eric.auger/linux.git (branch 4.1-rc1_forward) The patch series was tested on Calxeda Midway (ARMv7) where one xgmac is assigned to KVM host while the second one is assigned to the guest. Reworked PCI device is not tested. Wiki for Calxeda Midway setup: https://wiki.linaro.org/LEG/Engineering/Virtualization/Platform_Device_Passthrough_on_Midway History: v1 - v2: - update following x introduction of kvm qemu_irq/gsi hash table x new irq connect notifier x 2 stage eventfd/irqfd setup which complexifies irq forwarding setup v1: - that code originally was in KVM platform device passthrough series (v8), now moved in a separate RFC since dependent on many RFCs. Best Regards Eric Eric Auger (4): linux-headers: Update KVM header for KVM-VFIO FORWARD/UNFORWARD hw/vfio/common: vfio_kvm_device_fd moved in the common header kvm: add kvm_vfio_get_device_irq hw/vfio/platform: add forwarded irq support hw/vfio/common.c| 2 +- hw/vfio/platform.c | 103 +--- include/hw/vfio/vfio-common.h | 4 ++ include/hw/vfio/vfio-platform.h | 3 ++ include/sysemu/kvm.h| 5 ++ kvm-all.c | 32 + linux-headers/linux/kvm.h | 12 + trace-events| 1 + 8 files changed, 154 insertions(+), 8 deletions(-) -- 1.8.3.2
[Qemu-devel] [RFC v2 3/4] kvm: add kvm_vfio_get_device_irq
Since the introduction of the qemu_irq/gsi hash table in kvm, the gsi information is stored in kvm. New functions are introduced to allocate/populate a kvm_vfio_dev_irq struct pointer from a qemu_irq object and free it. Signed-off-by: Eric Auger eric.au...@linaro.org --- include/sysemu/kvm.h | 5 + kvm-all.c| 32 2 files changed, 37 insertions(+) diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index bc3f230..42cc6c4 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -423,6 +423,11 @@ int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, qemu_irq irq); void kvm_irqchip_set_qemuirq_gsi(KVMState *s, qemu_irq irq, int gsi); +struct kvm_vfio_dev_irq; +int kvm_vfio_get_device_irq(KVMState *s, int fd, int index, +int start, int count, qemu_irq irq, +struct kvm_vfio_dev_irq **vfio_dev_irq); +void kvm_vfio_put_device_irq(struct kvm_vfio_dev_irq *vfio_dev_irq); void kvm_pc_gsi_handler(void *opaque, int n, int level); void kvm_pc_setup_irq_routing(bool pci_enabled); void kvm_init_irq_routing(KVMState *s); diff --git a/kvm-all.c b/kvm-all.c index d2cb7ed..83a9689 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1454,6 +1454,38 @@ static int kvm_irqchip_create(MachineState *machine, KVMState *s) return 0; } +int kvm_vfio_get_device_irq(KVMState *s, int fd, int index, +int start, int count, qemu_irq irq, +struct kvm_vfio_dev_irq **vfio_dev_irq) +{ +gpointer key, gsi; +gboolean found = g_hash_table_lookup_extended(s-gsimap, irq, key, gsi); +struct kvm_vfio_dev_irq *pirq; +__u32 *pgsi; +int argsz; + +if (!found) { +return -ENXIO; +} + +argsz = sizeof(*pirq) + sizeof(*pgsi); +pirq = g_malloc0(argsz); +pirq-argsz = argsz; +pirq-fd = fd; +pirq-index = index; +pirq-start = start; +pirq-count = count; +pgsi = (__u32 *)pirq-gsi; +*pgsi = GPOINTER_TO_INT(gsi); +*vfio_dev_irq = pirq; +return 0; +} + +void kvm_vfio_put_device_irq(struct kvm_vfio_dev_irq *vfio_dev_irq) +{ +g_free(vfio_dev_irq); +} + /* Find number of supported CPUs using the recommended * procedure from the kernel API documentation to cope with * older kernels that may be missing capabilities. -- 1.8.3.2
[Qemu-devel] [RFC v2 4/4] hw/vfio/platform: add forwarded irq support
Tests whether the forwarded IRQ modality is available. In the positive device IRQs are forwarded. This control is achieved with KVM-VFIO device. with such a modality injection still is handled through irqfds. However end of interrupt is not trapped anymore. As soon as the guest completes its virtual IRQ, the corresponding physical IRQ is completed and the same physical IRQ can hit again. A new x-forward property enables to force forwarding off although enabled by the kernel. Signed-off-by: Eric Auger eric.au...@linaro.org --- v1 - v2: - use kvm_vfio_get|put_device_irq, new irq connect notifier and integrate with 2 stage eventfd/irqfd setup v1: - moved in a separate series v8 - v9 (KVM platform device passthrough series): - use new kvm_vfio_dev_irq struct Signed-off-by: Eric Auger eric.au...@linaro.org --- hw/vfio/platform.c | 103 +--- include/hw/vfio/vfio-platform.h | 3 ++ trace-events| 1 + 3 files changed, 100 insertions(+), 7 deletions(-) diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index 901b98e..52c6d59 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -411,6 +411,88 @@ fail_irqfd: return; } +/* + * Functions used with forwarding capability + */ + +static bool has_kvm_vfio_forward_capability(void) +{ +struct kvm_device_attr attr = { + .group = KVM_DEV_VFIO_DEVICE, + .attr = KVM_DEV_VFIO_DEVICE_FORWARD_IRQ}; + +if (ioctl(vfio_kvm_device_fd, KVM_HAS_DEVICE_ATTR, attr) == 0) { +return true; +} else { +return false; +} +} + +static void vfio_start_forward_injection(SysBusDevice *sbdev, qemu_irq irq) +{ +VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev); +VFIOINTp *intp; +bool found = false; +struct kvm_device_attr attr = { + .group = KVM_DEV_VFIO_DEVICE, + .attr = KVM_DEV_VFIO_DEVICE_FORWARD_IRQ}; + +QLIST_FOREACH(intp, vdev-intp_list, next) { +if (intp-qemuirq == irq) { +found = true; +break; +} +} +assert(found); + +if (intp-forwarded) { +return; +} + +/* + * stop VFIO signaling and unmask the physical IRQ since + * forwarding cannot be set if the IRQ is active or vfio masked + */ +vfio_disable_irqindex(intp-vdev-vbasedev, intp-pin); +vfio_unmask_single_irqindex(intp-vdev-vbasedev, intp-pin); + +kvm_vfio_get_device_irq(kvm_state, intp-vdev-vbasedev.fd, +intp-pin, 0, 1, intp-qemuirq, intp-fwd_irq); + +attr.addr = (uint64_t)(unsigned long)intp-fwd_irq; + +if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, attr) 0) { +error_report(vfio: failed to forward irq %d, do standard irqfd, + intp-pin); +kvm_vfio_put_device_irq(intp-fwd_irq); +} else { +trace_vfio_platform_start_fwd_injection(intp-pin); +intp-forwarded = true; +} + +if (kvm_irqchip_add_irqfd_notifier(kvm_state, intp-interrupt, + intp-unmask, irq) 0) { +goto fail_irqfd; +} + +if (vfio_set_trigger_eventfd(intp, NULL) 0) { +goto fail_vfio; +} +/* only used if forwarding setup failed */ +if (vfio_set_resample_eventfd(intp) 0) { +goto fail_vfio; +} + +intp-kvm_accel = true; +return; +fail_vfio: +kvm_irqchip_remove_irqfd_notifier(kvm_state, intp-interrupt, irq); +fail_irqfd: +vfio_start_eventfd_injection(intp); +vfio_unmask_single_irqindex(vdev-vbasedev, intp-pin); +return; +} + #endif /* CONFIG_KVM */ /* VFIO skeleton */ @@ -655,13 +737,6 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp) vbasedev-type = VFIO_DEVICE_TYPE_PLATFORM; vbasedev-ops = vfio_platform_ops; -#ifdef CONFIG_KVM -if (kvm_irqfds_enabled() kvm_resamplefds_enabled() -vdev-irqfd_allowed) { -sbc-connect_irq_notifier = vfio_start_irqfd_injection; -} -#endif - trace_vfio_platform_realize(vbasedev-name, vdev-compat); ret = vfio_base_device_init(vbasedev); @@ -679,6 +754,19 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp) QLIST_FOREACH(intp, vdev-intp_list, next) { vfio_start_eventfd_injection(intp); } + +#ifdef CONFIG_KVM +if (kvm_irqfds_enabled() kvm_resamplefds_enabled() +vdev-irqfd_allowed) { +if (has_kvm_vfio_forward_capability() + vdev-forward_allowed) { +sbc-connect_irq_notifier = vfio_start_forward_injection; +} else { +sbc-connect_irq_notifier = vfio_start_irqfd_injection; +} +} +#endif + } static const VMStateDescription vfio_platform_vmstate = { @@ -692,6 +780,7 @@ static Property vfio_platform_dev_properties[] = { DEFINE_PROP_UINT32(mmap-timeout-ms, VFIOPlatformDevice, mmap_timeout, 1100), DEFINE_PROP_BOOL(x-irqfd, VFIOPlatformDevice, irqfd_allowed, true),
[Qemu-devel] [RFC v2 1/4] linux-headers: Update KVM header for KVM-VFIO FORWARD/UNFORWARD
Integrate updated KVM-VFIO API related to forwarded IRQ Update the kvm header according to the header found in http://git.linaro.org/people/eric.auger/linux.git branch 4.1-rc1_forward Signed-off-by: Eric Auger eric.au...@linaro.org --- linux-headers/linux/kvm.h | 12 1 file changed, 12 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index b96d978..95fea92 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -999,6 +999,9 @@ struct kvm_device_attr { #define KVM_DEV_VFIO_GROUP1 #define KVM_DEV_VFIO_GROUP_ADD 1 #define KVM_DEV_VFIO_GROUP_DEL 2 +#define KVM_DEV_VFIO_DEVICE 2 +#define KVM_DEV_VFIO_DEVICE_FORWARD_IRQ 1 +#define KVM_DEV_VFIO_DEVICE_UNFORWARD_IRQ2 enum kvm_device_type { KVM_DEV_TYPE_FSL_MPIC_20= 1, @@ -1018,6 +1021,15 @@ enum kvm_device_type { KVM_DEV_TYPE_MAX, }; +struct kvm_vfio_dev_irq { + __u32 argsz; /* structure length */ + __u32 fd; /* file descriptor of the VFIO device */ + __u32 index; /* VFIO device IRQ index */ + __u32 start; /* start of subindex range */ + __u32 count; /* size of subindex range */ + __u32 gsi[]; /* gsi, ie. virtual IRQ number */ +}; + /* * ioctls for VM fds */ -- 1.8.3.2
[Qemu-devel] [RFC v2 2/4] hw/vfio/common: vfio_kvm_device_fd moved in the common header
the device is now used in platform for forwarded IRQ setup Signed-off-by: Eric Auger eric.au...@linaro.org --- hw/vfio/common.c | 2 +- include/hw/vfio/vfio-common.h | 4 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index b012620..18ad67c 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -44,7 +44,7 @@ struct vfio_as_head vfio_address_spaces = * initialized, this file descriptor is only released on QEMU exit and * we'll re-use it should another vfio device be attached before then. */ -static int vfio_kvm_device_fd = -1; +int vfio_kvm_device_fd = -1; #endif /* diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 59a321d..53d0e68 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -40,6 +40,10 @@ #define VFIO_ALLOW_KVM_MSI 1 #define VFIO_ALLOW_KVM_MSIX 1 +#ifdef CONFIG_KVM +extern int vfio_kvm_device_fd; +#endif + enum { VFIO_DEVICE_TYPE_PCI = 0, VFIO_DEVICE_TYPE_PLATFORM = 1, -- 1.8.3.2
Re: [Qemu-devel] [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
I find out the subject is wrong in v5/v6. Just update the subject as below. Subject: [PATCH v6 3/6] Qemu-Xen-vTPM: Register Xen stubdom vTPM frontend driver This drvier transfers any request/repond between TPM xenstubdoms driver and Xen vTPM stubdom, and facilitates communications between Xen vTPM stubdom domain and vTPM xenstubdoms driver. It is a glue for the TPM xenstubdoms driver and Xen stubdom vTPM domain that provides the actual TPM functionality. (Xen) Xen backend driver should run before running this frontend, and initialize XenStore as the following for communication. [XenStore] for example: Domain 0: runs QEMU for guest A Domain 1: vtpmmgr Domain 2: vTPM for guest A Domain 3: HVM guest A [...] local = domain = 0 = frontend = vtpm = 2 = 0 = backend = /local/domain/2/backend/vtpm/0/0 backend-id = 2 state = * handle = 0 domain = Domain3's name ring-ref = * event-channel = * feature-protocol-v2 = 1 backend = qdisk = [...] console = vif = [...] 2 = [...] backend = vtpm = 0 = 0 = frontend = /local/domain/0/frontend/vtpm/2/0 frontend-id = 0 ('0', frontend is running in Domain-0) [...] 3 = [...] device = (frontend device, the backend is running in QEMU/.etc) vkbd = [...] vif = [...] .. (QEMU) xen_vtpmdev_ops is initialized with the following process: xen_hvm_init() [...] --xen_fe_register(vtpm, ...) --xenstore_fe_scan() --xen_fe_try_init(ops) -- XenDevOps.init() --xen_fe_get_xendev() -- XenDevOps.alloc() --xen_fe_check() --xen_fe_try_initialise() -- XenDevOps.initialise() --xen_fe_try_connected() -- XenDevOps.connected() --xs_watch() [...] -Quan -Original Message- From: Xu, Quan Sent: Monday, May 04, 2015 3:23 PM To: stefano.stabell...@eu.citrix.com; stef...@linux.vnet.ibm.com; ebl...@redhat.com Cc: qemu-devel@nongnu.org; wei.l...@citrix.com; dgde...@tycho.nsa.gov; xen-de...@lists.xen.org; Xu, Quan Subject: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure This patch adds infrastructure for xen front drivers living in qemu, so drivers don't need to implement common stuff on their own. It's mostly xenbus management stuff: some functions to access XenStore, setting up XenStore watches, callbacks on device discovery and state changes, and handle event channel between the virtual machines. Call xen_fe_register() function to register XenDevOps, and make sure, [...] 3 = [...] device = (frontend device, the backend is running in QEMU/.etc) vkbd = [...] vif = [...] .. (QEMU) xen_vtpmdev_ops is initialized with the following process: xen_hvm_init() [...] --xen_fe_register(vtpm, ...) --xenstore_fe_scan() --xen_fe_try_init(ops) -- XenDevOps.init() --xen_fe_get_xendev() -- XenDevOps.alloc() --xen_fe_check() --xen_fe_try_initialise() -- XenDevOps.initialise() --xen_fe_try_connected() -- XenDevOps.connected() --xs_watch() [...] Signed-off-by: Quan Xu quan...@intel.com --Changes in v6: -Replace buf_size with PAGE_SIZE and use length rather than shr-length. --- hw/tpm/Makefile.objs | 1 + hw/tpm/xen_vtpm_frontend.c | 315 +++ hw/xen/xen_frontend.c| 20 +++ include/hw/xen/xen_backend.h | 5 + include/hw/xen/xen_common.h | 6 + xen-hvm.c| 5 + 6 files changed, 352 insertions(+) create mode 100644 hw/tpm/xen_vtpm_frontend.c diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index 99f5983..57919fa 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,2 +1,3 @@ common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c new file mode 100644 index 000..d6e7cc6 --- /dev/null +++ b/hw/tpm/xen_vtpm_frontend.c @@ -0,0 +1,315 @@ +/* + * Connect to Xen vTPM stubdom domain + * + * Copyright (c) 2015 Intel Corporation + * Authors: + *Quan Xu quan...@intel.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + *
Re: [Qemu-devel] [PATCH v5 06/20] hw/arm/virt-acpi-build: Generation of DSDT table for virt devices
On Mon, 04 May 2015 19:11:39 +0800 Shannon Zhao shannon.z...@linaro.org wrote: On 2015/5/4 17:58, Igor Mammedov wrote: On Wed, 15 Apr 2015 21:24:55 +0800 Shannon Zhao zhaoshengl...@huawei.com wrote: From: Shannon Zhao shannon.z...@linaro.org DSDT consists of the usual common table header plus a definition block in AML encoding which describes all devices in the platform. After initializing DSDT with header information the namespace is created which is followed by the device encodings. The devices are described using the Resource Template for the 32-Bit Fixed Memory Range and the Extended Interrupt Descriptors. Signed-off-by: Shannon Zhao zhaoshengl...@huawei.com Signed-off-by: Shannon Zhao shannon.z...@linaro.org --- hw/arm/virt-acpi-build.c | 128 +++ 1 file changed, 128 insertions(+) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index c5a3cf9..d044880 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -50,6 +50,130 @@ #include qom/qom-qobject.h #include exec/ram_addr.h +static void acpi_dsdt_add_cpus(Aml *scope, int max_cpus) +{ +uint16_t i; + +for (i = 0; i max_cpus; i++) { +Aml *dev = aml_device(C%03x, i); +aml_append(dev, aml_name_decl(_HID, aml_string(ACPI0007))); +aml_append(dev, aml_name_decl(_UID, aml_int(i))); +Aml *crs = aml_resource_template(); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} +} Is maxcpus a correct here? Usually maxcpus includes non present CPUs as well but there is no STA method that tells whether it's present or not. 5.2.12.14 GICC Structure In the GICC interrupt model, logical processors are required to have a Processor Device object in the DSDT Here we create Processor Device object for all possible CPUs and in MADT the gicc-flags tells whether it's present or not. And this flags is for kernel booting initialization, not for dynamic configuration. BTW, ARM doesn't support vCPU hotplug now. If we want to support hotplug later, we should add _STA method for each Processor. lack of _STA in current code implicitly means present, while flag in MADT could say not present. Since currently cpu hotplug is not supported for ARM, pls use smp_cpus instead of max_cpus and create only device objects and MADT entries only for present CPUs. + +static void acpi_dsdt_add_uart(Aml *scope, const MemMap *uart_memmap, + const int *uart_irq) +{ +Aml *dev = aml_device(COM0); +aml_append(dev, aml_name_decl(_HID, aml_string(ARMH0011))); +aml_append(dev, aml_name_decl(_UID, aml_int(0))); + +Aml *crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(uart_memmap-addr, + uart_memmap-size, aml_ReadWrite)); +aml_append(crs, + aml_interrupt(aml_consumer, aml_level, aml_active_high, + aml_exclusive, aml_not_wake_capable, *uart_irq + 32)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} + +static void acpi_dsdt_add_rtc(Aml *scope, const MemMap *rtc_memmap, + const int *rtc_irq) +{ +Aml *dev = aml_device(RTC0); +aml_append(dev, aml_name_decl(_HID, aml_string(LNRO0013))); +aml_append(dev, aml_name_decl(_UID, aml_int(0))); + +Aml *crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(rtc_memmap-addr, + rtc_memmap-size, aml_ReadWrite)); +aml_append(crs, + aml_interrupt(aml_consumer, aml_level, aml_active_high, + aml_exclusive, aml_not_wake_capable, *rtc_irq + 32)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} + +static void acpi_dsdt_add_flash(Aml *scope, const MemMap *flash_memmap) +{ +Aml *dev, *crs; +hwaddr base = flash_memmap-addr; +hwaddr size = flash_memmap-size; + +dev = aml_device(FLS0); +aml_append(dev, aml_name_decl(_HID, aml_string(LNRO0015))); +aml_append(dev, aml_name_decl(_UID, aml_int(0))); + +crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(base, size, aml_ReadWrite)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); + +dev = aml_device(FLS1); +aml_append(dev, aml_name_decl(_HID, aml_string(LNRO0015))); +aml_append(dev, aml_name_decl(_UID, aml_int(1))); +crs = aml_resource_template(); +aml_append(crs, aml_memory32_fixed(base + size, size, aml_ReadWrite)); +aml_append(dev, aml_name_decl(_CRS, crs)); +aml_append(scope, dev); +} + +static void acpi_dsdt_add_virtio(Aml *scope, const MemMap *virtio_mmio_memmap, +
Re: [Qemu-devel] [PATCH] cpu: Register QOM links at /machine/cpus/index
On Mon, 04 May 2015 11:59:52 +0200 Paolo Bonzini pbonz...@redhat.com wrote: On 04/05/2015 11:47, Igor Mammedov wrote: On Thu, 30 Apr 2015 16:19:07 -0300 Eduardo Habkost ehabk...@redhat.com wrote: This will provide a predictable path for the CPU objects, and a more powerful alternative for the query-cpus QMP command, as now every QOM property on CPU objects can be easily queried. provided the way cpu_index is generated, path won't be predictable/stable with CPU unplug. I'd rather use DEVICE-id instead of cpu_index. Can we use the APIC id then? Perhaps wrapped with a CPUState-level method get_stable_processor_id()? We have CPUClass-get_arch_id() which results in APIC id for target-i386. But I'd rather see an arbitrary DEVICE-id as index/name, that way when -device cpu-foo,id=cpuXXX becomes functional we would have 1:1 mapping between CLI and /machine/cpus/ view. Paolo
Re: [Qemu-devel] [PATCH] cpu: Register QOM links at /machine/cpus/index
On 04/05/2015 15:16, Igor Mammedov wrote: Can we use the APIC id then? Perhaps wrapped with a CPUState-level method get_stable_processor_id()? We have CPUClass-get_arch_id() which results in APIC id for target-i386. But I'd rather see an arbitrary DEVICE-id as index/name, that way when -device cpu-foo,id=cpuXXX becomes functional we would have 1:1 mapping between CLI and /machine/cpus/ view. CPUs would already be available at /machine/peripheral. I think aliases should provide alternative indexing whenever possible---not simply filter by device type. Paolo
Re: [Qemu-devel] [PATCH] cpu: Register QOM links at /machine/cpus/index
On Mon, May 04, 2015 at 03:16:16PM +0200, Igor Mammedov wrote: On Mon, 04 May 2015 11:59:52 +0200 Paolo Bonzini pbonz...@redhat.com wrote: On 04/05/2015 11:47, Igor Mammedov wrote: On Thu, 30 Apr 2015 16:19:07 -0300 Eduardo Habkost ehabk...@redhat.com wrote: This will provide a predictable path for the CPU objects, and a more powerful alternative for the query-cpus QMP command, as now every QOM property on CPU objects can be easily queried. provided the way cpu_index is generated, path won't be predictable/stable with CPU unplug. I'd rather use DEVICE-id instead of cpu_index. Can we use the APIC id then? Perhaps wrapped with a CPUState-level method get_stable_processor_id()? We have CPUClass-get_arch_id() which results in APIC id for target-i386. But I'd rather see an arbitrary DEVICE-id as index/name, that way when -device cpu-foo,id=cpuXXX becomes functional we would have 1:1 mapping between CLI and /machine/cpus/ view. An arbitrary device ID sounds better to me, because it allows us to change guest-visible behavior without breaking QMP client expectations. The only question is what should be the default device ID for the CPUs created by -smp and cpu-add. I was going to suggest get_arch_id(), but cpu_index may be a better candidate for the same reason above: it is truly an arbitrary ID that doesn't depend on guest-visible bits. -- Eduardo
Re: [Qemu-devel] [PATCH 1/1] vl.c: Since the help says that 'disk_image' is a raw hard disk image, pass format=raw
Kevin Wolf kw...@redhat.com writes: Am 01.05.2015 um 01:28 hat Don Slutz geschrieben: [...] So do you want a more complex patch that allows the format to be specified? Only for 'disk_image'? Include -hd* ? I'm afraid that there is no nice way to improve the plain 'disk_image' case. You would have to add another option, and then it's not any better than -hda and friends any more. -hda in turn could be extended to take additional options (i.e. it becomes something like -drive with implied index=0), but then there's little reason not to use -drive. Would likely break images with ',' in their name. [...]
[Qemu-devel] [PATCH 1/2] block: minimal bounce buffer alignment
The patch introduces new concept: minimal memory alignment for bounce buffers. Original so called optimal value is actually minimal required value for aligment. It should be used for validation that the IOVec is properly aligned and bounce buffer is not required. Though, from the performance point of view, it would be better if bounce buffer or IOVec allocated by QEMU will be aligned stricter. The patch does not change any alignment value yet. Signed-off-by: Denis V. Lunev d...@openvz.org CC: Paolo Bonzini pbonz...@redhat.com CC: Kevin Wolf kw...@redhat.com CC: Stefan Hajnoczi stefa...@redhat.com --- block.c | 11 +++ block/io.c| 7 ++- block/raw-posix.c | 1 + include/block/block.h | 2 ++ include/block/block_int.h | 3 +++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index 7904098..e293907 100644 --- a/block.c +++ b/block.c @@ -113,6 +113,16 @@ size_t bdrv_opt_mem_align(BlockDriverState *bs) return bs-bl.opt_mem_alignment; } +size_t bdrv_min_mem_align(BlockDriverState *bs) +{ +if (!bs || !bs-drv) { +/* 4k should be on the safe side */ +return 4096; +} + +return bs-bl.min_mem_alignment; +} + /* check if the path starts with protocol: */ int path_has_protocol(const char *path) { @@ -890,6 +900,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, } assert(bdrv_opt_mem_align(bs) != 0); +assert(bdrv_min_mem_align(bs) != 0); assert((bs-request_alignment != 0) || bs-sg); return 0; diff --git a/block/io.c b/block/io.c index 1ce62c4..908a3d1 100644 --- a/block/io.c +++ b/block/io.c @@ -201,8 +201,10 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) } bs-bl.opt_transfer_length = bs-file-bl.opt_transfer_length; bs-bl.max_transfer_length = bs-file-bl.max_transfer_length; +bs-bl.min_mem_alignment = bs-file-bl.min_mem_alignment; bs-bl.opt_mem_alignment = bs-file-bl.opt_mem_alignment; } else { +bs-bl.min_mem_alignment = 512; bs-bl.opt_mem_alignment = 512; } @@ -221,6 +223,9 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) bs-bl.opt_mem_alignment = MAX(bs-bl.opt_mem_alignment, bs-backing_hd-bl.opt_mem_alignment); +bs-bl.min_mem_alignment = +MAX(bs-bl.min_mem_alignment, +bs-backing_hd-bl.min_mem_alignment); } /* Then let the driver override it */ @@ -2489,7 +2494,7 @@ void *qemu_try_blockalign0(BlockDriverState *bs, size_t size) bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) { int i; -size_t alignment = bdrv_opt_mem_align(bs); +size_t alignment = bdrv_min_mem_align(bs); for (i = 0; i qiov-niov; i++) { if ((uintptr_t) qiov-iov[i].iov_base % alignment) { diff --git a/block/raw-posix.c b/block/raw-posix.c index 24d8582..7083924 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -725,6 +725,7 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) BDRVRawState *s = bs-opaque; raw_probe_alignment(bs, s-fd, errp); +bs-bl.min_mem_alignment = s-buf_align; bs-bl.opt_mem_alignment = s-buf_align; } diff --git a/include/block/block.h b/include/block/block.h index 7d1a717..c1c963e 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -440,6 +440,8 @@ void bdrv_img_create(const char *filename, const char *fmt, /* Returns the alignment in bytes that is required so that no bounce buffer * is required throughout the stack */ +size_t bdrv_min_mem_align(BlockDriverState *bs); +/* Returns optimal alignment in bytes for bounce buffer */ size_t bdrv_opt_mem_align(BlockDriverState *bs); void bdrv_set_guest_block_size(BlockDriverState *bs, int align); void *qemu_blockalign(BlockDriverState *bs, size_t size); diff --git a/include/block/block_int.h b/include/block/block_int.h index db29b74..f004378 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -313,6 +313,9 @@ typedef struct BlockLimits { int max_transfer_length; /* memory alignment so that no bounce buffer is needed */ +size_t min_mem_alignment; + +/* memory alignment for bounce buffer */ size_t opt_mem_alignment; } BlockLimits; -- 1.9.1
[Qemu-devel] [PATCH v5 0/2] block: enforce minimal 4096 alignment in qemu_blockalign
The following sequence int fd = open(argv[1], O_RDWR | O_CREAT | O_DIRECT, 0644); for (i = 0; i 10; i++) write(fd, buf, 4096); iperforms 5% better if buf is aligned to 4096 bytes rather then to 512 bytes. I have used the following program to test #define _GNU_SOURCE #include stdio.h #include unistd.h #include fcntl.h #include sys/types.h #include malloc.h #include string.h int main(int argc, char *argv[]) { int fd = open(argv[1], O_RDWR | O_CREAT | O_DIRECT, 0644); void *buf; int i = 0, align = atoi(argv[2]); do { buf = memalign(align, 4096); if (align = 4096) break; if ((unsigned long)buf 4095) break; i++; } while (1); printf(%d %p\n, i, buf); memset(buf, 0x11, 4096); for (i = 0; i 10; i++) { lseek(fd, SEEK_CUR, 4096); write(fd, buf, 4096); } close(fd); return 0; } for in in `seq 1 30` ; do a.out aa ; done The file was placed into 8 GB partition on HDD below to avoid speed change due to different offset on disk. Results are reliable: - 189 vs 180 seconds on Linux 3.16 The following setups have been tested: 1) ext4 with block size equals to 1024 over 512/512 physical/logical sector size SSD disk 2) ext4 with block size equals to 4096 over 512/512 physical/logical sector size SSD disk 3) ext4 with block size equals to 4096 over 512/4096 physical/logical sector size rotational disk (WDC WD20EZRX) 4) xfs with block size equals to 4096 over 512/512 physical/logical sector size SSD disk The difference is quite reliable and the same 5%. qemu-io -n -c 'write -P 0xaa 0 1G' 1.img for image in qcow2 format is 1% faster. Changes from v4: - patches reordered - dropped conversion from 512 to BDRV_SECTOR_SIZE - getpagesize() is replaced with MAX(4096, getpagesize()) as suggested by Kevin Changes from v3: - portable way to calculate system page size used - 512/4096 values are replaced with proper macros/values Changes from v2: - opt_mem_alignment is split to opt_mem_alignment for bounce buffering and min_mem_alignment to check buffers coming from guest. Changes from v1: - enforces 4096 alignment in qemu_(try_)blockalign, avoid touching of bdrv_qiov_is_aligned path not to enforce additional bounce buffering as suggested by Paolo - reduces 10% to 5% in patch description to better fit 180 vs 189 difference Signed-off-by: Denis V. Lunev d...@openvz.org CC: Paolo Bonzini pbonz...@redhat.com CC: Kevin Wolf kw...@redhat.com CC: Stefan Hajnoczi stefa...@redhat.com
[Qemu-devel] [PATCH 2/2] block: align bounce buffers to page
The following sequence int fd = open(argv[1], O_RDWR | O_CREAT | O_DIRECT, 0644); for (i = 0; i 10; i++) write(fd, buf, 4096); performs 5% better if buf is aligned to 4096 bytes. The difference is quite reliable. On the other hand we do not want at the moment to enforce bounce buffering if guest request is aligned to 512 bytes. The patch changes default bounce buffer optimal alignment to MAX(page size, 4k). 4k is chosen as maximal known sector size on real HDD. Signed-off-by: Denis V. Lunev d...@openvz.org CC: Paolo Bonzini pbonz...@redhat.com CC: Kevin Wolf kw...@redhat.com CC: Stefan Hajnoczi stefa...@redhat.com --- block.c | 8 block/io.c| 2 +- block/raw-posix.c | 14 -- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/block.c b/block.c index e293907..325f727 100644 --- a/block.c +++ b/block.c @@ -106,8 +106,8 @@ int is_windows_drive(const char *filename) size_t bdrv_opt_mem_align(BlockDriverState *bs) { if (!bs || !bs-drv) { -/* 4k should be on the safe side */ -return 4096; +/* page size or 4k (hdd sector size) should be on the safe side */ +return MAX(4096, getpagesize()); } return bs-bl.opt_mem_alignment; @@ -116,8 +116,8 @@ size_t bdrv_opt_mem_align(BlockDriverState *bs) size_t bdrv_min_mem_align(BlockDriverState *bs) { if (!bs || !bs-drv) { -/* 4k should be on the safe side */ -return 4096; +/* page size or 4k (hdd sector size) should be on the safe side */ +return MAX(4096, getpagesize()); } return bs-bl.min_mem_alignment; diff --git a/block/io.c b/block/io.c index 908a3d1..071652c 100644 --- a/block/io.c +++ b/block/io.c @@ -205,7 +205,7 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) bs-bl.opt_mem_alignment = bs-file-bl.opt_mem_alignment; } else { bs-bl.min_mem_alignment = 512; -bs-bl.opt_mem_alignment = 512; +bs-bl.opt_mem_alignment = getpagesize(); } if (bs-backing_hd) { diff --git a/block/raw-posix.c b/block/raw-posix.c index 7083924..04f3d4e 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -301,6 +301,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) { BDRVRawState *s = bs-opaque; char *buf; +size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize()); /* For /dev/sg devices the alignment is not really used. With buffered I/O, we don't have any restrictions. */ @@ -330,9 +331,9 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) /* If we could not get the sizes so far, we can only guess them */ if (!s-buf_align) { size_t align; -buf = qemu_memalign(MAX_BLOCKSIZE, 2 * MAX_BLOCKSIZE); -for (align = 512; align = MAX_BLOCKSIZE; align = 1) { -if (raw_is_io_aligned(fd, buf + align, MAX_BLOCKSIZE)) { +buf = qemu_memalign(max_align, 2 * max_align); +for (align = 512; align = max_align; align = 1) { +if (raw_is_io_aligned(fd, buf + align, max_align)) { s-buf_align = align; break; } @@ -342,8 +343,8 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) if (!bs-request_alignment) { size_t align; -buf = qemu_memalign(s-buf_align, MAX_BLOCKSIZE); -for (align = 512; align = MAX_BLOCKSIZE; align = 1) { +buf = qemu_memalign(s-buf_align, max_align); +for (align = 512; align = max_align; align = 1) { if (raw_is_io_aligned(fd, buf, align)) { bs-request_alignment = align; break; @@ -726,7 +727,8 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) raw_probe_alignment(bs, s-fd, errp); bs-bl.min_mem_alignment = s-buf_align; -bs-bl.opt_mem_alignment = s-buf_align; +if (bs-bl.min_mem_alignment bs-bl.opt_mem_alignment) +bs-bl.opt_mem_alignment = bs-bl.min_mem_alignment; } static int check_for_dasd(int fd) -- 1.9.1
Re: [Qemu-devel] [PATCH] coverity: fix address_space_rw model
Paolo Bonzini pbonz...@redhat.com writes: If the is_write argument is true, address_space_rw writes to memory and thus reads from the buffer. The opposite holds if is_write is false. Fix the model. Cc: Markus Armbruster arm...@redhat.com Signed-off-by: Paolo Bonzini pbonz...@redhat.com --- scripts/coverity-model.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/coverity-model.c b/scripts/coverity-model.c index 224d2d1..617f67d 100644 --- a/scripts/coverity-model.c +++ b/scripts/coverity-model.c @@ -49,7 +49,7 @@ typedef uint64_t hwaddr; typedef uint32_t MemTxResult; typedef uint64_t MemTxAttrs; -static void __write(uint8_t *buf, ssize_t len) +static void __bufwrite(uint8_t *buf, ssize_t len) { int first, last; __coverity_negative_sink__(len); @@ -59,7 +59,7 @@ static void __write(uint8_t *buf, ssize_t len) __coverity_writeall__(buf); } -static void __read(uint8_t *buf, ssize_t len) +static void __bufread(uint8_t *buf, ssize_t len) { __coverity_negative_sink__(len); if (len == 0) return; @@ -74,7 +74,7 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, // TODO: investigate impact of treating reads as producing // tainted data, with __coverity_tainted_data_argument__(buf). -if (is_write) __write(buf, len); else __read(buf, len); +if (is_write) __bufread(buf, len); else __bufwrite(buf, len); return result; } Good one :) I can take this through my tree. Thanks!
Re: [Qemu-devel] [PATCH] cpu: Register QOM links at /machine/cpus/index
On Mon, May 04, 2015 at 03:19:32PM +0200, Paolo Bonzini wrote: On 04/05/2015 15:16, Igor Mammedov wrote: Can we use the APIC id then? Perhaps wrapped with a CPUState-level method get_stable_processor_id()? We have CPUClass-get_arch_id() which results in APIC id for target-i386. But I'd rather see an arbitrary DEVICE-id as index/name, that way when -device cpu-foo,id=cpuXXX becomes functional we would have 1:1 mapping between CLI and /machine/cpus/ view. CPUs would already be available at /machine/peripheral. I think aliases should provide alternative indexing whenever possible---not simply filter by device type. Could you clarify what you mean by alternative indexing? All I am trying to provide right now is having a predictable path for CPUs, it doesn't matter if using -device, device_add, -smp, or cpu-add. Filtering by device type is not what I need, here. If we can make the CPU QOM path predictable inside /machine/peripheral or anywhere else, that would be enough to me[1]. device IDs are predictable when using -device because they are in the command-line. And they are predictable for -smp CPUs if we use cpu_index as default ID. Making the path depend on guest-visible bits that can change depending on the architeture or machine would make the path less predictable. I have an alternative patch that simply adds a qom-path field to query-cpus. If we find out that making commitments about QOM paths is too hard, I can submit it instead. [1] Is there anybody or any document that can explain to me what all the containers inside /machine mean? I see /machine/peripheral, /machine/peripheral-anon, /machine/unattached, here, and I don't know what they mean. -- Eduardo
Re: [Qemu-devel] [PATCH 1/1] vl.c: Since the help says that 'disk_image' is a raw hard disk image, pass format=raw
Am 04.05.2015 um 15:39 hat Markus Armbruster geschrieben: Kevin Wolf kw...@redhat.com writes: Am 01.05.2015 um 01:28 hat Don Slutz geschrieben: [...] So do you want a more complex patch that allows the format to be specified? Only for 'disk_image'? Include -hd* ? I'm afraid that there is no nice way to improve the plain 'disk_image' case. You would have to add another option, and then it's not any better than -hda and friends any more. -hda in turn could be extended to take additional options (i.e. it becomes something like -drive with implied index=0), but then there's little reason not to use -drive. Would likely break images with ',' in their name. A possible justification would be that -hda is a convenience option that, similar to HMP, is meant only for human users and if you use it in scripts and it changes, you get to keep both pieces. In addition, while some use cases would be affected, most of them wouldn't, even in scripts. Whether or not this justification is valid might be controversial. Kevin
Re: [Qemu-devel] [PATCH] ps2 keyboard:fix can't use ps2 keyboard if typing many times After leaving grub and before finishing linux kernel ps2 driver initialization
On 05/03/2015 10:32 AM, penghao...@sina.com wrote: Poor subject line. Please try to keep subjects under 65 characters in length (see 'git shortlog -30' for good examples). Maybe: keyboard: handle ps2 typing buffer overrun Starting a linux guest with ps2 keyboard ,if you type many times during leaving grub and into linux kernel ,then you can't use keyboard after linux initialization finished. Also, wrap your commit body messages to fit with 78 columns or so. Spacing is wrong: s/Starting a/Staring a/; s/keyboard ,if/keyboard, if/; s/kernel ,then/kernel, then/ during grub,the work method of ps2 keyboard is like this: first ,ps2 keyboard driver send command KBD_CCMD_KBD_ENABLE, second,if there is a keyboard input,then ps2 keyboard driver read data. third ,ps2 keyboard driver send command KBD_CCMD_KBD_ENABLE, Again, in English, no space before comma, but space afterwards. ... this is diffrent method of linux kernel . s/diffrent/different/; s/ ././ After leaving grub and before finishing linux kernel ps2 driver initialization,if you type many times,the input data keep saving the ps2 queue in qemu .Before linux kernel initialize ps2 keyboard,linux call i8042_init-i8042_controller_check,if i8042_controller_check return fail,then linux kernel ps2 keyboard driver will never initialize. More spacing errors; no trailing space, long line. (linux kernel 2.6.32 i8042.c) static int i8042_controller_check(void) { if (i8042_flush() == I8042_BUFFER_SIZE) return -ENODEV; return 0; } static int i8042_flush(void) {... while (((str = i8042_read_status()) I8042_STR_OBF) (i I8042_BUFFER_SIZE)) { udelay(50); data = i8042_read_data(); i++; } return i; } Indentation is weird. during calling i8042_flush it is full in qemu queue . ps_read_data: s-update_irq(s-update_arg, 0); s-update_irq(s-update_arg, q-count != 0); because q-count!=0, kbd_update_irq can set I8042_STR_OBF.Then i8042_flush() will return I8042_BUFFER_SIZE. Signed-off-by: Hao Pengpenghao...@sina.co --- ps2.c.orig 2015-04-25 09:44:38.865777168 -0400 Missing the usual '---' separator between the commit body and the patch proper; also missing the diffstat. Life is easier if you use 'git format-patch' and/or 'git send-email' to format your patch messages. More hints at: http://wiki.qemu.org/Contribute/SubmitAPatch -- Eric Blake eblake redhat com+1-919-301-3266 Libvirt virtualization library http://libvirt.org signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [RFC PATCH v3 05/24] spapr: Reorganize CPU dt generation code
On Mon, Apr 27, 2015 at 11:06:07AM +0530, Bharata B Rao wrote: On Sun, Apr 26, 2015 at 05:17:48PM +0530, Bharata B Rao wrote: On Fri, Apr 24, 2015 at 12:17:27PM +0530, Bharata B Rao wrote: Reorganize CPU device tree generation code so that it be reused from hotplug path. CPU dt entries are now generated from spapr_finalize_fdt() instead of spapr_create_fdt_skel(). Creating CPU DT entries from spapr_finalize_fdt() instead of spapr_create_fdt_skel() has an interesting side effect. snip In both the cases, I am adding CPU DT nodes from QEMU in the same order, but not sure why the guest kernel discovers them in different orders in each case. Nikunj and I tracked this down to the difference in device tree APIs that we are using in two cases. When CPU DT nodes are created from spapr_create_fdt_skel(), we are using fdt_begin_node() API which does sequential write and hence CPU DT nodes end up in the same order in which they are created. However in my patch when I create CPU DT entries in spapr_finalize_fdt(), I am using fdt_add_subnode() which ends up writing the CPU DT node at the same parent offset for all the CPUs. This results in CPU DT nodes being generated in reverse order in FDT. +static void spapr_populate_cpus_dt_node(void *fdt, sPAPREnvironment *spapr) +{ +CPUState *cs; +int cpus_offset; +char *nodename; +int smt = kvmppc_smt_threads(); + +cpus_offset = fdt_add_subnode(fdt, 0, cpus); +_FDT(cpus_offset); +_FDT((fdt_setprop_cell(fdt, cpus_offset, #address-cells, 0x1))); +_FDT((fdt_setprop_cell(fdt, cpus_offset, #size-cells, 0x0))); + +CPU_FOREACH(cs) { +PowerPCCPU *cpu = POWERPC_CPU(cs); +int index = ppc_get_vcpu_dt_id(cpu); +DeviceClass *dc = DEVICE_GET_CLASS(cs); +int offset; + +if ((index % smt) != 0) { +continue; +} + +nodename = g_strdup_printf(%s@%x, dc-fw_name, index); +offset = fdt_add_subnode(fdt, cpus_offset, nodename); +g_free(nodename); +_FDT(offset); +spapr_populate_cpu_dt(cs, fdt, offset); +} I can simply fix this by walking the CPUs in reverse order in the above code which makes the guest kernel to discover the CPU DT nodes in the right order. s/CPU_FOREACH(cs)/CPU_FOREACH_REVERSE(cs) will solve this problem. Would this be the right approach or should we just leave it to the guest kernel to discover and enumerate CPUs in whatever order it finds the DT nodes in FDT ? So using CPU_FOREACH_REVERSE(cs) appears to be right way to handle this. Yes, I think so. In theory it shouldn't matter, but I think it's safer to retain the device tree order. -- David Gibson| I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson pgpo6LKENe_VG.pgp Description: PGP signature
Re: [Qemu-devel] [RFC PATCH v3 02/24] spapr: Add DRC dt entries for CPUs
On Fri, Apr 24, 2015 at 12:17:24PM +0530, Bharata B Rao wrote: Advertise CPU DR-capability to the guest via device tree. Signed-off-by: Bharata B Rao bhar...@linux.vnet.ibm.com Signed-off-by: Michael Roth mdr...@linux.vnet.ibm.com [spapr_drc_reset implementation] --- hw/ppc/spapr.c | 29 + 1 file changed, 29 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 981814d..9ea3a38 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -807,6 +807,15 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, spapr_populate_chosen_stdout(fdt, spapr-vio_bus); } +if (spapr-dr_cpu_enabled) { +int offset = fdt_path_offset(fdt, /cpus); +ret = spapr_drc_populate_dt(fdt, offset, NULL, +SPAPR_DR_CONNECTOR_TYPE_CPU); +if (ret 0) { +fprintf(stderr, Couldn't set up CPU DR device tree properties\n); +} +} + _FDT((fdt_pack(fdt))); if (fdt_totalsize(fdt) FDT_MAX_SIZE) { @@ -1393,6 +1402,16 @@ static SaveVMHandlers savevm_htab_handlers = { .load_state = htab_load, }; +static void spapr_drc_reset(void *opaque) +{ +sPAPRDRConnector *drc = opaque; +DeviceState *d = DEVICE(drc); + +if (d) { +device_reset(d); +} +} Why do these need an explicit reset, rather than having their reset hook automatically called by the qdev infrastructure? I'm guessing it's something to do with how these are linked into the qdev tree, but it could do with a comment clarifying this. /* pSeries LPAR / sPAPR hardware init */ static void ppc_spapr_init(MachineState *machine) { @@ -1418,6 +1437,7 @@ static void ppc_spapr_init(MachineState *machine) long load_limit, fw_size; bool kernel_le = false; char *filename; +int smt = kvmppc_smt_threads(); msi_supported = true; @@ -1482,6 +1502,15 @@ static void ppc_spapr_init(MachineState *machine) spapr-dr_cpu_enabled = smc-dr_cpu_enabled; spapr-dr_lmb_enabled = smc-dr_lmb_enabled; +if (spapr-dr_cpu_enabled) { +for (i = 0; i max_cpus/smp_threads; i++) { +sPAPRDRConnector *drc = +spapr_dr_connector_new(OBJECT(machine), + SPAPR_DR_CONNECTOR_TYPE_CPU, i * smt); +qemu_register_reset(spapr_drc_reset, drc); +} +} + /* init CPUs */ if (cpu_model == NULL) { cpu_model = kvm_enabled() ? host : POWER7; -- David Gibson| I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson pgpGFRxlyMeny.pgp Description: PGP signature
Re: [Qemu-devel] [RFC PATCH v3 05/24] spapr: Reorganize CPU dt generation code
On Fri, Apr 24, 2015 at 12:17:27PM +0530, Bharata B Rao wrote: Reorganize CPU device tree generation code so that it be reused from hotplug path. CPU dt entries are now generated from spapr_finalize_fdt() instead of spapr_create_fdt_skel(). Note: This is how the split-up looks like now: Boot path - spapr_finalize_fdt spapr_populate_cpus_dt_node spapr_populate_cpu_dt spapr_fixup_cpu_numa_dt spapr_fixup_cpu_smt_dt Hotplug path spapr_cpu_plug spapr_populate_hotplug_cpu_dt spapr_populate_cpu_dt spapr_fixup_cpu_numa_dt spapr_fixup_cpu_smt_dt ibm,cas path spapr_h_cas_compose_response spapr_fixup_cpu_dt spapr_fixup_cpu_numa_dt spapr_fixup_cpu_smt_dt Signed-off-by: Bharata B Rao bhar...@linux.vnet.ibm.com Reviewed-by: David Gibson da...@gibson.dropbear.id.au -- David Gibson| I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson pgp17UGy3PQaz.pgp Description: PGP signature
[Qemu-devel] [PATCH v8 04/40] qapi: Fix generation of 'size' builtin type
We were missing the 'size' builtin type (which means that QAPI using [ 'size' ] would fail to compile). Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- scripts/qapi.py | 1 + tests/qapi-schema/qapi-schema-test.json | 3 ++- tests/qapi-schema/qapi-schema-test.out | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 2b5775d..d470347 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -29,6 +29,7 @@ builtin_types = { 'uint16': 'QTYPE_QINT', 'uint32': 'QTYPE_QINT', 'uint64': 'QTYPE_QINT', +'size': 'QTYPE_QINT', } def error_path(parent): diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index d43b5fd..84f0f07 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -74,7 +74,8 @@ 'u64': ['uint64'], 'number': ['number'], 'boolean': ['bool'], -'string': ['str'] } } +'string': ['str'], +'sizes': ['size'] } } # testing commands { 'command': 'user_def_cmd', 'data': {} } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 08d7304..915a61b 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -12,7 +12,7 @@ OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]), OrderedDict([('union', 'UserDefFlatUnion2'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefC'), ('value2', 'UserDefB'), ('value3', 'UserDefA')]))]), 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([('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']), ('sizes', ['size'])]))]), OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]), OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]), OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('*ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]), -- 2.1.0
[Qemu-devel] [PATCH v8 03/40] qapi: Simplify builtin type handling
There was some redundancy between builtin_types[] and builtin_type_qtypes{}. Merge them into one. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- scripts/qapi-types.py | 10 +- scripts/qapi-visit.py | 6 +++--- scripts/qapi.py | 8 +--- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index db87218..e400b03 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -182,8 +182,8 @@ const int %(name)s_qtypes[QTYPE_MAX] = { for key in members: qapi_type = members[key] -if builtin_type_qtypes.has_key(qapi_type): -qtype = builtin_type_qtypes[qapi_type] +if builtin_types.has_key(qapi_type): +qtype = builtin_types[qapi_type] elif find_struct(qapi_type): qtype = QTYPE_QDICT elif find_union(qapi_type): @@ -398,7 +398,7 @@ exprs = parse_schema(input_file) exprs = filter(lambda expr: not expr.has_key('gen'), exprs) fdecl.write(guardstart(QAPI_TYPES_BUILTIN_STRUCT_DECL)) -for typename in builtin_types: +for typename in builtin_types.keys(): fdecl.write(generate_fwd_struct(typename, None, builtin_type=True)) fdecl.write(guardend(QAPI_TYPES_BUILTIN_STRUCT_DECL)) @@ -426,7 +426,7 @@ for expr in exprs: # to avoid header dependency hell, we always generate declarations # for built-in types in our header files and simply guard them fdecl.write(guardstart(QAPI_TYPES_BUILTIN_CLEANUP_DECL)) -for typename in builtin_types: +for typename in builtin_types.keys(): fdecl.write(generate_type_cleanup_decl(typename + List)) fdecl.write(guardend(QAPI_TYPES_BUILTIN_CLEANUP_DECL)) @@ -435,7 +435,7 @@ fdecl.write(guardend(QAPI_TYPES_BUILTIN_CLEANUP_DECL)) # over these cases if do_builtins: fdef.write(guardstart(QAPI_TYPES_BUILTIN_CLEANUP_DEF)) -for typename in builtin_types: +for typename in builtin_types.keys(): fdef.write(generate_type_cleanup(typename + List)) fdef.write(guardend(QAPI_TYPES_BUILTIN_CLEANUP_DEF)) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 1be4d67..41596bb 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -261,7 +261,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e disc_type = '%sKind' % (name) for key in members: -assert (members[key] in builtin_types +assert (members[key] in builtin_types.keys() or find_struct(members[key]) or find_union(members[key]) or find_enum(members[key])), Invalid anonymous union member @@ -538,7 +538,7 @@ exprs = parse_schema(input_file) # to avoid header dependency hell, we always generate declarations # for built-in types in our header files and simply guard them fdecl.write(guardstart(QAPI_VISIT_BUILTIN_VISITOR_DECL)) -for typename in builtin_types: +for typename in builtin_types.keys(): fdecl.write(generate_declaration(typename, None, builtin_type=True)) fdecl.write(guardend(QAPI_VISIT_BUILTIN_VISITOR_DECL)) @@ -546,7 +546,7 @@ fdecl.write(guardend(QAPI_VISIT_BUILTIN_VISITOR_DECL)) # have the functions defined, so we use -b option to provide control # over these cases if do_builtins: -for typename in builtin_types: +for typename in builtin_types.keys(): fdef.write(generate_visit_list(typename, None)) for expr in exprs: diff --git a/scripts/qapi.py b/scripts/qapi.py index 77d46aa..2b5775d 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -16,13 +16,7 @@ from ordereddict import OrderedDict import os import sys -builtin_types = [ -'str', 'int', 'number', 'bool', -'int8', 'int16', 'int32', 'int64', -'uint8', 'uint16', 'uint32', 'uint64' -] - -builtin_type_qtypes = { +builtin_types = { 'str': 'QTYPE_QSTRING', 'int': 'QTYPE_QINT', 'number': 'QTYPE_QFLOAT', -- 2.1.0
[Qemu-devel] [PATCH v8 15/40] qapi: Document new 'alternate' meta-type
The next patch will quit special-casing 'union':'Foo', 'discriminator':{} and instead use 'alternate':'Foo'. Separating docs from implementation makes it easier to focus on wording without holding up code. In particular, making alternate a separate type makes for a nice type hierarchy: / meta-type --\ / |\ simple typesalternate complex types | | | | built-in enum type(struct) union | \//\ numeric string simple flat A later patch will then clean up 'type' vs. 'struct' confusion. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- docs/qapi-code-gen.txt | 57 +++--- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 6404a2d..588b110 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -85,11 +85,12 @@ the definition of complex structs that can have mutually recursive types, and allows for indefinite nesting of QMP that satisfies the schema. A type name should not be defined more than once. -There are six top-level expressions recognized by the parser: -'include', 'command', 'type', 'enum', 'union', and 'event'. There are -several built-in types, such as 'int' and 'str'; additionally, the -top-level expressions can define complex types, enumeration types, and -several flavors of union types. The 'command' and 'event' expressions +There are seven top-level expressions recognized by the parser: +'include', 'command', 'type', 'enum', 'union', 'alternate', and +'event'. There are several groups of types: simple types (a number of +built-in types, such as 'int' and 'str'; as well as enumerations), +complex types (structs and two flavors of unions), and alternate types +(a choice between other types). The 'command' and 'event' expressions can refer to existing types by name, or list an anonymous type as a dictionary. Listing a type name inside an array refers to a single-dimension array of that type; multi-dimension arrays are not @@ -261,14 +262,12 @@ open-coding the field to be type 'str'. Usage: { 'union': STRING, 'data': DICT } or:{ 'union': STRING, 'data': DICT, 'base': COMPLEX-TYPE-NAME, 'discriminator': ENUM-MEMBER-OF-BASE } -or:{ 'union': STRING, 'data': DICT, 'discriminator': {} } Union types are used to let the user choose between several different -variants for an object. There are three flavors: simple (no -discriminator or base), flat (both base and discriminator are -strings), and anonymous (discriminator is an empty dictionary). A -union type is defined using a data dictionary as explained in the -following paragraphs. +variants for an object. There are two flavors: simple (no +discriminator or base), flat (both discriminator and base). A union +type is defined using a data dictionary as explained in the following +paragraphs. A simple union type defines a mapping from automatic discriminator values to data types like in this example: @@ -350,20 +349,36 @@ is identical on the wire to: 'data': { 'one': 'Branch1', 'two': 'Branch2' } } -The final flavor of unions is an anonymous union. While the other two -union types are always passed as a JSON object in the wire format, an -anonymous union instead allows the direct use of different types in -its place. Anonymous unions are declared using an empty dictionary as -their discriminator. The discriminator values never appear on the -wire, they are only used in the generated C code. Anonymous unions -cannot have a base type. +=== Alternate types === - { 'union': 'BlockRef', - 'discriminator': {}, +Usage: { 'alternate': STRING, 'data': DICT } + +An alternate type is one that allows a choice between two or more JSON +data types (string, integer, number, or object, but currently not +array) on the wire. The definition is similar to a simple union type, +where each branch of the union names a QAPI type. For example: + + { 'alternate': 'BlockRef', 'data': { 'definition': 'BlockdevOptions', 'reference': 'str' } } -This example allows using both of the following example objects: +Just like for a simple union, an implicit C enum 'NameKind' is created +to enumerate the branches for the alternate 'Name'. + +Unlike a union, the discriminator string is never passed on the wire +for QMP. Instead, the value's JSON type serves as an implicit +discriminator, which in turn means that an alternate can only express +a choice between types represented differently in JSON. If a branch +is typed as the 'bool' built-in, the alternate accepts true and false; +if it is typed as any of the various numeric built-ins, it accepts a +JSON number; if it is typed as a 'str' built-in or named enum type, it +accepts a JSON string; and if it is typed as a
[Qemu-devel] [PATCH v8 11/40] qapi: Tighten checking of unions
Previous commits demonstrated that the generator had several flaws with less-than-perfect unions: - a simple union that listed the same branch twice (or two variant names that map to the same C enumerator, including the implicit MAX sentinel) ended up generating invalid C code - an anonymous union that listed two branches with the same qtype ended up generating invalid C code - the generator crashed on anonymous union attempts to use an array type - the generator was silently ignoring a base type for anonymous unions - the generator allowed unknown types or nested anonymous unions as a branch in an anonymous union Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- v7: improved comments in alternate-array --- scripts/qapi-types.py | 13 +--- scripts/qapi.py| 89 +- tests/qapi-schema/alternate-array.err | 1 + tests/qapi-schema/alternate-array.exit | 2 +- tests/qapi-schema/alternate-array.json | 2 +- tests/qapi-schema/alternate-array.out | 4 - tests/qapi-schema/alternate-base.err | 1 + tests/qapi-schema/alternate-base.exit | 2 +- tests/qapi-schema/alternate-base.json | 2 +- tests/qapi-schema/alternate-base.out | 4 - tests/qapi-schema/alternate-clash.err | 1 + tests/qapi-schema/alternate-clash.exit | 2 +- tests/qapi-schema/alternate-clash.json | 2 +- tests/qapi-schema/alternate-clash.out | 3 - tests/qapi-schema/alternate-conflict-dict.err | 1 + tests/qapi-schema/alternate-conflict-dict.exit | 2 +- tests/qapi-schema/alternate-conflict-dict.json | 2 +- tests/qapi-schema/alternate-conflict-dict.out | 6 -- tests/qapi-schema/alternate-conflict-string.err| 1 + tests/qapi-schema/alternate-conflict-string.exit | 2 +- tests/qapi-schema/alternate-conflict-string.json | 2 +- tests/qapi-schema/alternate-conflict-string.out| 5 -- tests/qapi-schema/alternate-nested.err | 1 + tests/qapi-schema/alternate-nested.exit| 2 +- tests/qapi-schema/alternate-nested.json| 2 +- tests/qapi-schema/alternate-nested.out | 5 -- tests/qapi-schema/alternate-unknown.err| 1 + tests/qapi-schema/alternate-unknown.exit | 2 +- tests/qapi-schema/alternate-unknown.json | 2 +- tests/qapi-schema/alternate-unknown.out| 3 - tests/qapi-schema/flat-union-bad-base.err | 2 +- tests/qapi-schema/flat-union-bad-base.json | 2 +- tests/qapi-schema/flat-union-bad-discriminator.err | 1 + .../qapi-schema/flat-union-bad-discriminator.exit | 2 +- .../qapi-schema/flat-union-bad-discriminator.json | 2 +- tests/qapi-schema/flat-union-bad-discriminator.out | 10 --- tests/qapi-schema/flat-union-inline.err| 2 +- tests/qapi-schema/flat-union-inline.json | 2 +- tests/qapi-schema/flat-union-no-base.err | 2 +- tests/qapi-schema/flat-union-no-base.json | 2 +- tests/qapi-schema/union-bad-branch.err | 1 + tests/qapi-schema/union-bad-branch.exit| 2 +- tests/qapi-schema/union-bad-branch.json| 2 +- tests/qapi-schema/union-bad-branch.out | 6 -- tests/qapi-schema/union-max.err| 1 + tests/qapi-schema/union-max.exit | 2 +- tests/qapi-schema/union-max.json | 2 +- tests/qapi-schema/union-max.out| 3 - 48 files changed, 110 insertions(+), 103 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index f6fb930..2390887 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -181,17 +181,8 @@ const int %(name)s_qtypes[QTYPE_MAX] = { name=name) for key in members: -qapi_type = members[key] -if builtin_types.has_key(qapi_type): -qtype = builtin_types[qapi_type] -elif find_struct(qapi_type): -qtype = QTYPE_QDICT -elif find_union(qapi_type): -qtype = QTYPE_QDICT -elif find_enum(qapi_type): -qtype = QTYPE_QSTRING -else: -assert False, Invalid anonymous union member +qtype = find_anonymous_member_qtype(members[key]) +assert qtype, Invalid anonymous union member ret += mcgen(''' [ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s, diff --git a/scripts/qapi.py b/scripts/qapi.py index 438468e..5f0f699 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -224,6 +224,23 @@ def find_base_fields(base): return None return base_struct_define['data'] +# Return the qtype of an anonymous union branch, or None on error. +def find_anonymous_member_qtype(qapi_type): +if builtin_types.has_key(qapi_type): +return builtin_types[qapi_type] +elif
[Qemu-devel] [PATCH v8 05/40] qapi: Require ASCII in schema
Python 2 and Python 3 have a wild history of whether strings default to ascii or unicode, where Python 3 requires checking isinstance(foo, basestr) to cover all strings, but where that code is not portable to Python 2. It's simpler to just state that we don't care about Unicode strings, and to just always use the simpler isinstance(foo, str) everywhere. I'm no python expert, so I'm basing it on this conversation: https://lists.gnu.org/archive/html/qemu-devel/2014-09/msg05278.html Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- scripts/qapi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index d470347..20ee505 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -2,7 +2,7 @@ # QAPI helper library # # Copyright IBM, Corp. 2011 -# Copyright (c) 2013 Red Hat Inc. +# Copyright (c) 2013-2015 Red Hat Inc. # # Authors: # Anthony Liguori aligu...@us.ibm.com @@ -354,7 +354,7 @@ def parse_schema(input_file): return exprs def parse_args(typeinfo): -if isinstance(typeinfo, basestring): +if isinstance(typeinfo, str): struct = find_struct(typeinfo) assert struct != None typeinfo = struct['data'] -- 2.1.0
[Qemu-devel] [PATCH v8 07/40] qapi: Better error messages for bad enums
The previous commit demonstrated that the generator had several flaws with less-than-perfect enums: - an enum that listed the same string twice (or two variant strings that map to the same C enumerator) ended up generating an invalid C enum - because the generator adds a _MAX terminator to each enum, the use of an enum member 'max' can also cause this clash - if an enum omits 'data', the generator left a python stack trace rather than a graceful message - an enum that used a non-array 'data' was silently accepted by the parser - an enum that used non-string members in the 'data' member was silently accepted by the parser Add check_enum to cover these situations, and update testcases to match. While valid .json files won't trigger any of these cases, we might as well be nicer to developers that make a typo while trying to add new QAPI code. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- v7: double the fix in enum-max-member comment --- scripts/qapi.py | 34 +++- tests/qapi-schema/enum-clash-member.err | 1 + tests/qapi-schema/enum-clash-member.exit | 2 +- tests/qapi-schema/enum-clash-member.json | 2 +- tests/qapi-schema/enum-clash-member.out | 3 --- tests/qapi-schema/enum-dict-member.err | 1 + tests/qapi-schema/enum-dict-member.exit | 2 +- tests/qapi-schema/enum-dict-member.json | 2 +- tests/qapi-schema/enum-dict-member.out | 3 --- tests/qapi-schema/enum-max-member.err| 1 + tests/qapi-schema/enum-max-member.exit | 2 +- tests/qapi-schema/enum-max-member.json | 2 +- tests/qapi-schema/enum-max-member.out| 3 --- tests/qapi-schema/enum-missing-data.err | 7 +-- tests/qapi-schema/enum-missing-data.json | 2 +- tests/qapi-schema/enum-wrong-data.err| 1 + tests/qapi-schema/enum-wrong-data.exit | 2 +- tests/qapi-schema/enum-wrong-data.json | 2 +- tests/qapi-schema/enum-wrong-data.out| 3 --- 19 files changed, 43 insertions(+), 32 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 20ee505..3ce8c33 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -311,13 +311,37 @@ def check_union(expr, expr_info): # 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_enum(expr, expr_info): +name = expr['enum'] +members = expr.get('data') +values = { 'MAX': '(automatic)' } + +if not isinstance(members, list): +raise QAPIExprError(expr_info, +Enum '%s' requires an array for 'data' % name) +for member in members: +if not isinstance(member, str): +raise QAPIExprError(expr_info, +Enum '%s' member '%s' is not a string +% (name, member)) +key = _generate_enum_string(member) +if key in values: +raise QAPIExprError(expr_info, +Enum '%s' member '%s' clashes with '%s' +% (name, member, values[key])) +values[key] = member + 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']) -if expr.has_key('event'): -check_event(expr, expr_elem['info']) +info = expr_elem['info'] + +if expr.has_key('enum'): +check_enum(expr, info) +elif expr.has_key('union'): +check_union(expr, info) +elif expr.has_key('event'): +check_event(expr, info) def parse_schema(input_file): try: @@ -331,7 +355,7 @@ def parse_schema(input_file): for expr_elem in schema.exprs: expr = expr_elem['expr'] if expr.has_key('enum'): -add_enum(expr['enum'], expr['data']) +add_enum(expr['enum'], expr.get('data')) elif expr.has_key('union'): add_union(expr) elif expr.has_key('type'): diff --git a/tests/qapi-schema/enum-clash-member.err b/tests/qapi-schema/enum-clash-member.err index e69de29..48bd136 100644 --- a/tests/qapi-schema/enum-clash-member.err +++ b/tests/qapi-schema/enum-clash-member.err @@ -0,0 +1 @@ +tests/qapi-schema/enum-clash-member.json:2: Enum 'MyEnum' member 'ONE' clashes with 'one' diff --git a/tests/qapi-schema/enum-clash-member.exit b/tests/qapi-schema/enum-clash-member.exit index 573541a..d00491f 100644 --- a/tests/qapi-schema/enum-clash-member.exit +++ b/tests/qapi-schema/enum-clash-member.exit @@ -1 +1 @@ -0 +1 diff --git a/tests/qapi-schema/enum-clash-member.json b/tests/qapi-schema/enum-clash-member.json index 99d442a..b7dc02a 100644 --- a/tests/qapi-schema/enum-clash-member.json +++ b/tests/qapi-schema/enum-clash-member.json @@ -1,2 +1,2 @@ -# FIXME: we should reject enums where members will clash when mapped to C enum +# we
[Qemu-devel] [PATCH v8 31/40] qapi: Forbid 'type' in schema
Referring to type as both a meta-type (built-in, enum, union, alternate, or struct) and a specific type (the name that the schema uses for declaring structs) is confusing. Finish up the conversion to using struct in qapi schema by removing the hack in the generator that allowed 'type'. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- v7: split from the previous patch --- scripts/qapi.py | 14 -- 1 file changed, 14 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index ff337c2..ff53360 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -617,20 +617,6 @@ def parse_schema(input_file): for expr_elem in schema.exprs: expr = expr_elem['expr'] info = expr_elem['info'] - -# back-compat hack until all schemas have been converted; -# preserve the ordering of the original expression -if expr.has_key('type'): -seen_type = False -for (key, value) in expr.items(): -if key == 'type': -seen_type = True -del expr['type'] -expr['struct'] = value -elif seen_type: -del expr[key] -expr[key] = value - if expr.has_key('enum'): check_keys(expr_elem, 'enum', ['data']) add_enum(expr['enum'], info, expr['data']) -- 2.1.0
[Qemu-devel] [PATCH v8 10/40] qapi: Forbid base without discriminator in unions
None of the existing QMP or QGA interfaces uses a union with a base type but no discriminator; it is easier to avoid this in the generator to save room for other future extensions more likely to be useful. An earlier commit added a union-base-no-discriminator test to ensure that we eventually give a decent error message; likewise, removing UserDefUnion outright is okay, because we moved all the tests we wish to keep into the tests of the simple union UserDefNativeListUnion in the previous commit. Now is the time to actually forbid simple union with base, and remove the last vestiges from the testsuite. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- v7: improve commit message --- scripts/qapi-types.py | 7 ++--- scripts/qapi-visit.py | 11 +++ scripts/qapi.py| 20 ++-- tests/qapi-schema/qapi-schema-test.json| 4 --- tests/qapi-schema/qapi-schema-test.out | 2 -- tests/qapi-schema/union-base-no-discriminator.err | 1 + tests/qapi-schema/union-base-no-discriminator.exit | 2 +- tests/qapi-schema/union-base-no-discriminator.json | 2 +- tests/qapi-schema/union-base-no-discriminator.out | 8 - tests/test-qmp-input-visitor.c | 19 tests/test-qmp-output-visitor.c| 36 -- 11 files changed, 21 insertions(+), 91 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index e400b03..f6fb930 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -242,10 +242,9 @@ struct %(name)s ''') if base: -base_fields = find_struct(base)['data'] -if discriminator: -base_fields = base_fields.copy() -del base_fields[discriminator] +assert discriminator +base_fields = find_struct(base)['data'].copy() +del base_fields[discriminator] ret += generate_struct_fields(base_fields) else: assert not discriminator diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 41596bb..dbf0101 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -310,16 +310,15 @@ def generate_visit_union(expr): 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) +# 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'] -if discriminator: -base_fields = base_fields.copy() -del base_fields[discriminator] +assert discriminator +base_fields = find_struct(base)['data'].copy() +del base_fields[discriminator] ret += generate_visit_struct_fields(name, , , base_fields) if discriminator: diff --git a/scripts/qapi.py b/scripts/qapi.py index 3ce8c33..438468e 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -259,22 +259,22 @@ def check_union(expr, expr_info): discriminator = expr.get('discriminator') members = expr['data'] -# If the object has a member 'base', its value must name a complex type. -if base: +# If the object has a member 'base', its value must name a complex type, +# and there must be a discriminator. +if base is not None: +if discriminator is None: +raise QAPIExprError(expr_info, +Union '%s' requires a discriminator to go +along with base %name) 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 == {}: +# If the union object has no member 'discriminator', it's a +# simple union. If 'discriminator' is {}, it is an anonymous union. +if not discriminator or discriminator == {}: enum_define = None # Else, it's a flat union. diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 84f0f07..b134f3f 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -36,10 +36,6 @@ { 'type': 'UserDefC', 'data': { 'string1': 'str', 'string2': 'str' } } -{ 'union': 'UserDefUnion', - 'base': 'UserDefZero', -
[Qemu-devel] [PATCH v8 09/40] qapi: Clean up test coverage of simple unions
The tests of UserDefNativeListUnion serve to validate code generation of simple unions without a base type, except that it did not have full coverage in the strict test. The next commits will remove tests and support for simple unions with a base type, so there is no real loss at repurposing that test here as opposed to churn of adding a new test then deleting the old one. Fix some indentation and long lines while at it. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- tests/test-qmp-input-strict.c | 57 +++--- tests/test-qmp-input-visitor.c | 61 + tests/test-qmp-output-visitor.c | 38 - 3 files changed, 86 insertions(+), 70 deletions(-) diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c index d5360c6..486848e 100644 --- a/tests/test-qmp-input-strict.c +++ b/tests/test-qmp-input-strict.c @@ -1,7 +1,7 @@ /* * QMP Input Visitor unit-tests (strict mode). * - * Copyright (C) 2011-2012 Red Hat Inc. + * Copyright (C) 2011-2012, 2015 Red Hat Inc. * * Authors: * Luiz Capitulino lcapitul...@redhat.com @@ -141,18 +141,18 @@ static void test_validate_list(TestInputVisitorData *data, qapi_free_UserDefOneList(head); } -static void test_validate_union(TestInputVisitorData *data, - const void *unused) +static void test_validate_union_native_list(TestInputVisitorData *data, +const void *unused) { -UserDefUnion *tmp = NULL; +UserDefNativeListUnion *tmp = NULL; Visitor *v; Error *err = NULL; -v = validate_test_init(data, { 'type': 'b', 'integer': 41, 'data' : { 'integer': 42 } }); +v = validate_test_init(data, { 'type': 'integer', 'data' : [ 1, 2 ] }); -visit_type_UserDefUnion(v, tmp, NULL, err); +visit_type_UserDefNativeListUnion(v, tmp, NULL, err); g_assert(!err); -qapi_free_UserDefUnion(tmp); +qapi_free_UserDefNativeListUnion(tmp); } static void test_validate_union_flat(TestInputVisitorData *data, @@ -232,18 +232,19 @@ static void test_validate_fail_list(TestInputVisitorData *data, qapi_free_UserDefOneList(head); } -static void test_validate_fail_union(TestInputVisitorData *data, - const void *unused) +static void test_validate_fail_union_native_list(TestInputVisitorData *data, + const void *unused) { -UserDefUnion *tmp = NULL; +UserDefNativeListUnion *tmp = NULL; Error *err = NULL; Visitor *v; -v = validate_test_init(data, { 'type': 'b', 'data' : { 'integer': 42 } }); +v = validate_test_init(data, + { 'type': 'integer', 'data' : [ 'string' ] }); -visit_type_UserDefUnion(v, tmp, NULL, err); +visit_type_UserDefNativeListUnion(v, tmp, NULL, err); g_assert(err); -qapi_free_UserDefUnion(tmp); +qapi_free_UserDefNativeListUnion(tmp); } static void test_validate_fail_union_flat(TestInputVisitorData *data, @@ -304,31 +305,31 @@ int main(int argc, char **argv) g_test_init(argc, argv, NULL); validate_test_add(/visitor/input-strict/pass/struct, - testdata, test_validate_struct); + testdata, test_validate_struct); validate_test_add(/visitor/input-strict/pass/struct-nested, - testdata, test_validate_struct_nested); + testdata, test_validate_struct_nested); validate_test_add(/visitor/input-strict/pass/list, - testdata, test_validate_list); -validate_test_add(/visitor/input-strict/pass/union, - testdata, test_validate_union); + testdata, test_validate_list); validate_test_add(/visitor/input-strict/pass/union-flat, - testdata, test_validate_union_flat); + testdata, test_validate_union_flat); validate_test_add(/visitor/input-strict/pass/union-anon, - testdata, test_validate_union_anon); + testdata, test_validate_union_anon); +validate_test_add(/visitor/input-strict/pass/union-native-list, + testdata, test_validate_union_native_list); validate_test_add(/visitor/input-strict/fail/struct, - testdata, test_validate_fail_struct); + testdata, test_validate_fail_struct); validate_test_add(/visitor/input-strict/fail/struct-nested, - testdata, test_validate_fail_struct_nested); + testdata, test_validate_fail_struct_nested); validate_test_add(/visitor/input-strict/fail/list, - testdata, test_validate_fail_list); -validate_test_add(/visitor/input-strict/fail/union, - testdata, test_validate_fail_union); +
[Qemu-devel] [PATCH v8 27/40] qapi: More rigorous checking for type safety bypass
Now that we have a way to validate every type, we can also be stricter about enforcing that callers that want to bypass type safety in generated code. Prior to this patch, it didn't matter what value was associated with the key 'gen', but it looked odd that 'gen':'yes' could result in bypassing the generated code. These changes also enforce the changes made earlier in the series for documentation and consolidation of using '**' as the wildcard type, as well as 'gen':false as the canonical spelling for requesting type bypass. Note that 'gen':false is a one-way switch away from the default; we do not support 'gen':true (similar for 'success-response'). In practice, this doesn't matter. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- v7: fix typo in commit message --- scripts/qapi.py| 22 +- tests/qapi-schema/type-bypass-bad-gen.err | 1 + tests/qapi-schema/type-bypass-bad-gen.exit | 2 +- tests/qapi-schema/type-bypass-bad-gen.json | 2 +- tests/qapi-schema/type-bypass-bad-gen.out | 3 --- tests/qapi-schema/type-bypass-no-gen.err | 1 + tests/qapi-schema/type-bypass-no-gen.exit | 2 +- tests/qapi-schema/type-bypass-no-gen.json | 2 +- tests/qapi-schema/type-bypass-no-gen.out | 3 --- 9 files changed, 23 insertions(+), 15 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index b218ee5..07ae141 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -324,14 +324,15 @@ def check_name(expr_info, source, name, allow_optional = False, %s uses invalid name '%s' % (source, name)) def check_type(expr_info, source, value, allow_array = False, - allow_dict = False, allow_optional = False, allow_metas = []): + allow_dict = False, allow_optional = False, + allow_star = False, allow_metas = []): global all_names orig_value = value if value is None: return -if value == '**': +if allow_star and value == '**': return # Check if array type for value is okay @@ -348,6 +349,10 @@ def check_type(expr_info, source, value, allow_array = False, # Check if type name for value is okay if isinstance(value, str): +if value == '**': +raise QAPIExprError(expr_info, +%s uses '**' but did not request 'gen':false +% source) if not value in all_names: raise QAPIExprError(expr_info, %s uses unknown type '%s' @@ -371,19 +376,22 @@ def check_type(expr_info, source, value, allow_array = False, check_type(expr_info, Member '%s' of %s % (key, source), arg, allow_array=True, allow_dict=True, allow_optional=True, allow_metas=['built-in', 'union', 'alternate', 'struct', -'enum']) +'enum'], allow_star=allow_star) def check_command(expr, expr_info): name = expr['command'] +allow_star = expr.has_key('gen') + check_type(expr_info, 'data' for command '%s' % name, expr.get('data'), allow_dict=True, allow_optional=True, - allow_metas=['union', 'struct']) + allow_metas=['union', 'struct'], allow_star=allow_star) returns_meta = ['union', 'struct'] if name in returns_whitelist: returns_meta += ['built-in', 'alternate', 'enum'] check_type(expr_info, 'returns' for command '%s' % name, expr.get('returns'), allow_array=True, allow_dict=True, - allow_optional=True, allow_metas=returns_meta) + allow_optional=True, allow_metas=returns_meta, + allow_star=allow_star) def check_event(expr, expr_info): global events @@ -579,6 +587,10 @@ def check_keys(expr_elem, meta, required, optional=[]): raise QAPIExprError(info, Unknown key '%s' in %s '%s' % (key, meta, name)) +if (key == 'gen' or key == 'success-response') and value != False: +raise QAPIExprError(info, +'%s' of %s '%s' should only use false value +% (key, meta, name)) for key in required: if not expr.has_key(key): raise QAPIExprError(info, diff --git a/tests/qapi-schema/type-bypass-bad-gen.err b/tests/qapi-schema/type-bypass-bad-gen.err index e69de29..a83c3c6 100644 --- a/tests/qapi-schema/type-bypass-bad-gen.err +++ b/tests/qapi-schema/type-bypass-bad-gen.err @@ -0,0 +1 @@ +tests/qapi-schema/type-bypass-bad-gen.json:2: 'gen' of command 'foo' should only use false value diff --git a/tests/qapi-schema/type-bypass-bad-gen.exit b/tests/qapi-schema/type-bypass-bad-gen.exit index 573541a..d00491f 100644 --- a/tests/qapi-schema/type-bypass-bad-gen.exit +++
[Qemu-devel] [PATCH v8 28/40] qapi: Prefer 'struct' over 'type' in generator
Referring to type as both a meta-type (built-in, enum, union, alternate, or struct) and a specific type (the name that the schema uses for declaring structs) is confusing. The confusion is only made worse by the fact that the generator mostly already refers to struct even when dealing with expr['type']. This commit changes the generator to consistently refer to it as struct everywhere, plus a single back-compat tweak that allows accepting the existing .json files as-is, so that the meat of this change is separate from the mindless churn of that change. Fix the testsuite fallout for error messages that change, and in some cases, become more legible. Improve comments to better match our intentions where a struct (rather than any complex type) is required. Note that in some cases, an error message now refers to 'struct' while the schema still refers to 'type'; that will be cleaned up in the later commit to the schema. Signed-off-by: Eric Blake ebl...@redhat.com --- v7: enhance commit message; change check_struct() to refer to 'struct' rather than 'type'; update a few more comments at this point (enough fallout that I dropped Markus' R-b) --- scripts/qapi-types.py | 16 scripts/qapi-visit.py | 8 ++-- scripts/qapi.py| 46 ++ tests/qapi-schema/alternate-good.out | 4 +- tests/qapi-schema/bad-base.err | 2 +- tests/qapi-schema/bad-ident.err| 2 +- tests/qapi-schema/bad-type-bool.err| 2 +- tests/qapi-schema/data-member-array.out| 4 +- tests/qapi-schema/double-type.err | 2 +- tests/qapi-schema/flat-union-bad-base.json | 2 +- tests/qapi-schema/flat-union-base-star.err | 2 +- tests/qapi-schema/flat-union-base-star.json| 2 +- tests/qapi-schema/flat-union-base-union.err| 2 +- tests/qapi-schema/flat-union-base-union.json | 2 +- tests/qapi-schema/flat-union-branch-clash.out | 12 +++--- tests/qapi-schema/flat-union-inline.json | 2 +- tests/qapi-schema/flat-union-int-branch.json | 2 +- .../flat-union-invalid-discriminator.err | 2 +- tests/qapi-schema/flat-union-reverse-define.out| 12 +++--- tests/qapi-schema/qapi-schema-test.out | 44 ++--- tests/qapi-schema/union-invalid-base.err | 2 +- tests/qapi-schema/unknown-expr-key.err | 2 +- 22 files changed, 93 insertions(+), 81 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 9c8d68c..a429d9e 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -83,7 +83,7 @@ def generate_struct_fields(members): def generate_struct(expr): -structname = expr.get('type', ) +structname = expr.get('struct', ) fieldname = expr.get('field', ) members = expr['data'] base = expr.get('base') @@ -394,8 +394,8 @@ fdecl.write(guardend(QAPI_TYPES_BUILTIN_STRUCT_DECL)) for expr in exprs: ret = \n -if expr.has_key('type'): -ret += generate_fwd_struct(expr['type'], expr['data']) +if expr.has_key('struct'): +ret += generate_fwd_struct(expr['struct'], expr['data']) elif expr.has_key('enum'): ret += generate_enum(expr['enum'], expr['data']) + \n ret += generate_fwd_enum_struct(expr['enum'], expr['data']) @@ -435,12 +435,12 @@ if do_builtins: for expr in exprs: ret = \n -if expr.has_key('type'): +if expr.has_key('struct'): ret += generate_struct(expr) + \n -ret += generate_type_cleanup_decl(expr['type'] + List) -fdef.write(generate_type_cleanup(expr['type'] + List) + \n) -ret += generate_type_cleanup_decl(expr['type']) -fdef.write(generate_type_cleanup(expr['type']) + \n) +ret += generate_type_cleanup_decl(expr['struct'] + List) +fdef.write(generate_type_cleanup(expr['struct'] + List) + \n) +ret += generate_type_cleanup_decl(expr['struct']) +fdef.write(generate_type_cleanup(expr['struct']) + \n) elif expr.has_key('union'): ret += generate_union(expr, 'union') ret += generate_type_cleanup_decl(expr['union'] + List) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 9222671..c739a95 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -178,7 +178,7 @@ def generate_visit_struct_body(field_prefix, name, members): def generate_visit_struct(expr): -name = expr['type'] +name = expr['struct'] members = expr['data'] base = expr.get('base') @@ -545,12 +545,12 @@ if do_builtins: fdef.write(generate_visit_list(typename, None)) for expr in exprs: -if expr.has_key('type'): +if expr.has_key('struct'): ret = generate_visit_struct(expr) -ret += generate_visit_list(expr['type'], expr['data']) +ret +=
[Qemu-devel] [PATCH v8 21/40] qapi: Allow true, false and null in schema json
From: Fam Zheng f...@redhat.com In the near term, we will use it for a sensible-looking 'gen':false inside command declarations, instead of the current ugly 'gen':'no'. In the long term, it will allow conversion from shorthand with defaults mentioned only in side-band documentation: 'data':{'*flag':'bool', '*string':'str'} into an explicit default value documentation, as in: 'data':{'flag':{'type':'bool', 'optional':true, 'default':true}, 'string':{'type':'str', 'optional':true, 'default':null}} We still don't parse integer values (also necessary before we can allow explicit defaults), but that can come in a later series. Update the testsuite to match an improved error message. Signed-off-by: Fam Zheng f...@redhat.com Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- scripts/qapi.py | 21 ++--- tests/qapi-schema/bad-type-bool.err | 2 +- tests/qapi-schema/bad-type-bool.json | 1 - 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index eea0976..686bc86 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -158,6 +158,20 @@ class QAPISchema: return else: string += ch +elif self.tok in tfn: +val = self.src[self.cursor - 1:] +if val.startswith(true): +self.val = True +self.cursor += 3 +return +elif val.startswith(false): +self.val = False +self.cursor += 4 +return +elif val.startswith(null): +self.val = None +self.cursor += 3 +return elif self.tok == '\n': if self.cursor == len(self.src): self.tok = None @@ -197,8 +211,9 @@ class QAPISchema: if self.tok == ']': self.accept() return expr -if not self.tok in [ '{', '[', ' ]: -raise QAPISchemaError(self, 'Expected {, [, ] or string') +if not self.tok in {['tfn: +raise QAPISchemaError(self, 'Expected {, [, ], string, ' + 'boolean or null') while True: expr.append(self.get_expr(True)) if self.tok == ']': @@ -217,7 +232,7 @@ class QAPISchema: elif self.tok == '[': self.accept() expr = self.get_values() -elif self.tok == ': +elif self.tok in 'tfn: expr = self.val self.accept() else: diff --git a/tests/qapi-schema/bad-type-bool.err b/tests/qapi-schema/bad-type-bool.err index badb7c2..de6168c 100644 --- a/tests/qapi-schema/bad-type-bool.err +++ b/tests/qapi-schema/bad-type-bool.err @@ -1 +1 @@ -tests/qapi-schema/bad-type-bool.json:3:11: Stray t +tests/qapi-schema/bad-type-bool.json:2: 'type' key must have a string value diff --git a/tests/qapi-schema/bad-type-bool.json b/tests/qapi-schema/bad-type-bool.json index 22d6369..e1e9fb0 100644 --- a/tests/qapi-schema/bad-type-bool.json +++ b/tests/qapi-schema/bad-type-bool.json @@ -1,3 +1,2 @@ # we reject an expression with a metatype that is not a string -# FIXME: once the parser understands bool inputs, improve the error message { 'type': true, 'data': { } } -- 2.1.0
[Qemu-devel] [PATCH v8 36/40] qapi: Drop support for inline nested types
A future patch will be using a 'name':{dictionary} entry in the QAPI schema to specify a default value for an optional argument (see previous commit messages for more details why); but existing use of inline nested structs conflicts with that goal. Now that all commands have been changed to avoid inline nested structs, nuke support for them, and turn it into a hard error. Update the testsuite to reflect tighter parsing rules. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- scripts/qapi-commands.py | 8 +++--- scripts/qapi-event.py| 4 +-- scripts/qapi-types.py| 9 ++- scripts/qapi-visit.py| 37 scripts/qapi.py | 20 ++- tests/qapi-schema/event-nest-struct.err | 2 +- tests/qapi-schema/nested-struct-data.err | 1 + tests/qapi-schema/nested-struct-data.exit| 2 +- tests/qapi-schema/nested-struct-data.json| 2 +- tests/qapi-schema/nested-struct-data.out | 3 --- tests/qapi-schema/nested-struct-returns.err | 1 + tests/qapi-schema/nested-struct-returns.exit | 2 +- tests/qapi-schema/nested-struct-returns.json | 2 +- tests/qapi-schema/nested-struct-returns.out | 3 --- 14 files changed, 27 insertions(+), 69 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index cb78682..93e43f0 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -28,7 +28,7 @@ def type_visitor(name): def generate_command_decl(name, args, ret_type): arglist= -for argname, argtype, optional, structured in parse_args(args): +for argname, argtype, optional in parse_args(args): argtype = c_type(argtype, is_param=True) if optional: arglist += bool has_%s, % c_var(argname) @@ -53,7 +53,7 @@ def gen_sync_call(name, args, ret_type, indent=0): retval= if ret_type: retval = retval = -for argname, argtype, optional, structured in parse_args(args): +for argname, argtype, optional in parse_args(args): if optional: arglist += has_%s, % c_var(argname) arglist += %s, % (c_var(argname)) @@ -96,7 +96,7 @@ Visitor *v; def gen_visitor_input_vars_decl(args): ret = push_indent() -for argname, argtype, optional, structured in parse_args(args): +for argname, argtype, optional in parse_args(args): if optional: ret += mcgen(''' bool has_%(argname)s = false; @@ -139,7 +139,7 @@ v = qapi_dealloc_get_visitor(md); v = qmp_input_get_visitor(mi); ''') -for argname, argtype, optional, structured in parse_args(args): +for argname, argtype, optional in parse_args(args): if optional: ret += mcgen(''' visit_optional(v, has_%(c_name)s, %(name)s, %(errp)s); diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index 601e307..47dc041 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -21,7 +21,7 @@ def _generate_event_api_name(event_name, params): l = len(api_name) if params: -for argname, argentry, optional, structured in parse_args(params): +for argname, argentry, optional in parse_args(params): if optional: api_name += bool has_%s,\n % c_var(argname) api_name += .ljust(l) @@ -93,7 +93,7 @@ def generate_event_implement(api_name, event_name, params): , event_name = event_name) -for argname, argentry, optional, structured in parse_args(params): +for argname, argentry, optional in parse_args(params): if optional: ret += mcgen( if (has_%(var)s) { diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index a429d9e..2bf8145 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -63,18 +63,13 @@ typedef struct %(name)sList def generate_struct_fields(members): ret = '' -for argname, argentry, optional, structured in parse_args(members): +for argname, argentry, optional in parse_args(members): if optional: ret += mcgen(''' bool has_%(c_name)s; ''', c_name=c_var(argname)) -if structured: -push_indent() -ret += generate_struct({ field: argname, data: argentry}) -pop_indent() -else: -ret += mcgen(''' +ret += mcgen(''' %(c_type)s %(c_name)s; ''', c_type=c_type(argentry), c_name=c_var(argname)) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index c739a95..6156162 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -51,27 +51,6 @@ def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = else: full_name = %s_%s % (name, fn_prefix) -for argname, argentry, optional, structured in parse_args(members): -
[Qemu-devel] [PATCH v8 14/40] qapi: Rename anonymous union type in test
Reduce churn in the future patch that replaces anonymous unions with a new metatype 'alternate' by changing 'AnonUnion' to 'Alternate'. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- tests/qapi-schema/qapi-schema-test.json | 2 +- tests/qapi-schema/qapi-schema-test.out | 4 ++-- tests/test-qmp-input-strict.c | 28 ++-- tests/test-qmp-input-visitor.c | 16 tests/test-qmp-output-visitor.c | 16 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index b134f3f..e1d35e1 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -53,7 +53,7 @@ 'discriminator': 'enum1', 'data': { 'value1' : 'UserDefC', 'value2' : 'UserDefB', 'value3' : 'UserDefA' } } -{ 'union': 'UserDefAnonUnion', +{ 'union': 'UserDefAlternate', 'discriminator': {}, 'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 664ae7b..b55ab8d 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -10,7 +10,7 @@ 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', 'UserDefFlatUnion2'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefC'), ('value2', 'UserDefB'), ('value3', 'UserDefA')]))]), - OrderedDict([('union', 'UserDefAnonUnion'), ('discriminator', OrderedDict()), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]), + OrderedDict([('union', 'UserDefAlternate'), ('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']), ('sizes', ['size'])]))]), OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]), OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]), @@ -23,7 +23,7 @@ OrderedDict([('event', 'EVENT_C'), ('data', OrderedDict([('*a', 'int'), ('*b', 'UserDefOne'), ('c', 'str')]))]), OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))])] [{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, - {'enum_name': 'UserDefAnonUnionKind', 'enum_values': None}, + {'enum_name': 'UserDefAlternateKind', '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')]))]), diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c index 486848e..a5f7bf3 100644 --- a/tests/test-qmp-input-strict.c +++ b/tests/test-qmp-input-strict.c @@ -173,18 +173,18 @@ static void test_validate_union_flat(TestInputVisitorData *data, qapi_free_UserDefFlatUnion(tmp); } -static void test_validate_union_anon(TestInputVisitorData *data, - const void *unused) +static void test_validate_alternate(TestInputVisitorData *data, +const void *unused) { -UserDefAnonUnion *tmp = NULL; +UserDefAlternate *tmp = NULL; Visitor *v; Error *err = NULL; v = validate_test_init(data, 42); -visit_type_UserDefAnonUnion(v, tmp, NULL, err); +visit_type_UserDefAlternate(v, tmp, NULL, err); g_assert(!err); -qapi_free_UserDefAnonUnion(tmp); +qapi_free_UserDefAlternate(tmp); } static void test_validate_fail_struct(TestInputVisitorData *data, @@ -276,18 +276,18 @@ static void test_validate_fail_union_flat_no_discrim(TestInputVisitorData *data, qapi_free_UserDefFlatUnion2(tmp); } -static void test_validate_fail_union_anon(TestInputVisitorData *data, - const void *unused) +static void test_validate_fail_alternate(TestInputVisitorData *data, + const void *unused) { -UserDefAnonUnion *tmp = NULL; +UserDefAlternate *tmp = NULL; Visitor *v; Error *err = NULL; v =
[Qemu-devel] [PATCH v8 29/40] qapi: Document 'struct' metatype
Referring to type as both a meta-type (built-in, enum, union, alternate, or struct) and a specific type (the name that the schema uses for declaring structs) is confusing. Now that the generator accepts 'struct' as a synonym for 'type', update all documentation to use saner wording. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- v7: fix typo in commit message, s/complex type/struct/ in documenting relation of simple union to flat union --- docs/qapi-code-gen.txt | 58 +- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 588b110..a874a6d 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -72,7 +72,7 @@ x.y.z)' comment. For example: # # Since: 0.14.0 ## -{ 'type': 'BlockStats', +{ 'struct': 'BlockStats', 'data': {'*device': 'str', 'stats': 'BlockDeviceStats', '*parent': 'BlockStats', '*backing': 'BlockStats'} } @@ -86,7 +86,7 @@ types, and allows for indefinite nesting of QMP that satisfies the schema. A type name should not be defined more than once. There are seven top-level expressions recognized by the parser: -'include', 'command', 'type', 'enum', 'union', 'alternate', and +'include', 'command', 'struct', 'enum', 'union', 'alternate', and 'event'. There are several groups of types: simple types (a number of built-in types, such as 'int' and 'str'; as well as enumerations), complex types (structs and two flavors of unions), and alternate types @@ -128,9 +128,9 @@ In the rest of this document, usage lines are given for each expression type, with literal strings written in lower case and placeholders written in capitals. If a literal string includes a prefix of '*', that key/value pair can be omitted from the expression. -For example, a usage statement that includes '*base':COMPLEX-TYPE-NAME +For example, a usage statement that includes '*base':STRUCT-NAME means that an expression has an optional key 'base', which if present -must have a value that forms a complex type name. +must have a value that forms a struct name. === Built-in Types === @@ -168,17 +168,17 @@ an outer file. The parser may be made stricter in the future to prevent incomplete include files. -=== Complex types === +=== Struct types === -Usage: { 'type': STRING, 'data': DICT, '*base': COMPLEX-TYPE-NAME } +Usage: { 'struct': STRING, 'data': DICT, '*base': STRUCT-NAME } -A complex type is a dictionary containing a single 'data' key whose +A struct is a dictionary containing a single 'data' key whose value is a dictionary. This corresponds to a struct in C or an Object in JSON. Each value of the 'data' dictionary must be the name of a type, or a one-element array containing a type name. An example of a -complex type is: +struct is: - { 'type': 'MyType', + { 'struct': 'MyType', 'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } } The use of '*' as a prefix to the name means the member is optional in @@ -211,13 +211,13 @@ A structure that is used in both input and output of various commands must consider the backwards compatibility constraints of both directions of use. -A complex type definition can specify another complex type as its base. +A struct definition can specify another struct as its base. In this case, the fields of the base type are included as top-level fields -of the new complex type's dictionary in the QMP wire format. An example +of the new struct's dictionary in the QMP wire format. An example definition is: - { 'type': 'BlockdevOptionsGenericFormat', 'data': { 'file': 'str' } } - { 'type': 'BlockdevOptionsGenericCOWFormat', + { 'struct': 'BlockdevOptionsGenericFormat', 'data': { 'file': 'str' } } + { 'struct': 'BlockdevOptionsGenericCOWFormat', 'base': 'BlockdevOptionsGenericFormat', 'data': { '*backing': 'str' } } @@ -252,7 +252,7 @@ converting between strings and enum values. Since the wire format always passes by name, it is acceptable to reorder or add new enumeration members in any location without breaking QMP clients; however, removing enum values would break compatibility. For any -complex type that has a field that will only contain a finite set of +struct that has a field that will only contain a finite set of string values, using an enum type for that field is better than open-coding the field to be type 'str'. @@ -260,7 +260,7 @@ open-coding the field to be type 'str'. === Union types === Usage: { 'union': STRING, 'data': DICT } -or:{ 'union': STRING, 'data': DICT, 'base': COMPLEX-TYPE-NAME, +or:{ 'union': STRING, 'data': DICT, 'base': STRUCT-NAME, 'discriminator': ENUM-MEMBER-OF-BASE } Union types are used to let the user choose between several different @@ -272,8 +272,8 @@ paragraphs. A simple union type defines a mapping from automatic discriminator values to data
[Qemu-devel] [PATCH v8 13/40] qapi: Segregate anonymous unions into alternates in generator
Special-casing 'discriminator == {}' for handling anonymous unions is getting awkward; since this particular type is not always a dictionary on the wire, it is easier to treat it as a completely different class of type, alternate, so that if a type is listed in the union_types array, we know it is not an anonymous union. This patch just further segregates union handling, to make sure that anonymous unions are not stored in union_types, and splitting up check_union() into separate functions. A future patch will change the qapi grammar, and having the segregation already in place will make it easier to deal with the distinct meta-type. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- scripts/qapi-types.py | 6 +-- scripts/qapi-visit.py | 4 +- scripts/qapi.py | 88 ++- tests/qapi-schema/alternate-base.err | 2 +- tests/qapi-schema/alternate-clash.err | 2 +- 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 2390887..c9e0201 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -170,7 +170,7 @@ typedef enum %(name)s return lookup_decl + enum_decl -def generate_anon_union_qtypes(expr): +def generate_alternate_qtypes(expr): name = expr['union'] members = expr['data'] @@ -181,7 +181,7 @@ const int %(name)s_qtypes[QTYPE_MAX] = { name=name) for key in members: -qtype = find_anonymous_member_qtype(members[key]) +qtype = find_alternate_member_qtype(members[key]) assert qtype, Invalid anonymous union member ret += mcgen(''' @@ -408,7 +408,7 @@ for expr in exprs: fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys())) if expr.get('discriminator') == {}: -fdef.write(generate_anon_union_qtypes(expr)) +fdef.write(generate_alternate_qtypes(expr)) else: continue fdecl.write(ret) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index dbf0101..6bd2b6b 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -237,7 +237,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **er ''', name=name) -def generate_visit_anon_union(name, members): +def generate_visit_alternate(name, members): ret = mcgen(''' void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) @@ -302,7 +302,7 @@ def generate_visit_union(expr): if discriminator == {}: assert not base -return generate_visit_anon_union(name, members) +return generate_visit_alternate(name, members) enum_define = discriminator_find_enum_define(expr) if enum_define: diff --git a/scripts/qapi.py b/scripts/qapi.py index 0c3459b..0b88325 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -224,21 +224,16 @@ def find_base_fields(base): return None return base_struct_define['data'] -# Return the qtype of an anonymous union branch, or None on error. -def find_anonymous_member_qtype(qapi_type): +# Return the qtype of an alternate branch, or None on error. +def find_alternate_member_qtype(qapi_type): if builtin_types.has_key(qapi_type): return builtin_types[qapi_type] elif find_struct(qapi_type): return QTYPE_QDICT elif find_enum(qapi_type): return QTYPE_QSTRING -else: -union = find_union(qapi_type) -if union: -discriminator = union.get('discriminator') -if discriminator == {}: -return None -return QTYPE_QDICT +elif find_union(qapi_type): +return QTYPE_QDICT return None # Return the discriminator enum define if discriminator is specified as an @@ -276,7 +271,6 @@ def check_union(expr, expr_info): discriminator = expr.get('discriminator') members = expr['data'] values = { 'MAX': '(automatic)' } -types_seen = {} # If the object has a member 'base', its value must name a complex type, # and there must be a discriminator. @@ -286,13 +280,15 @@ def check_union(expr, expr_info): Union '%s' requires a discriminator to go along with base %name) -# If the union object has no member 'discriminator', it's a -# simple union. If 'discriminator' is {}, it is an anonymous union. -if discriminator is None or discriminator == {}: +# Two types of unions, determined by discriminator. +assert discriminator != {} + +# With no discriminator it is a simple union. +if discriminator is None: enum_define = None if base is not None: raise QAPIExprError(expr_info, -Union '%s' must not have a base +
[Qemu-devel] [PATCH v8 25/40] qapi: Require valid names
Previous commits demonstrated that the generator overlooked various bad naming situations: - types, commands, and events need a valid name - enum members must be valid names, when combined with prefix - union and alternate branches cannot be marked optional Valid upstream names match [a-zA-Z][a-zA-Z0-9_-]*; valid downstream names match __[a-zA-Z][a-zA-Z0-9._-]*. Enumerations match the weaker [a-zA-Z0-9._-]+ (in part thanks to QKeyCode picking an enum that starts with a digit, which we can't change now due to backwards compatibility). Rather than call out three separate regex, this patch just uses a broader combination that allows both upstream and downstream names, as well as a small hack that realizes that any enum name is merely a suffix to an already valid name prefix (that is, any enum name is valid if prepending _ fits the normal rules). We could reject new enumeration names beginning with a digit by whitelisting existing exceptions. We could also be stricter about the distinction between upstream names (no leading underscore, no use of dot) and downstream (mandatory leading double underscore), but it is probably not worth the bother. Signed-off-by: Eric Blake ebl...@redhat.com --- v7: improve commit message v8: Prefer '_' + name over _%s % name (drop R-b) --- scripts/qapi.py| 63 -- tests/qapi-schema/bad-ident.err| 1 + tests/qapi-schema/bad-ident.exit | 2 +- tests/qapi-schema/bad-ident.json | 2 +- tests/qapi-schema/bad-ident.out| 3 -- tests/qapi-schema/enum-bad-name.err| 1 + tests/qapi-schema/enum-bad-name.exit | 2 +- tests/qapi-schema/enum-bad-name.json | 2 +- tests/qapi-schema/enum-bad-name.out| 3 -- tests/qapi-schema/enum-dict-member.err | 2 +- tests/qapi-schema/flat-union-bad-discriminator.err | 2 +- .../flat-union-optional-discriminator.err | 1 + .../flat-union-optional-discriminator.exit | 2 +- .../flat-union-optional-discriminator.json | 2 +- .../flat-union-optional-discriminator.out | 7 --- tests/qapi-schema/union-optional-branch.err| 1 + tests/qapi-schema/union-optional-branch.exit | 2 +- tests/qapi-schema/union-optional-branch.json | 2 +- tests/qapi-schema/union-optional-branch.out| 3 -- 19 files changed, 60 insertions(+), 43 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 61e1c43..f627126 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -276,8 +276,31 @@ def discriminator_find_enum_define(expr): return find_enum(discriminator_type) +valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$') +def check_name(expr_info, source, name, allow_optional = False, + enum_member = False): +global valid_name +membername = name + +if not isinstance(name, str): +raise QAPIExprError(expr_info, +%s requires a string name % source) +if name.startswith('*'): +membername = name[1:] +if not allow_optional: +raise QAPIExprError(expr_info, +%s does not allow optional name '%s' +% (source, name)) +# Enum members can start with a digit, because the generated C +# code always prefixes it with the enum name +if enum_member: +membername = '_' + membername +if not valid_name.match(membername): +raise QAPIExprError(expr_info, +%s uses invalid name '%s' % (source, name)) + def check_type(expr_info, source, value, allow_array = False, - allow_dict = False, allow_metas = []): + allow_dict = False, allow_optional = False, allow_metas = []): global all_names orig_value = value @@ -319,18 +342,21 @@ def check_type(expr_info, source, value, allow_array = False, raise QAPIExprError(expr_info, %s should be a type name % source) for (key, arg) in value.items(): +check_name(expr_info, Member of %s % source, key, + allow_optional=allow_optional) check_type(expr_info, Member '%s' of %s % (key, source), arg, - allow_array=True, allow_dict=True, + allow_array=True, allow_dict=True, allow_optional=True, allow_metas=['built-in', 'union', 'alternate', 'struct', 'enum']) def check_command(expr, expr_info): name = expr['command'] check_type(expr_info, 'data' for command '%s' % name, - expr.get('data'), allow_dict=True, + expr.get('data'), allow_dict=True, allow_optional=True, allow_metas=['union', 'struct']) check_type(expr_info, 'returns' for command '%s' % name, expr.get('returns'), allow_array=True,
[Qemu-devel] [PATCH v8 17/40] qapi: Add some expr tests
Demonstrate that the qapi generator doesn't deal well with expressions that aren't up to par. Later patches will improve the expected results as the generator is made stricter. Only a few of the the added tests actually behave sanely at rejecting obvious problems or demonstrating success. Note that in some cases, we reject bad QAPI merely because our pseudo-JSON parser does not yet know how to parse numbers. This series does not address that, but when a later series adds support for numeric defaults of integer fields, the testsuite will ensure that we don't lose the error (and hopefully that the error message quality is improved). Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- v7: fix commit typo --- tests/Makefile | 8 +--- tests/qapi-schema/bad-base.err | 0 tests/qapi-schema/bad-base.exit | 1 + tests/qapi-schema/bad-base.json | 3 +++ tests/qapi-schema/bad-base.out | 4 tests/qapi-schema/bad-ident.err | 0 tests/qapi-schema/bad-ident.exit | 1 + tests/qapi-schema/bad-ident.json | 2 ++ tests/qapi-schema/bad-ident.out | 3 +++ tests/qapi-schema/bad-type-bool.err | 1 + tests/qapi-schema/bad-type-bool.exit | 1 + tests/qapi-schema/bad-type-bool.json | 3 +++ tests/qapi-schema/bad-type-bool.out | 0 tests/qapi-schema/bad-type-dict.err | 0 tests/qapi-schema/bad-type-dict.exit | 1 + tests/qapi-schema/bad-type-dict.json | 2 ++ tests/qapi-schema/bad-type-dict.out | 3 +++ tests/qapi-schema/bad-type-int.err | 1 + tests/qapi-schema/bad-type-int.exit | 1 + tests/qapi-schema/bad-type-int.json | 3 +++ tests/qapi-schema/bad-type-int.out | 0 tests/qapi-schema/double-data.err| 1 + tests/qapi-schema/double-data.exit | 1 + tests/qapi-schema/double-data.json | 2 ++ tests/qapi-schema/double-data.out| 0 tests/qapi-schema/double-type.err| 0 tests/qapi-schema/double-type.exit | 1 + tests/qapi-schema/double-type.json | 2 ++ tests/qapi-schema/double-type.out| 3 +++ tests/qapi-schema/event-case.err | 0 tests/qapi-schema/event-case.exit| 1 + tests/qapi-schema/event-case.json| 3 +++ tests/qapi-schema/event-case.out | 3 +++ tests/qapi-schema/ident-with-escape.err | 0 tests/qapi-schema/ident-with-escape.exit | 1 + tests/qapi-schema/ident-with-escape.json | 4 tests/qapi-schema/ident-with-escape.out | 3 +++ tests/qapi-schema/missing-type.err | 0 tests/qapi-schema/missing-type.exit | 1 + tests/qapi-schema/missing-type.json | 2 ++ tests/qapi-schema/missing-type.out | 3 +++ tests/qapi-schema/unknown-expr-key.err | 0 tests/qapi-schema/unknown-expr-key.exit | 1 + tests/qapi-schema/unknown-expr-key.json | 2 ++ tests/qapi-schema/unknown-expr-key.out | 3 +++ 45 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 tests/qapi-schema/bad-base.err create mode 100644 tests/qapi-schema/bad-base.exit create mode 100644 tests/qapi-schema/bad-base.json create mode 100644 tests/qapi-schema/bad-base.out create mode 100644 tests/qapi-schema/bad-ident.err create mode 100644 tests/qapi-schema/bad-ident.exit create mode 100644 tests/qapi-schema/bad-ident.json create mode 100644 tests/qapi-schema/bad-ident.out create mode 100644 tests/qapi-schema/bad-type-bool.err create mode 100644 tests/qapi-schema/bad-type-bool.exit create mode 100644 tests/qapi-schema/bad-type-bool.json create mode 100644 tests/qapi-schema/bad-type-bool.out create mode 100644 tests/qapi-schema/bad-type-dict.err create mode 100644 tests/qapi-schema/bad-type-dict.exit create mode 100644 tests/qapi-schema/bad-type-dict.json create mode 100644 tests/qapi-schema/bad-type-dict.out create mode 100644 tests/qapi-schema/bad-type-int.err create mode 100644 tests/qapi-schema/bad-type-int.exit create mode 100644 tests/qapi-schema/bad-type-int.json create mode 100644 tests/qapi-schema/bad-type-int.out create mode 100644 tests/qapi-schema/double-data.err create mode 100644 tests/qapi-schema/double-data.exit create mode 100644 tests/qapi-schema/double-data.json create mode 100644 tests/qapi-schema/double-data.out create mode 100644 tests/qapi-schema/double-type.err create mode 100644 tests/qapi-schema/double-type.exit create mode 100644 tests/qapi-schema/double-type.json create mode 100644 tests/qapi-schema/double-type.out create mode 100644 tests/qapi-schema/event-case.err create mode 100644 tests/qapi-schema/event-case.exit create mode 100644 tests/qapi-schema/event-case.json create mode 100644 tests/qapi-schema/event-case.out create mode 100644 tests/qapi-schema/ident-with-escape.err create mode 100644 tests/qapi-schema/ident-with-escape.exit create mode 100644 tests/qapi-schema/ident-with-escape.json create mode 100644 tests/qapi-schema/ident-with-escape.out create mode 100644
[Qemu-devel] [PATCH v8 12/40] qapi: Prepare for catching more semantic parse errors
This patch widens the scope of a try block (with the attending reindentation required by Python) in preparation for a future patch adding more instances of QAPIExprError inside the block. It's easier to separate indentation from semantic changes, so this patch has no real behavior change. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- scripts/qapi.py | 37 - 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 5f0f699..0c3459b 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -399,6 +399,7 @@ def check_exprs(schema): check_event(expr, info) def parse_schema(input_file): +# First pass: read entire file into memory try: schema = QAPISchema(open(input_file, r)) except (QAPISchemaError, QAPIExprError), e: @@ -407,24 +408,26 @@ def parse_schema(input_file): exprs = [] -for expr_elem in schema.exprs: -expr = expr_elem['expr'] -if expr.has_key('enum'): -add_enum(expr['enum'], expr.get('data')) -elif expr.has_key('union'): -add_union(expr) -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: +# Next pass: learn the types. +for expr_elem in schema.exprs: +expr = expr_elem['expr'] +if expr.has_key('enum'): +add_enum(expr['enum'], expr.get('data')) +elif expr.has_key('union'): +add_union(expr) +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']) + +# Final pass - validate that exprs make sense check_exprs(schema) except QAPIExprError, e: print sys.stderr, e -- 2.1.0
[Qemu-devel] [PATCH v8 39/40] qapi: Support (subset of) \u escapes in strings
The handling of \ inside QAPI strings was less than ideal, and really only worked JSON's \/, \\, \, and our extension of \' (an obvious extension, when you realize we use '' instead of for strings). For other things, like '\n', it resulted in a literal 'n' instead of a newline. Of course, at the moment, we really have no use for escaped characters, as QAPI has to map to C identifiers, and we currently support ASCII only for that. But down the road, we may add support for default values for string parameters to a command or struct; if that happens, it would be nice to correctly support all JSON escape sequences, such as \n or \u. This gets us closer, by supporting Unicode escapes in the ASCII range. Since JSON does not require \OCTAL or \xXX escapes, and our QMP implementation does not understand them either, I intentionally reject it here, but it would be an easy addition if we desired it. Likewise, intentionally refusing the NUL byte means we don't have to worry about C strings being shorter than the qapi input. Signed-off-by: Eric Blake ebl...@redhat.com --- v7: add escape-outside-string, unknown-escape, and tighten parser to reject unknown escapes and \u --- scripts/qapi.py | 36 +++- tests/Makefile | 2 ++ tests/qapi-schema/escape-outside-string.err | 1 + tests/qapi-schema/escape-outside-string.exit | 1 + tests/qapi-schema/escape-outside-string.json | 3 +++ tests/qapi-schema/escape-outside-string.out | 0 tests/qapi-schema/escape-too-big.err | 1 + tests/qapi-schema/escape-too-big.exit| 1 + tests/qapi-schema/escape-too-big.json| 3 +++ tests/qapi-schema/escape-too-big.out | 0 tests/qapi-schema/escape-too-short.err | 1 + tests/qapi-schema/escape-too-short.exit | 1 + tests/qapi-schema/escape-too-short.json | 3 +++ tests/qapi-schema/escape-too-short.out | 0 tests/qapi-schema/ident-with-escape.err | 1 - tests/qapi-schema/ident-with-escape.exit | 2 +- tests/qapi-schema/ident-with-escape.json | 2 +- tests/qapi-schema/ident-with-escape.out | 3 +++ tests/qapi-schema/unicode-str.err| 1 + tests/qapi-schema/unicode-str.exit | 1 + tests/qapi-schema/unicode-str.json | 2 ++ tests/qapi-schema/unicode-str.out| 0 tests/qapi-schema/unknown-escape.err | 1 + tests/qapi-schema/unknown-escape.exit| 1 + tests/qapi-schema/unknown-escape.json| 3 +++ tests/qapi-schema/unknown-escape.out | 0 26 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 tests/qapi-schema/escape-outside-string.err create mode 100644 tests/qapi-schema/escape-outside-string.exit create mode 100644 tests/qapi-schema/escape-outside-string.json create mode 100644 tests/qapi-schema/escape-outside-string.out create mode 100644 tests/qapi-schema/escape-too-big.err create mode 100644 tests/qapi-schema/escape-too-big.exit create mode 100644 tests/qapi-schema/escape-too-big.json create mode 100644 tests/qapi-schema/escape-too-big.out create mode 100644 tests/qapi-schema/escape-too-short.err create mode 100644 tests/qapi-schema/escape-too-short.exit create mode 100644 tests/qapi-schema/escape-too-short.json create mode 100644 tests/qapi-schema/escape-too-short.out create mode 100644 tests/qapi-schema/unicode-str.err create mode 100644 tests/qapi-schema/unicode-str.exit create mode 100644 tests/qapi-schema/unicode-str.json create mode 100644 tests/qapi-schema/unicode-str.out create mode 100644 tests/qapi-schema/unknown-escape.err create mode 100644 tests/qapi-schema/unknown-escape.exit create mode 100644 tests/qapi-schema/unknown-escape.json create mode 100644 tests/qapi-schema/unknown-escape.out diff --git a/scripts/qapi.py b/scripts/qapi.py index 3c8ce45..14468ba 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -173,7 +173,41 @@ class QAPISchema: raise QAPISchemaError(self, 'Missing terminating \'') if esc: -string += ch +if ch == 'b': +string += '\b' +elif ch == 'f': +string += '\f' +elif ch == 'n': +string += '\n' +elif ch == 'r': +string += '\r' +elif ch == 't': +string += '\t' +elif ch == 'u': +value = 0 +for x in range(0, 4): +ch = self.src[self.cursor] +self.cursor += 1 +if ch not in 0123456789abcdefABCDEF: +raise QAPISchemaError(self, +
[Qemu-devel] [PATCH v8 19/40] qapi: Add tests of redefined expressions
Demonstrate that the qapi generator doesn't deal very well with redefined expressions. At the parse level, they are silently accepted; and while the testsuite just stops at parsing, I've further tested that many of them cause generator crashes or invalid C code if they were appended to qapi-schema-test.json. A later patch will tighten things up and adjust the testsuite to match. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- tests/Makefile | 2 ++ tests/qapi-schema/command-int.err| 0 tests/qapi-schema/command-int.exit | 1 + tests/qapi-schema/command-int.json | 3 +++ tests/qapi-schema/command-int.out| 3 +++ tests/qapi-schema/event-max.err | 0 tests/qapi-schema/event-max.exit | 1 + tests/qapi-schema/event-max.json | 2 ++ tests/qapi-schema/event-max.out | 3 +++ tests/qapi-schema/redefined-builtin.err | 0 tests/qapi-schema/redefined-builtin.exit | 1 + tests/qapi-schema/redefined-builtin.json | 2 ++ tests/qapi-schema/redefined-builtin.out | 3 +++ tests/qapi-schema/redefined-command.err | 0 tests/qapi-schema/redefined-command.exit | 1 + tests/qapi-schema/redefined-command.json | 3 +++ tests/qapi-schema/redefined-command.out | 4 tests/qapi-schema/redefined-event.err| 0 tests/qapi-schema/redefined-event.exit | 1 + tests/qapi-schema/redefined-event.json | 3 +++ tests/qapi-schema/redefined-event.out| 4 tests/qapi-schema/redefined-type.err | 0 tests/qapi-schema/redefined-type.exit| 1 + tests/qapi-schema/redefined-type.json| 3 +++ tests/qapi-schema/redefined-type.out | 4 25 files changed, 45 insertions(+) create mode 100644 tests/qapi-schema/command-int.err create mode 100644 tests/qapi-schema/command-int.exit create mode 100644 tests/qapi-schema/command-int.json create mode 100644 tests/qapi-schema/command-int.out create mode 100644 tests/qapi-schema/event-max.err create mode 100644 tests/qapi-schema/event-max.exit create mode 100644 tests/qapi-schema/event-max.json create mode 100644 tests/qapi-schema/event-max.out create mode 100644 tests/qapi-schema/redefined-builtin.err create mode 100644 tests/qapi-schema/redefined-builtin.exit create mode 100644 tests/qapi-schema/redefined-builtin.json create mode 100644 tests/qapi-schema/redefined-builtin.out create mode 100644 tests/qapi-schema/redefined-command.err create mode 100644 tests/qapi-schema/redefined-command.exit create mode 100644 tests/qapi-schema/redefined-command.json create mode 100644 tests/qapi-schema/redefined-command.out create mode 100644 tests/qapi-schema/redefined-event.err create mode 100644 tests/qapi-schema/redefined-event.exit create mode 100644 tests/qapi-schema/redefined-event.json create mode 100644 tests/qapi-schema/redefined-event.out create mode 100644 tests/qapi-schema/redefined-type.err create mode 100644 tests/qapi-schema/redefined-type.exit create mode 100644 tests/qapi-schema/redefined-type.json create mode 100644 tests/qapi-schema/redefined-type.out diff --git a/tests/Makefile b/tests/Makefile index 835ec9c..c27940c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -214,6 +214,8 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \ missing-type.json bad-ident.json ident-with-escape.json \ double-type.json bad-base.json bad-type-bool.json bad-type-int.json \ bad-type-dict.json double-data.json unknown-expr-key.json \ + redefined-type.json redefined-command.json redefined-builtin.json \ + redefined-event.json command-int.json event-max.json \ missing-colon.json missing-comma-list.json \ missing-comma-object.json non-objects.json \ qapi-schema-test.json quoted-structural-chars.json \ diff --git a/tests/qapi-schema/command-int.err b/tests/qapi-schema/command-int.err new file mode 100644 index 000..e69de29 diff --git a/tests/qapi-schema/command-int.exit b/tests/qapi-schema/command-int.exit new file mode 100644 index 000..573541a --- /dev/null +++ b/tests/qapi-schema/command-int.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/command-int.json b/tests/qapi-schema/command-int.json new file mode 100644 index 000..fcbb643 --- /dev/null +++ b/tests/qapi-schema/command-int.json @@ -0,0 +1,3 @@ +# FIXME: we should reject collisions between commands and types +{ 'command': 'int', 'data': { 'character': 'str' }, + 'returns': { 'value': 'int' } } diff --git a/tests/qapi-schema/command-int.out b/tests/qapi-schema/command-int.out new file mode 100644 index 000..d8e1854 --- /dev/null +++ b/tests/qapi-schema/command-int.out @@ -0,0 +1,3 @@ +[OrderedDict([('command', 'int'), ('data', OrderedDict([('character', 'str')])), ('returns', OrderedDict([('value', 'int')]))])] +[] +[] diff --git a/tests/qapi-schema/event-max.err b/tests/qapi-schema/event-max.err new file mode 100644 index 000..e69de29 diff --git
[Qemu-devel] [PATCH v8 26/40] qapi: Whitelist commands that don't return dictionary
...or an array of dictionaries. Although we have to cater to existing commands, returning a non-dictionary means the command is not extensible (no new name/value pairs can be added if more information must be returned in parallel). By making the whitelist explicit, any new command that falls foul of this practice will have to be self-documenting, which will encourage developers to either justify the action or rework the design to use a dictionary after all. It's a little bit sloppy that we share a single whitelist among three clients (it's too permissive for each). If this is a problem, a future patch could tighten things by having the generator take the whitelist as an argument (as in scripts/qapi-commands.py --legacy-returns=...), or by having the generator output C code that requires explicit use of the whitelist (as in: #ifndef FROBNICATE_LEGACY_RETURN_OK # error Command 'frobnicate' should return a dictionary #endif then having the callers define appropriate macros). But until we need such fine-grained separation (if ever), this patch does the job just fine. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- scripts/qapi.py | 31 --- tests/qapi-schema/returns-alternate.err | 1 + tests/qapi-schema/returns-alternate.exit | 2 +- tests/qapi-schema/returns-alternate.json | 2 +- tests/qapi-schema/returns-alternate.out | 4 tests/qapi-schema/returns-int.json | 3 ++- tests/qapi-schema/returns-int.out| 2 +- tests/qapi-schema/returns-whitelist.err | 1 + tests/qapi-schema/returns-whitelist.exit | 2 +- tests/qapi-schema/returns-whitelist.json | 2 +- tests/qapi-schema/returns-whitelist.out | 7 --- 11 files changed, 37 insertions(+), 20 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index f627126..b218ee5 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -32,6 +32,30 @@ builtin_types = { 'size': 'QTYPE_QINT', } +# Whitelist of commands allowed to return a non-dictionary +returns_whitelist = [ +# From QMP: +'human-monitor-command', +'query-migrate-cache-size', +'query-tpm-models', +'query-tpm-types', +'ringbuf-read', + +# From QGA: +'guest-file-open', +'guest-fsfreeze-freeze', +'guest-fsfreeze-freeze-list', +'guest-fsfreeze-status', +'guest-fsfreeze-thaw', +'guest-get-time', +'guest-set-vcpus', +'guest-sync', +'guest-sync-delimited', + +# From qapi-schema-test: +'user_def_cmd3', +] + enum_types = [] struct_types = [] union_types = [] @@ -354,11 +378,12 @@ def check_command(expr, expr_info): check_type(expr_info, 'data' for command '%s' % name, expr.get('data'), allow_dict=True, allow_optional=True, allow_metas=['union', 'struct']) +returns_meta = ['union', 'struct'] +if name in returns_whitelist: +returns_meta += ['built-in', 'alternate', 'enum'] check_type(expr_info, 'returns' for command '%s' % name, expr.get('returns'), allow_array=True, allow_dict=True, - allow_optional=True, - allow_metas=['built-in', 'union', 'alternate', 'struct', -'enum']) + allow_optional=True, allow_metas=returns_meta) def check_event(expr, expr_info): global events diff --git a/tests/qapi-schema/returns-alternate.err b/tests/qapi-schema/returns-alternate.err index e69de29..dfbb419 100644 --- a/tests/qapi-schema/returns-alternate.err +++ b/tests/qapi-schema/returns-alternate.err @@ -0,0 +1 @@ +tests/qapi-schema/returns-alternate.json:3: 'returns' for command 'oops' cannot use alternate type 'Alt' diff --git a/tests/qapi-schema/returns-alternate.exit b/tests/qapi-schema/returns-alternate.exit index 573541a..d00491f 100644 --- a/tests/qapi-schema/returns-alternate.exit +++ b/tests/qapi-schema/returns-alternate.exit @@ -1 +1 @@ -0 +1 diff --git a/tests/qapi-schema/returns-alternate.json b/tests/qapi-schema/returns-alternate.json index b3b91fd..972390c 100644 --- a/tests/qapi-schema/returns-alternate.json +++ b/tests/qapi-schema/returns-alternate.json @@ -1,3 +1,3 @@ -# FIXME: we should reject returns if it is an alternate type +# we reject returns if it is an alternate type { 'alternate': 'Alt', 'data': { 'a': 'int', 'b': 'str' } } { 'command': 'oops', 'returns': 'Alt' } diff --git a/tests/qapi-schema/returns-alternate.out b/tests/qapi-schema/returns-alternate.out index 8a03ed3..e69de29 100644 --- a/tests/qapi-schema/returns-alternate.out +++ b/tests/qapi-schema/returns-alternate.out @@ -1,4 +0,0 @@ -[OrderedDict([('alternate', 'Alt'), ('data', OrderedDict([('a', 'int'), ('b', 'str')]))]), - OrderedDict([('command', 'oops'), ('returns', 'Alt')])] -[{'enum_name': 'AltKind', 'enum_values': None}] -[] diff --git a/tests/qapi-schema/returns-int.json b/tests/qapi-schema/returns-int.json index 7888fb1..870ec63 100644 ---
[Qemu-devel] [PATCH v8 16/40] qapi: Use 'alternate' to replace anonymous union
Previous patches have led up to the point where I create the new meta-type 'alternate':'Foo'. See the previous patches for documentation; I intentionally split as much work into earlier patches to minimize the size of this patch, but a lot of it is churn due to testsuite fallout after updating to the new type. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- v7: rebase to earlier changes, move flat-union-bsae-union comment change to correct commit --- qapi/block-core.json | 6 ++-- scripts/qapi-types.py | 26 -- scripts/qapi-visit.py | 17 scripts/qapi.py| 32 ++ tests/qapi-schema/alternate-array.err | 2 +- tests/qapi-schema/alternate-array.json | 5 ++-- tests/qapi-schema/alternate-base.err | 2 +- tests/qapi-schema/alternate-base.json | 5 ++-- tests/qapi-schema/alternate-clash.err | 2 +- tests/qapi-schema/alternate-clash.json | 5 ++-- tests/qapi-schema/alternate-conflict-dict.err | 2 +- tests/qapi-schema/alternate-conflict-dict.json | 5 ++-- tests/qapi-schema/alternate-conflict-string.err| 2 +- tests/qapi-schema/alternate-conflict-string.json | 5 ++-- tests/qapi-schema/alternate-good.json | 5 ++-- tests/qapi-schema/alternate-good.out | 4 +-- tests/qapi-schema/alternate-nested.err | 2 +- tests/qapi-schema/alternate-nested.json| 10 +++ tests/qapi-schema/alternate-unknown.err| 2 +- tests/qapi-schema/alternate-unknown.json | 5 ++-- tests/qapi-schema/flat-union-bad-discriminator.err | 2 +- .../qapi-schema/flat-union-bad-discriminator.json | 3 +- tests/qapi-schema/qapi-schema-test.json| 3 +- tests/qapi-schema/qapi-schema-test.out | 2 +- 24 files changed, 77 insertions(+), 77 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 1c17224..3d20e61 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1503,8 +1503,7 @@ # # Since: 2.2 ## -{ 'union': 'Qcow2OverlapChecks', - 'discriminator': {}, +{ 'alternate': 'Qcow2OverlapChecks', 'data': { 'flags': 'Qcow2OverlapCheckFlags', 'mode': 'Qcow2OverlapCheckMode' } } @@ -1795,8 +1794,7 @@ # # Since: 1.7 ## -{ 'union': 'BlockdevRef', - 'discriminator': {}, +{ 'alternate': 'BlockdevRef', 'data': { 'definition': 'BlockdevOptions', 'reference': 'str' } } diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index c9e0201..9c8d68c 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -172,7 +172,7 @@ typedef enum %(name)s def generate_alternate_qtypes(expr): -name = expr['union'] +name = expr['alternate'] members = expr['data'] ret = mcgen(''' @@ -182,7 +182,7 @@ const int %(name)s_qtypes[QTYPE_MAX] = { for key in members: qtype = find_alternate_member_qtype(members[key]) -assert qtype, Invalid anonymous union member +assert qtype, Invalid alternate member ret += mcgen(''' [ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s, @@ -197,9 +197,9 @@ const int %(name)s_qtypes[QTYPE_MAX] = { return ret -def generate_union(expr): +def generate_union(expr, meta): -name = expr['union'] +name = expr[meta] typeinfo = expr['data'] base = expr.get('base') @@ -243,7 +243,7 @@ struct %(name)s ret += mcgen(''' }; ''') -if discriminator == {}: +if meta == 'alternate': ret += mcgen(''' extern const int %(name)s_qtypes[]; ''', @@ -407,8 +407,12 @@ for expr in exprs: 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_alternate_qtypes(expr)) +elif expr.has_key('alternate'): +ret += generate_fwd_struct(expr['alternate'], expr['data']) + \n +ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys()) +fdef.write(generate_enum_lookup('%sKind' % expr['alternate'], +expr['data'].keys())) +fdef.write(generate_alternate_qtypes(expr)) else: continue fdecl.write(ret) @@ -438,11 +442,17 @@ for expr in exprs: ret += generate_type_cleanup_decl(expr['type']) fdef.write(generate_type_cleanup(expr['type']) + \n) elif expr.has_key('union'): -ret += generate_union(expr) +ret += generate_union(expr, 'union') ret += generate_type_cleanup_decl(expr['union'] + List) fdef.write(generate_type_cleanup(expr['union'] + List) + \n) ret +=
Re: [Qemu-devel] [RFC PATCH v3 08/24] ppc: Prepare CPU socket/core abstraction
On Fri, 24 Apr 2015 12:17:30 +0530 Bharata B Rao bhar...@linux.vnet.ibm.com wrote: Signed-off-by: Bharata B Rao bhar...@linux.vnet.ibm.com Signed-off-by: Andreas Färber afaer...@suse.de Not sure if QEMU is fully following the kernel Sob-process, but if that's the case, I think your Sob should be below the one of Andreas in case you're the last person who touched the patch (and I think that's the case here since you've sent it out)? Also a short patch description would be really nice. Thomas
[Qemu-devel] [PATCH v8 18/40] qapi: Better error messages for bad expressions
The previous commit demonstrated that the generator overlooked some fairly basic broken expressions: - missing metataype - metatype key has a non-string value - unknown key in relation to the metatype - conflicting metatype (this patch treats the second metatype as an unknown key of the first key visited, which is not necessarily the first key the user typed) Add check_keys to cover these situations, and update testcases to match. A couple other tests (enum-missing-data, indented-expr) had to change since the validation added here occurs so early. Conversely, changes to ident-with-escape results show that we still have problems where our handling of escape sequences differs from true JSON, which will matter down the road if we allow arbitrary default string values for optional parameters (but for now is not too bad, as we currently can avoid unicode escaping as we don't need to represent anything beyond C identifier material). While valid .json files won't trigger any of these cases, we might as well be nicer to developers that make a typo while trying to add new QAPI code. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- scripts/qapi.py | 44 +++- tests/qapi-schema/alternate-base.err | 2 +- tests/qapi-schema/bad-type-dict.err | 1 + tests/qapi-schema/bad-type-dict.exit | 2 +- tests/qapi-schema/bad-type-dict.json | 2 +- tests/qapi-schema/bad-type-dict.out | 3 --- tests/qapi-schema/double-type.err| 1 + tests/qapi-schema/double-type.exit | 2 +- tests/qapi-schema/double-type.json | 2 +- tests/qapi-schema/double-type.out| 3 --- tests/qapi-schema/enum-missing-data.err | 2 +- tests/qapi-schema/ident-with-escape.err | 1 + tests/qapi-schema/ident-with-escape.exit | 2 +- tests/qapi-schema/ident-with-escape.out | 3 --- tests/qapi-schema/indented-expr.json | 4 +-- tests/qapi-schema/indented-expr.out | 2 +- tests/qapi-schema/missing-type.err | 1 + tests/qapi-schema/missing-type.exit | 2 +- tests/qapi-schema/missing-type.json | 2 +- tests/qapi-schema/missing-type.out | 3 --- tests/qapi-schema/unknown-expr-key.err | 1 + tests/qapi-schema/unknown-expr-key.exit | 2 +- tests/qapi-schema/unknown-expr-key.json | 2 +- tests/qapi-schema/unknown-expr-key.out | 3 --- 24 files changed, 56 insertions(+), 36 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 05c38c5..868f08b 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -348,11 +348,6 @@ def check_alternate(expr, expr_info): values = { 'MAX': '(automatic)' } types_seen = {} -if expr.get('base') is not None: -raise QAPIExprError(expr_info, -Alternate '%s' must not have a base -% name) - # Check every branch for (key, value) in members.items(): # Check for conflicts in the generated enum @@ -414,6 +409,26 @@ def check_exprs(schema): elif expr.has_key('event'): check_event(expr, info) +def check_keys(expr_elem, meta, required, optional=[]): +expr = expr_elem['expr'] +info = expr_elem['info'] +name = expr[meta] +if not isinstance(name, str): +raise QAPIExprError(info, +'%s' key must have a string value % meta) +required = required + [ meta ] +for (key, value) in expr.items(): +if not key in required and not key in optional: +raise QAPIExprError(info, +Unknown key '%s' in %s '%s' +% (key, meta, name)) +for key in required: +if not expr.has_key(key): +raise QAPIExprError(info, +Key '%s' is missing from %s '%s' +% (key, meta, name)) + + def parse_schema(input_file): # First pass: read entire file into memory try: @@ -425,15 +440,30 @@ def parse_schema(input_file): exprs = [] try: -# Next pass: learn the types. +# Next pass: learn the types and check for valid expression keys. At +# this point, top-level 'include' has already been flattened. for expr_elem in schema.exprs: expr = expr_elem['expr'] if expr.has_key('enum'): -add_enum(expr['enum'], expr.get('data')) +check_keys(expr_elem, 'enum', ['data']) +add_enum(expr['enum'], expr['data']) elif expr.has_key('union'): +check_keys(expr_elem, 'union', ['data'], + ['base', 'discriminator']) add_union(expr) +elif expr.has_key('alternate'): +check_keys(expr_elem, 'alternate', ['data']) elif expr.has_key('type'): +check_keys(expr_elem, 'type', ['data'], ['base'])
[Qemu-devel] [PATCH v8 32/40] qapi: Merge UserDefTwo and UserDefNested in tests
In the testsuite, UserDefTwo and UserDefNested were identical structs other than the member names. Reduce code duplication by having just one type, and choose names that also favor reuse. This will also make it easier for a later patch to get rid of inline nested types in QAPI. When touching code related to allocations, convert g_malloc0(sizeof(Type)) to the more typesafe g_new0(Type, 1). Ensure that 'make check-qapi-schema check-unit' still passes. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- tests/qapi-schema/qapi-schema-test.json | 10 + tests/qapi-schema/qapi-schema-test.out | 6 +-- tests/test-qmp-commands.c | 34 +++ tests/test-qmp-input-strict.c | 17 tests/test-qmp-input-visitor.c | 17 tests/test-qmp-output-visitor.c | 48 +++--- tests/test-visitor-serialization.c | 73 + 7 files changed, 102 insertions(+), 103 deletions(-) diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index f10efe2..a6be983 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -15,16 +15,10 @@ 'data': { 'string': 'str', '*enum1': 'EnumOne' } } { 'struct': 'UserDefTwo', - 'data': { 'string': 'str', -'dict': { 'string': 'str', - 'dict': { 'userdef': 'UserDefOne', 'string': 'str' }, - '*dict2': { 'userdef': 'UserDefOne', 'string': 'str' } } } } - -{ 'struct': 'UserDefNested', 'data': { 'string0': 'str', 'dict1': { 'string1': 'str', - 'dict2': { 'userdef1': 'UserDefOne', 'string2': 'str' }, - '*dict3': { 'userdef2': 'UserDefOne', 'string3': 'str' } } } } + 'dict2': { 'userdef': 'UserDefOne', 'string': 'str' }, + '*dict3': { 'userdef': 'UserDefOne', 'string': 'str' } } } } # for testing unions { 'struct': 'UserDefA', diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 83ab1a5..48f8f0e 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -2,8 +2,7 @@ OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]), - OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string', 'str'), ('dict', OrderedDict([('string', 'str'), ('dict', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')])), ('*dict2', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]))]))]), - OrderedDict([('struct', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]), + OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')])), ('*dict3', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]))]))]), OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]), @@ -28,8 +27,7 @@ [OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]), - OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string', 'str'), ('dict', OrderedDict([('string', 'str'), ('dict', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')])), ('*dict2', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]))]))]), - OrderedDict([('struct', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]), + OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')])),
[Qemu-devel] [PATCH v8 20/40] qapi: Better error messages for duplicated expressions
The previous commit demonstrated that the generator overlooked duplicate expressions: - a complex type or command reusing a built-in type name - redeclaration of a type name, whether by the same or different metatype - redeclaration of a command or event - collision of a type with implicit 'Kind' enum for a union - collision with an implicit MAX enum constant Since the c_type() function in the generator treats all names as being in the same namespace, this patch adds a global array to track all known names and their source, to prevent collisions before it can cause further problems. While valid .json files won't trigger any of these cases, we might as well be nicer to developers that make a typo while trying to add new QAPI code. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- scripts/qapi.py | 63 +--- tests/qapi-schema/command-int.err| 1 + tests/qapi-schema/command-int.exit | 2 +- tests/qapi-schema/command-int.json | 2 +- tests/qapi-schema/command-int.out| 3 -- tests/qapi-schema/enum-union-clash.err | 1 + tests/qapi-schema/enum-union-clash.exit | 2 +- tests/qapi-schema/enum-union-clash.json | 2 +- tests/qapi-schema/enum-union-clash.out | 5 --- tests/qapi-schema/event-max.err | 1 + tests/qapi-schema/event-max.exit | 2 +- tests/qapi-schema/event-max.json | 2 +- tests/qapi-schema/event-max.out | 3 -- tests/qapi-schema/redefined-builtin.err | 1 + tests/qapi-schema/redefined-builtin.exit | 2 +- tests/qapi-schema/redefined-builtin.json | 2 +- tests/qapi-schema/redefined-builtin.out | 3 -- tests/qapi-schema/redefined-command.err | 1 + tests/qapi-schema/redefined-command.exit | 2 +- tests/qapi-schema/redefined-command.json | 2 +- tests/qapi-schema/redefined-command.out | 4 -- tests/qapi-schema/redefined-event.err| 1 + tests/qapi-schema/redefined-event.exit | 2 +- tests/qapi-schema/redefined-event.json | 2 +- tests/qapi-schema/redefined-event.out| 4 -- tests/qapi-schema/redefined-type.err | 1 + tests/qapi-schema/redefined-type.exit| 2 +- tests/qapi-schema/redefined-type.json| 2 +- tests/qapi-schema/redefined-type.out | 4 -- 29 files changed, 70 insertions(+), 54 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 868f08b..eea0976 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -32,6 +32,12 @@ builtin_types = { 'size': 'QTYPE_QINT', } +enum_types = [] +struct_types = [] +union_types = [] +events = [] +all_names = {} + def error_path(parent): res = while parent: @@ -256,7 +262,14 @@ def discriminator_find_enum_define(expr): return find_enum(discriminator_type) def check_event(expr, expr_info): +global events +name = expr['event'] params = expr.get('data') + +if name.upper() == 'MAX': +raise QAPIExprError(expr_info, Event name 'MAX' cannot be created) +events.append(name) + if params: for argname, argentry, optional, structured in parse_args(params): if structured: @@ -430,6 +443,9 @@ def check_keys(expr_elem, meta, required, optional=[]): def parse_schema(input_file): +global all_names +exprs = [] + # First pass: read entire file into memory try: schema = QAPISchema(open(input_file, r)) @@ -437,30 +453,34 @@ def parse_schema(input_file): print sys.stderr, e exit(1) -exprs = [] - try: # Next pass: learn the types and check for valid expression keys. At # this point, top-level 'include' has already been flattened. +for builtin in builtin_types.keys(): +all_names[builtin] = 'built-in' for expr_elem in schema.exprs: expr = expr_elem['expr'] +info = expr_elem['info'] if expr.has_key('enum'): check_keys(expr_elem, 'enum', ['data']) -add_enum(expr['enum'], expr['data']) +add_enum(expr['enum'], info, expr['data']) elif expr.has_key('union'): check_keys(expr_elem, 'union', ['data'], ['base', 'discriminator']) -add_union(expr) +add_union(expr, info) elif expr.has_key('alternate'): check_keys(expr_elem, 'alternate', ['data']) +add_name(expr['alternate'], info, 'alternate') elif expr.has_key('type'): check_keys(expr_elem, 'type', ['data'], ['base']) -add_struct(expr) +add_struct(expr, info) elif expr.has_key('command'): check_keys(expr_elem, 'command', [], ['data', 'returns', 'gen', 'success-response']) +add_name(expr['command'], info, 'command') elif expr.has_key('event'):
[Qemu-devel] [PATCH v8 22/40] qapi: Unify type bypass and add tests
For a few QMP commands, we are forced to pass an arbitrary type without tracking it properly in QAPI. Among the existing clients, this unnamed type was spelled 'dict', 'visitor', and '**'; this patch standardizes on '**', matching the documentation changes earlier in the series. Meanwhile, for the 'gen' key, we have been ignoring the value, although the schema consistently used 'no' ('success-response' was hard-coded to checking for 'no'). But now that we can support a literal false in the schema, we might as well use that rather than ignoring the value or special-casing a random string. Note that these are one-way switches (use of 'gen':true is not the same as omitting 'gen'). Also, the use of '**' requires 'gen':false, but the use of 'gen':false does not mandate the use of '**'. There is no difference to the generated code. Add some tests on what we'd like to guarantee, although it will take later patches to clean up test results and actually enforce the use of a bool parameter. Signed-off-by: Eric Blake ebl...@redhat.com --- v8: Drop R-b, due to additional change to scripts to avoid regression in success-response handling --- qapi-schema.json | 14 +++--- qga/qapi-schema.json | 8 scripts/qapi-commands.py | 9 ++--- tests/Makefile | 1 + tests/qapi-schema/type-bypass-bad-gen.err | 0 tests/qapi-schema/type-bypass-bad-gen.exit | 1 + tests/qapi-schema/type-bypass-bad-gen.json | 2 ++ tests/qapi-schema/type-bypass-bad-gen.out | 3 +++ tests/qapi-schema/type-bypass-no-gen.err | 0 tests/qapi-schema/type-bypass-no-gen.exit | 1 + tests/qapi-schema/type-bypass-no-gen.json | 2 ++ tests/qapi-schema/type-bypass-no-gen.out | 3 +++ tests/qapi-schema/type-bypass.err | 0 tests/qapi-schema/type-bypass.exit | 1 + tests/qapi-schema/type-bypass.json | 2 ++ tests/qapi-schema/type-bypass.out | 3 +++ 16 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 tests/qapi-schema/type-bypass-bad-gen.err create mode 100644 tests/qapi-schema/type-bypass-bad-gen.exit create mode 100644 tests/qapi-schema/type-bypass-bad-gen.json create mode 100644 tests/qapi-schema/type-bypass-bad-gen.out create mode 100644 tests/qapi-schema/type-bypass-no-gen.err create mode 100644 tests/qapi-schema/type-bypass-no-gen.exit create mode 100644 tests/qapi-schema/type-bypass-no-gen.json create mode 100644 tests/qapi-schema/type-bypass-no-gen.out create mode 100644 tests/qapi-schema/type-bypass.err create mode 100644 tests/qapi-schema/type-bypass.exit create mode 100644 tests/qapi-schema/type-bypass.json create mode 100644 tests/qapi-schema/type-bypass.out diff --git a/qapi-schema.json b/qapi-schema.json index ac9594d..7f4cf86 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1561,8 +1561,8 @@ ## { 'command': 'qom-get', 'data': { 'path': 'str', 'property': 'str' }, - 'returns': 'visitor', - 'gen': 'no' } + 'returns': '**', + 'gen': false } ## # @qom-set: @@ -1579,8 +1579,8 @@ # Since: 1.2 ## { 'command': 'qom-set', - 'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' }, - 'gen': 'no' } + 'data': { 'path': 'str', 'property': 'str', 'value': '**' }, + 'gen': false } ## # @set_password: @@ -1943,7 +1943,7 @@ ## { 'command': 'netdev_add', 'data': {'type': 'str', 'id': 'str', '*props': '**'}, - 'gen': 'no' } + 'gen': false } ## # @netdev_del: @@ -1976,8 +1976,8 @@ # Since: 2.0 ## { 'command': 'object-add', - 'data': {'qom-type': 'str', 'id': 'str', '*props': 'dict'}, - 'gen': 'no' } + 'data': {'qom-type': 'str', 'id': 'str', '*props': '**'}, + 'gen': false } ## # @object-del: diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 5c4cd40..fecc442 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -195,7 +195,7 @@ # Since: 0.15.0 ## { 'command': 'guest-shutdown', 'data': { '*mode': 'str' }, - 'success-response': 'no' } + 'success-response': false } ## # @guest-file-open: @@ -470,7 +470,7 @@ # # Since: 1.1 ## -{ 'command': 'guest-suspend-disk', 'success-response': 'no' } +{ 'command': 'guest-suspend-disk', 'success-response': false } ## # @guest-suspend-ram @@ -502,7 +502,7 @@ # # Since: 1.1 ## -{ 'command': 'guest-suspend-ram', 'success-response': 'no' } +{ 'command': 'guest-suspend-ram', 'success-response': false } ## # @guest-suspend-hybrid @@ -529,7 +529,7 @@ # # Since: 1.1 ## -{ 'command': 'guest-suspend-hybrid', 'success-response': 'no' } +{ 'command': 'guest-suspend-hybrid', 'success-response': false } ## # @GuestIpAddressType: diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 053ba85..cb78682 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -2,7 +2,7 @@ # QAPI command marshaller generator # # Copyright IBM, Corp. 2011 -# Copyright (C) 2014 Red Hat, Inc. +# Copyright (C) 2014-2015 Red
[Qemu-devel] [PATCH v8 30/40] qapi: Use 'struct' instead of 'type' in schema
Referring to type as both a meta-type (built-in, enum, union, alternate, or struct) and a specific type (the name that the schema uses for declaring structs) is confusing. Do the bulk of the conversion to struct in qapi schema, with a fairly mechanical: for f in `find -name '*.json'; do sed -i s/'type'/'struct'/; done followed by manually filtering out the places where we have a 'type' embedded in 'data'. Then tweak a couple of tests whose output changes slightly due to longer lines. I also verified that the generated files for QMP and QGA (such as qmp-commands.h) are the same before and after, as assurance that I didn't leave in any accidental member name changes. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- v7: rebase on top of commit a113534, split out trailing cleanups to separate commit to make this even more mechanical --- qapi-schema.json | 166 ++--- qapi/block-core.json | 66 qapi/block.json| 2 +- qapi/common.json | 4 +- qapi/trace.json| 2 +- qga/qapi-schema.json | 28 ++-- tests/qapi-schema/alternate-array.json | 2 +- tests/qapi-schema/alternate-base.json | 2 +- tests/qapi-schema/alternate-conflict-dict.json | 4 +- tests/qapi-schema/alternate-good.json | 2 +- tests/qapi-schema/bad-base.json| 2 +- tests/qapi-schema/bad-ident.json | 2 +- tests/qapi-schema/bad-type-bool.json | 2 +- tests/qapi-schema/bad-type-int.err | 2 +- tests/qapi-schema/bad-type-int.json| 2 +- tests/qapi-schema/data-member-array.json | 2 +- tests/qapi-schema/double-data.err | 2 +- tests/qapi-schema/double-data.json | 2 +- tests/qapi-schema/double-type.json | 2 +- tests/qapi-schema/flat-union-bad-base.json | 4 +- .../qapi-schema/flat-union-bad-discriminator.json | 6 +- tests/qapi-schema/flat-union-base-star.json| 4 +- tests/qapi-schema/flat-union-base-union.json | 4 +- tests/qapi-schema/flat-union-branch-clash.json | 6 +- tests/qapi-schema/flat-union-inline.json | 2 +- tests/qapi-schema/flat-union-int-branch.json | 4 +- .../qapi-schema/flat-union-invalid-branch-key.json | 6 +- .../flat-union-invalid-discriminator.json | 6 +- tests/qapi-schema/flat-union-no-base.json | 4 +- .../flat-union-optional-discriminator.json | 4 +- tests/qapi-schema/flat-union-reverse-define.json | 6 +- .../flat-union-string-discriminator.json | 6 +- tests/qapi-schema/qapi-schema-test.json| 22 +-- tests/qapi-schema/redefined-builtin.json | 2 +- tests/qapi-schema/redefined-type.json | 2 +- tests/qapi-schema/union-bad-branch.json| 4 +- tests/qapi-schema/union-base-no-discriminator.json | 6 +- tests/qapi-schema/union-invalid-base.json | 4 +- tests/qapi-schema/unknown-expr-key.json| 2 +- 39 files changed, 200 insertions(+), 200 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index 7f4cf86..6a4e0df 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -71,7 +71,7 @@ # # Since 0.14.0 ## -{ 'type': 'NameInfo', 'data': {'*name': 'str'} } +{ 'struct': 'NameInfo', 'data': {'*name': 'str'} } ## # @query-name: @@ -95,7 +95,7 @@ # # Since: 0.14.0 ## -{ 'type': 'KvmInfo', 'data': {'enabled': 'bool', 'present': 'bool'} } +{ 'struct': 'KvmInfo', 'data': {'enabled': 'bool', 'present': 'bool'} } ## # @query-kvm: @@ -170,7 +170,7 @@ # # Notes: @singlestep is enabled through the GDB stub ## -{ 'type': 'StatusInfo', +{ 'struct': 'StatusInfo', 'data': {'running': 'bool', 'singlestep': 'bool', 'status': 'RunState'} } ## @@ -195,7 +195,7 @@ # # Notes: If no UUID was specified for the guest, a null UUID is returned. ## -{ 'type': 'UuidInfo', 'data': {'UUID': 'str'} } +{ 'struct': 'UuidInfo', 'data': {'UUID': 'str'} } ## # @query-uuid: @@ -226,7 +226,7 @@ # # Since: 0.14.0 ## -{ 'type': 'ChardevInfo', 'data': {'label': 'str', +{ 'struct': 'ChardevInfo', 'data': {'label': 'str', 'filename': 'str', 'frontend-open': 'bool'} } @@ -250,7 +250,7 @@ # # Since: 2.0 ## -{ 'type': 'ChardevBackendInfo', 'data': {'name': 'str'} } +{ 'struct': 'ChardevBackendInfo', 'data': {'name': 'str'} } ## # @query-chardev-backends: @@ -339,7 +339,7 @@ # # Since: 1.2.0 ## -{ 'type': 'EventInfo', 'data': {'name': 'str'} } +{ 'struct': 'EventInfo', 'data': {'name': 'str'} } ## # @query-events: @@ -380,7 +380,7 @@ # # Since: 0.14.0 ## -{ 'type': 'MigrationStats',
[Qemu-devel] [PATCH v8 35/40] qapi: Drop inline nested structs in query-pci
A future patch will be using a 'name':{dictionary} entry in the QAPI schema to specify a default value for an optional argument (see previous commit message for more details why); but existing use of inline nested structs conflicts with that goal. This patch fixes one of only two commands relying on nested types, by breaking the nesting into an explicit type; it means that the type is now boxed instead of unboxed in C code, but the QMP wire format is unaffected by this change. Prefer the safer g_new0() while making the conversion, and reduce some long lines. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- hmp.c| 26 hw/pci/pci.c | 42 ++ qapi-schema.json | 90 ++-- 3 files changed, 98 insertions(+), 60 deletions(-) diff --git a/hmp.c b/hmp.c index 97d9c2c..3010d04 100644 --- a/hmp.c +++ b/hmp.c @@ -648,14 +648,14 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev) dev-slot, dev-function); monitor_printf(mon, ); -if (dev-class_info.has_desc) { -monitor_printf(mon, %s, dev-class_info.desc); +if (dev-class_info-has_desc) { +monitor_printf(mon, %s, dev-class_info-desc); } else { -monitor_printf(mon, Class %04 PRId64, dev-class_info.q_class); +monitor_printf(mon, Class %04 PRId64, dev-class_info-q_class); } monitor_printf(mon, : PCI device %04 PRIx64 :%04 PRIx64 \n, - dev-id.vendor, dev-id.device); + dev-id-vendor, dev-id-device); if (dev-has_irq) { monitor_printf(mon, IRQ % PRId64 .\n, dev-irq); @@ -663,25 +663,25 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev) if (dev-has_pci_bridge) { monitor_printf(mon, BUS % PRId64 .\n, - dev-pci_bridge-bus.number); + dev-pci_bridge-bus-number); monitor_printf(mon, secondary bus % PRId64 .\n, - dev-pci_bridge-bus.secondary); + dev-pci_bridge-bus-secondary); monitor_printf(mon, subordinate bus % PRId64 .\n, - dev-pci_bridge-bus.subordinate); + dev-pci_bridge-bus-subordinate); monitor_printf(mon, IO range [0x%04PRIx64, 0x%04PRIx64]\n, - dev-pci_bridge-bus.io_range-base, - dev-pci_bridge-bus.io_range-limit); + dev-pci_bridge-bus-io_range-base, + dev-pci_bridge-bus-io_range-limit); monitor_printf(mon, memory range [0x%08PRIx64, 0x%08PRIx64]\n, - dev-pci_bridge-bus.memory_range-base, - dev-pci_bridge-bus.memory_range-limit); + dev-pci_bridge-bus-memory_range-base, + dev-pci_bridge-bus-memory_range-limit); monitor_printf(mon, prefetchable memory range [0x%08PRIx64, 0x%08PRIx64]\n, - dev-pci_bridge-bus.prefetchable_range-base, - dev-pci_bridge-bus.prefetchable_range-limit); + dev-pci_bridge-bus-prefetchable_range-base, + dev-pci_bridge-bus-prefetchable_range-limit); } for (region = dev-regions; region; region = region-next) { diff --git a/hw/pci/pci.c b/hw/pci/pci.c index b3d5100..f5c7a99 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1456,24 +1456,26 @@ static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus, int bus_num) { PciBridgeInfo *info; +PciMemoryRange *range; -info = g_malloc0(sizeof(*info)); +info = g_new0(PciBridgeInfo, 1); -info-bus.number = dev-config[PCI_PRIMARY_BUS]; -info-bus.secondary = dev-config[PCI_SECONDARY_BUS]; -info-bus.subordinate = dev-config[PCI_SUBORDINATE_BUS]; +info-bus = g_new0(PciBusInfo, 1); +info-bus-number = dev-config[PCI_PRIMARY_BUS]; +info-bus-secondary = dev-config[PCI_SECONDARY_BUS]; +info-bus-subordinate = dev-config[PCI_SUBORDINATE_BUS]; -info-bus.io_range = g_malloc0(sizeof(*info-bus.io_range)); -info-bus.io_range-base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); -info-bus.io_range-limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO); +range = info-bus-io_range = g_new0(PciMemoryRange, 1); +range-base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); +range-limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO); -info-bus.memory_range = g_malloc0(sizeof(*info-bus.memory_range)); -info-bus.memory_range-base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); -info-bus.memory_range-limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); +range =
[Qemu-devel] [PATCH v8 34/40] qapi: Drop inline nested struct in query-version
A future patch will be using a 'name':{dictionary} entry in the QAPI schema to specify a default value for an optional argument (see previous commit message for more details why); but existing use of inline nested structs conflicts with that goal. This patch fixes one of only two commands relying on nested types, by breaking the nesting into an explicit type; it means that the type is now boxed instead of unboxed in C code, but the QMP wire format is unaffected by this change. Prefer the safer g_new0() while making the conversion. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- hmp.c| 2 +- qapi/common.json | 26 +++--- qmp.c| 9 + 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/hmp.c b/hmp.c index d85d913..97d9c2c 100644 --- a/hmp.c +++ b/hmp.c @@ -60,7 +60,7 @@ void hmp_info_version(Monitor *mon, const QDict *qdict) info = qmp_query_version(NULL); monitor_printf(mon, % PRId64 .% PRId64 .% PRId64 %s\n, - info-qemu.major, info-qemu.minor, info-qemu.micro, + info-qemu-major, info-qemu-minor, info-qemu-micro, info-package); qapi_free_VersionInfo(info); diff --git a/qapi/common.json b/qapi/common.json index 12431c6..bad56bf 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -29,15 +29,28 @@ 'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap' ] } ## +# @VersionTriple +# +# A three-part version number. +# +# @qemu.major: The major version number. +# +# @qemu.minor: The minor version number. +# +# @qemu.micro: The micro version number. +# +# Since: 2.4 +## +{ 'struct': 'VersionTriple', + 'data': {'major': 'int', 'minor': 'int', 'micro': 'int'} } + + +## # @VersionInfo: # # A description of QEMU's version. # -# @qemu.major: The major version of QEMU -# -# @qemu.minor: The minor version of QEMU -# -# @qemu.micro: The micro version of QEMU. By current convention, a micro +# @qemu:The version of QEMU. By current convention, a micro # version of 50 signifies a development branch. A micro version # greater than or equal to 90 signifies a release candidate for # the next minor version. A micro version of less than 50 @@ -51,8 +64,7 @@ # Since: 0.14.0 ## { 'struct': 'VersionInfo', - 'data': {'qemu': {'major': 'int', 'minor': 'int', 'micro': 'int'}, - 'package': 'str'} } + 'data': {'qemu': 'VersionTriple', 'package': 'str'} } ## # @query-version: diff --git a/qmp.c b/qmp.c index e6c7050..3f5dfe3 100644 --- a/qmp.c +++ b/qmp.c @@ -45,15 +45,16 @@ NameInfo *qmp_query_name(Error **errp) VersionInfo *qmp_query_version(Error **errp) { -VersionInfo *info = g_malloc0(sizeof(*info)); +VersionInfo *info = g_new0(VersionInfo, 1); const char *version = QEMU_VERSION; char *tmp; -info-qemu.major = strtol(version, tmp, 10); +info-qemu = g_new0(VersionTriple, 1); +info-qemu-major = strtol(version, tmp, 10); tmp++; -info-qemu.minor = strtol(tmp, tmp, 10); +info-qemu-minor = strtol(tmp, tmp, 10); tmp++; -info-qemu.micro = strtol(tmp, tmp, 10); +info-qemu-micro = strtol(tmp, tmp, 10); info-package = g_strdup(QEMU_PKGVERSION); return info; -- 2.1.0
[Qemu-devel] [PATCH v8 01/40] qapi: Add copyright declaration on docs
While our top-level COPYING with its GPLv2+ license applies to any documentation file that omits explicit instructions, these days it's better to be a good example of calling out our intentions. Correct use of GPL requires the use of a copyright statement, so I'm adding notice to two QAPI documents, by attributing these files to the initial authors and major contributors. I used: $ git blame --line-porcelain $file \ | sed -n 's/^author //p' | sort | uniq -c | sort -rn to determine authorship of these two files. qmp-spec.txt blames entirely to Red Hat (easy, since my contribution falls in that category); while qapi-code-gen.txt has multiple contributors representing multiple entities. But since it was originally supplied by Michael Roth, the notice I added there copies the notice he has used in other files. As there is no intended change in license from the implicit one previously present from the top level, I have not bothered to CC other contributors; if we want to weaken things to something looser (such as LGPL) so that there is no question that someone re-implementing the spec is not forced to use GPL, that would be a different commit. CC: Michael Roth mdr...@linux.vnet.ibm.com Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- v7: Drop date stamp that is too likely to go stale [Markus] --- docs/qapi-code-gen.txt | 8 docs/qmp/qmp-spec.txt | 8 2 files changed, 16 insertions(+) diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 8313ba6..e8bbaf8 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -1,5 +1,13 @@ = How to use the QAPI code generator = +Copyright IBM Corp. 2011 +Copyright (C) 2012-2015 Red Hat, Inc. + +This work is licensed under the terms of the GNU GPL, version 2 or +later. See the COPYING file in the top-level directory. + +== Introduction == + QAPI is a native C API within QEMU which provides management-level functionality to internal/external users. For external users/processes, this interface is made available by a JSON-based diff --git a/docs/qmp/qmp-spec.txt b/docs/qmp/qmp-spec.txt index 22568c6..cb1600a 100644 --- a/docs/qmp/qmp-spec.txt +++ b/docs/qmp/qmp-spec.txt @@ -1,5 +1,13 @@ QEMU Machine Protocol Specification +0. About This Document +== + +Copyright (C) 2009-2015 Red Hat, Inc. + +This work is licensed under the terms of the GNU GPL, version 2 or +later. See the COPYING file in the top-level directory. + 1. Introduction === -- 2.1.0
[Qemu-devel] [PATCH v8 40/40] qapi: Check for member name conflicts with a base class
Our type inheritance for both 'struct' and for flat 'union' merges key/value pairs from the base class with those from the type in question. Although the C code currently boxes things so that there is a distinction between which member is referred to, the QMP wire format does not allow passing a key more than once in a single object. Besides, if we ever change the generated C code to not be quite so boxy, we'd want to avoid duplicate member names there, too. Fix a testsuite entry added in an earlier patch, as well as adding a couple more tests to ensure we have appropriate coverage. Ensure that collisions are detected, regardless of whether there is a difference in opinion on whether the member name is optional. Signed-off-by: Eric Blake ebl...@redhat.com --- v7: rebase to earlier changes, reuse base instead of expr['base'] v8: dectect collision in mis-matched optional names (drop R-b) --- scripts/qapi.py| 23 ++- tests/Makefile | 3 ++- tests/qapi-schema/flat-union-branch-clash.err | 1 + tests/qapi-schema/flat-union-branch-clash.exit | 2 +- tests/qapi-schema/flat-union-branch-clash.json | 4 ++-- tests/qapi-schema/flat-union-branch-clash.out | 9 - tests/qapi-schema/struct-base-clash-deep.err | 1 + tests/qapi-schema/struct-base-clash-deep.exit | 1 + tests/qapi-schema/struct-base-clash-deep.json | 9 + tests/qapi-schema/struct-base-clash-deep.out | 0 tests/qapi-schema/struct-base-clash.err| 1 + tests/qapi-schema/struct-base-clash.exit | 1 + tests/qapi-schema/struct-base-clash.json | 6 ++ tests/qapi-schema/struct-base-clash.out| 0 14 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 tests/qapi-schema/struct-base-clash-deep.err create mode 100644 tests/qapi-schema/struct-base-clash-deep.exit create mode 100644 tests/qapi-schema/struct-base-clash-deep.json create mode 100644 tests/qapi-schema/struct-base-clash-deep.out create mode 100644 tests/qapi-schema/struct-base-clash.err create mode 100644 tests/qapi-schema/struct-base-clash.exit create mode 100644 tests/qapi-schema/struct-base-clash.json create mode 100644 tests/qapi-schema/struct-base-clash.out diff --git a/scripts/qapi.py b/scripts/qapi.py index 14468ba..edfaf9e 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -414,6 +414,20 @@ def check_type(expr_info, source, value, allow_array = False, allow_metas=['built-in', 'union', 'alternate', 'struct', 'enum']) +def check_member_clash(expr_info, base_name, data, source = ): +base = find_struct(base_name) +assert base +base_members = base['data'] +for key in data.keys(): +if key.startswith('*'): +key = key[1:] +if key in base_members or *%s %key in base_members: +raise QAPIExprError(expr_info, +Member name '%s'%s clashes with base '%s' +%(key, source, base_name)) +if base.get('base'): +check_member_clash(expr_info, base['base'], data, source) + def check_command(expr, expr_info): name = expr['command'] allow_star = expr.has_key('gen') @@ -503,9 +517,14 @@ def check_union(expr, expr_info): check_name(expr_info, Member of union '%s' % name, key) # Each value must name a known type; furthermore, in flat unions, -# branches must be a struct +# branches must be a struct with no overlapping member names check_type(expr_info, Member '%s' of union '%s' % (key, name), value, allow_array=True, allow_metas=allow_metas) +if base: +branch_struct = find_struct(value) +assert branch_struct +check_member_clash(expr_info, base, branch_struct['data'], +of branch '%s' %key) # If the discriminator names an enum type, then all members # of 'data' must also be members of the enum type. @@ -582,6 +601,8 @@ def check_struct(expr, expr_info): allow_dict=True, allow_optional=True) check_type(expr_info, 'base' for struct '%s' % name, expr.get('base'), allow_metas=['struct']) +if expr.get('base'): +check_member_clash(expr_info, expr['base'], expr['data']) def check_exprs(schema): for expr_elem in schema.exprs: diff --git a/tests/Makefile b/tests/Makefile index 547a249..666aee2 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -243,7 +243,8 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \ include-simple.json include-relpath.json include-format-err.json \ include-non-file.json include-no-file.json include-before-err.json \ include-nested-err.json include-self-cycle.json include-cycle.json \ - include-repetition.json event-nest-struct.json event-case.json) + include-repetition.json
[Qemu-devel] [PATCH v8 24/40] qapi: More rigourous checking of types
Now that we know every expression is valid with regards to its keys, we can add further tests that those keys refer to valid types. With this patch, all uses of a type (the 'data': of command, type, union, alternate, and event; the 'returns': of command; the 'base': of type and union) must resolve to an appropriate subset of metatypes declared by the current qapi parse; this includes recursing into each member of a data dictionary. Dealing with '**' and nested anonymous structs will be done in later patches. Update the testsuite to match improved output. Signed-off-by: Eric Blake ebl...@redhat.com Reviewed-by: Markus Armbruster arm...@redhat.com --- v7: typo fix for 'furthermore' --- scripts/qapi.py | 96 +--- tests/qapi-schema/alternate-array.err| 2 +- tests/qapi-schema/alternate-nested.err | 2 +- tests/qapi-schema/alternate-unknown.err | 2 +- tests/qapi-schema/bad-base.err | 1 + tests/qapi-schema/bad-base.exit | 2 +- tests/qapi-schema/bad-base.json | 2 +- tests/qapi-schema/bad-base.out | 4 -- tests/qapi-schema/bad-data.err | 1 + tests/qapi-schema/bad-data.exit | 2 +- tests/qapi-schema/bad-data.json | 2 +- tests/qapi-schema/bad-data.out | 3 - tests/qapi-schema/data-array-empty.err | 1 + tests/qapi-schema/data-array-empty.exit | 2 +- tests/qapi-schema/data-array-empty.json | 2 +- tests/qapi-schema/data-array-empty.out | 3 - tests/qapi-schema/data-array-unknown.err | 1 + tests/qapi-schema/data-array-unknown.exit| 2 +- tests/qapi-schema/data-array-unknown.json| 2 +- tests/qapi-schema/data-array-unknown.out | 3 - tests/qapi-schema/data-int.err | 1 + tests/qapi-schema/data-int.exit | 2 +- tests/qapi-schema/data-int.json | 2 +- tests/qapi-schema/data-int.out | 3 - tests/qapi-schema/data-member-array-bad.err | 1 + tests/qapi-schema/data-member-array-bad.exit | 2 +- tests/qapi-schema/data-member-array-bad.json | 2 +- tests/qapi-schema/data-member-array-bad.out | 3 - tests/qapi-schema/data-member-unknown.err| 1 + tests/qapi-schema/data-member-unknown.exit | 2 +- tests/qapi-schema/data-member-unknown.json | 2 +- tests/qapi-schema/data-member-unknown.out| 3 - tests/qapi-schema/data-unknown.err | 1 + tests/qapi-schema/data-unknown.exit | 2 +- tests/qapi-schema/data-unknown.json | 2 +- tests/qapi-schema/data-unknown.out | 3 - tests/qapi-schema/flat-union-int-branch.err | 1 + tests/qapi-schema/flat-union-int-branch.exit | 2 +- tests/qapi-schema/flat-union-int-branch.json | 2 +- tests/qapi-schema/flat-union-int-branch.out | 7 -- tests/qapi-schema/returns-array-bad.err | 1 + tests/qapi-schema/returns-array-bad.exit | 2 +- tests/qapi-schema/returns-array-bad.json | 2 +- tests/qapi-schema/returns-array-bad.out | 3 - tests/qapi-schema/returns-unknown.err| 1 + tests/qapi-schema/returns-unknown.exit | 2 +- tests/qapi-schema/returns-unknown.json | 2 +- tests/qapi-schema/returns-unknown.out| 3 - tests/qapi-schema/union-unknown.err | 1 + tests/qapi-schema/union-unknown.exit | 2 +- tests/qapi-schema/union-unknown.json | 2 +- tests/qapi-schema/union-unknown.out | 3 - 52 files changed, 126 insertions(+), 77 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 686bc86..61e1c43 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -276,6 +276,64 @@ def discriminator_find_enum_define(expr): return find_enum(discriminator_type) +def check_type(expr_info, source, value, allow_array = False, + allow_dict = False, allow_metas = []): +global all_names +orig_value = value + +if value is None: +return + +if value == '**': +return + +# Check if array type for value is okay +if isinstance(value, list): +if not allow_array: +raise QAPIExprError(expr_info, +%s cannot be an array % source) +if len(value) != 1 or not isinstance(value[0], str): +raise QAPIExprError(expr_info, +%s: array type must contain single type name +% source) +value = value[0] +orig_value = array of %s %value + +# Check if type name for value is okay +if isinstance(value, str): +if not value in all_names: +raise QAPIExprError(expr_info, +%s uses unknown type '%s' +% (source, orig_value)) +if not all_names[value] in allow_metas: +raise QAPIExprError(expr_info, +%s cannot use %s type '%s' +