Coverage Report

Created: 2025-11-11 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-ifwi-fpt-firmware.c
Line
Count
Source
1
/*
2
 * Copyright 2022 Richard Hughes <richard@hughsie.com>
3
 * Copyright 2022 Intel
4
 *
5
 * SPDX-License-Identifier: LGPL-2.1-or-later
6
 */
7
8
#define G_LOG_DOMAIN "FuFirmware"
9
10
#include "config.h"
11
12
#include <string.h>
13
14
#include "fu-byte-array.h"
15
#include "fu-ifwi-fpt-firmware.h"
16
#include "fu-ifwi-struct.h"
17
#include "fu-partial-input-stream.h"
18
#include "fu-string.h"
19
20
/**
21
 * FuIfwiFptFirmware:
22
 *
23
 * An Intel Flash Program Tool (aka FPT) header can be found in IFWI (Integrated Firmware Image)
24
 * firmware blobs which are used in various Intel products using an IPU (Infrastructure Processing
25
 * Unit).
26
 *
27
 * This could include hardware like SmartNICs, GPUs, camera and audio devices.
28
 *
29
 * See also: [class@FuFirmware]
30
 */
31
32
628
G_DEFINE_TYPE(FuIfwiFptFirmware, fu_ifwi_fpt_firmware, FU_TYPE_FIRMWARE)
33
628
34
1.08k
#define FU_IFWI_FPT_MAX_ENTRIES 56
35
36
static gboolean
37
fu_ifwi_fpt_firmware_validate(FuFirmware *firmware,
38
            GInputStream *stream,
39
            gsize offset,
40
            GError **error)
41
766k
{
42
766k
  return fu_struct_ifwi_fpt_validate_stream(stream, offset, error);
43
766k
}
44
45
static gboolean
46
fu_ifwi_fpt_firmware_parse(FuFirmware *firmware,
47
         GInputStream *stream,
48
         FuFirmwareParseFlags flags,
49
         GError **error)
50
458
{
51
458
  guint32 num_of_entries;
52
458
  gsize offset = 0;
53
458
  g_autoptr(FuStructIfwiFpt) st_hdr = NULL;
54
55
  /* sanity check */
56
458
  st_hdr = fu_struct_ifwi_fpt_parse_stream(stream, offset, error);
57
458
  if (st_hdr == NULL)
58
0
    return FALSE;
59
458
  num_of_entries = fu_struct_ifwi_fpt_get_num_of_entries(st_hdr);
60
458
  if (num_of_entries > FU_IFWI_FPT_MAX_ENTRIES) {
61
52
    g_set_error(error,
62
52
          FWUPD_ERROR,
63
52
          FWUPD_ERROR_INVALID_DATA,
64
52
          "invalid FPT number of entries %u",
65
52
          num_of_entries);
66
52
    return FALSE;
67
52
  }
68
406
  if (fu_struct_ifwi_fpt_get_header_version(st_hdr) <
69
406
      FU_STRUCT_IFWI_FPT_DEFAULT_HEADER_VERSION) {
70
7
    g_set_error(error,
71
7
          FWUPD_ERROR,
72
7
          FWUPD_ERROR_INVALID_DATA,
73
7
          "invalid FPT header version: 0x%x",
74
7
          fu_struct_ifwi_fpt_get_header_version(st_hdr));
75
7
    return FALSE;
76
7
  }
77
78
  /* offset by header length */
79
399
  offset += fu_struct_ifwi_fpt_get_header_length(st_hdr);
80
81
  /* read out entries */
82
3.41k
  for (guint i = 0; i < num_of_entries; i++) {
83
3.36k
    guint32 data_length;
84
3.36k
    guint32 partition_name;
85
3.36k
    g_autofree gchar *id = NULL;
86
3.36k
    g_autoptr(FuFirmware) img = fu_firmware_new();
87
3.36k
    g_autoptr(FuStructIfwiFptEntry) st_ent = NULL;
88
89
    /* read IDX */
90
3.36k
    st_ent = fu_struct_ifwi_fpt_entry_parse_stream(stream, offset, error);
91
3.36k
    if (st_ent == NULL)
92
166
      return FALSE;
93
3.20k
    partition_name = fu_struct_ifwi_fpt_entry_get_partition_name(st_ent);
94
3.20k
    fu_firmware_set_idx(img, partition_name);
95
96
    /* convert to text form for convenience */
97
3.20k
    id = fu_strsafe((const gchar *)&partition_name, sizeof(partition_name));
98
3.20k
    if (id != NULL)
99
1.57k
      fu_firmware_set_id(img, id);
100
101
    /* get data at offset using zero-copy */
102
3.20k
    data_length = fu_struct_ifwi_fpt_entry_get_length(st_ent);
103
3.20k
    if (data_length != 0x0) {
104
1.90k
      guint32 data_offset = fu_struct_ifwi_fpt_entry_get_offset(st_ent);
105
1.90k
      g_autoptr(GInputStream) partial_stream = NULL;
106
1.90k
      partial_stream =
107
1.90k
          fu_partial_input_stream_new(stream, data_offset, data_length, error);
108
1.90k
      if (partial_stream == NULL) {
109
183
        g_prefix_error_literal(error, "failed to cut FPT image: ");
110
183
        return FALSE;
111
183
      }
112
1.72k
      if (!fu_firmware_parse_stream(img, partial_stream, 0x0, flags, error))
113
0
        return FALSE;
114
1.72k
      fu_firmware_set_offset(img, data_offset);
115
1.72k
    }
116
3.01k
    if (!fu_firmware_add_image(firmware, img, error))
117
0
      return FALSE;
118
119
    /* next */
120
3.01k
    offset += st_ent->buf->len;
121
3.01k
  }
122
123
  /* success */
124
50
  return TRUE;
125
399
}
126
127
static GByteArray *
128
fu_ifwi_fpt_firmware_write(FuFirmware *firmware, GError **error)
129
50
{
130
50
  gsize offset = 0;
131
50
  g_autoptr(FuStructIfwiFpt) st = fu_struct_ifwi_fpt_new();
132
50
  g_autoptr(GPtrArray) imgs = fu_firmware_get_images(firmware);
133
134
  /* fixup the image offsets */
135
50
  offset += st->buf->len;
136
50
  offset += FU_STRUCT_IFWI_FPT_ENTRY_SIZE * imgs->len;
137
50
  for (guint i = 0; i < imgs->len; i++) {
138
48
    FuFirmware *img = g_ptr_array_index(imgs, i);
139
48
    g_autoptr(GBytes) blob = NULL;
140
48
    blob = fu_firmware_get_bytes(img, error);
141
48
    if (blob == NULL) {
142
48
      g_prefix_error(error, "image 0x%x: ", i);
143
48
      return NULL;
144
48
    }
145
0
    fu_firmware_set_offset(img, offset);
146
0
    offset += g_bytes_get_size(blob);
147
0
  }
148
149
  /* write the header */
150
2
  fu_struct_ifwi_fpt_set_num_of_entries(st, imgs->len);
151
152
  /* add entries */
153
2
  for (guint i = 0; i < imgs->len; i++) {
154
0
    FuFirmware *img = g_ptr_array_index(imgs, i);
155
0
    g_autoptr(FuStructIfwiFptEntry) st_ent = fu_struct_ifwi_fpt_entry_new();
156
0
    fu_struct_ifwi_fpt_entry_set_partition_name(st_ent, fu_firmware_get_idx(img));
157
0
    fu_struct_ifwi_fpt_entry_set_offset(st_ent, fu_firmware_get_offset(img));
158
0
    fu_struct_ifwi_fpt_entry_set_length(st_ent, fu_firmware_get_size(img));
159
0
    fu_byte_array_append_array(st->buf, st_ent->buf);
160
0
  }
161
162
  /* add entry data */
163
2
  for (guint i = 0; i < imgs->len; i++) {
164
0
    FuFirmware *img = g_ptr_array_index(imgs, i);
165
0
    g_autoptr(GBytes) blob = NULL;
166
0
    blob = fu_firmware_get_bytes(img, error);
167
0
    if (blob == NULL)
168
0
      return NULL;
169
0
    fu_byte_array_append_bytes(st->buf, blob);
170
0
  }
171
172
  /* success */
173
2
  return g_steal_pointer(&st->buf);
174
2
}
175
176
static void
177
fu_ifwi_fpt_firmware_init(FuIfwiFptFirmware *self)
178
628
{
179
628
  fu_firmware_set_images_max(FU_FIRMWARE(self), FU_IFWI_FPT_MAX_ENTRIES);
180
628
}
181
182
static void
183
fu_ifwi_fpt_firmware_class_init(FuIfwiFptFirmwareClass *klass)
184
1
{
185
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
186
1
  firmware_class->validate = fu_ifwi_fpt_firmware_validate;
187
1
  firmware_class->parse = fu_ifwi_fpt_firmware_parse;
188
1
  firmware_class->write = fu_ifwi_fpt_firmware_write;
189
1
}
190
191
/**
192
 * fu_ifwi_fpt_firmware_new:
193
 *
194
 * Creates a new #FuFirmware of Intel Flash Program Tool format
195
 *
196
 * Since: 1.8.2
197
 **/
198
FuFirmware *
199
fu_ifwi_fpt_firmware_new(void)
200
0
{
201
0
  return FU_FIRMWARE(g_object_new(FU_TYPE_IFWI_FPT_FIRMWARE, NULL));
202
0
}