fwupd/plugins/thunderbolt/fu-thunderbolt-firmware-update.c
2021-08-24 11:18:40 -05:00

116 lines
2.9 KiB
C

/*
* Copyright (C) 2020 Mario Limonciello <mario.limonciello@dell.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <fwupdplugin.h>
#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);
}