/* * Copyright (C) 2021 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include #include #include "fu-acpi-phat-version-element.h" struct _FuAcpiPhatVersionElement { FuFirmware parent_instance; gchar *guid; gchar *producer_id; }; G_DEFINE_TYPE(FuAcpiPhatVersionElement, fu_acpi_phat_version_element, FU_TYPE_FIRMWARE) static void fu_acpi_phat_version_element_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn) { FuAcpiPhatVersionElement *self = FU_ACPI_PHAT_VERSION_ELEMENT(firmware); if (self->guid != NULL) fu_xmlb_builder_insert_kv(bn, "guid", self->guid); if (self->producer_id != NULL) fu_xmlb_builder_insert_kv(bn, "producer_id", self->producer_id); } static gboolean fu_acpi_phat_version_element_parse(FuFirmware *firmware, GBytes *fw, guint64 addr_start, guint64 addr_end, FwupdInstallFlags flags, GError **error) { FuAcpiPhatVersionElement *self = FU_ACPI_PHAT_VERSION_ELEMENT(firmware); fwupd_guid_t component_id = {0x0}; gchar producer_id[4] = {'\0'}; gsize bufsz = 0; guint64 version_value = 0; const guint8 *buf = g_bytes_get_data(fw, &bufsz); /* hardcoded */ fu_firmware_set_size(firmware, 28); if (!fu_memcpy_safe((guint8 *)&component_id, sizeof(component_id), 0x0, /* dst */ buf, bufsz, 0, /* src */ sizeof(component_id), error)) return FALSE; self->guid = fwupd_guid_to_string(&component_id, FWUPD_GUID_FLAG_MIXED_ENDIAN); if (!fu_common_read_uint64_safe(buf, bufsz, 16, &version_value, G_LITTLE_ENDIAN, error)) return FALSE; fu_firmware_set_version_raw(firmware, version_value); if (!fu_memcpy_safe((guint8 *)producer_id, sizeof(producer_id), 0x0, /* dst */ buf, bufsz, 24, /* src */ sizeof(producer_id), error)) return FALSE; if (memcmp(producer_id, "\0\0\0\0", 4) == 0) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "PHAT version element invalid"); return FALSE; } self->producer_id = fu_common_strsafe((const gchar *)producer_id, sizeof(producer_id)); return TRUE; } static GBytes * fu_acpi_phat_version_element_write(FuFirmware *firmware, GError **error) { FuAcpiPhatVersionElement *self = FU_ACPI_PHAT_VERSION_ELEMENT(firmware); fwupd_guid_t guid = {0x0}; guint8 producer_id[4] = {'\0'}; g_autoptr(GByteArray) buf = g_byte_array_new(); /* component ID */ if (self->guid != NULL) { if (!fwupd_guid_from_string(self->guid, &guid, FWUPD_GUID_FLAG_MIXED_ENDIAN, error)) return NULL; } g_byte_array_append(buf, guid, sizeof(guid)); /* version value */ fu_byte_array_append_uint64(buf, fu_firmware_get_version_raw(firmware), G_LITTLE_ENDIAN); /* producer ID */ if (self->producer_id != NULL) { gsize producer_idsz = strlen(self->producer_id); if (!fu_memcpy_safe(producer_id, sizeof(producer_id), 0x0, /* dst */ (const guint8 *)self->producer_id, producer_idsz, 0x0, /* src */ producer_idsz, error)) return NULL; } g_byte_array_append(buf, producer_id, sizeof(producer_id)); /* success */ return g_byte_array_free_to_bytes(g_steal_pointer(&buf)); } static void fu_acpi_phat_version_element_set_guid(FuAcpiPhatVersionElement *self, const gchar *guid) { g_free(self->guid); self->guid = g_strdup(guid); } static void fu_acpi_phat_version_element_set_producer_id(FuAcpiPhatVersionElement *self, const gchar *producer_id) { g_free(self->producer_id); self->producer_id = g_strdup(producer_id); } static gboolean fu_acpi_phat_version_element_build(FuFirmware *firmware, XbNode *n, GError **error) { FuAcpiPhatVersionElement *self = FU_ACPI_PHAT_VERSION_ELEMENT(firmware); const gchar *tmp; /* optional properties */ tmp = xb_node_query_text(n, "producer_id", NULL); if (tmp != NULL) fu_acpi_phat_version_element_set_producer_id(self, tmp); tmp = xb_node_query_text(n, "guid", NULL); if (tmp != NULL) fu_acpi_phat_version_element_set_guid(self, tmp); /* success */ return TRUE; } static void fu_acpi_phat_version_element_init(FuAcpiPhatVersionElement *self) { } static void fu_acpi_phat_version_element_finalize(GObject *object) { FuAcpiPhatVersionElement *self = FU_ACPI_PHAT_VERSION_ELEMENT(object); g_free(self->guid); g_free(self->producer_id); G_OBJECT_CLASS(fu_acpi_phat_version_element_parent_class)->finalize(object); } static void fu_acpi_phat_version_element_class_init(FuAcpiPhatVersionElementClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS(klass); object_class->finalize = fu_acpi_phat_version_element_finalize; klass_firmware->parse = fu_acpi_phat_version_element_parse; klass_firmware->write = fu_acpi_phat_version_element_write; klass_firmware->export = fu_acpi_phat_version_element_export; klass_firmware->build = fu_acpi_phat_version_element_build; } FuFirmware * fu_acpi_phat_version_element_new(void) { return FU_FIRMWARE(g_object_new(FU_TYPE_ACPI_PHAT_VERSION_ELEMENT, NULL)); }