/* * Copyright (C) 2021 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include #include "fu-efi-firmware-volume.h" /** * FuIfdBios: * * An Intel BIOS section. * * See also: [class@FuFirmware] */ G_DEFINE_TYPE(FuIfdBios, fu_ifd_bios, FU_TYPE_IFD_IMAGE) #define FU_IFD_BIOS_FIT_SIGNATURE 0x5449465F #define FU_IFD_BIOS_FIT_SIZE 0x150000 static gboolean fu_ifd_bios_parse(FuFirmware *firmware, GBytes *fw, guint64 addr_start, guint64 addr_end, FwupdInstallFlags flags, GError **error) { gsize bufsz = 0; gsize offset = 0x0; guint32 sig; const guint8 *buf = g_bytes_get_data(fw, &bufsz); /* jump 16MiB as required */ if (bufsz > 0x100000) offset += 0x100000; /* read each volume in order */ while (offset < bufsz) { g_autoptr(FuFirmware) firmware_tmp = NULL; g_autoptr(GBytes) fw_offset = NULL; /* ignore _FIT_ as EOF */ if (!fu_common_read_uint32_safe(buf, bufsz, offset, &sig, G_LITTLE_ENDIAN, error)) { g_prefix_error(error, "failed to read start signature: "); return FALSE; } if (sig == FU_IFD_BIOS_FIT_SIGNATURE) break; if (sig == 0xffffffff) break; /* FV */ fw_offset = fu_common_bytes_new_offset(fw, offset, bufsz - offset, error); if (fw_offset == NULL) return FALSE; firmware_tmp = fu_firmware_new_from_gtypes(fw_offset, flags, error, FU_TYPE_EFI_FIRMWARE_VOLUME, G_TYPE_INVALID); if (firmware_tmp == NULL) { g_prefix_error(error, "failed to read @0x%x of 0x%x: ", (guint)offset, (guint)bufsz); return FALSE; } fu_firmware_set_offset(firmware_tmp, offset); fu_firmware_add_image(firmware, firmware_tmp); /* next! */ offset += fu_firmware_get_size(firmware_tmp); } /* success */ return TRUE; } static void fu_ifd_bios_init(FuIfdBios *self) { fu_firmware_set_alignment(FU_FIRMWARE(self), FU_FIRMWARE_ALIGNMENT_4K); } static void fu_ifd_bios_class_init(FuIfdBiosClass *klass) { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS(klass); klass_firmware->parse = fu_ifd_bios_parse; } /** * fu_ifd_bios_new: * * Creates a new #FuFirmware * * Since: 1.6.2 **/ FuFirmware * fu_ifd_bios_new(void) { return FU_FIRMWARE(g_object_new(FU_TYPE_IFD_BIOS, NULL)); }