/* * Copyright (C) 2020 Mario Limonciello * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include #include "fu-thunderbolt-firmware-update.h" #include "fu-thunderbolt-firmware.h" struct _FuThunderboltFirmwareUpdate { FuThunderboltFirmwareClass parent_instance; }; G_DEFINE_TYPE(FuThunderboltFirmwareUpdate, fu_thunderbolt_firmware_update, FU_TYPE_THUNDERBOLT_FIRMWARE) static inline gboolean fu_thunderbolt_firmware_valid_farb_pointer(guint32 pointer) { return pointer != 0 && pointer != 0xFFFFFF; } static gboolean fu_thunderbolt_firmware_read_farb_pointer_impl(FuThunderboltFirmwareUpdate *self, FuThunderboltSection section, guint32 offset, guint32 *value, GError **error) { FuThunderboltFirmware *tbt = FU_THUNDERBOLT_FIRMWARE(self); guint32 tmp = 0; if (!fu_thunderbolt_firmware_read_location(tbt, section, offset, (guint8 *)&tmp, 3, /* 24 bits */ error)) { g_prefix_error(error, "failed to read farb pointer: "); return FALSE; } *value = GUINT32_FROM_LE(tmp); return TRUE; } /* returns invalid FARB pointer on error */ static guint32 fu_thunderbolt_firmware_read_farb_pointer(FuThunderboltFirmwareUpdate *self, GError **error) { guint32 value; if (!fu_thunderbolt_firmware_read_farb_pointer_impl(self, _SECTION_DIGITAL, 0x0, &value, error)) return 0; if (fu_thunderbolt_firmware_valid_farb_pointer(value)) return value; if (!fu_thunderbolt_firmware_read_farb_pointer_impl(self, _SECTION_DIGITAL, 0x1000, &value, error)) return 0; if (!fu_thunderbolt_firmware_valid_farb_pointer(value)) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Invalid FW image file format"); return 0; } return value; } static gboolean fu_thunderbolt_firmware_update_parse(FuFirmware *firmware, GBytes *fw, guint64 addr_start, guint64 addr_end, FwupdInstallFlags flags, GError **error) { FuThunderboltFirmwareUpdate *self = FU_THUNDERBOLT_FIRMWARE_UPDATE(firmware); guint32 offset = fu_thunderbolt_firmware_read_farb_pointer(self, error); if (offset == 0) return FALSE; g_debug("detected digital section begins at 0x%x", offset); fu_thunderbolt_firmware_set_digital(FU_THUNDERBOLT_FIRMWARE(firmware), offset); return TRUE; } static void fu_thunderbolt_firmware_update_init(FuThunderboltFirmwareUpdate *self) { } static void fu_thunderbolt_firmware_update_class_init(FuThunderboltFirmwareUpdateClass *klass) { FuThunderboltFirmwareClass *klass_firmware = FU_THUNDERBOLT_FIRMWARE_CLASS(klass); klass_firmware->parse = fu_thunderbolt_firmware_update_parse; } FuThunderboltFirmwareUpdate * fu_thunderbolt_firmware_update_new(void) { return g_object_new(FU_TYPE_THUNDERBOLT_FIRMWARE_UPDATE, NULL); }