2019-02-19 19:35:43 +03:00
# include <config.h>
2019-04-04 16:52:53 +03:00
# include <inttypes.h>
2019-02-19 19:35:43 +03:00
# include "testutils.h"
2019-02-21 17:24:00 +03:00
# include "virfilewrapper.h"
2019-02-19 19:35:43 +03:00
# include "qemu/qemu_firmware.h"
2019-02-21 17:24:00 +03:00
# include "configmake.h"
2019-02-19 19:35:43 +03:00
# define VIR_FROM_THIS VIR_FROM_QEMU
/* A very basic test. Parse given JSON firmware description into
* an internal structure , format it back and compare with the
* contents of the file ( minus some keys that are not parsed ) .
*/
static int
testParseFormatFW ( const void * opaque )
{
const char * filename = opaque ;
2022-02-03 16:43:18 +03:00
g_autofree char * inpath = NULL ;
g_autofree char * outpath = NULL ;
2019-10-15 15:47:50 +03:00
g_autoptr ( qemuFirmware ) fw = NULL ;
g_autoptr ( virJSONValue ) json = NULL ;
2019-10-15 16:16:31 +03:00
g_autofree char * expected = NULL ;
g_autofree char * actual = NULL ;
2022-02-03 16:43:18 +03:00
g_autofree char * buf = NULL ;
2019-02-19 19:35:43 +03:00
2022-02-03 16:43:18 +03:00
inpath = g_strdup_printf ( " %s/qemufirmwaredata/%s " , abs_srcdir , filename ) ;
outpath = g_strdup_printf ( " %s/qemufirmwaredata/out/%s " , abs_srcdir , filename ) ;
2019-02-19 19:35:43 +03:00
2022-02-03 16:43:18 +03:00
if ( ! ( fw = qemuFirmwareParse ( inpath ) ) )
2019-02-19 19:35:43 +03:00
return - 1 ;
2022-02-03 16:43:18 +03:00
if ( virFileExists ( outpath ) ) {
if ( virFileReadAll ( outpath ,
1024 * 1024 , /* 1MiB */
& buf ) < 0 )
return - 1 ;
} else {
if ( virFileReadAll ( inpath ,
1024 * 1024 , /* 1MiB */
& buf ) < 0 )
return - 1 ;
}
2019-02-19 19:35:43 +03:00
if ( ! ( json = virJSONValueFromString ( buf ) ) )
return - 1 ;
/* Description and tags are not parsed. */
if ( virJSONValueObjectRemoveKey ( json , " description " , NULL ) < 0 | |
virJSONValueObjectRemoveKey ( json , " tags " , NULL ) < 0 )
return - 1 ;
if ( ! ( expected = virJSONValueToString ( json , true ) ) )
return - 1 ;
if ( ! ( actual = qemuFirmwareFormat ( fw ) ) )
return - 1 ;
return virTestCompareToString ( expected , actual ) ;
}
2019-02-21 17:24:00 +03:00
static int
2019-10-14 15:45:03 +03:00
testFWPrecedence ( const void * opaque G_GNUC_UNUSED )
2019-02-21 17:24:00 +03:00
{
2019-10-15 16:16:31 +03:00
g_autofree char * fakehome = NULL ;
2020-12-01 11:21:32 +03:00
g_auto ( GStrv ) fwList = NULL ;
2019-02-21 17:24:00 +03:00
const char * expected [ ] = {
PREFIX " /share/qemu/firmware/40-bios.json " ,
SYSCONFDIR " /qemu/firmware/40-ovmf-sb-keys.json " ,
2022-02-03 16:43:18 +03:00
PREFIX " /share/qemu/firmware/45-ovmf-sev-stateless.json " ,
2019-02-21 17:24:00 +03:00
PREFIX " /share/qemu/firmware/50-ovmf-sb-keys.json " ,
2022-02-03 16:43:18 +03:00
PREFIX " /share/qemu/firmware/55-ovmf-sb-combined.json " ,
2023-03-15 22:51:51 +03:00
PREFIX " /share/qemu/firmware/60-ovmf-sb.json " ,
2019-02-21 17:24:00 +03:00
PREFIX " /share/qemu/firmware/61-ovmf.json " ,
2023-01-27 19:48:43 +03:00
PREFIX " /share/qemu/firmware/65-ovmf-qcow2.json " ,
PREFIX " /share/qemu/firmware/66-aavmf-qcow2.json " ,
2019-02-21 17:24:00 +03:00
PREFIX " /share/qemu/firmware/70-aavmf.json " ,
2021-02-05 19:34:13 +03:00
NULL
2019-02-21 17:24:00 +03:00
} ;
2021-02-05 19:34:13 +03:00
const char * * e ;
GStrv f ;
2019-02-21 17:24:00 +03:00
2019-10-20 14:49:46 +03:00
fakehome = g_strdup ( abs_srcdir " /qemufirmwaredata/home/user/.config " ) ;
2019-02-21 17:24:00 +03:00
2019-12-18 20:16:19 +03:00
g_setenv ( " XDG_CONFIG_HOME " , fakehome , TRUE ) ;
2019-02-21 17:24:00 +03:00
if ( qemuFirmwareFetchConfigs ( & fwList , false ) < 0 )
return - 1 ;
if ( ! fwList ) {
fprintf ( stderr , " Expected a non-NULL result, but got a NULL result \n " ) ;
return - 1 ;
}
2021-02-05 19:34:13 +03:00
for ( e = expected , f = fwList ; * f | | * e ; ) {
if ( STRNEQ_NULLABLE ( * f , * e ) ) {
2019-02-21 17:24:00 +03:00
fprintf ( stderr ,
2021-02-05 19:34:13 +03:00
" Unexpected path. Expected %s got %s \n " ,
NULLSTR ( * e ) , NULLSTR ( * f ) ) ;
2019-02-21 17:24:00 +03:00
return - 1 ;
}
2021-02-05 19:34:13 +03:00
if ( * f )
f + + ;
if ( * e )
e + + ;
2019-02-21 17:24:00 +03:00
}
return 0 ;
}
2019-04-04 16:52:53 +03:00
struct supportedData {
const char * machine ;
virArch arch ;
bool secure ;
2019-08-05 17:11:26 +03:00
const char * fwlist ;
2019-04-04 16:52:53 +03:00
unsigned int * interfaces ;
size_t ninterfaces ;
} ;
static int
testSupportedFW ( const void * opaque )
{
const struct supportedData * data = opaque ;
uint64_t actualInterfaces ;
uint64_t expectedInterfaces = 0 ;
bool actualSecure ;
2021-03-11 10:16:13 +03:00
virFirmware * * expFWs = NULL ;
2019-08-05 17:11:26 +03:00
size_t nexpFWs = 0 ;
2021-03-11 10:16:13 +03:00
virFirmware * * actFWs = NULL ;
2019-08-05 17:11:26 +03:00
size_t nactFWs = 0 ;
2019-04-04 16:52:53 +03:00
size_t i ;
2019-08-05 17:11:26 +03:00
int ret = - 1 ;
2019-04-04 16:52:53 +03:00
for ( i = 0 ; i < data - > ninterfaces ; i + + )
expectedInterfaces | = 1ULL < < data - > interfaces [ i ] ;
2019-08-05 17:11:26 +03:00
if ( virFirmwareParseList ( data - > fwlist , & expFWs , & nexpFWs ) < 0 ) {
fprintf ( stderr , " Unable to parse list of expected FW paths \n " ) ;
return - 1 ;
}
/* virFirmwareParseList() expects to see pairs of paths: ${FW}:${NVRAM}.
* Well , some images don ' t have a NVRAM store . In that case NULL was passed :
* $ { FW } : NULL . Now iterate over expected firmwares and fix this . */
for ( i = 0 ; i < nexpFWs ; i + + ) {
2021-03-11 10:16:13 +03:00
virFirmware * tmp = expFWs [ i ] ;
2019-08-05 17:11:26 +03:00
if ( STREQ ( tmp - > nvram , " NULL " ) )
VIR_FREE ( tmp - > nvram ) ;
}
2019-04-04 16:52:53 +03:00
if ( qemuFirmwareGetSupported ( data - > machine , data - > arch , false ,
2019-08-05 17:11:26 +03:00
& actualInterfaces , & actualSecure , & actFWs , & nactFWs ) < 0 ) {
2019-04-04 16:52:53 +03:00
fprintf ( stderr , " Unable to get list of supported interfaces \n " ) ;
2019-08-05 17:11:26 +03:00
goto cleanup ;
2019-04-04 16:52:53 +03:00
}
if ( actualInterfaces ! = expectedInterfaces ) {
fprintf ( stderr ,
" Mismatch in supported interfaces. "
" Expected 0x% " PRIx64 " got 0x% " PRIx64 " \n " ,
expectedInterfaces , actualInterfaces ) ;
2019-08-05 17:11:26 +03:00
goto cleanup ;
2019-04-04 16:52:53 +03:00
}
if ( actualSecure ! = data - > secure ) {
fprintf ( stderr ,
" Mismatch in SMM requirement/support. "
" Expected %d got %d \n " ,
data - > secure , actualSecure ) ;
2019-08-05 17:11:26 +03:00
goto cleanup ;
2019-04-04 16:52:53 +03:00
}
2019-08-05 17:11:26 +03:00
for ( i = 0 ; i < nactFWs ; i + + ) {
2021-03-11 10:16:13 +03:00
virFirmware * actFW = actFWs [ i ] ;
virFirmware * expFW = NULL ;
2019-08-05 17:11:26 +03:00
if ( i > = nexpFWs ) {
fprintf ( stderr , " Unexpected FW image: %s NVRAM: %s \n " ,
actFW - > name , NULLSTR ( actFW - > nvram ) ) ;
goto cleanup ;
}
expFW = expFWs [ i ] ;
if ( STRNEQ ( actFW - > name , expFW - > name ) | |
STRNEQ_NULLABLE ( actFW - > nvram , expFW - > nvram ) ) {
fprintf ( stderr , " Unexpected FW image: %s NVRAM: %s \n "
" Expected: %s NVRAM: %s \n " ,
actFW - > name , NULLSTR ( actFW - > nvram ) ,
expFW - > name , NULLSTR ( expFW - > nvram ) ) ;
goto cleanup ;
}
}
if ( i < nexpFWs ) {
fprintf ( stderr , " Expected FW image: %s NVRAM: %s got nothing \n " ,
expFWs [ i ] - > name , NULLSTR ( expFWs [ i ] - > nvram ) ) ;
goto cleanup ;
}
ret = 0 ;
cleanup :
virFirmwareFreeList ( actFWs , nactFWs ) ;
virFirmwareFreeList ( expFWs , nexpFWs ) ;
return ret ;
2019-04-04 16:52:53 +03:00
}
2019-02-19 19:35:43 +03:00
static int
mymain ( void )
{
int ret = 0 ;
2019-02-21 17:24:00 +03:00
virFileWrapperAddPrefix ( SYSCONFDIR " /qemu/firmware " ,
abs_srcdir " /qemufirmwaredata/etc/qemu/firmware " ) ;
virFileWrapperAddPrefix ( PREFIX " /share/qemu/firmware " ,
abs_srcdir " /qemufirmwaredata/usr/share/qemu/firmware " ) ;
virFileWrapperAddPrefix ( " /home/user/.config/qemu/firmware " ,
abs_srcdir " /qemufirmwaredata/home/user/.config/qemu/firmware " ) ;
2019-02-19 19:35:43 +03:00
# define DO_PARSE_TEST(filename) \
do { \
if ( virTestRun ( " QEMU FW " filename , \
testParseFormatFW , filename ) < 0 ) \
ret = - 1 ; \
} while ( 0 )
2019-02-21 17:24:00 +03:00
DO_PARSE_TEST ( " usr/share/qemu/firmware/40-bios.json " ) ;
2022-02-03 16:43:18 +03:00
DO_PARSE_TEST ( " usr/share/qemu/firmware/45-ovmf-sev-stateless.json " ) ;
2019-02-21 17:24:00 +03:00
DO_PARSE_TEST ( " usr/share/qemu/firmware/50-ovmf-sb-keys.json " ) ;
2022-02-03 16:43:18 +03:00
DO_PARSE_TEST ( " usr/share/qemu/firmware/55-ovmf-sb-combined.json " ) ;
2019-02-21 17:24:00 +03:00
DO_PARSE_TEST ( " usr/share/qemu/firmware/60-ovmf-sb.json " ) ;
DO_PARSE_TEST ( " usr/share/qemu/firmware/61-ovmf.json " ) ;
2023-01-27 19:48:43 +03:00
DO_PARSE_TEST ( " usr/share/qemu/firmware/65-ovmf-qcow2.json " ) ;
DO_PARSE_TEST ( " usr/share/qemu/firmware/66-aavmf-qcow2.json " ) ;
2019-02-21 17:24:00 +03:00
DO_PARSE_TEST ( " usr/share/qemu/firmware/70-aavmf.json " ) ;
if ( virTestRun ( " QEMU FW precedence test " , testFWPrecedence , NULL ) < 0 )
ret = - 1 ;
2019-02-19 19:35:43 +03:00
2019-08-05 17:11:26 +03:00
/* The @fwlist contains pairs of ${FW}:${NVRAM}. If there's
* no NVRAM expected pass literal " NULL " and test fixes that
* later . */
# define DO_SUPPORTED_TEST(machine, arch, secure, fwlist, ...) \
2019-04-04 16:52:53 +03:00
do { \
unsigned int interfaces [ ] = { __VA_ARGS__ } ; \
2019-08-05 17:11:26 +03:00
struct supportedData data = { machine , arch , secure , fwlist , \
2019-10-15 14:55:26 +03:00
interfaces , G_N_ELEMENTS ( interfaces ) } ; \
2019-04-04 16:52:53 +03:00
if ( virTestRun ( " QEMU FW SUPPORTED " machine " " # arch , \
testSupportedFW , & data ) < 0 ) \
ret = - 1 ; \
} while ( 0 )
DO_SUPPORTED_TEST ( " pc-i440fx-3.1 " , VIR_ARCH_X86_64 , false ,
2019-08-05 17:11:26 +03:00
" /usr/share/seabios/bios-256k.bin:NULL: "
2023-01-27 19:48:43 +03:00
" /usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd: "
" /usr/share/OVMF/OVMF_CODE.qcow2:/usr/share/OVMF/OVMF_VARS.qcow2 " ,
2019-04-04 16:52:53 +03:00
VIR_DOMAIN_OS_DEF_FIRMWARE_BIOS ,
VIR_DOMAIN_OS_DEF_FIRMWARE_EFI ) ;
DO_SUPPORTED_TEST ( " pc-i440fx-3.1 " , VIR_ARCH_I686 , false ,
2019-08-05 17:11:26 +03:00
" /usr/share/seabios/bios-256k.bin:NULL " ,
2019-04-04 16:52:53 +03:00
VIR_DOMAIN_OS_DEF_FIRMWARE_BIOS ) ;
DO_SUPPORTED_TEST ( " pc-q35-3.1 " , VIR_ARCH_X86_64 , true ,
2019-08-05 17:11:26 +03:00
" /usr/share/seabios/bios-256k.bin:NULL: "
" /usr/share/OVMF/OVMF_CODE.secboot.fd:/usr/share/OVMF/OVMF_VARS.secboot.fd: "
2022-02-03 16:43:18 +03:00
" /usr/share/OVMF/OVMF.sev.fd:NULL: "
" /usr/share/OVMF/OVMF.secboot.fd:NULL: "
2023-03-15 22:51:51 +03:00
" /usr/share/OVMF/OVMF_CODE.secboot.fd:/usr/share/OVMF/OVMF_VARS.fd: "
2023-01-27 19:48:43 +03:00
" /usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd: "
" /usr/share/OVMF/OVMF_CODE.qcow2:/usr/share/OVMF/OVMF_VARS.qcow2 " ,
2019-04-04 16:52:53 +03:00
VIR_DOMAIN_OS_DEF_FIRMWARE_BIOS ,
VIR_DOMAIN_OS_DEF_FIRMWARE_EFI ) ;
DO_SUPPORTED_TEST ( " pc-q35-3.1 " , VIR_ARCH_I686 , false ,
2019-08-05 17:11:26 +03:00
" /usr/share/seabios/bios-256k.bin:NULL " ,
2019-04-04 16:52:53 +03:00
VIR_DOMAIN_OS_DEF_FIRMWARE_BIOS ) ;
DO_SUPPORTED_TEST ( " virt-3.1 " , VIR_ARCH_AARCH64 , false ,
2023-01-27 19:48:43 +03:00
" /usr/share/AAVMF/AAVMF_CODE.qcow2:/usr/share/AAVMF/AAVMF_VARS.qcow2: "
2019-08-05 17:11:26 +03:00
" /usr/share/AAVMF/AAVMF_CODE.fd:/usr/share/AAVMF/AAVMF_VARS.fd " ,
2019-04-04 16:52:53 +03:00
VIR_DOMAIN_OS_DEF_FIRMWARE_EFI ) ;
2019-03-13 11:56:47 +03:00
virFileWrapperClearPrefixes ( ) ;
2019-02-19 19:35:43 +03:00
return ret = = 0 ? EXIT_SUCCESS : EXIT_FAILURE ;
}
VIR_TEST_MAIN ( mymain )