Coverage Report

Created: 2026-08-15 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-ifd-firmware.c
Line
Count
Source
1
/*
2
 * Copyright 2021 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
5.62k
#define G_LOG_DOMAIN "FuIfdFirmware"
8
9
#include "config.h"
10
11
#include "fu-byte-array.h"
12
#include "fu-common.h"
13
#include "fu-composite-input-stream.h"
14
#include "fu-efi-volume.h"
15
#include "fu-ifd-bios.h"
16
#include "fu-ifd-firmware.h"
17
#include "fu-ifd-image.h"
18
#include "fu-ifd-struct.h"
19
#include "fu-input-stream.h"
20
#include "fu-mem.h"
21
#include "fu-partial-input-stream.h"
22
23
/**
24
 * FuIfdFirmware:
25
 *
26
 * An Intel Flash Descriptor.
27
 *
28
 * See also: [class@FuFirmware]
29
 */
30
31
typedef struct {
32
  gboolean new_layout;
33
  guint32 descriptor_map0;
34
  guint32 descriptor_map1;
35
  guint32 descriptor_map2;
36
  guint8 num_regions;
37
  guint8 num_components;
38
  guint32 flash_region_base_addr;
39
  guint32 flash_component_base_addr;
40
  guint32 flash_master_base_addr;
41
  guint32 flash_master[4]; /* indexed from 1, ignore [0] */
42
  guint32 flash_ich_strap_base_addr;
43
  guint32 flash_mch_strap_base_addr;
44
  guint32 components_rcd;
45
  guint32 illegal_jedec;
46
  guint32 illegal_jedec1;
47
  guint32 *flash_descriptor_regs;
48
} FuIfdFirmwarePrivate;
49
50
7.13k
G_DEFINE_TYPE_WITH_PRIVATE(FuIfdFirmware, fu_ifd_firmware, FU_TYPE_FIRMWARE)
51
7.13k
#define GET_PRIVATE(o) (fu_ifd_firmware_get_instance_private(o))
52
53
2.86k
#define FU_IFD_SIZE (4 * FU_KB)
54
55
#define FU_IFD_FDBAR_FLASH_UPPER_MAP1 0x0EFC
56
#define FU_IFD_FDBAR_OEM_SECTION      0x0F00
57
58
6.82k
#define FU_IFD_FREG_BASE(freg)  (((freg) << 12) & 0x07FFF000)
59
6.82k
#define FU_IFD_FREG_LIMIT(freg) ((((freg) >> 4) & 0x07FFF000) | 0x00000FFF)
60
61
static void
62
fu_ifd_firmware_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn)
63
0
{
64
0
  FuIfdFirmware *self = FU_IFD_FIRMWARE(firmware);
65
0
  FuIfdFirmwarePrivate *priv = GET_PRIVATE(self);
66
0
  fu_xmlb_builder_insert_kx(bn, "descriptor_map0", priv->descriptor_map0);
67
0
  fu_xmlb_builder_insert_kx(bn, "descriptor_map1", priv->descriptor_map1);
68
0
  fu_xmlb_builder_insert_kx(bn, "descriptor_map2", priv->descriptor_map2);
69
0
  fu_xmlb_builder_insert_kx(bn, "num_regions", priv->num_regions);
70
0
  fu_xmlb_builder_insert_kx(bn, "num_components", priv->num_components + 1);
71
0
  fu_xmlb_builder_insert_kx(bn, "flash_region_base_addr", priv->flash_region_base_addr);
72
0
  fu_xmlb_builder_insert_kx(bn, "flash_component_base_addr", priv->flash_component_base_addr);
73
0
  fu_xmlb_builder_insert_kx(bn, "flash_master_base_addr", priv->flash_master_base_addr);
74
0
  fu_xmlb_builder_insert_kx(bn, "flash_ich_strap_base_addr", priv->flash_ich_strap_base_addr);
75
0
  fu_xmlb_builder_insert_kx(bn, "flash_mch_strap_base_addr", priv->flash_mch_strap_base_addr);
76
0
  fu_xmlb_builder_insert_kx(bn, "components_rcd", priv->components_rcd);
77
0
  fu_xmlb_builder_insert_kx(bn, "illegal_jedec", priv->illegal_jedec);
78
0
  fu_xmlb_builder_insert_kx(bn, "illegal_jedec1", priv->illegal_jedec1);
79
0
  if (flags & FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG) {
80
0
    for (guint i = 1; i < 3; i++) {
81
0
      g_autofree gchar *title = g_strdup_printf("flash_master%x", i + 1);
82
0
      fu_xmlb_builder_insert_kx(bn, title, priv->flash_master[i]);
83
0
    }
84
0
    if (priv->flash_descriptor_regs != NULL) {
85
0
      for (guint i = 0; i < priv->num_regions; i++) {
86
0
        g_autofree gchar *title =
87
0
            g_strdup_printf("flash_descriptor_reg%x", i);
88
0
        fu_xmlb_builder_insert_kx(bn,
89
0
                title,
90
0
                priv->flash_descriptor_regs[i]);
91
0
      }
92
0
    }
93
0
  }
94
0
}
95
96
static gboolean
97
fu_ifd_firmware_validate(FuFirmware *firmware, FuInputStream *stream, gsize offset, GError **error)
98
2.13k
{
99
2.13k
  return fu_struct_ifd_fdbar_validate_stream(stream, offset, error);
100
2.13k
}
101
102
static FuInputStream *
103
fu_ifd_firmware_fixup_stream(FuInputStream *stream, GError **error)
104
2.03k
{
105
2.03k
  const guint8 buf[] = {0xFF};
106
2.03k
  gsize streamsz = 0;
107
2.03k
  g_autoptr(GBytes) blob = g_bytes_new(buf, sizeof(buf));
108
2.03k
  g_autoptr(FuInputStream) stream2 = fu_composite_input_stream_new();
109
110
  /* already aligned */
111
2.03k
  if (!fu_input_stream_size(stream, &streamsz, error))
112
0
    return NULL;
113
2.03k
  if (((streamsz >> 1) << 1) == streamsz)
114
1.19k
    return g_object_ref(stream);
115
116
  /* pad with one trailing byte */
117
839
  if (!fu_composite_input_stream_add_stream(FU_COMPOSITE_INPUT_STREAM(stream2),
118
839
              stream,
119
839
              error))
120
0
    return NULL;
121
839
  if (!fu_composite_input_stream_add_bytes(FU_COMPOSITE_INPUT_STREAM(stream2), blob, error))
122
0
    return NULL;
123
839
  return g_steal_pointer(&stream2);
124
839
}
125
126
static FuIfdAccess
127
fu_ifd_firmware_region_to_access(FuIfdRegion region, guint32 flash_master, gboolean new_layout)
128
9.73k
{
129
9.73k
  guint8 bit_r = 0;
130
9.73k
  guint8 bit_w = 0;
131
132
  /* new layout */
133
9.73k
  if (new_layout) {
134
    /*
135
     * Skylake+ master layout:
136
     *  bits  0..3  ext_read   (regions 12..15)
137
     *  bits  4..7  ext_write  (regions 12..15)
138
     *  bits  8..19 read       (regions 0..11)
139
     *  bits 20..31 write      (regions 0..11)
140
     */
141
6.88k
    if (region < 12) {
142
6.88k
      bit_r = (flash_master >> (region + 8)) & 0b1;
143
6.88k
      bit_w = (flash_master >> (region + 20)) & 0b1;
144
6.88k
    } else {
145
0
      guint8 ext_idx = (guint8)(region - 12);
146
0
      bit_r = (flash_master >> ext_idx) & 0b1;
147
0
      bit_w = (flash_master >> (4 + ext_idx)) & 0b1;
148
0
    }
149
6.88k
    return (bit_r ? FU_IFD_ACCESS_READ : FU_IFD_ACCESS_NONE) |
150
6.88k
           (bit_w ? FU_IFD_ACCESS_WRITE : FU_IFD_ACCESS_NONE);
151
6.88k
  }
152
153
  /* old layout */
154
2.84k
  if (region == FU_IFD_REGION_DESC) {
155
273
    bit_r = 16;
156
273
    bit_w = 24;
157
2.57k
  } else if (region == FU_IFD_REGION_BIOS) {
158
2.10k
    bit_r = 17;
159
2.10k
    bit_w = 25;
160
2.10k
  } else if (region == FU_IFD_REGION_ME) {
161
99
    bit_r = 18;
162
99
    bit_w = 26;
163
363
  } else if (region == FU_IFD_REGION_GBE) {
164
126
    bit_r = 19;
165
126
    bit_w = 27;
166
237
  } else if (region == FU_IFD_REGION_PLATFORM) {
167
159
    bit_r = 20;
168
159
    bit_w = 28;
169
159
  }
170
2.84k
  return ((flash_master >> bit_r) & 0b1 ? FU_IFD_ACCESS_READ : FU_IFD_ACCESS_NONE) |
171
2.84k
         ((flash_master >> bit_w) & 0b1 ? FU_IFD_ACCESS_WRITE : FU_IFD_ACCESS_NONE);
172
9.73k
}
173
174
static gboolean
175
fu_ifd_firmware_parse(FuFirmware *firmware,
176
          FuInputStream *stream,
177
          FuFirmwareParseFlags flags,
178
          GError **error)
179
2.06k
{
180
2.06k
  FuIfdFirmware *self = FU_IFD_FIRMWARE(firmware);
181
2.06k
  FuIfdFirmwarePrivate *priv = GET_PRIVATE(self);
182
2.06k
  gsize streamsz = 0;
183
2.06k
  g_autoptr(FuStructIfdFcba) st_fcba = NULL;
184
2.06k
  g_autoptr(FuStructIfdFdbar) st_fdbar = NULL;
185
2.06k
  g_autoptr(FuInputStream) stream2 = NULL;
186
187
  /* check size */
188
2.06k
  if (!fu_input_stream_size(stream, &streamsz, error))
189
0
    return FALSE;
190
2.06k
  if (streamsz < FU_IFD_SIZE) {
191
28
    g_set_error(error,
192
28
          FWUPD_ERROR,
193
28
          FWUPD_ERROR_INTERNAL,
194
28
          "file is too small, expected streamsz >= 0x%x",
195
28
          (guint)FU_IFD_SIZE);
196
28
    return FALSE;
197
28
  }
198
199
  /* some test IFD images were captured missing the final byte -- so align up */
200
2.03k
  stream2 = fu_ifd_firmware_fixup_stream(stream, error);
201
2.03k
  if (stream2 == NULL)
202
0
    return FALSE;
203
204
  /* descriptor registers */
205
2.03k
  st_fdbar = fu_struct_ifd_fdbar_parse_stream(stream, 0x0, error);
206
2.03k
  if (st_fdbar == NULL)
207
0
    return FALSE;
208
2.03k
  priv->descriptor_map0 = fu_struct_ifd_fdbar_get_descriptor_map0(st_fdbar);
209
2.03k
  priv->num_regions = (priv->descriptor_map0 >> 24) & 0b111;
210
2.03k
  if (priv->num_regions == 0)
211
1.03k
    priv->num_regions = 10;
212
213
  /*
214
   * Choose master layout based on number of regions parsed from the descriptor:
215
   * - Old layout (pre-Skylake) used 5/7 regions and different bit positions.
216
   * - New layout (Skylake+) uses 10 or more regions and the split ext/read/write fields.
217
   */
218
2.03k
  priv->new_layout = priv->num_regions >= 10;
219
2.03k
  priv->num_components = (priv->descriptor_map0 >> 8) & 0b11;
220
2.03k
  priv->flash_component_base_addr = (priv->descriptor_map0 << 4) & 0x00000FF0;
221
2.03k
  priv->flash_region_base_addr = (priv->descriptor_map0 >> 12) & 0x00000FF0;
222
2.03k
  priv->descriptor_map1 = fu_struct_ifd_fdbar_get_descriptor_map1(st_fdbar);
223
2.03k
  priv->flash_master_base_addr = (priv->descriptor_map1 << 4) & 0x00000FF0;
224
2.03k
  priv->flash_ich_strap_base_addr = (priv->descriptor_map1 >> 12) & 0x00000FF0;
225
2.03k
  priv->descriptor_map2 = fu_struct_ifd_fdbar_get_descriptor_map2(st_fdbar);
226
2.03k
  priv->flash_mch_strap_base_addr = (priv->descriptor_map2 << 4) & 0x00000FF0;
227
228
  /* FCBA */
229
2.03k
  st_fcba = fu_struct_ifd_fcba_parse_stream(stream, priv->flash_component_base_addr, error);
230
2.03k
  if (st_fcba == NULL)
231
0
    return FALSE;
232
2.03k
  priv->components_rcd = fu_struct_ifd_fcba_get_flcomp(st_fcba);
233
2.03k
  priv->illegal_jedec = fu_struct_ifd_fcba_get_flill(st_fcba);
234
2.03k
  priv->illegal_jedec1 = fu_struct_ifd_fcba_get_flill1(st_fcba);
235
236
  /* FMBA */
237
2.03k
  if (!fu_input_stream_read_u32(stream,
238
2.03k
              priv->flash_master_base_addr + 0x0,
239
2.03k
              &priv->flash_master[1],
240
2.03k
              G_LITTLE_ENDIAN,
241
2.03k
              error))
242
0
    return FALSE;
243
2.03k
  if (!fu_input_stream_read_u32(stream,
244
2.03k
              priv->flash_master_base_addr + 0x4,
245
2.03k
              &priv->flash_master[2],
246
2.03k
              G_LITTLE_ENDIAN,
247
2.03k
              error))
248
0
    return FALSE;
249
2.03k
  if (!fu_input_stream_read_u32(stream,
250
2.03k
              priv->flash_master_base_addr + 0x8,
251
2.03k
              &priv->flash_master[3],
252
2.03k
              G_LITTLE_ENDIAN,
253
2.03k
              error))
254
0
    return FALSE;
255
256
  /* FRBA */
257
2.03k
  priv->flash_descriptor_regs = g_new0(guint32, priv->num_regions);
258
15.2k
  for (guint i = 0; i < priv->num_regions; i++) {
259
13.2k
    if (!fu_input_stream_read_u32(stream,
260
13.2k
                priv->flash_region_base_addr + (i * sizeof(guint32)),
261
13.2k
                &priv->flash_descriptor_regs[i],
262
13.2k
                G_LITTLE_ENDIAN,
263
13.2k
                error))
264
3
      return FALSE;
265
13.2k
  }
266
7.63k
  for (guint i = 0; i < priv->num_regions; i++) {
267
6.82k
    const gchar *freg_str = fu_ifd_region_to_string(i);
268
6.82k
    guint32 freg_base = FU_IFD_FREG_BASE(priv->flash_descriptor_regs[i]);
269
6.82k
    guint32 freg_limt = FU_IFD_FREG_LIMIT(priv->flash_descriptor_regs[i]);
270
6.82k
    guint32 freg_size;
271
6.82k
    g_autoptr(FuFirmware) img = NULL;
272
6.82k
    g_autoptr(FuInputStream) partial_stream = NULL;
273
274
    /* invalid - check before subtraction */
275
6.82k
    if (freg_base > freg_limt)
276
2.36k
      continue;
277
4.46k
    freg_size = (freg_limt - freg_base) + 1;
278
279
    /* create image */
280
4.46k
    g_debug("freg %s 0x%04x -> 0x%04x", freg_str, freg_base, freg_limt);
281
4.46k
    partial_stream = fu_partial_input_stream_new(stream2, freg_base, freg_size, error);
282
4.46k
    if (partial_stream == NULL) {
283
526
      g_prefix_error_literal(error, "failed to cut IFD image: ");
284
526
      return FALSE;
285
526
    }
286
287
    /* do not parse all the EFI volumes if we only care about the structure */
288
3.93k
    if (i == FU_IFD_REGION_BIOS &&
289
2.00k
        (flags & FU_FIRMWARE_PARSE_FLAG_ONLY_PARTITION_LAYOUT) == 0) {
290
2.00k
      img = fu_ifd_bios_new();
291
2.00k
    } else {
292
1.92k
      img = fu_ifd_image_new();
293
1.92k
    }
294
3.93k
    if (!fu_firmware_parse_stream(img,
295
3.93k
                partial_stream,
296
3.93k
                0x0,
297
3.93k
                flags | FU_FIRMWARE_PARSE_FLAG_NO_SEARCH,
298
3.93k
                error))
299
691
      return FALSE;
300
3.24k
    fu_firmware_set_addr(img, freg_base);
301
3.24k
    fu_firmware_set_idx(img, i);
302
3.24k
    if (freg_str != NULL)
303
2.97k
      fu_firmware_set_id(img, freg_str);
304
3.24k
    if (!fu_firmware_add_image(firmware, img, error))
305
0
      return FALSE;
306
307
    /* is writable by anything other than the region itself */
308
12.9k
    for (FuIfdRegion r = 1; r <= 3; r++) {
309
9.73k
      FuIfdAccess acc;
310
9.73k
      acc = fu_ifd_firmware_region_to_access(i,
311
9.73k
                     priv->flash_master[r],
312
9.73k
                     priv->new_layout);
313
9.73k
      fu_ifd_image_set_access(FU_IFD_IMAGE(img), r, acc);
314
9.73k
    }
315
3.24k
  }
316
317
  /* success */
318
813
  return TRUE;
319
2.03k
}
320
321
/**
322
 * fu_ifd_firmware_check_jedec_cmd:
323
 * @self: a #FuIfdFirmware
324
 * @cmd: a JEDEC command, e.g. 0x42 for "whole chip erase"
325
 *
326
 * Checks a JEDEC command to see if it has been put on the "illegal_jedec" list.
327
 *
328
 * Returns: %TRUE if the command is allowed
329
 *
330
 * Since: 1.6.2
331
 **/
332
gboolean
333
fu_ifd_firmware_check_jedec_cmd(FuIfdFirmware *self, guint8 cmd)
334
0
{
335
0
  FuIfdFirmwarePrivate *priv = GET_PRIVATE(self);
336
0
  for (guint j = 0; j < 32; j += 8) {
337
0
    if (((priv->illegal_jedec >> j) & 0xff) == cmd)
338
0
      return FALSE;
339
0
    if (((priv->illegal_jedec1 >> j) & 0xff) == cmd)
340
0
      return FALSE;
341
0
  }
342
0
  return TRUE;
343
0
}
344
345
static GByteArray *
346
fu_ifd_firmware_write(FuFirmware *firmware, GError **error)
347
813
{
348
813
  FuIfdFirmware *self = FU_IFD_FIRMWARE(firmware);
349
813
  FuIfdFirmwarePrivate *priv = GET_PRIVATE(self);
350
813
  gsize bufsz_max = 0x0;
351
813
  g_autoptr(GByteArray) buf = g_byte_array_new();
352
813
  g_autoptr(FuStructIfdFcba) st_fcba = fu_struct_ifd_fcba_new();
353
813
  g_autoptr(FuStructIfdFdbar) st_fdbar = fu_struct_ifd_fdbar_new();
354
813
  g_autoptr(GHashTable) blobs = NULL;
355
813
  g_autoptr(FuFirmware) img_desc = NULL;
356
357
  /* if the descriptor does not exist, then add something plausible */
358
813
  img_desc = fu_firmware_get_image_by_idx(firmware, FU_IFD_REGION_DESC, NULL);
359
813
  if (img_desc == NULL) {
360
772
    g_autoptr(GByteArray) buf_desc = g_byte_array_new();
361
772
    g_autoptr(GBytes) blob_desc = NULL;
362
772
    fu_byte_array_set_size(buf_desc, FU_IFD_SIZE, 0x00);
363
364
    /* success */
365
772
    blob_desc = g_bytes_new(buf_desc->data, buf_desc->len);
366
772
    img_desc = fu_firmware_new_from_bytes(blob_desc);
367
772
    fu_firmware_set_addr(img_desc, 0x0);
368
772
    fu_firmware_set_idx(img_desc, FU_IFD_REGION_DESC);
369
772
    fu_firmware_set_id(img_desc, "desc");
370
772
    if (!fu_firmware_add_image(firmware, img_desc, error))
371
0
      return NULL;
372
772
  }
373
374
  /* generate ahead of time */
375
813
  blobs = g_hash_table_new_full(g_direct_hash,
376
813
              g_direct_equal,
377
813
              NULL,
378
813
              (GDestroyNotify)g_bytes_unref);
379
2.64k
  for (guint i = 0; i < priv->num_regions; i++) {
380
2.11k
    gsize image_end;
381
2.11k
    g_autoptr(FuFirmware) img = fu_firmware_get_image_by_idx(firmware, i, NULL);
382
2.11k
    g_autoptr(GBytes) blob = NULL;
383
384
2.11k
    if (img == NULL)
385
371
      continue;
386
1.74k
    blob = fu_firmware_write(img, error);
387
1.74k
    if (blob == NULL) {
388
277
      g_prefix_error(error, "failed to write %s: ", fu_firmware_get_id(img));
389
277
      return NULL;
390
277
    }
391
1.46k
    if (g_bytes_get_data(blob, NULL) == NULL) {
392
0
      g_set_error(error,
393
0
            FWUPD_ERROR,
394
0
            FWUPD_ERROR_INTERNAL,
395
0
            "failed to write %s",
396
0
            fu_firmware_get_id(img));
397
0
      return NULL;
398
0
    }
399
1.46k
    g_hash_table_insert(blobs, GUINT_TO_POINTER(i), g_bytes_ref(blob));
400
401
    /* check total size with overflow checking */
402
1.46k
    image_end = fu_firmware_get_addr(img);
403
1.46k
    if (!fu_size_checked_inc(&image_end, g_bytes_get_size(blob), error)) {
404
0
      g_prefix_error(error,
405
0
               "size overflow for image %s: ",
406
0
               fu_firmware_get_id(img));
407
0
      return NULL;
408
0
    }
409
1.46k
    bufsz_max = MAX(image_end, bufsz_max);
410
1.46k
  }
411
536
  fu_byte_array_set_size(buf, bufsz_max, 0x00);
412
413
  /* descriptor map */
414
536
  fu_struct_ifd_fdbar_set_descriptor_map0(st_fdbar, priv->descriptor_map0);
415
536
  fu_struct_ifd_fdbar_set_descriptor_map1(st_fdbar, priv->descriptor_map1);
416
536
  fu_struct_ifd_fdbar_set_descriptor_map2(st_fdbar, priv->descriptor_map2);
417
536
  if (!fu_memcpy_safe(buf->data,
418
536
          buf->len,
419
536
          0x0,
420
536
          st_fdbar->buf->data,
421
536
          st_fdbar->buf->len,
422
536
          0x0,
423
536
          st_fdbar->buf->len,
424
536
          error))
425
0
    return NULL;
426
427
  /* FCBA */
428
536
  fu_struct_ifd_fcba_set_flcomp(st_fcba, priv->components_rcd);
429
536
  fu_struct_ifd_fcba_set_flill(st_fcba, priv->illegal_jedec);
430
536
  fu_struct_ifd_fcba_set_flill1(st_fcba, priv->illegal_jedec1);
431
536
  if (!fu_memcpy_safe(buf->data,
432
536
          buf->len,
433
536
          priv->flash_component_base_addr,
434
536
          st_fcba->buf->data,
435
536
          st_fcba->buf->len,
436
536
          0x0,
437
536
          st_fcba->buf->len,
438
536
          error))
439
0
    return NULL;
440
441
  /* FRBA */
442
1.69k
  for (guint i = 0; i < priv->num_regions; i++) {
443
1.16k
    guint32 freg_base = 0x7FFF000;
444
1.16k
    guint32 freg_limt = 0x0;
445
1.16k
    guint32 flreg;
446
1.16k
    g_autoptr(FuFirmware) img = fu_firmware_get_image_by_idx(firmware, i, NULL);
447
1.16k
    if (img != NULL) {
448
1.06k
      GBytes *blob =
449
1.06k
          g_hash_table_lookup(blobs, GUINT_TO_POINTER(fu_firmware_get_idx(img)));
450
1.06k
      freg_base = fu_firmware_get_addr(img);
451
1.06k
      freg_limt = (freg_base + g_bytes_get_size(blob)) - 1;
452
1.06k
    }
453
1.16k
    flreg = ((freg_limt << 4) & 0xFFFF0000) | (freg_base >> 12);
454
1.16k
    g_debug("freg 0x%04x -> 0x%04x = 0x%08x", freg_base, freg_limt, flreg);
455
1.16k
    if (!fu_memwrite_uint32_safe(buf->data,
456
1.16k
               buf->len,
457
1.16k
               priv->flash_region_base_addr + (i * sizeof(guint32)),
458
1.16k
               flreg,
459
1.16k
               G_LITTLE_ENDIAN,
460
1.16k
               error))
461
2
      return NULL;
462
1.16k
  }
463
464
  /* write images at correct offsets */
465
1.15k
  for (guint i = 1; i < priv->num_regions; i++) {
466
620
    GBytes *blob;
467
620
    g_autoptr(FuFirmware) img = fu_firmware_get_image_by_idx(firmware, i, NULL);
468
620
    if (img == NULL)
469
92
      continue;
470
528
    blob = g_hash_table_lookup(blobs, GUINT_TO_POINTER(fu_firmware_get_idx(img)));
471
528
    if (!fu_memcpy_safe(buf->data,
472
528
            buf->len,
473
528
            fu_firmware_get_addr(img),
474
528
            g_bytes_get_data(blob, NULL),
475
528
            g_bytes_get_size(blob),
476
528
            0x0,
477
528
            g_bytes_get_size(blob),
478
528
            error))
479
0
      return NULL;
480
528
  }
481
482
  /* success */
483
534
  return g_steal_pointer(&buf);
484
534
}
485
486
static gboolean
487
fu_ifd_firmware_build(FuFirmware *firmware, XbNode *n, GError **error)
488
0
{
489
0
  FuIfdFirmware *self = FU_IFD_FIRMWARE(firmware);
490
0
  FuIfdFirmwarePrivate *priv = GET_PRIVATE(self);
491
0
  guint64 tmp;
492
493
  /* optional properties */
494
0
  tmp = xb_node_query_text_as_uint(n, "descriptor_map0", NULL);
495
0
  if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT32)
496
0
    priv->descriptor_map0 = tmp;
497
0
  tmp = xb_node_query_text_as_uint(n, "descriptor_map1", NULL);
498
0
  if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT32)
499
0
    priv->descriptor_map1 = tmp;
500
0
  tmp = xb_node_query_text_as_uint(n, "descriptor_map2", NULL);
501
0
  if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT32)
502
0
    priv->descriptor_map2 = tmp;
503
0
  tmp = xb_node_query_text_as_uint(n, "components_rcd", NULL);
504
0
  if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT32)
505
0
    priv->components_rcd = tmp;
506
0
  tmp = xb_node_query_text_as_uint(n, "illegal_jedec", NULL);
507
0
  if (tmp != G_MAXUINT64) {
508
0
    priv->illegal_jedec = tmp & 0xFFFFFFFF;
509
0
    priv->illegal_jedec1 = tmp >> 32;
510
0
  }
511
512
  /* success */
513
0
  return TRUE;
514
0
}
515
516
static void
517
fu_ifd_firmware_init(FuIfdFirmware *self)
518
2.13k
{
519
2.13k
  FuIfdFirmwarePrivate *priv = GET_PRIVATE(self);
520
521
  /* some good defaults */
522
2.13k
  priv->new_layout = TRUE;
523
2.13k
  priv->num_regions = 10;
524
2.13k
  priv->flash_region_base_addr = 0x40;
525
2.13k
  priv->flash_component_base_addr = 0x30;
526
2.13k
  priv->flash_master_base_addr = 0x80;
527
2.13k
  priv->flash_master[1] = 0x00A00F00;
528
2.13k
  priv->flash_master[2] = 0x00400D00;
529
2.13k
  priv->flash_master[3] = 0x00800900;
530
2.13k
  priv->flash_ich_strap_base_addr = 0x100;
531
2.13k
  priv->flash_mch_strap_base_addr = 0x300;
532
2.13k
}
533
534
static void
535
fu_ifd_firmware_finalize(GObject *object)
536
2.13k
{
537
2.13k
  FuIfdFirmware *self = FU_IFD_FIRMWARE(object);
538
2.13k
  FuIfdFirmwarePrivate *priv = GET_PRIVATE(self);
539
2.13k
  g_free(priv->flash_descriptor_regs);
540
2.13k
  G_OBJECT_CLASS(fu_ifd_firmware_parent_class)->finalize(object);
541
2.13k
}
542
543
static void
544
fu_ifd_firmware_class_init(FuIfdFirmwareClass *klass)
545
1
{
546
1
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
547
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
548
1
  fu_firmware_add_image_gtype(firmware_class, FU_TYPE_FIRMWARE);
549
1
  fu_firmware_add_image_gtype(firmware_class, FU_TYPE_IFD_BIOS);
550
1
  fu_firmware_add_image_gtype(firmware_class, FU_TYPE_IFD_IMAGE);
551
1
  fu_firmware_add_image_gtype(firmware_class, FU_TYPE_EFI_VOLUME);
552
1
  object_class->finalize = fu_ifd_firmware_finalize;
553
1
  fu_firmware_set_size_max(firmware_class, 1 * FU_GB);
554
1
  firmware_class->validate = fu_ifd_firmware_validate;
555
1
  firmware_class->export = fu_ifd_firmware_export;
556
1
  firmware_class->parse = fu_ifd_firmware_parse;
557
1
  firmware_class->write = fu_ifd_firmware_write;
558
1
  firmware_class->build = fu_ifd_firmware_build;
559
1
}
560
561
/**
562
 * fu_ifd_firmware_new:
563
 *
564
 * Creates a new #FuFirmware of sub type Ifd
565
 *
566
 * Since: 1.6.2
567
 **/
568
FuFirmware *
569
fu_ifd_firmware_new(void)
570
0
{
571
0
  return FU_FIRMWARE(g_object_new(FU_TYPE_IFD_FIRMWARE, NULL));
572
0
}