ASSERT_STREQ(config->vars, "/test/vars.fd");
ASSERT_STREQ(config->format, "raw");
ASSERT_FALSE(ovmf_config_is_stateless(config));
- ASSERT_FALSE(config->supports_sb);
+ ASSERT_FALSE(ovmf_config_has_feature(config, "secure-boot"));
config = ovmf_config_free(config);
/* With FIND_OVMF_STATELESS only firmware in stateless flash mode is considered. */
/* The first matching descriptor in sort order wins. */
check_find(STRV_MAKE("vmspawn-test-e1"), /* exclude= */ NULL, /* flags= */ 0, "/test/e-both.fd", &config);
- ASSERT_TRUE(config->supports_sb);
+ ASSERT_TRUE(ovmf_config_has_feature(config, "secure-boot"));
config = ovmf_config_free(config);
/* Descriptors with an excluded feature are skipped. */
- check_find(STRV_MAKE("vmspawn-test-e1"), STRV_MAKE("vmspawn-test-e2"), /* flags= */ 0, "/test/e-one.fd", /* ret= */ NULL);
+ check_find(STRV_MAKE("vmspawn-test-e1"), STRV_MAKE("vmspawn-test-e2"), /* flags= */ 0, "/test/e-one.fd", &config);
+ ASSERT_TRUE(ovmf_config_has_feature(config, "vmspawn-test-e1"));
+ ASSERT_FALSE(ovmf_config_has_feature(config, "vmspawn-test-e2"));
+ config = ovmf_config_free(config);
/* Inclusion wins over exclusion. */
- check_find(STRV_MAKE("vmspawn-test-e1", "vmspawn-test-e2"), STRV_MAKE("vmspawn-test-e2"), /* flags= */ 0, "/test/e-both.fd", /* ret= */ NULL);
+ check_find(STRV_MAKE("vmspawn-test-e1", "vmspawn-test-e2"), STRV_MAKE("vmspawn-test-e2"), /* flags= */ 0, "/test/e-both.fd", &config);
+ ASSERT_TRUE(ovmf_config_has_feature(config, "vmspawn-test-e1"));
+ ASSERT_TRUE(ovmf_config_has_feature(config, "vmspawn-test-e2"));
+ config = ovmf_config_free(config);
/* All included features must be present. */
check_find(STRV_MAKE("vmspawn-test-e1", "vmspawn-test-nonexistent"), /* exclude= */ NULL, /* flags= */ 0, /* expect_path= */ NULL, /* ret= */ NULL);
free(config->vars_format);
free(config->device);
free(config->mode);
+ strv_free(config->features);
return mfree(config);
}
+bool ovmf_config_has_feature(const OvmfConfig *config, const char *feature) {
+ assert(config);
+ assert(feature);
+
+ return strv_contains(config->features, feature);
+}
+
static bool firmware_is_stateless(const char *device, const char *mode) {
/* Memory-mapped firmware (loaded via -bios) carries no NVRAM. For flash, only mode "stateless"
* is stateless: an absent mode means "split" (executable plus NVRAM template), and "combined"
return false;
}
-static bool firmware_data_supports_sb(const FirmwareData *fwd) {
- assert(fwd);
-
- return strv_contains(fwd->features, "secure-boot");
-}
-
static FirmwareData* firmware_data_free(FirmwareData *fwd) {
if (!fwd)
return NULL;
.vars_format = TAKE_PTR(fwd->vars_format),
.device = TAKE_PTR(fwd->device),
.mode = TAKE_PTR(fwd->mode),
- .supports_sb = firmware_data_supports_sb(fwd),
+ .features = TAKE_PTR(fwd->features),
};
*ret = TAKE_PTR(config);
char *vars_format;
char *device;
char *mode;
- bool supports_sb;
+ char **features;
} OvmfConfig;
static inline const char* ovmf_config_format(const OvmfConfig *c) {
static inline const char* ovmf_config_vars_format(const OvmfConfig *c) {
return ASSERT_PTR(c)->vars_format ?: "raw";
}
+
bool ovmf_config_is_stateless(const OvmfConfig *config);
+bool ovmf_config_has_feature(const OvmfConfig *config, const char *feature);
OvmfConfig* ovmf_config_free(OvmfConfig *ovmf_config);
DEFINE_TRIVIAL_CLEANUP_FUNC(OvmfConfig*, ovmf_config_free);
return r;
}
- if (set_contains(arg_firmware_features_include, "secure-boot") && !ovmf_config->supports_sb)
+ /* Flash mode "combined" places the variable store in the (writable) executable,
+ * which would have to be cloned for each guest. */
+ if (streq_ptr(ovmf_config->mode, "combined"))
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "Firmware descriptor '%s' declares flash mode 'combined', which is not supported.",
+ arg_firmware ?: ovmf_config->path);
+
+ if (arg_confidential_computing != COCO_NO) {
+ const char *coco_feature = coco_firmware_feature_to_string(arg_confidential_computing);
+
+ if (!ovmf_config_has_feature(ovmf_config, coco_feature))
+ return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE),
+ "Firmware descriptor '%s' does not declare the '%s' feature, but "
+ "--coco=%s requires firmware built specifically for it.",
+ arg_firmware ?: ovmf_config->path, coco_feature,
+ confidential_computing_to_string(arg_confidential_computing));
+ if (!ovmf_config_is_stateless(ovmf_config))
+ return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE),
+ "Firmware descriptor '%s' does not describe stateless firmware, "
+ "but --coco=%s requires stateless firmware.",
+ arg_firmware ?: ovmf_config->path,
+ confidential_computing_to_string(arg_confidential_computing));
+ if (!streq(ovmf_config_format(ovmf_config), "raw"))
+ return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE),
+ "Firmware image '%s' is in %s format, "
+ "but --coco=%s requires a raw image.",
+ ovmf_config->path, ovmf_config_format(ovmf_config),
+ confidential_computing_to_string(arg_confidential_computing));
+ }
+
+ bool sb = ovmf_config_has_feature(ovmf_config, "secure-boot");
+ if (set_contains(arg_firmware_features_include, "secure-boot") && !sb)
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE),
"Secure Boot requested, but selected OVMF firmware doesn't support it.");
- log_debug("Using OVMF firmware %s Secure Boot support.", ovmf_config->supports_sb ? "with" : "without");
+ log_debug("Using OVMF firmware %s Secure Boot support.", sb ? "with" : "without");
}
_cleanup_(machine_bind_user_context_freep) MachineBindUserContext *bind_user_context = NULL;
}
if (ovmf_config && ARCHITECTURE_SUPPORTS_SMM && arg_confidential_computing == COCO_NO) {
- r = qemu_config_key(config_file, "smm", on_off(ovmf_config->supports_sb));
+ bool sb = ovmf_config_has_feature(ovmf_config, "secure-boot");
+ r = qemu_config_key(config_file, "smm", on_off(sb));
if (r < 0)
return r;
}