diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-03-04 11:04:31 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-03-04 11:04:31 +0000 |
commit | 1d31f1872b337e4acac5bf6b3c2a45b66e43b494 (patch) | |
tree | b1c71f789d14aee7d170af69fab5a7a8b817c1a3 /tests | |
parent | 20b084c4b1401b7f8fbc385649d48c67b6f43d44 (diff) | |
parent | 88c869198aa630e0477d653d0abf3f42c7c44d1f (diff) |
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pci, pc, virtio: fixes, cleanups, tests
Lots of work on tests: BiosTablesTest UEFI app,
vhost-user testing for non-Linux hosts.
Misc cleanups and fixes all over the place
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
# gpg: Signature made Fri 22 Feb 2019 15:51:40 GMT
# gpg: using RSA key 281F0DB8D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full]
# gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [full]
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67
# Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469
* remotes/mst/tags/for_upstream: (26 commits)
pci: Sanity test minimum downstream LNKSTA
hw/smbios: fix offset of type 3 sku field
pci: Move NVIDIA vendor id to the rest of ids
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
virtio-balloon: Use ram_block_discard_range() instead of raw madvise()
virtio-balloon: Rework ballon_page() interface
virtio-balloon: Corrections to address verification
virtio-balloon: Remove unnecessary MADV_WILLNEED on deflate
i386/kvm: ignore masked irqs when update msi routes
contrib/vhost-user-blk: fix the compilation issue
Revert "contrib/vhost-user-blk: fix the compilation issue"
pc-dimm: use same mechanism for [get|set]_addr
tests/data: introduce "uefi-boot-images" with the "bios-tables-test" ISOs
tests/uefi-test-tools: add build scripts
tests: introduce "uefi-test-tools" with the BiosTablesTest UEFI app
roms: build the EfiRom utility from the roms/edk2 submodule
roms: add the edk2 project as a git submodule
vhost-user-test: create a temporary directory per TestServer
vhost-user-test: small changes to init_hugepagefs
vhost-user-test: create a main loop per TestServer
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Makefile.include | 5 | ||||
-rw-r--r-- | tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2 | bin | 0 -> 11776 bytes | |||
-rw-r--r-- | tests/data/uefi-boot-images/bios-tables-test.arm.iso.qcow2 | bin | 0 -> 11776 bytes | |||
-rw-r--r-- | tests/data/uefi-boot-images/bios-tables-test.i386.iso.qcow2 | bin | 0 -> 12800 bytes | |||
-rw-r--r-- | tests/data/uefi-boot-images/bios-tables-test.x86_64.iso.qcow2 | bin | 0 -> 13312 bytes | |||
-rw-r--r-- | tests/uefi-test-tools/.gitignore | 3 | ||||
-rw-r--r-- | tests/uefi-test-tools/LICENSE | 25 | ||||
-rw-r--r-- | tests/uefi-test-tools/Makefile | 106 | ||||
-rw-r--r-- | tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.c | 130 | ||||
-rw-r--r-- | tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.inf | 41 | ||||
-rw-r--r-- | tests/uefi-test-tools/UefiTestToolsPkg/Include/Guid/BiosTablesTest.h | 67 | ||||
-rw-r--r-- | tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dec | 27 | ||||
-rw-r--r-- | tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc | 69 | ||||
-rwxr-xr-x | tests/uefi-test-tools/build.sh | 145 | ||||
-rw-r--r-- | tests/vhost-user-test.c | 160 |
15 files changed, 695 insertions, 83 deletions
diff --git a/tests/Makefile.include b/tests/Makefile.include index ca0166f4f3..c2ac4b8d4c 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -216,10 +216,7 @@ check-qtest-i386-$(CONFIG_USB_XHCI_NEC) += tests/usb-hcd-xhci-test$(EXESUF) check-qtest-i386-y += tests/cpu-plug-test$(EXESUF) check-qtest-i386-y += tests/q35-test$(EXESUF) check-qtest-i386-y += tests/vmgenid-test$(EXESUF) -check-qtest-i386-$(CONFIG_VHOST_USER_NET_TEST_i386) += tests/vhost-user-test$(EXESUF) -ifeq ($(CONFIG_VHOST_USER_NET_TEST_i386),) -check-qtest-x86_64-$(CONFIG_VHOST_USER_NET_TEST_x86_64) += tests/vhost-user-test$(EXESUF) -endif +check-qtest-i386-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test$(EXESUF) check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-swtpm-test$(EXESUF) check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-test$(EXESUF) check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-swtpm-test$(EXESUF) diff --git a/tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2 b/tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2 Binary files differnew file mode 100644 index 0000000000..ac0b7b1b8f --- /dev/null +++ b/tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2 diff --git a/tests/data/uefi-boot-images/bios-tables-test.arm.iso.qcow2 b/tests/data/uefi-boot-images/bios-tables-test.arm.iso.qcow2 Binary files differnew file mode 100644 index 0000000000..d20fa7c819 --- /dev/null +++ b/tests/data/uefi-boot-images/bios-tables-test.arm.iso.qcow2 diff --git a/tests/data/uefi-boot-images/bios-tables-test.i386.iso.qcow2 b/tests/data/uefi-boot-images/bios-tables-test.i386.iso.qcow2 Binary files differnew file mode 100644 index 0000000000..26c882baea --- /dev/null +++ b/tests/data/uefi-boot-images/bios-tables-test.i386.iso.qcow2 diff --git a/tests/data/uefi-boot-images/bios-tables-test.x86_64.iso.qcow2 b/tests/data/uefi-boot-images/bios-tables-test.x86_64.iso.qcow2 Binary files differnew file mode 100644 index 0000000000..9ec3c1f20b --- /dev/null +++ b/tests/data/uefi-boot-images/bios-tables-test.x86_64.iso.qcow2 diff --git a/tests/uefi-test-tools/.gitignore b/tests/uefi-test-tools/.gitignore new file mode 100644 index 0000000000..9f246701de --- /dev/null +++ b/tests/uefi-test-tools/.gitignore @@ -0,0 +1,3 @@ +Build +Conf +log diff --git a/tests/uefi-test-tools/LICENSE b/tests/uefi-test-tools/LICENSE new file mode 100644 index 0000000000..38b78aecdb --- /dev/null +++ b/tests/uefi-test-tools/LICENSE @@ -0,0 +1,25 @@ +All the files in this directory and subdirectories are released under the +2-Clause BSD License (see header in each file). + +Copyright (C) 2019, Red Hat, Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/uefi-test-tools/Makefile b/tests/uefi-test-tools/Makefile new file mode 100644 index 0000000000..1d78bc14d5 --- /dev/null +++ b/tests/uefi-test-tools/Makefile @@ -0,0 +1,106 @@ +# Makefile for the test helper UEFI applications that run in guests. +# +# Copyright (C) 2019, Red Hat, Inc. +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# <http://opensource.org/licenses/bsd-license.php>. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +edk2_dir := ../../roms/edk2 +images_dir := ../data/uefi-boot-images +emulation_targets := arm aarch64 i386 x86_64 +uefi_binaries := bios-tables-test +intermediate_suffixes := .efi .fat .iso.raw + +images: $(foreach binary,$(uefi_binaries), \ + $(foreach target,$(emulation_targets), \ + $(images_dir)/$(binary).$(target).iso.qcow2)) + +# Preserve all intermediate targets if the build succeeds. +# - Intermediate targets help with development & debugging. +# - Preserving intermediate targets also keeps spurious changes out of the +# final build products, in case the user re-runs "make" without any changes +# to the UEFI source code. Normally, the intermediate files would have been +# removed by the last "make" invocation, hence the re-run would rebuild them +# from the unchanged UEFI sources. Unfortunately, the "mkdosfs" and +# "genisoimage" utilities embed timestamp-based information in their outputs, +# which causes git to report differences for the tracked qcow2 ISO images. +.SECONDARY: $(foreach binary,$(uefi_binaries), \ + $(foreach target,$(emulation_targets), \ + $(foreach suffix,$(intermediate_suffixes), \ + Build/$(binary).$(target)$(suffix)))) + +# In the pattern rules below, the stem (%, $*) stands for +# "$(binary).$(target)". + +# Convert the raw ISO image to a qcow2 one, enabling compression, and using a +# small cluster size. This allows for small binary files under git control, +# hence for small binary patches. +$(images_dir)/%.iso.qcow2: Build/%.iso.raw + mkdir -p -- $(images_dir) + $${QTEST_QEMU_IMG:-qemu-img} convert -f raw -O qcow2 -c \ + -o cluster_size=512 -- $< $@ + +# Embed the "UEFI system partition" into an ISO9660 file system as an ElTorito +# boot image. +Build/%.iso.raw: Build/%.fat + genisoimage -input-charset ASCII -efi-boot $(notdir $<) -no-emul-boot \ + -quiet -o $@ -- $< + +# Define chained macros in order to map QEMU system emulation targets to +# *short* UEFI architecture identifiers. Periods are allowed in, and ultimately +# stripped from, the argument. +map_arm_to_uefi = $(subst arm,ARM,$(1)) +map_aarch64_to_uefi = $(subst aarch64,AA64,$(call map_arm_to_uefi,$(1))) +map_i386_to_uefi = $(subst i386,IA32,$(call map_aarch64_to_uefi,$(1))) +map_x86_64_to_uefi = $(subst x86_64,X64,$(call map_i386_to_uefi,$(1))) +map_to_uefi = $(subst .,,$(call map_x86_64_to_uefi,$(1))) + +# Format a "UEFI system partition", using the UEFI binary as the default boot +# loader. Add 10% size for filesystem metadata, round up to the next KB, and +# make sure the size is large enough for a FAT filesystem. Name the filesystem +# after the UEFI binary. (Excess characters are automatically dropped from the +# filesystem label.) +Build/%.fat: Build/%.efi + rm -f -- $@ + uefi_bin_b=$$(stat --format=%s -- $<) && \ + uefi_fat_kb=$$(( (uefi_bin_b * 11 / 10 + 1023) / 1024 )) && \ + uefi_fat_kb=$$(( uefi_fat_kb >= 64 ? uefi_fat_kb : 64 )) && \ + mkdosfs -C $@ -n $(basename $(@F)) -- $$uefi_fat_kb + MTOOLS_SKIP_CHECK=1 mmd -i $@ ::EFI + MTOOLS_SKIP_CHECK=1 mmd -i $@ ::EFI/BOOT + MTOOLS_SKIP_CHECK=1 mcopy -i $@ -- $< \ + ::EFI/BOOT/BOOT$(call map_to_uefi,$(suffix $*)).EFI + +# In the pattern rules below, the stem (%, $*) stands for "$(target)" only. The +# association between the UEFI binary (such as "bios-tables-test") and the +# component name from the edk2 platform DSC file (such as "BiosTablesTest") is +# explicit in each rule. + +# "build.sh" invokes the "build" utility of edk2 BaseTools. In any given edk2 +# workspace, at most one "build" instance may be operating at a time. Therefore +# we must serialize the rebuilding of targets in this Makefile. +.NOTPARALLEL: + +# In turn, the "build" utility of edk2 BaseTools invokes another "make". +# Although the outer "make" process advertizes its job server to all child +# processes via MAKEFLAGS in the environment, the outer "make" closes the job +# server file descriptors (exposed in MAKEFLAGS) before executing a recipe -- +# unless the recipe is recognized as a recursive "make" recipe. Recipes that +# call $(MAKE) are classified automatically as recursive; for "build.sh" below, +# we must mark the recipe manually as recursive, by using the "+" indicator. +# This way, when the inner "make" starts a parallel build of the target edk2 +# module, it can communicate with the outer "make"'s job server. +Build/bios-tables-test.%.efi: build-edk2-tools + +./build.sh $(edk2_dir) BiosTablesTest $* $@ + +build-edk2-tools: + $(MAKE) -C $(edk2_dir)/BaseTools + +clean: + rm -rf Build Conf log + $(MAKE) -C $(edk2_dir)/BaseTools clean diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.c b/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.c new file mode 100644 index 0000000000..b208e17fb0 --- /dev/null +++ b/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.c @@ -0,0 +1,130 @@ +/** @file + Populate the BIOS_TABLES_TEST structure. + + Copyright (C) 2019, Red Hat, Inc. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License that accompanies this + distribution. The full text of the license may be found at + <http://opensource.org/licenses/bsd-license.php>. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include <Guid/Acpi.h> +#include <Guid/BiosTablesTest.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + +/** + Wait for a keypress with a message that the application is about to exit. +**/ +STATIC +VOID +WaitForExitKeyPress ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Idx; + EFI_INPUT_KEY Key; + + if (gST->ConIn == NULL) { + return; + } + AsciiPrint ("%a: press any key to exit\n", gEfiCallerBaseName); + Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Idx); + if (EFI_ERROR (Status)) { + return; + } + gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); +} + +EFI_STATUS +EFIAPI +BiosTablesTestMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + VOID *Pages; + volatile BIOS_TABLES_TEST *BiosTablesTest; + CONST VOID *Rsdp10; + CONST VOID *Rsdp20; + CONST EFI_CONFIGURATION_TABLE *ConfigTable; + CONST EFI_CONFIGURATION_TABLE *ConfigTablesEnd; + volatile EFI_GUID *InverseSignature; + UINTN Idx; + + Pages = AllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof *BiosTablesTest), + SIZE_1MB); + if (Pages == NULL) { + AsciiErrorPrint ("%a: AllocateAlignedPages() failed\n", + gEfiCallerBaseName); + // + // Assuming the application was launched by the boot manager as a boot + // loader, exiting with error will cause the boot manager to proceed with + // the remaining boot options. If there are no other boot options, the boot + // manager menu will be pulled up. Give the user a chance to read the error + // message. + // + WaitForExitKeyPress (); + return EFI_OUT_OF_RESOURCES; + } + + // + // Locate both gEfiAcpi10TableGuid and gEfiAcpi20TableGuid config tables in + // one go. + // + Rsdp10 = NULL; + Rsdp20 = NULL; + ConfigTable = gST->ConfigurationTable; + ConfigTablesEnd = gST->ConfigurationTable + gST->NumberOfTableEntries; + while ((Rsdp10 == NULL || Rsdp20 == NULL) && ConfigTable < ConfigTablesEnd) { + if (CompareGuid (&ConfigTable->VendorGuid, &gEfiAcpi10TableGuid)) { + Rsdp10 = ConfigTable->VendorTable; + } else if (CompareGuid (&ConfigTable->VendorGuid, &gEfiAcpi20TableGuid)) { + Rsdp20 = ConfigTable->VendorTable; + } + ++ConfigTable; + } + + AsciiPrint ("%a: BiosTablesTest=%p Rsdp10=%p Rsdp20=%p\n", + gEfiCallerBaseName, Pages, Rsdp10, Rsdp20); + + // + // Store the RSD PTR address(es) first, then the signature second. + // + BiosTablesTest = Pages; + BiosTablesTest->Rsdp10 = (UINTN)Rsdp10; + BiosTablesTest->Rsdp20 = (UINTN)Rsdp20; + + MemoryFence(); + + InverseSignature = &BiosTablesTest->InverseSignatureGuid; + InverseSignature->Data1 = gBiosTablesTestGuid.Data1; + InverseSignature->Data1 ^= MAX_UINT32; + InverseSignature->Data2 = gBiosTablesTestGuid.Data2; + InverseSignature->Data2 ^= MAX_UINT16; + InverseSignature->Data3 = gBiosTablesTestGuid.Data3; + InverseSignature->Data3 ^= MAX_UINT16; + for (Idx = 0; Idx < sizeof InverseSignature->Data4; ++Idx) { + InverseSignature->Data4[Idx] = gBiosTablesTestGuid.Data4[Idx]; + InverseSignature->Data4[Idx] ^= MAX_UINT8; + } + + // + // The wait below has dual purpose. First, it blocks the application without + // wasting VCPU cycles while the hypervisor is scanning guest RAM. Second, + // assuming the application was launched by the boot manager as a boot + // loader, exiting the app with success causes the boot manager to pull up + // the boot manager menu at once (regardless of other boot options); the wait + // gives the user a chance to read the info printed above. + // + WaitForExitKeyPress (); + return EFI_SUCCESS; +} diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.inf b/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.inf new file mode 100644 index 0000000000..924d8a80d0 --- /dev/null +++ b/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.inf @@ -0,0 +1,41 @@ +## @file +# Populate the BIOS_TABLES_TEST structure. +# +# Copyright (C) 2019, Red Hat, Inc. +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# <http://opensource.org/licenses/bsd-license.php>. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +## + +[Defines] + INF_VERSION = 1.27 + BASE_NAME = BiosTablesTest + UEFI_SPECIFICATION_VERSION = 2.31 + FILE_GUID = 87f00433-3b7c-45c3-ae78-a56495bd4e62 + MODULE_TYPE = UEFI_APPLICATION + ENTRY_POINT = BiosTablesTestMain + +[Sources] + BiosTablesTest.c + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiApplicationEntryPoint + UefiBootServicesTableLib + UefiLib + +[Guids] + gBiosTablesTestGuid + gEfiAcpi10TableGuid + gEfiAcpi20TableGuid + +[Packages] + MdePkg/MdePkg.dec + UefiTestToolsPkg/UefiTestToolsPkg.dec diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/Include/Guid/BiosTablesTest.h b/tests/uefi-test-tools/UefiTestToolsPkg/Include/Guid/BiosTablesTest.h new file mode 100644 index 0000000000..0b72c61254 --- /dev/null +++ b/tests/uefi-test-tools/UefiTestToolsPkg/Include/Guid/BiosTablesTest.h @@ -0,0 +1,67 @@ +/** @file + Expose the address(es) of the ACPI RSD PTR table(s) in a MB-aligned structure + to the hypervisor. + + The hypervisor locates the MB-aligned structure based on the signature GUID + that is at offset 0 in the structure. Once the RSD PTR address(es) are + retrieved, the hypervisor may perform various ACPI checks. + + This feature is a development aid, for supporting ACPI table unit tests in + hypervisors. Do not enable in production builds. + + Copyright (C) 2019, Red Hat, Inc. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License that accompanies this + distribution. The full text of the license may be found at + <http://opensource.org/licenses/bsd-license.php>. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#ifndef __BIOS_TABLES_TEST_H__ +#define __BIOS_TABLES_TEST_H__ + +#include <Uefi/UefiBaseType.h> + +#define BIOS_TABLES_TEST_GUID \ + { \ + 0x5478594e, \ + 0xdfcb, \ + 0x425f, \ + { 0x8e, 0x42, 0xc8, 0xaf, 0xf8, 0x8a, 0x88, 0x7a } \ + } + +extern EFI_GUID gBiosTablesTestGuid; + +// +// The following structure must be allocated in Boot Services Data type memory, +// aligned at a 1MB boundary. +// +#pragma pack (1) +typedef struct { + // + // The signature GUID is written to the MB-aligned structure from + // gBiosTablesTestGuid, but with all bits inverted. That's the actual GUID + // value that the hypervisor should look for at each MB boundary, looping + // over all guest RAM pages with that alignment, until a match is found. The + // bit-flipping occurs in order not to store the actual GUID in any UEFI + // executable, which might confuse guest memory analysis. Note that EFI_GUID + // has little endian representation. + // + EFI_GUID InverseSignatureGuid; + // + // The Rsdp10 and Rsdp20 fields may be read when the signature GUID matches. + // Rsdp10 is the guest-physical address of the ACPI 1.0 specification RSD PTR + // table, in 8-byte little endian representation. Rsdp20 is the same, for the + // ACPI 2.0 or later specification RSD PTR table. Each of these fields may be + // zero (independently of the other) if the UEFI System Table does not + // provide the corresponding UEFI Configuration Table. + // + EFI_PHYSICAL_ADDRESS Rsdp10; + EFI_PHYSICAL_ADDRESS Rsdp20; +} BIOS_TABLES_TEST; +#pragma pack () + +#endif // __BIOS_TABLES_TEST_H__ diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dec b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dec new file mode 100644 index 0000000000..ed3a2fe110 --- /dev/null +++ b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dec @@ -0,0 +1,27 @@ +## @file +# edk2 package declaration for the test helper UEFI applications that run in +# guests. +# +# Copyright (C) 2019, Red Hat, Inc. +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# <http://opensource.org/licenses/bsd-license.php>. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +## + +[Defines] + DEC_SPECIFICATION = 1.27 + PACKAGE_NAME = UefiTestToolsPkg + PACKAGE_GUID = 7b3f1794-0c85-4b27-a536-44dbf0b0669c + PACKAGE_VERSION = 0.1 + +[Includes] + Include + +[Guids] + gBiosTablesTestGuid = {0x5478594e, 0xdfcb, 0x425f, {0x8e, 0x42, 0xc8, 0xaf, 0xf8, 0x8a, 0x88, 0x7a}} + diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc new file mode 100644 index 0000000000..c8511cd732 --- /dev/null +++ b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc @@ -0,0 +1,69 @@ +## @file +# edk2 platform description for the test helper UEFI applications that run in +# guests. +# +# Copyright (C) 2019, Red Hat, Inc. +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# <http://opensource.org/licenses/bsd-license.php>. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +## + +[Defines] + DSC_SPECIFICATION = 1.28 + PLATFORM_GUID = 6750ccc1-8365-49f0-8437-948e516a9f55 + PLATFORM_VERSION = 0.1 + PLATFORM_NAME = UefiTestTools + SKUID_IDENTIFIER = DEFAULT + SUPPORTED_ARCHITECTURES = ARM|AARCH64|IA32|X64 + BUILD_TARGETS = DEBUG + +[BuildOptions.IA32] + GCC:*_*_IA32_CC_FLAGS = -mno-mmx -mno-sse + +[BuildOptions.X64] + GCC:*_*_X64_CC_FLAGS = -mno-mmx -mno-sse + +[BuildOptions.ARM.EDKII.UEFI_APPLICATION] + GCC:*_*_ARM_DLINK_FLAGS = -z common-page-size=0x1000 + +[BuildOptions.AARCH64.EDKII.UEFI_APPLICATION] + GCC:*_*_AARCH64_DLINK_FLAGS = -z common-page-size=0x1000 + +[BuildOptions] + GCC:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES + +[SkuIds] + 0|DEFAULT + +[LibraryClasses] + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibDevicePathProtocol.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + +[LibraryClasses.ARM, LibraryClasses.AARCH64] + BaseMemoryLib|MdePkg/Library/BaseMemoryLibOptDxe/BaseMemoryLibOptDxe.inf + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf + +[LibraryClasses.IA32, LibraryClasses.X64] + BaseMemoryLib|MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.inf + +[PcdsFixedAtBuild] + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8040004F + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F + +[Components] + UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.inf diff --git a/tests/uefi-test-tools/build.sh b/tests/uefi-test-tools/build.sh new file mode 100755 index 0000000000..155cb75c4d --- /dev/null +++ b/tests/uefi-test-tools/build.sh @@ -0,0 +1,145 @@ +#!/bin/bash + +# Build script that determines the edk2 toolchain to use, invokes the edk2 +# "build" utility, and copies the built UEFI binary to the requested location. +# +# Copyright (C) 2019, Red Hat, Inc. +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# <http://opensource.org/licenses/bsd-license.php>. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +set -e -u -C + +# Save the command line arguments. We need to reset $# to 0 before sourcing +# "edksetup.sh", as it will inherit $@. +program_name=$(basename -- "$0") +edk2_dir=$1 +dsc_component=$2 +emulation_target=$3 +uefi_binary=$4 +shift 4 + +# Set up the environment for edk2 building. +export PACKAGES_PATH=$(realpath -- "$edk2_dir") +export WORKSPACE=$PWD +mkdir -p Conf + +# Source "edksetup.sh" carefully. +set +e +u +C +source "$PACKAGES_PATH/edksetup.sh" +ret=$? +set -e -u -C +if [ $ret -ne 0 ]; then + exit $ret +fi + +# Map the QEMU system emulation target to the following types of architecture +# identifiers: +# - edk2, +# - gcc cross-compilation. +# Cover only those targets that are supported by the UEFI spec and edk2. +case "$emulation_target" in + (arm) + edk2_arch=ARM + gcc_arch=arm + ;; + (aarch64) + edk2_arch=AARCH64 + gcc_arch=aarch64 + ;; + (i386) + edk2_arch=IA32 + gcc_arch=i686 + ;; + (x86_64) + edk2_arch=X64 + gcc_arch=x86_64 + ;; + (*) + printf '%s: unknown/unsupported QEMU system emulation target "%s"\n' \ + "$program_name" "$emulation_target" >&2 + exit 1 + ;; +esac + +# Check if cross-compilation is needed. +host_arch=$(uname -m) +if [ "$gcc_arch" == "$host_arch" ] || + ( [ "$gcc_arch" == i686 ] && [ "$host_arch" == x86_64 ] ); then + cross_prefix= +else + cross_prefix=${gcc_arch}-linux-gnu- +fi + +# Expose cross_prefix (which is possibly empty) to the edk2 tools. While at it, +# determine the suitable edk2 toolchain as well. +# - For ARM and AARCH64, edk2 only offers the GCC5 toolchain tag, which covers +# the gcc-5+ releases. +# - For IA32 and X64, edk2 offers the GCC44 through GCC49 toolchain tags, in +# addition to GCC5. Unfortunately, the mapping between the toolchain tags and +# the actual gcc releases isn't entirely trivial. Run "git-blame" on +# "OvmfPkg/build.sh" in edk2 for more information. +# And, because the above is too simple, we have to assign cross_prefix to an +# edk2 build variable that is specific to both the toolchain tag and the target +# architecture. +case "$edk2_arch" in + (ARM) + edk2_toolchain=GCC5 + export GCC5_ARM_PREFIX=$cross_prefix + ;; + (AARCH64) + edk2_toolchain=GCC5 + export GCC5_AARCH64_PREFIX=$cross_prefix + ;; + (IA32|X64) + gcc_version=$("${cross_prefix}gcc" -v 2>&1 | tail -1 | awk '{print $3}') + case "$gcc_version" in + ([1-3].*|4.[0-3].*) + printf '%s: unsupported gcc version "%s"\n' \ + "$program_name" "$gcc_version" >&2 + exit 1 + ;; + (4.4.*) + edk2_toolchain=GCC44 + ;; + (4.5.*) + edk2_toolchain=GCC45 + ;; + (4.6.*) + edk2_toolchain=GCC46 + ;; + (4.7.*) + edk2_toolchain=GCC47 + ;; + (4.8.*) + edk2_toolchain=GCC48 + ;; + (4.9.*|6.[0-2].*) + edk2_toolchain=GCC49 + ;; + (*) + edk2_toolchain=GCC5 + ;; + esac + eval "export ${edk2_toolchain}_BIN=\$cross_prefix" + ;; +esac + +# Build the UEFI binary +mkdir -p log +build \ + --arch="$edk2_arch" \ + --buildtarget=DEBUG \ + --platform=UefiTestToolsPkg/UefiTestToolsPkg.dsc \ + --tagname="$edk2_toolchain" \ + --module="UefiTestToolsPkg/$dsc_component/$dsc_component.inf" \ + --log="log/$dsc_component.$edk2_arch.log" \ + --report-file="log/$dsc_component.$edk2_arch.report" +cp -a -- \ + "Build/UefiTestTools/DEBUG_${edk2_toolchain}/$edk2_arch/$dsc_component.efi" \ + "$uefi_binary" diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index d961bd09d1..4cd0a97f13 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -27,10 +27,13 @@ #include "libqos/malloc-pc.h" #include "hw/virtio/virtio-net.h" -#include <linux/vhost.h> -#include <linux/virtio_ids.h> -#include <linux/virtio_net.h> +#include "standard-headers/linux/vhost_types.h" +#include "standard-headers/linux/virtio_ids.h" +#include "standard-headers/linux/virtio_net.h" + +#ifdef CONFIG_LINUX #include <sys/vfs.h> +#endif #define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM," \ @@ -139,10 +142,15 @@ typedef struct TestServer { gchar *socket_path; gchar *mig_path; gchar *chr_name; + const gchar *mem_path; + gchar *tmpfs; CharBackend chr; int fds_num; int fds[VHOST_MEMORY_MAX_NREGIONS]; VhostUserMemory memory; + GMainContext *context; + GMainLoop *loop; + GThread *thread; GMutex data_mutex; GCond data_cond; int log_fd; @@ -157,9 +165,6 @@ static TestServer *test_server_new(const gchar *name); static void test_server_free(TestServer *server); static void test_server_listen(TestServer *server); -static const char *tmpfs; -static const char *root; - enum test_memfd { TEST_MEMFD_AUTO, TEST_MEMFD_YES, @@ -167,7 +172,7 @@ enum test_memfd { }; static char *get_qemu_cmd(TestServer *s, - int mem, enum test_memfd memfd, const char *mem_path, + int mem, enum test_memfd memfd, const char *chr_opts, const char *extra) { if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check(0)) { @@ -182,7 +187,7 @@ static char *get_qemu_cmd(TestServer *s, } else { return g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem, - mem_path, s->chr_name, s->socket_path, + s->mem_path, s->chr_name, s->socket_path, chr_opts, s->chr_name, extra); } } @@ -459,13 +464,20 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) g_mutex_unlock(&s->data_mutex); } -static const char *init_hugepagefs(const char *path) +static const char *init_hugepagefs(void) { +#ifdef CONFIG_LINUX + const char *path = getenv("QTEST_HUGETLBFS_PATH"); struct statfs fs; int ret; + if (!path) { + return NULL; + } + if (access(path, R_OK | W_OK | X_OK)) { g_test_message("access on path (%s): %s\n", path, strerror(errno)); + abort(); return NULL; } @@ -475,21 +487,42 @@ static const char *init_hugepagefs(const char *path) if (ret != 0) { g_test_message("statfs on path (%s): %s\n", path, strerror(errno)); + abort(); return NULL; } if (fs.f_type != HUGETLBFS_MAGIC) { g_test_message("Warning: path not on HugeTLBFS: %s\n", path); + abort(); return NULL; } return path; +#else + return NULL; +#endif } static TestServer *test_server_new(const gchar *name) { TestServer *server = g_new0(TestServer, 1); + char template[] = "/tmp/vhost-test-XXXXXX"; + const char *tmpfs; + + server->context = g_main_context_new(); + server->loop = g_main_loop_new(server->context, FALSE); + + /* run the main loop thread so the chardev may operate */ + server->thread = g_thread_new(NULL, thread_function, server->loop); + + tmpfs = mkdtemp(template); + if (!tmpfs) { + g_test_message("mkdtemp on path (%s): %s", template, strerror(errno)); + } + g_assert(tmpfs); + server->tmpfs = g_strdup(tmpfs); + server->mem_path = init_hugepagefs() ? : server->tmpfs; server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name); server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name); server->chr_name = g_strdup_printf("chr-%s", name); @@ -519,13 +552,13 @@ static void test_server_create_chr(TestServer *server, const gchar *opt) Chardev *chr; chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt); - chr = qemu_chr_new(server->chr_name, chr_path, NULL); + chr = qemu_chr_new(server->chr_name, chr_path, server->context); g_free(chr_path); g_assert_nonnull(chr); qemu_chr_fe_init(&server->chr, chr, &error_abort); qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read, - chr_event, NULL, server, NULL, true); + chr_event, NULL, server, server->context, true); } static void test_server_listen(TestServer *server) @@ -533,9 +566,28 @@ static void test_server_listen(TestServer *server) test_server_create_chr(server, ",server,nowait"); } -static gboolean _test_server_free(TestServer *server) +static void test_server_free(TestServer *server) { - int i; + int i, ret; + + /* finish the helper thread and dispatch pending sources */ + g_main_loop_quit(server->loop); + g_thread_join(server->thread); + while (g_main_context_pending(NULL)) { + g_main_context_iteration(NULL, TRUE); + } + + unlink(server->socket_path); + g_free(server->socket_path); + + unlink(server->mig_path); + g_free(server->mig_path); + + ret = rmdir(server->tmpfs); + if (ret != 0) { + g_test_message("unable to rmdir: path (%s): %s", + server->tmpfs, strerror(errno)); + } qemu_chr_fe_deinit(&server->chr, true); @@ -547,24 +599,13 @@ static gboolean _test_server_free(TestServer *server) close(server->log_fd); } - unlink(server->socket_path); - g_free(server->socket_path); - - unlink(server->mig_path); - g_free(server->mig_path); - g_free(server->chr_name); g_assert(server->bus); qpci_free_pc(server->bus); + g_main_loop_unref(server->loop); + g_main_context_unref(server->context); g_free(server); - - return FALSE; -} - -static void test_server_free(TestServer *server) -{ - g_idle_add((GSourceFunc)_test_server_free, server); } static void wait_for_log_fd(TestServer *s) @@ -665,7 +706,7 @@ static void test_read_guest_mem(const void *arg) "read-guest-memfd" : "read-guest-mem"); test_server_listen(server); - qemu_cmd = get_qemu_cmd(server, 512, memfd, root, "", ""); + qemu_cmd = get_qemu_cmd(server, 512, memfd, "", ""); s = qtest_start(qemu_cmd); g_free(qemu_cmd); @@ -700,7 +741,7 @@ static void test_migrate(void) test_server_listen(s); test_server_listen(dest); - cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, "", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, "", ""); from = qtest_start(cmd); g_free(cmd); @@ -713,7 +754,7 @@ static void test_migrate(void) g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8)); tmp = g_strdup_printf(" -incoming %s", uri); - cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, root, "", tmp); + cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, "", tmp); g_free(tmp); to = qtest_init(cmd); g_free(cmd); @@ -723,7 +764,7 @@ static void test_migrate(void) sizeof(TestMigrateSource)); ((TestMigrateSource *)source)->src = s; ((TestMigrateSource *)source)->dest = dest; - g_source_attach(source, NULL); + g_source_attach(source, s->context); /* slow down migration to have time to fiddle with log */ /* TODO: qtest could learn to break on some places */ @@ -820,10 +861,11 @@ connect_thread(gpointer data) static void test_reconnect_subprocess(void) { TestServer *s = test_server_new("reconnect"); + GSource *src; char *cmd; g_thread_new("connect", connect_thread, s); - cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -837,7 +879,10 @@ static void test_reconnect_subprocess(void) /* reconnect */ s->fds_num = 0; s->rings = 0; - g_idle_add(reconnect_cb, s); + src = g_idle_source_new(); + g_source_set_callback(src, reconnect_cb, s, NULL); + g_source_attach(src, s->context); + g_source_unref(src); g_assert(wait_for_fds(s)); wait_for_rings_started(s, 2); @@ -865,7 +910,7 @@ static void test_connect_fail_subprocess(void) s->test_fail = true; g_thread_new("connect", connect_thread, s); - cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -898,7 +943,7 @@ static void test_flags_mismatch_subprocess(void) s->test_flags = TEST_FLAGS_DISCONNECT; g_thread_new("connect", connect_thread, s); - cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -946,7 +991,7 @@ static void test_multiqueue(void) cmd = g_strdup_printf( QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d " "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d", - 512, 512, root, s->chr_name, + 512, 512, s->mem_path, s->chr_name, s->socket_path, "", s->chr_name, s->queues, s->queues * 2 + 2); } @@ -966,35 +1011,11 @@ static void test_multiqueue(void) int main(int argc, char **argv) { - const char *hugefs; - int ret; - char template[] = "/tmp/vhost-test-XXXXXX"; - GMainLoop *loop; - GThread *thread; - g_test_init(&argc, &argv, NULL); module_call_init(MODULE_INIT_QOM); qemu_add_opts(&qemu_chardev_opts); - tmpfs = mkdtemp(template); - if (!tmpfs) { - g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno)); - } - g_assert(tmpfs); - - hugefs = getenv("QTEST_HUGETLBFS_PATH"); - if (hugefs) { - root = init_hugepagefs(hugefs); - g_assert(root); - } else { - root = tmpfs; - } - - loop = g_main_loop_new(NULL, FALSE); - /* run the main loop thread so the chardev may operate */ - thread = g_thread_new(NULL, thread_function, loop); - if (qemu_memfd_check(0)) { qtest_add_data_func("/vhost-user/read-guest-mem/memfd", GINT_TO_POINTER(TEST_MEMFD_YES), @@ -1018,24 +1039,5 @@ int main(int argc, char **argv) qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch); } - ret = g_test_run(); - - /* cleanup */ - - /* finish the helper thread and dispatch pending sources */ - g_main_loop_quit(loop); - g_thread_join(thread); - while (g_main_context_pending(NULL)) { - g_main_context_iteration (NULL, TRUE); - } - g_main_loop_unref(loop); - - ret = rmdir(tmpfs); - if (ret != 0) { - g_test_message("unable to rmdir: path (%s): %s\n", - tmpfs, strerror(errno)); - } - g_assert_cmpint(ret, ==, 0); - - return ret; + return g_test_run(); } |