Coverage Report

Created: 2026-07-16 07:10

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