mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-16 06:09:07 +00:00
Make the version parsing more resilient to corrupt firmware
This commit is contained in:
parent
53fc7961dc
commit
fe68ff584f
@ -94,8 +94,6 @@ fu_provider_udev_verify (FuProvider *provider,
|
|||||||
rom = fu_rom_new ();
|
rom = fu_rom_new ();
|
||||||
if (!fu_rom_load_file (rom, file, NULL, error))
|
if (!fu_rom_load_file (rom, file, NULL, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (!fu_rom_generate_checksum (rom, NULL, error))
|
|
||||||
return FALSE;
|
|
||||||
fu_device_set_metadata (device, FU_DEVICE_KEY_FIRMWARE_HASH,
|
fu_device_set_metadata (device, FU_DEVICE_KEY_FIRMWARE_HASH,
|
||||||
fu_rom_get_checksum (rom));
|
fu_rom_get_checksum (rom));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
739
src/fu-rom.c
739
src/fu-rom.c
@ -34,6 +34,28 @@ static void fu_rom_finalize (GObject *object);
|
|||||||
|
|
||||||
#define FU_ROM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), FU_TYPE_ROM, FuRomPrivate))
|
#define FU_ROM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), FU_TYPE_ROM, FuRomPrivate))
|
||||||
|
|
||||||
|
/* data from http://resources.infosecinstitute.com/pci-expansion-rom/ */
|
||||||
|
typedef struct {
|
||||||
|
guint32 rom_len;
|
||||||
|
guint32 entry_point;
|
||||||
|
guint8 reserved[18];
|
||||||
|
guint16 cpi_ptr;
|
||||||
|
guint16 vendor_id;
|
||||||
|
guint16 device_id;
|
||||||
|
guint16 device_list_ptr;
|
||||||
|
guint16 data_len;
|
||||||
|
guint8 data_rev;
|
||||||
|
guint32 class_code;
|
||||||
|
guint32 image_len;
|
||||||
|
guint16 revision_level;
|
||||||
|
guint8 code_type;
|
||||||
|
guint8 last_image;
|
||||||
|
guint32 max_runtime_len;
|
||||||
|
guint16 config_header_ptr;
|
||||||
|
guint16 dmtf_clp_ptr;
|
||||||
|
guint32 offset_in_buffer;
|
||||||
|
} FuRomPciHeader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FuRomPrivate:
|
* FuRomPrivate:
|
||||||
*
|
*
|
||||||
@ -47,7 +69,7 @@ struct _FuRomPrivate
|
|||||||
gchar *version;
|
gchar *version;
|
||||||
guint16 vendor;
|
guint16 vendor;
|
||||||
guint16 model;
|
guint16 model;
|
||||||
guint16 rom_length;
|
GPtrArray *hdrs; /* of FuRomPciHeader */
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE (FuRom, fu_rom, G_TYPE_OBJECT)
|
G_DEFINE_TYPE (FuRom, fu_rom, G_TYPE_OBJECT)
|
||||||
@ -79,6 +101,8 @@ fu_rom_strstr_bin (guint8 *haystack, gsize haystack_len, const gchar *needle)
|
|||||||
{
|
{
|
||||||
guint i;
|
guint i;
|
||||||
guint needle_len = strlen (needle);
|
guint needle_len = strlen (needle);
|
||||||
|
if (needle_len > haystack_len)
|
||||||
|
return NULL;
|
||||||
for (i = 0; i < haystack_len - needle_len; i++) {
|
for (i = 0; i < haystack_len - needle_len; i++) {
|
||||||
if (memcmp (haystack + i, needle, needle_len) == 0)
|
if (memcmp (haystack + i, needle, needle_len) == 0)
|
||||||
return &haystack[i];
|
return &haystack[i];
|
||||||
@ -105,93 +129,268 @@ fu_rom_blank_serial_numbers (guint8 *buffer, guint buffer_sz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fu_rom_find_and_blank_serial_numbers:
|
* fu_rom_get_hex_dump:
|
||||||
|
**/
|
||||||
|
static gchar *
|
||||||
|
fu_rom_get_hex_dump (guint8 *buffer, gssize sz)
|
||||||
|
{
|
||||||
|
GString *str = NULL;
|
||||||
|
guint i;
|
||||||
|
str = g_string_new ("");
|
||||||
|
for (i = 0; i < sz; i++) {
|
||||||
|
g_string_append_printf (str, "%02x ", buffer[i]);
|
||||||
|
}
|
||||||
|
g_string_append (str, " ");
|
||||||
|
for (i = 0; i < sz; i++) {
|
||||||
|
gchar tmp = '?';
|
||||||
|
if (g_ascii_isprint (buffer[i]))
|
||||||
|
tmp = buffer[i];
|
||||||
|
g_string_append_printf (str, "%c", tmp);
|
||||||
|
}
|
||||||
|
return g_string_free (str, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guint8 segment_kind;
|
||||||
|
guint16 next_offset;
|
||||||
|
} FooRomPciCertificateHdr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_rom_pci_print_certificate_data:
|
||||||
**/
|
**/
|
||||||
static void
|
static void
|
||||||
fu_rom_find_and_blank_serial_numbers (guint8 *buffer, guint buffer_sz)
|
fu_rom_pci_print_certificate_data (guint8 *buffer, gssize sz)
|
||||||
{
|
{
|
||||||
guint8 *tmp;
|
guint16 off = 0;
|
||||||
guint len;
|
_cleanup_free_ gchar *hdr_str = NULL;
|
||||||
|
|
||||||
if (buffer_sz < 4)
|
/* 27 byte header, unknown purpose */
|
||||||
return;
|
hdr_str = fu_rom_get_hex_dump (buffer+off, 27);
|
||||||
tmp = fu_rom_strstr_bin (buffer, buffer_sz, "PPID");
|
g_debug (" ISBN header: %s", hdr_str);
|
||||||
if (tmp != NULL) {
|
buffer += 27;
|
||||||
len = fu_rom_blank_serial_numbers (tmp, buffer_sz - (tmp - buffer));
|
|
||||||
g_debug ("cleared %i chars", len);
|
while (TRUE) {
|
||||||
|
/* 29 byte header to the segment, then data:
|
||||||
|
* 0x01 = type. 0x1 = certificate, 0x2 = hashes?
|
||||||
|
* 0x13,0x14 = offset to next segment */
|
||||||
|
FooRomPciCertificateHdr h;
|
||||||
|
_cleanup_free_ gchar *segment_str = NULL;
|
||||||
|
segment_str = fu_rom_get_hex_dump (buffer+off, 29);
|
||||||
|
g_debug (" ISBN segment: %s", segment_str);
|
||||||
|
h.segment_kind = buffer[off+1];
|
||||||
|
h.next_offset = ((guint16) buffer[off+14] << 8) + buffer[off+13];
|
||||||
|
if (h.next_offset == 0x0000) {
|
||||||
|
/* length of this segment must be (sz - off - 27) */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (h.segment_kind == 0x01 && FALSE) {
|
||||||
|
_cleanup_free_ gchar *cert = NULL;
|
||||||
|
cert = g_strndup ((gchar*) buffer + off + 29, h.next_offset - off - 29);
|
||||||
|
g_debug ("%s(%i)", cert, h.next_offset - off - 29);
|
||||||
|
}
|
||||||
|
off = h.next_offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* data from http://resources.infosecinstitute.com/pci-expansion-rom/ */
|
/**
|
||||||
typedef struct {
|
* fu_rom_pci_code_type_to_string:
|
||||||
guint8 rom_signature[2]; /* 0x55 0xaa */
|
**/
|
||||||
guint8 rom_size; /* of 512 bytes */
|
static const gchar *
|
||||||
guint8 entry_point[3];
|
fu_rom_pci_code_type_to_string (guint8 code_type)
|
||||||
guint8 reserved[18];
|
{
|
||||||
guint16 cpi_ptr;
|
if (code_type == 0)
|
||||||
} FuRomPciHeader;
|
return "Intel86";
|
||||||
|
if (code_type == 1)
|
||||||
|
return "OpenFirmware";
|
||||||
|
if (code_type == 2)
|
||||||
|
return "PA-RISC";
|
||||||
|
if (code_type == 3)
|
||||||
|
return "EFI";
|
||||||
|
return "reserved";
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
/**
|
||||||
guint8 signature[4]; /* PCIR */
|
* fu_rom_pci_header_get_checksum:
|
||||||
guint16 vendor_id;
|
**/
|
||||||
guint16 device_id;
|
static guint8
|
||||||
guint16 device_list_ptr;
|
fu_rom_pci_header_get_checksum (FuRomPciHeader *hdr, guint8 *buffer, gssize sz)
|
||||||
guint16 pci_data_length;
|
{
|
||||||
guint8 pci_data_revision; /* expected 3 */
|
guint8 chksum_check = 0x00;
|
||||||
guint8 class_code[3];
|
guint i;
|
||||||
guint16 image_len; /* of 512 bytes */
|
for (i = 0; i < hdr->image_len; i++)
|
||||||
guint16 revision_level;
|
chksum_check += buffer[hdr->offset_in_buffer + i];
|
||||||
guint8 code_type;
|
return chksum_check;
|
||||||
guint8 last_image_indicator; /* 1 = last image */
|
}
|
||||||
guint16 max_runtime_len; /* of 512 bytes */
|
|
||||||
guint16 config_header_ptr;
|
/**
|
||||||
guint16 dmtf_clp_entry_point;
|
* fu_rom_pci_print_header:
|
||||||
} FuRomPciData;
|
**/
|
||||||
|
static void
|
||||||
|
fu_rom_pci_print_header (FuRomPciHeader *hdr, guint8 *buffer, gssize sz)
|
||||||
|
{
|
||||||
|
guint8 chksum_check;
|
||||||
|
_cleanup_free_ gchar *data_str = NULL;
|
||||||
|
_cleanup_free_ gchar *reserved_str = NULL;
|
||||||
|
|
||||||
|
g_debug ("PCI Header");
|
||||||
|
g_debug (" RomSize: 0x%04x", hdr->rom_len);
|
||||||
|
g_debug (" EntryPnt: 0x%06x", hdr->entry_point);
|
||||||
|
reserved_str = fu_rom_get_hex_dump (hdr->reserved, 18);
|
||||||
|
g_debug (" Reserved: %s", reserved_str);
|
||||||
|
g_debug (" CpiPtr: 0x%04x", hdr->cpi_ptr);
|
||||||
|
|
||||||
|
/* print the data */
|
||||||
|
buffer += hdr->offset_in_buffer + hdr->cpi_ptr;
|
||||||
|
g_debug (" PCI Data");
|
||||||
|
g_debug (" VendorID: 0x%04x", hdr->vendor_id);
|
||||||
|
g_debug (" DeviceID: 0x%04x", hdr->device_id);
|
||||||
|
g_debug (" DevList: 0x%04x", hdr->device_list_ptr);
|
||||||
|
g_debug (" DataLen: 0x%04x", hdr->data_len);
|
||||||
|
g_debug (" DataRev: 0x%04x", hdr->data_rev);
|
||||||
|
if (hdr->image_len < 0x0f) {
|
||||||
|
data_str = fu_rom_get_hex_dump (&buffer[hdr->data_len], hdr->image_len);
|
||||||
|
g_debug (" ImageLen: 0x%04x [%s]", hdr->image_len, data_str);
|
||||||
|
} else {
|
||||||
|
data_str = fu_rom_get_hex_dump (&buffer[hdr->data_len], 0x0f);
|
||||||
|
g_debug (" ImageLen: 0x%04x [%s...]", hdr->image_len, data_str);
|
||||||
|
}
|
||||||
|
g_debug (" RevLevel: 0x%04x", hdr->revision_level);
|
||||||
|
g_debug (" CodeType: 0x%02x [%s]", hdr->code_type,
|
||||||
|
fu_rom_pci_code_type_to_string (hdr->code_type));
|
||||||
|
g_debug (" LastImg: 0x%02x [%s]", hdr->last_image,
|
||||||
|
hdr->last_image == 0x80 ? "yes" : "no");
|
||||||
|
g_debug (" MaxRunLen: 0x%04x", hdr->max_runtime_len);
|
||||||
|
g_debug (" ConfigHdr: 0x%04x", hdr->config_header_ptr);
|
||||||
|
g_debug (" ClpPtr: 0x%04x", hdr->dmtf_clp_ptr);
|
||||||
|
|
||||||
|
/* dump the ISBN */
|
||||||
|
if (hdr->code_type == 0x70 &&
|
||||||
|
memcmp (&buffer[hdr->data_len], "ISBN", 4) == 0) {
|
||||||
|
fu_rom_pci_print_certificate_data (&buffer[hdr->data_len],
|
||||||
|
hdr->image_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify the checksum byte */
|
||||||
|
if (hdr->image_len <= sz && hdr->image_len > 0) {
|
||||||
|
buffer -= hdr->cpi_ptr;
|
||||||
|
chksum_check = fu_rom_pci_header_get_checksum (hdr, buffer, sz);
|
||||||
|
if (chksum_check == 0x00) {
|
||||||
|
g_debug (" ChkSum: 0x%02x [valid]",
|
||||||
|
buffer[hdr->image_len-1]);
|
||||||
|
} else {
|
||||||
|
g_debug (" ChkSum: 0x%02x [failed, got 0x%02x]",
|
||||||
|
buffer[hdr->image_len-1],
|
||||||
|
chksum_check);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g_debug (" ChkSum: 0x?? [unknown]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_rom_find_and_blank_serial_numbers:
|
||||||
|
**/
|
||||||
|
static void
|
||||||
|
fu_rom_find_and_blank_serial_numbers (FuRom *rom, guint8 *buffer, gsize sz)
|
||||||
|
{
|
||||||
|
FuRomPrivate *priv = rom->priv;
|
||||||
|
FuRomPciHeader *hdr;
|
||||||
|
guint i;
|
||||||
|
guint8 *tmp;
|
||||||
|
|
||||||
|
for (i = 0; i < priv->hdrs->len; i++) {
|
||||||
|
guint32 off;
|
||||||
|
|
||||||
|
hdr = g_ptr_array_index (priv->hdrs, i);
|
||||||
|
g_debug ("Looking for serial numbers at ROM 0x%04x", hdr->offset_in_buffer);
|
||||||
|
|
||||||
|
if (priv->kind == FU_ROM_KIND_PCI)
|
||||||
|
continue;
|
||||||
|
if (priv->kind == FU_ROM_KIND_INTEL)
|
||||||
|
continue;
|
||||||
|
if (hdr->image_len < 4)
|
||||||
|
continue;
|
||||||
|
if (hdr->image_len > sz)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Only NVIDIA and ATI embed the PPID in the ROM */
|
||||||
|
off = hdr->offset_in_buffer;
|
||||||
|
off += hdr->data_len;
|
||||||
|
if (off > sz)
|
||||||
|
continue;
|
||||||
|
tmp = fu_rom_strstr_bin (&buffer[off], hdr->image_len, "PPID");
|
||||||
|
if (tmp != NULL) {
|
||||||
|
guint len;
|
||||||
|
guint8 chk;
|
||||||
|
len = fu_rom_blank_serial_numbers (tmp, sz - (tmp - buffer));
|
||||||
|
g_debug ("cleared %i chars @ 0x%04lx", len, tmp - buffer);
|
||||||
|
|
||||||
|
/* we have to fix the checksum */
|
||||||
|
chk = fu_rom_pci_header_get_checksum (hdr, buffer, sz);
|
||||||
|
buffer[hdr->offset_in_buffer + hdr->image_len - 1] -= chk;
|
||||||
|
fu_rom_pci_print_header (hdr, buffer, sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fu_rom_pci_get_data:
|
* fu_rom_pci_get_data:
|
||||||
**/
|
**/
|
||||||
static FuRomPciData *
|
static gboolean
|
||||||
fu_rom_pci_get_data (FuRomPciHeader *hdr, gssize sz)
|
fu_rom_pci_parse_data (FuRomPciHeader *hdr, guint8 *buffer, gssize sz)
|
||||||
{
|
{
|
||||||
FuRomPciData *dtr;
|
|
||||||
|
|
||||||
/* check valid */
|
/* check valid */
|
||||||
if (hdr == NULL ||
|
if (hdr == NULL ||
|
||||||
hdr->cpi_ptr == 0x0000 ||
|
hdr->cpi_ptr == 0x0000) {
|
||||||
hdr->cpi_ptr > hdr->rom_size * 512) {
|
|
||||||
g_debug ("No PCI DATA");
|
g_debug ("No PCI DATA");
|
||||||
return NULL;
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (hdr->rom_len > 0 && hdr->cpi_ptr > hdr->rom_len) {
|
||||||
|
g_debug ("Invalid PCI DATA");
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gahh, CPI is out of the first chunk */
|
/* gahh, CPI is out of the first chunk */
|
||||||
if (hdr->cpi_ptr > sz) {
|
if (hdr->cpi_ptr > sz) {
|
||||||
g_debug ("No available PCI DATA");
|
g_debug ("No available PCI DATA");
|
||||||
return NULL;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check signature */
|
/* check signature */
|
||||||
dtr = (FuRomPciData *) &((guint8 *)hdr)[hdr->cpi_ptr];
|
if (memcmp (&buffer[hdr->cpi_ptr], "PCIR", 4) != 0) {
|
||||||
if (dtr == NULL ||
|
if (memcmp (&buffer[hdr->cpi_ptr], "RGIS", 4) == 0 ||
|
||||||
dtr->signature == NULL ||
|
memcmp (&buffer[hdr->cpi_ptr], "NPDS", 4) == 0 ||
|
||||||
memcmp (dtr->signature, "PCIR", 4) != 0) {
|
memcmp (&buffer[hdr->cpi_ptr], "NPDE", 4) == 0) {
|
||||||
g_debug ("Not PCI DATA");
|
g_debug ("-- using NVIDIA DATA quirk");
|
||||||
return NULL;
|
} else {
|
||||||
|
g_debug ("Not PCI DATA: %02x%02x%02x%02x [%c%c%c%c]",
|
||||||
|
buffer[hdr->cpi_ptr+0], buffer[hdr->cpi_ptr+1],
|
||||||
|
buffer[hdr->cpi_ptr+2], buffer[hdr->cpi_ptr+3],
|
||||||
|
buffer[hdr->cpi_ptr+0], buffer[hdr->cpi_ptr+1],
|
||||||
|
buffer[hdr->cpi_ptr+2], buffer[hdr->cpi_ptr+3]);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g_debug ("VendorID: 0x%04x", dtr->vendor_id);
|
|
||||||
g_debug ("DeviceID: 0x%04x", dtr->device_id);
|
/* parse */
|
||||||
g_debug ("DevList: 0x%04x", dtr->device_list_ptr);
|
buffer += hdr->cpi_ptr;
|
||||||
g_debug ("DataLen: 0x%04x", dtr->pci_data_length);
|
hdr->vendor_id = ((guint16) buffer[0x05] << 8) + buffer[0x04];
|
||||||
g_debug ("DataRev: 0x%04x", dtr->pci_data_revision);
|
hdr->device_id = ((guint16) buffer[0x07] << 8) + buffer[0x06];
|
||||||
g_debug ("ImageLen: 0x%04x", dtr->image_len * 512);
|
hdr->device_list_ptr = ((guint16) buffer[0x09] << 8) + buffer[0x08];
|
||||||
g_debug ("RevLevel: 0x%04x", dtr->revision_level);
|
hdr->data_len = ((guint16) buffer[0x0b] << 8) + buffer[0x0a];
|
||||||
g_debug ("CodeType: 0x%02x", dtr->code_type);
|
hdr->data_rev = buffer[0x0c];
|
||||||
g_debug ("LastImg: 0x%02x [%s]", dtr->last_image_indicator,
|
hdr->class_code = ((guint16) buffer[0x0f] << 16) +
|
||||||
dtr->last_image_indicator == 0x80 ? "yes" : "no");
|
((guint16) buffer[0x0e] << 8) +
|
||||||
g_debug ("MaxRunLen: 0x%04x", dtr->max_runtime_len);
|
buffer[0x0d];
|
||||||
g_debug ("ConfigHdr: 0x%04x", dtr->config_header_ptr);
|
hdr->image_len = (((guint16) buffer[0x11] << 8) + buffer[0x10]) * 512;
|
||||||
g_debug ("ClpPtr: 0x%04x", dtr->dmtf_clp_entry_point);
|
hdr->revision_level = ((guint16) buffer[0x13] << 8) + buffer[0x12];
|
||||||
return dtr;
|
hdr->code_type = buffer[0x14];
|
||||||
|
hdr->last_image = buffer[0x15];
|
||||||
|
hdr->max_runtime_len = (((guint16) buffer[0x17] << 8) +
|
||||||
|
buffer[0x16]) * 512;
|
||||||
|
hdr->config_header_ptr = ((guint16) buffer[0x19] << 8) + buffer[0x18];
|
||||||
|
hdr->dmtf_clp_ptr = ((guint16) buffer[0x1b] << 8) + buffer[0x1a];
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -200,37 +399,154 @@ fu_rom_pci_get_data (FuRomPciHeader *hdr, gssize sz)
|
|||||||
static FuRomPciHeader *
|
static FuRomPciHeader *
|
||||||
fu_rom_pci_get_header (guint8 *buffer, gssize sz)
|
fu_rom_pci_get_header (guint8 *buffer, gssize sz)
|
||||||
{
|
{
|
||||||
FuRomPciHeader *hdr = (FuRomPciHeader *) buffer;
|
FuRomPciHeader *hdr;
|
||||||
guint i;
|
|
||||||
_cleanup_string_free_ GString *str = NULL;
|
|
||||||
|
|
||||||
/* check signature */
|
/* check signature */
|
||||||
if (hdr == NULL ||
|
if (memcmp (buffer, "\x55\xaa", 2) != 0) {
|
||||||
hdr->rom_signature == NULL ||
|
if (memcmp (buffer, "\x56\x4e", 2) == 0) {
|
||||||
memcmp (hdr->rom_signature, "\x55\xaa", 2) != 0) {
|
g_debug ("-- using NVIDIA ROM quirk");
|
||||||
g_debug ("Not PCI ROM");
|
} else {
|
||||||
return NULL;
|
_cleanup_free_ gchar *sig_str = NULL;
|
||||||
|
sig_str = fu_rom_get_hex_dump (buffer, 16);
|
||||||
|
g_debug ("Not PCI ROM %s", sig_str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print details about the header */
|
/* decode structure */
|
||||||
g_debug ("RomSize: 0x%04x", hdr->rom_size * 512);
|
hdr = g_new0 (FuRomPciHeader, 1);
|
||||||
g_debug ("EntryPnt: 0x%02x%02x%02x",
|
hdr->rom_len = buffer[0x02] * 512;
|
||||||
hdr->entry_point[0],
|
hdr->entry_point = ((guint32) buffer[0x05] << 16) +
|
||||||
hdr->entry_point[1],
|
((guint16) buffer[0x04] << 8) +
|
||||||
hdr->entry_point[2]);
|
buffer[0x03];
|
||||||
str = g_string_new ("");
|
memcpy (&hdr->reserved, &buffer[6], 18);
|
||||||
for (i = 0; i < 18; i++) {
|
hdr->cpi_ptr = ((guint16) buffer[0x19] << 8) + buffer[0x18];
|
||||||
gchar tmp = '?';
|
|
||||||
if (g_ascii_isprint (hdr->reserved[i]))
|
/* parse the header data */
|
||||||
tmp = hdr->reserved[i];
|
g_debug ("looking for PCI DATA @ 0x%04x", hdr->cpi_ptr);
|
||||||
g_string_append_printf (str, "%02x [%c] ",
|
fu_rom_pci_parse_data (hdr, buffer, sz);
|
||||||
hdr->reserved[i], tmp);
|
|
||||||
}
|
|
||||||
g_debug ("Reserved: %s", str->str);
|
|
||||||
g_debug ("CpiPtr: 0x%04x", hdr->cpi_ptr);
|
|
||||||
return hdr;
|
return hdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_rom_find_version_pci:
|
||||||
|
**/
|
||||||
|
static gchar *
|
||||||
|
fu_rom_find_version_pci (FuRomPciHeader *hdr, guint8 *buffer, gsize sz)
|
||||||
|
{
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
/* ARC storage */
|
||||||
|
if (memcmp (hdr->reserved, "\0\0ARC", 5) == 0) {
|
||||||
|
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "BIOS: ");
|
||||||
|
if (str != NULL)
|
||||||
|
return g_strdup (str + 6);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_rom_find_version_nvidia:
|
||||||
|
**/
|
||||||
|
static gchar *
|
||||||
|
fu_rom_find_version_nvidia (FuRomPciHeader *hdr, guint8 *buffer, gsize sz)
|
||||||
|
{
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
/* static location for some firmware */
|
||||||
|
if (memcmp (buffer + 0x0d7, "Version ", 8) == 0)
|
||||||
|
return g_strdup ((gchar *) &buffer[0x0d7 + 8]);
|
||||||
|
if (memcmp (buffer + 0x155, "Version ", 8) == 0)
|
||||||
|
return g_strdup ((gchar *) &buffer[0x155 + 8]);
|
||||||
|
|
||||||
|
/* usual search string */
|
||||||
|
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "Version ");
|
||||||
|
if (str != NULL)
|
||||||
|
return g_strdup (str + 8);
|
||||||
|
|
||||||
|
/* broken */
|
||||||
|
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "Vension:");
|
||||||
|
if (str != NULL)
|
||||||
|
return g_strdup (str + 8);
|
||||||
|
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "Version");
|
||||||
|
if (str != NULL)
|
||||||
|
return g_strdup (str + 7);
|
||||||
|
|
||||||
|
/* fallback to VBIOS */
|
||||||
|
if (memcmp (buffer + 0xfa, "VBIOS Ver", 9) == 0)
|
||||||
|
return g_strdup ((gchar *) &buffer[0xfa + 9]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_rom_find_version_intel:
|
||||||
|
**/
|
||||||
|
static gchar *
|
||||||
|
fu_rom_find_version_intel (FuRomPciHeader *hdr, guint8 *buffer, gsize sz)
|
||||||
|
{
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
/* 2175_RYan PC 14.34 06/06/2013 21:27:53 */
|
||||||
|
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "Build Number:");
|
||||||
|
if (str != NULL) {
|
||||||
|
guint i;
|
||||||
|
_cleanup_strv_free_ gchar **split = NULL;
|
||||||
|
split = g_strsplit (str + 14, " ", -1);
|
||||||
|
for (i = 0; split[i] != NULL; i++) {
|
||||||
|
if (g_strstr_len (split[i], -1, ".") == NULL)
|
||||||
|
continue;
|
||||||
|
return g_strdup (split[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fallback to VBIOS */
|
||||||
|
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "VBIOS ");
|
||||||
|
if (str != NULL)
|
||||||
|
return g_strdup (str + 6);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_rom_find_version_ati:
|
||||||
|
**/
|
||||||
|
static gchar *
|
||||||
|
fu_rom_find_version_ati (FuRomPciHeader *hdr, guint8 *buffer, gsize sz)
|
||||||
|
{
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
str = (gchar *) fu_rom_strstr_bin (buffer, sz, " VER0");
|
||||||
|
if (str != NULL)
|
||||||
|
return g_strdup (str + 4);
|
||||||
|
|
||||||
|
/* broken */
|
||||||
|
str = (gchar *) fu_rom_strstr_bin (buffer, sz, " VR");
|
||||||
|
if (str != NULL)
|
||||||
|
return g_strdup (str + 4);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_rom_find_version:
|
||||||
|
**/
|
||||||
|
static gchar *
|
||||||
|
fu_rom_find_version (FuRomKind kind, FuRomPciHeader *hdr,
|
||||||
|
guint8 *buffer, gsize sz)
|
||||||
|
{
|
||||||
|
/* narrow the search space down a bit */
|
||||||
|
buffer = &buffer[hdr->offset_in_buffer];
|
||||||
|
sz = hdr->rom_len;
|
||||||
|
|
||||||
|
if (kind == FU_ROM_KIND_PCI)
|
||||||
|
return fu_rom_find_version_pci (hdr, buffer, sz);
|
||||||
|
if (kind == FU_ROM_KIND_NVIDIA)
|
||||||
|
return fu_rom_find_version_nvidia (hdr, buffer, sz);
|
||||||
|
if (kind == FU_ROM_KIND_INTEL)
|
||||||
|
return fu_rom_find_version_intel (hdr, buffer, sz);
|
||||||
|
if (kind == FU_ROM_KIND_ATI)
|
||||||
|
return fu_rom_find_version_ati (hdr, buffer, sz);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fu_rom_load_file:
|
* fu_rom_load_file:
|
||||||
**/
|
**/
|
||||||
@ -238,17 +554,16 @@ gboolean
|
|||||||
fu_rom_load_file (FuRom *rom, GFile *file, GCancellable *cancellable, GError **error)
|
fu_rom_load_file (FuRom *rom, GFile *file, GCancellable *cancellable, GError **error)
|
||||||
{
|
{
|
||||||
FuRomPrivate *priv = rom->priv;
|
FuRomPrivate *priv = rom->priv;
|
||||||
FuRomPciData *dtr = NULL;
|
|
||||||
FuRomPciHeader *hdr = NULL;
|
FuRomPciHeader *hdr = NULL;
|
||||||
const guint block_sz = 0x4000;
|
const gssize buffer_sz = 0x400000;
|
||||||
guint8 buffer[block_sz];
|
gssize sz;
|
||||||
gchar *str;
|
guint32 jump = 0;
|
||||||
guint hdr_sz = 0;
|
guint hdr_sz = 0;
|
||||||
guint i;
|
guint i;
|
||||||
guint number_reads = 0;
|
guint number_reads = 0;
|
||||||
gssize sz;
|
|
||||||
_cleanup_free_ gchar *fn = NULL;
|
|
||||||
_cleanup_error_free_ GError *error_local = NULL;
|
_cleanup_error_free_ GError *error_local = NULL;
|
||||||
|
_cleanup_free_ gchar *fn = NULL;
|
||||||
|
_cleanup_free_ guint8 *buffer = NULL;
|
||||||
_cleanup_object_unref_ GFileOutputStream *output_stream = NULL;
|
_cleanup_object_unref_ GFileOutputStream *output_stream = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (FU_IS_ROM (rom), FALSE);
|
g_return_val_if_fail (FU_IS_ROM (rom), FALSE);
|
||||||
@ -276,7 +591,8 @@ fu_rom_load_file (FuRom *rom, GFile *file, GCancellable *cancellable, GError **e
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* read out the header */
|
/* read out the header */
|
||||||
sz = g_input_stream_read (priv->stream, buffer, block_sz,
|
buffer = g_malloc (buffer_sz);
|
||||||
|
sz = g_input_stream_read (priv->stream, buffer, buffer_sz,
|
||||||
cancellable, error);
|
cancellable, error);
|
||||||
if (sz < 0)
|
if (sz < 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -289,11 +605,11 @@ fu_rom_load_file (FuRom *rom, GFile *file, GCancellable *cancellable, GError **e
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ensure we got enough data to fill the buffer */
|
/* ensure we got enough data to fill the buffer */
|
||||||
while (sz < block_sz) {
|
while (sz < buffer_sz) {
|
||||||
gssize sz_chunk;
|
gssize sz_chunk;
|
||||||
sz_chunk = g_input_stream_read (priv->stream,
|
sz_chunk = g_input_stream_read (priv->stream,
|
||||||
buffer + sz,
|
buffer + sz,
|
||||||
block_sz - sz,
|
buffer_sz - sz,
|
||||||
cancellable,
|
cancellable,
|
||||||
error);
|
error);
|
||||||
if (sz_chunk == 0)
|
if (sz_chunk == 0)
|
||||||
@ -313,40 +629,49 @@ fu_rom_load_file (FuRom *rom, GFile *file, GCancellable *cancellable, GError **e
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
g_debug ("ROM buffer filled %likb/%likb", sz / 0x400, buffer_sz / 0x400);
|
||||||
|
|
||||||
/* detect signed header and skip to option ROM */
|
/* detect optional IFR header and skip to option ROM */
|
||||||
if (memcmp (buffer, "NVGI", 4) == 0)
|
if (memcmp (buffer, "NVGI", 4) == 0)
|
||||||
hdr_sz = GUINT16_FROM_BE (buffer[0x15]);
|
hdr_sz = GUINT16_FROM_BE (buffer[0x15]);
|
||||||
|
|
||||||
/* firmware magic bytes */
|
/* read all the ROM headers */
|
||||||
if (memcmp (buffer + hdr_sz, "\x55\xaa", 2) == 0) {
|
while (sz > hdr_sz + jump) {
|
||||||
|
guint32 jump_sz;
|
||||||
/* find generic PCI option ROM */
|
g_debug ("looking for PCI ROM @ 0x%04x", hdr_sz + jump);
|
||||||
hdr = fu_rom_pci_get_header (&buffer[hdr_sz], sz - hdr_sz);
|
hdr = fu_rom_pci_get_header (&buffer[hdr_sz + jump], sz - hdr_sz - jump);
|
||||||
if (hdr != NULL) {
|
if (hdr == NULL) {
|
||||||
priv->rom_length = hdr->rom_size * 512;
|
g_debug ("found junk data, adding fake ROM header");
|
||||||
dtr = fu_rom_pci_get_data (hdr, sz - hdr_sz);
|
hdr = g_new0 (FuRomPciHeader, 1);
|
||||||
if (dtr != NULL) {
|
hdr->vendor_id = 0xdead;
|
||||||
priv->vendor = dtr->vendor_id;
|
hdr->device_id = 0xbeef;
|
||||||
priv->model = dtr->device_id;
|
hdr->code_type = 0xff;
|
||||||
priv->kind = FU_ROM_KIND_PCI;
|
hdr->last_image = 0x80;
|
||||||
}
|
hdr->offset_in_buffer = hdr_sz + jump;
|
||||||
|
hdr->rom_len = sz - (hdr_sz + jump);
|
||||||
|
hdr->image_len = hdr->rom_len;
|
||||||
|
g_ptr_array_add (priv->hdrs, hdr);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* detect intel header */
|
/* save this so we can fix checksums */
|
||||||
if (memcmp (hdr->reserved, "00000000000", 11) == 0)
|
hdr->offset_in_buffer = hdr_sz + jump;
|
||||||
hdr_sz = (buffer[0x1b] << 8) + buffer[0x1a];
|
|
||||||
|
|
||||||
if (memcmp (buffer + hdr_sz + 0x04, "K740", 4) == 0) {
|
/* we can't break on hdr->last_image as
|
||||||
priv->kind = FU_ROM_KIND_NVIDIA;
|
* NVIDIA uses packed but not merged extended headers */
|
||||||
} else if (memcmp (buffer + hdr_sz, "$VBT", 4) == 0) {
|
g_ptr_array_add (priv->hdrs, hdr);
|
||||||
priv->kind = FU_ROM_KIND_INTEL;
|
|
||||||
/* see drivers/gpu/drm/i915/intel_bios.h */
|
/* NVIDIA don't always set a ROM size for extensions */
|
||||||
hdr_sz += (buffer[hdr_sz + 23] << 8) + buffer[hdr_sz + 22];
|
jump_sz = hdr->rom_len;
|
||||||
} else if (memcmp(buffer + 0x30, " 761295520", 10) == 0) {
|
if (jump_sz == 0)
|
||||||
priv->kind = FU_ROM_KIND_ATI;
|
jump_sz = hdr->image_len;
|
||||||
}
|
if (jump_sz == 0x0)
|
||||||
} else {
|
break;
|
||||||
|
jump += jump_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we found nothing */
|
||||||
|
if (priv->hdrs->len == 0) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
FWUPD_ERROR_INVALID_FILE,
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
@ -355,6 +680,39 @@ fu_rom_load_file (FuRom *rom, GFile *file, GCancellable *cancellable, GError **e
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* print all headers */
|
||||||
|
for (i = 0; i < priv->hdrs->len; i++) {
|
||||||
|
hdr = g_ptr_array_index (priv->hdrs, i);
|
||||||
|
fu_rom_pci_print_header (hdr, buffer, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find first ROM header */
|
||||||
|
hdr = g_ptr_array_index (priv->hdrs, 0);
|
||||||
|
priv->vendor = hdr->vendor_id;
|
||||||
|
priv->model = hdr->device_id;
|
||||||
|
priv->kind = FU_ROM_KIND_PCI;
|
||||||
|
|
||||||
|
/* detect intel header */
|
||||||
|
if (memcmp (hdr->reserved, "00000000000", 11) == 0)
|
||||||
|
hdr_sz = (buffer[0x1b] << 8) + buffer[0x1a];
|
||||||
|
if (hdr_sz > sz) {
|
||||||
|
g_set_error_literal (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"firmware corrupt (overflow)");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp (buffer + hdr_sz + 0x04, "K74", 3) == 0) {
|
||||||
|
priv->kind = FU_ROM_KIND_NVIDIA;
|
||||||
|
} else if (memcmp (buffer + hdr_sz, "$VBT", 4) == 0) {
|
||||||
|
priv->kind = FU_ROM_KIND_INTEL;
|
||||||
|
/* see drivers/gpu/drm/i915/intel_bios.h */
|
||||||
|
hdr_sz += (buffer[hdr_sz + 23] << 8) + buffer[hdr_sz + 22];
|
||||||
|
} else if (memcmp(buffer + 0x30, " 761295520", 10) == 0) {
|
||||||
|
priv->kind = FU_ROM_KIND_ATI;
|
||||||
|
}
|
||||||
|
|
||||||
/* nothing */
|
/* nothing */
|
||||||
if (priv->kind == FU_ROM_KIND_UNKNOWN) {
|
if (priv->kind == FU_ROM_KIND_UNKNOWN) {
|
||||||
g_set_error_literal (error,
|
g_set_error_literal (error,
|
||||||
@ -365,100 +723,14 @@ fu_rom_load_file (FuRom *rom, GFile *file, GCancellable *cancellable, GError **e
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* find version string */
|
/* find version string */
|
||||||
switch (priv->kind) {
|
priv->version = fu_rom_find_version (priv->kind, hdr, buffer, sz);
|
||||||
case FU_ROM_KIND_PCI:
|
|
||||||
|
|
||||||
/* ARC storage */
|
|
||||||
if (memcmp (hdr->reserved, "\0\0ARC", 5) == 0) {
|
|
||||||
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "BIOS: ");
|
|
||||||
if (str != NULL)
|
|
||||||
priv->version = g_strdup (str + 6);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FU_ROM_KIND_NVIDIA:
|
|
||||||
|
|
||||||
/* static location for some firmware */
|
|
||||||
if (memcmp (buffer + hdr_sz + 0x0d7, "Version ", 8) == 0)
|
|
||||||
priv->version = g_strdup ((gchar *) &buffer[0x0d7 + hdr_sz + 8]);
|
|
||||||
else if (memcmp (buffer + hdr_sz + 0x155, "Version ", 8) == 0)
|
|
||||||
priv->version = g_strdup ((gchar *) &buffer[0x155 + hdr_sz + 8]);
|
|
||||||
|
|
||||||
/* usual search string */
|
|
||||||
if (priv->version == NULL) {
|
|
||||||
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "Version ");
|
|
||||||
if (str != NULL)
|
|
||||||
priv->version = g_strdup (str + 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* broken */
|
|
||||||
if (priv->version == NULL) {
|
|
||||||
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "Vension:");
|
|
||||||
if (str != NULL)
|
|
||||||
priv->version = g_strdup (str + 8);
|
|
||||||
}
|
|
||||||
if (priv->version == NULL) {
|
|
||||||
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "Version");
|
|
||||||
if (str != NULL)
|
|
||||||
priv->version = g_strdup (str + 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fallback to VBIOS */
|
|
||||||
if (priv->version == NULL &&
|
|
||||||
memcmp (buffer + hdr_sz + 0xfa, "VBIOS Ver", 9) == 0)
|
|
||||||
priv->version = g_strdup ((gchar *) &buffer[0xfa + hdr_sz + 9]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FU_ROM_KIND_INTEL:
|
|
||||||
if (priv->version == NULL) {
|
|
||||||
/* 2175_RYan PC 14.34 06/06/2013 21:27:53 */
|
|
||||||
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "Build Number:");
|
|
||||||
if (str != NULL) {
|
|
||||||
_cleanup_strv_free_ gchar **split = NULL;
|
|
||||||
split = g_strsplit (str + 14, " ", -1);
|
|
||||||
for (i = 0; split[i] != NULL; i++) {
|
|
||||||
if (g_strstr_len (split[i], -1, ".") == NULL)
|
|
||||||
continue;
|
|
||||||
priv->version = g_strdup (split[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fallback to VBIOS */
|
|
||||||
if (priv->version == NULL) {
|
|
||||||
str = (gchar *) fu_rom_strstr_bin (buffer, sz, "VBIOS ");
|
|
||||||
if (str != NULL) {
|
|
||||||
priv->version = g_strdup (str + 6);
|
|
||||||
g_strdelimit (priv->version, "\r\n ", '\0');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FU_ROM_KIND_ATI:
|
|
||||||
if (priv->version == NULL) {
|
|
||||||
str = (gchar *) fu_rom_strstr_bin (buffer, sz, " VER0");
|
|
||||||
if (str != NULL)
|
|
||||||
priv->version = g_strdup (str + 4);
|
|
||||||
}
|
|
||||||
/* broken */
|
|
||||||
if (priv->version == NULL) {
|
|
||||||
str = (gchar *) fu_rom_strstr_bin (buffer, sz, " VR");
|
|
||||||
if (str != NULL)
|
|
||||||
priv->version = g_strdup (str + 4);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fix */
|
|
||||||
if (priv->version != NULL) {
|
if (priv->version != NULL) {
|
||||||
g_strstrip (priv->version);
|
g_strstrip (priv->version);
|
||||||
g_strdelimit (priv->version, "\r\n ", '\0');
|
g_strdelimit (priv->version, "\r\n ", '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update checksum */
|
/* update checksum */
|
||||||
fu_rom_find_and_blank_serial_numbers (buffer, sz);
|
fu_rom_find_and_blank_serial_numbers (rom, buffer, sz);
|
||||||
g_checksum_update (priv->checksum_wip, buffer, sz);
|
g_checksum_update (priv->checksum_wip, buffer, sz);
|
||||||
|
|
||||||
/* not known */
|
/* not known */
|
||||||
@ -513,53 +785,10 @@ fu_rom_get_model (FuRom *rom)
|
|||||||
return rom->priv->model;
|
return rom->priv->model;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* fu_rom_generate_checksum:
|
|
||||||
*
|
|
||||||
* This adds the entire firmware image to the checksum data.
|
|
||||||
**/
|
|
||||||
gboolean
|
|
||||||
fu_rom_generate_checksum (FuRom *rom, GCancellable *cancellable, GError **error)
|
|
||||||
{
|
|
||||||
FuRomPrivate *priv = rom->priv;
|
|
||||||
const guint block_sz = 0x4000;
|
|
||||||
gssize cnt = block_sz;
|
|
||||||
guint8 buffer[block_sz];
|
|
||||||
|
|
||||||
g_return_val_if_fail (FU_IS_ROM (rom), FALSE);
|
|
||||||
|
|
||||||
while (TRUE) {
|
|
||||||
gssize sz;
|
|
||||||
sz = g_input_stream_read (G_INPUT_STREAM (priv->stream),
|
|
||||||
buffer, block_sz, NULL, NULL);
|
|
||||||
if (sz <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* blank out serial numbers */
|
|
||||||
fu_rom_find_and_blank_serial_numbers (buffer, sz);
|
|
||||||
|
|
||||||
cnt += sz;
|
|
||||||
fu_rom_find_and_blank_serial_numbers (buffer, sz);
|
|
||||||
g_checksum_update (priv->checksum_wip, buffer, sz);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* is the data wrapped up, e.g. NVGI */
|
|
||||||
if (priv->rom_length == 0 || cnt <= priv->rom_length) {
|
|
||||||
g_debug ("read %" G_GSSIZE_FORMAT " bytes from ROM", cnt);
|
|
||||||
} else {
|
|
||||||
g_debug ("read %" G_GSSIZE_FORMAT " bytes from ROM, %" G_GSIZE_FORMAT
|
|
||||||
" bytes more than expected", cnt, cnt - priv->rom_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fu_rom_get_checksum:
|
* fu_rom_get_checksum:
|
||||||
*
|
*
|
||||||
* This returns the checksum of the firmware.
|
* This returns the checksum of the firmware.
|
||||||
* If fu_rom_generate_checksum() has been called then the checksum is of the
|
|
||||||
* entire firmware image, and not just the header.
|
|
||||||
**/
|
**/
|
||||||
const gchar *
|
const gchar *
|
||||||
fu_rom_get_checksum (FuRom *rom)
|
fu_rom_get_checksum (FuRom *rom)
|
||||||
@ -587,6 +816,7 @@ fu_rom_init (FuRom *rom)
|
|||||||
{
|
{
|
||||||
rom->priv = FU_ROM_GET_PRIVATE (rom);
|
rom->priv = FU_ROM_GET_PRIVATE (rom);
|
||||||
rom->priv->checksum_wip = g_checksum_new (G_CHECKSUM_SHA1);
|
rom->priv->checksum_wip = g_checksum_new (G_CHECKSUM_SHA1);
|
||||||
|
rom->priv->hdrs = g_ptr_array_new_with_free_func (g_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -600,6 +830,7 @@ fu_rom_finalize (GObject *object)
|
|||||||
|
|
||||||
g_checksum_free (priv->checksum_wip);
|
g_checksum_free (priv->checksum_wip);
|
||||||
g_free (priv->version);
|
g_free (priv->version);
|
||||||
|
g_ptr_array_unref (priv->hdrs);
|
||||||
if (priv->stream != NULL)
|
if (priv->stream != NULL)
|
||||||
g_object_unref (priv->stream);
|
g_object_unref (priv->stream);
|
||||||
|
|
||||||
|
@ -66,9 +66,6 @@ gboolean fu_rom_load_file (FuRom *rom,
|
|||||||
GFile *file,
|
GFile *file,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
gboolean fu_rom_generate_checksum (FuRom *rom,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error);
|
|
||||||
FuRomKind fu_rom_get_kind (FuRom *rom);
|
FuRomKind fu_rom_get_kind (FuRom *rom);
|
||||||
const gchar *fu_rom_get_version (FuRom *rom);
|
const gchar *fu_rom_get_version (FuRom *rom);
|
||||||
const gchar *fu_rom_get_checksum (FuRom *rom);
|
const gchar *fu_rom_get_checksum (FuRom *rom);
|
||||||
|
@ -69,12 +69,12 @@ fu_rom_func (void)
|
|||||||
{ FU_ROM_KIND_ATI, /* atombios */
|
{ FU_ROM_KIND_ATI, /* atombios */
|
||||||
"Asus.R9290X.4096.131014.rom",
|
"Asus.R9290X.4096.131014.rom",
|
||||||
"015.039.000.006.003515",
|
"015.039.000.006.003515",
|
||||||
"2b159ae92517595d2cddb31193f5ed702ca3f803",
|
"d8e32fa09a00ab9dcc96a990266f3fe5a99eacc5",
|
||||||
0x1002, 0x67b0 },
|
0x1002, 0x67b0 },
|
||||||
{ FU_ROM_KIND_ATI, /* atombios, with serial */
|
{ FU_ROM_KIND_ATI, /* atombios, with serial */
|
||||||
"Asus.HD7970.3072.121018.rom",
|
"Asus.HD7970.3072.121018.rom",
|
||||||
"015.023.000.002.000000",
|
"015.023.000.002.000000",
|
||||||
"bceb6cd2adfc0b84ed92065bead4fa98ec70124e",
|
"e4107546d3df3e52db2068babbcacc6329f05d46",
|
||||||
0x1002, 0x6798 },
|
0x1002, 0x6798 },
|
||||||
{ FU_ROM_KIND_NVIDIA,
|
{ FU_ROM_KIND_NVIDIA,
|
||||||
"Asus.GTX480.1536.100406_1.rom",
|
"Asus.GTX480.1536.100406_1.rom",
|
||||||
@ -89,7 +89,7 @@ fu_rom_func (void)
|
|||||||
{ FU_ROM_KIND_NVIDIA, /* nvgi, with serial */
|
{ FU_ROM_KIND_NVIDIA, /* nvgi, with serial */
|
||||||
"Asus.TitanBlack.6144.140212.rom",
|
"Asus.TitanBlack.6144.140212.rom",
|
||||||
"80.80.4E.00.01",
|
"80.80.4E.00.01",
|
||||||
"e86482f5ce29f3f8468cb4077ab72f6f9c9abfd2",
|
"298627b23efea5a8fb62d992a66fba10b06a136d",
|
||||||
0x10de, 0x100c },
|
0x10de, 0x100c },
|
||||||
{ FU_ROM_KIND_UNKNOWN, NULL, NULL, NULL, 0x0000, 0x0000 }
|
{ FU_ROM_KIND_UNKNOWN, NULL, NULL, NULL, 0x0000, 0x0000 }
|
||||||
};
|
};
|
||||||
@ -112,9 +112,6 @@ fu_rom_func (void)
|
|||||||
ret = fu_rom_load_file (rom, file, NULL, &error);
|
ret = fu_rom_load_file (rom, file, NULL, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert (ret);
|
g_assert (ret);
|
||||||
ret = fu_rom_generate_checksum (rom, NULL, &error);
|
|
||||||
g_assert_no_error (error);
|
|
||||||
g_assert (ret);
|
|
||||||
g_assert_cmpstr (fu_rom_get_version (rom), ==, data[i].ver);
|
g_assert_cmpstr (fu_rom_get_version (rom), ==, data[i].ver);
|
||||||
g_assert_cmpstr (fu_rom_get_checksum (rom), ==, data[i].csum);
|
g_assert_cmpstr (fu_rom_get_checksum (rom), ==, data[i].csum);
|
||||||
g_assert_cmpint (fu_rom_get_kind (rom), ==, data[i].kind);
|
g_assert_cmpint (fu_rom_get_kind (rom), ==, data[i].kind);
|
||||||
@ -147,6 +144,7 @@ fu_rom_all_func (void)
|
|||||||
if (fn == NULL)
|
if (fn == NULL)
|
||||||
break;
|
break;
|
||||||
filename = g_build_filename (path, fn, NULL);
|
filename = g_build_filename (path, fn, NULL);
|
||||||
|
g_print ("\nparsing %s...", filename);
|
||||||
file = g_file_new_for_path (filename);
|
file = g_file_new_for_path (filename);
|
||||||
rom = fu_rom_new ();
|
rom = fu_rom_new ();
|
||||||
ret = fu_rom_load_file (rom, file, NULL, &error);
|
ret = fu_rom_load_file (rom, file, NULL, &error);
|
||||||
|
@ -807,10 +807,6 @@ fu_util_dump_rom (FuUtilPrivate *priv, gchar **values, GError **error)
|
|||||||
g_print ("%s\n", error_local->message);
|
g_print ("%s\n", error_local->message);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!fu_rom_generate_checksum (rom, NULL, &error_local)) {
|
|
||||||
g_print ("%s\n", error_local->message);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
g_print ("0x%04x:0x%04x -> %s [%s]\n",
|
g_print ("0x%04x:0x%04x -> %s [%s]\n",
|
||||||
fu_rom_get_vendor (rom),
|
fu_rom_get_vendor (rom),
|
||||||
fu_rom_get_model (rom),
|
fu_rom_get_model (rom),
|
||||||
@ -864,8 +860,6 @@ fu_util_verify_update (FuUtilPrivate *priv, gchar **values, GError **error)
|
|||||||
g_print ("%s\n", error_local->message);
|
g_print ("%s\n", error_local->message);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!fu_rom_generate_checksum (rom, NULL, error))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* add app to store */
|
/* add app to store */
|
||||||
app = as_app_new ();
|
app = as_app_new ();
|
||||||
|
Loading…
Reference in New Issue
Block a user