Coverage Report

Created: 2026-09-03 07:14

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.38k
#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
6.72k
G_DEFINE_TYPE_WITH_PRIVATE(FuIfdFirmware, fu_ifd_firmware, FU_TYPE_FIRMWARE)
51
6.72k
#define GET_PRIVATE(o) (fu_ifd_firmware_get_instance_private(o))
52
53
2.72k
#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.34k
#define FU_IFD_FREG_BASE(freg)  (((freg) << 12) & 0x07FFF000)
59
6.34k
#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
1.98k
{
99
1.98k
  return fu_struct_ifd_fdbar_validate_stream(stream, offset, error);
100
1.98k
}
101
102
static FuInputStream *
103
fu_ifd_firmware_fixup_stream(FuInputStream *stream, GError **error)
104
1.90k
{
105
1.90k
  const guint8 buf[] = {0xFF};
106
1.90k
  gsize streamsz = 0;
107
1.90k
  g_autoptr(GBytes) blob = g_bytes_new(buf, sizeof(buf));
108
1.90k
  g_autoptr(FuInputStream) stream2 = fu_composite_input_stream_new();
109
110
  /* already aligned */
111
1.90k
  if (!fu_input_stream_size(stream, &streamsz, error))
112
0
    return NULL;
113
1.90k
  if (((streamsz >> 1) << 1) == streamsz)
114
1.14k
    return g_object_ref(stream);
115
116
  /* pad with one trailing byte */
117
762
  if (!fu_composite_input_stream_add_stream(FU_COMPOSITE_INPUT_STREAM(stream2),
118
762
              stream,
119
762
              error))
120
0
    return NULL;
121
762
  if (!fu_composite_input_stream_add_bytes(FU_COMPOSITE_INPUT_STREAM(stream2), blob, error))
122
0
    return NULL;
123
762
  return g_steal_pointer(&stream2);
124
762
}
125
126
static FuIfdAccess
127
fu_ifd_firmware_region_to_access(FuIfdRegion region, guint32 flash_master, gboolean new_layout)
128
9.30k
{
129
9.30k
  guint8 bit_r = 0;
130
9.30k
  guint8 bit_w = 0;
131
132
  /* new layout */
133
9.30k
  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.45k
    if (region < 12) {
142
6.45k
      bit_r = (flash_master >> (region + 8)) & 0b1;
143
6.45k
      bit_w = (flash_master >> (region + 20)) & 0b1;
144
6.45k
    } 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.45k
    return (bit_r ? FU_IFD_ACCESS_READ : FU_IFD_ACCESS_NONE) |
150
6.45k
           (bit_w ? FU_IFD_ACCESS_WRITE : FU_IFD_ACCESS_NONE);
151
6.45k
  }
152
153
  /* old layout */
154
2.84k
  if (region == FU_IFD_REGION_DESC) {
155
264
    bit_r = 16;
156
264
    bit_w = 24;
157
2.57k
  } else if (region == FU_IFD_REGION_BIOS) {
158
2.16k
    bit_r = 17;
159
2.16k
    bit_w = 25;
160
2.16k
  } else if (region == FU_IFD_REGION_ME) {
161
99
    bit_r = 18;
162
99
    bit_w = 26;
163
315
  } else if (region == FU_IFD_REGION_GBE) {
164
120
    bit_r = 19;
165
120
    bit_w = 27;
166
195
  } else if (region == FU_IFD_REGION_PLATFORM) {
167
132
    bit_r = 20;
168
132
    bit_w = 28;
169
132
  }
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.30k
}
173
174
static gboolean
175
fu_ifd_firmware_parse(FuFirmware *firmware,
176
          FuInputStream *stream,
177
          FuFirmwareParseFlags flags,
178
          GError **error)
179
1.92k
{
180
1.92k
  FuIfdFirmware *self = FU_IFD_FIRMWARE(firmware);
181
1.92k
  FuIfdFirmwarePrivate *priv = GET_PRIVATE(self);
182
1.92k
  gsize streamsz = 0;
183
1.92k
  g_autoptr(FuStructIfdFcba) st_fcba = NULL;
184
1.92k
  g_autoptr(FuStructIfdFdbar) st_fdbar = NULL;
185
1.92k
  g_autoptr(FuInputStream) stream2 = NULL;
186
187
  /* check size */
188
1.92k
  if (!fu_input_stream_size(stream, &streamsz, error))
189
0
    return FALSE;
190
1.92k
  if (streamsz < FU_IFD_SIZE) {
191
25
    g_set_error(error,
192
25
          FWUPD_ERROR,
193
25
          FWUPD_ERROR_INTERNAL,
194
25
          "file is too small, expected streamsz >= 0x%x",
195
25
          (guint)FU_IFD_SIZE);
196
25
    return FALSE;
197
25
  }
198
199
  /* some test IFD images were captured missing the final byte -- so align up */
200
1.90k
  stream2 = fu_ifd_firmware_fixup_stream(stream, error);
201
1.90k
  if (stream2 == NULL)
202
0
    return FALSE;
203
204
  /* descriptor registers */
205
1.90k
  st_fdbar = fu_struct_ifd_fdbar_parse_stream(stream, 0x0, error);
206
1.90k
  if (st_fdbar == NULL)
207
0
    return FALSE;
208
1.90k
  priv->descriptor_map0 = fu_struct_ifd_fdbar_get_descriptor_map0(st_fdbar);
209
1.90k
  priv->num_regions = (priv->descriptor_map0 >> 24) & 0b111;
210
1.90k
  if (priv->num_regions == 0)
211
913
    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
1.90k
  priv->new_layout = priv->num_regions >= 10;
219
1.90k
  priv->num_components = (priv->descriptor_map0 >> 8) & 0b11;
220
1.90k
  priv->flash_component_base_addr = (priv->descriptor_map0 << 4) & 0x00000FF0;
221
1.90k
  priv->flash_region_base_addr = (priv->descriptor_map0 >> 12) & 0x00000FF0;
222
1.90k
  priv->descriptor_map1 = fu_struct_ifd_fdbar_get_descriptor_map1(st_fdbar);
223
1.90k
  priv->flash_master_base_addr = (priv->descriptor_map1 << 4) & 0x00000FF0;
224
1.90k
  priv->flash_ich_strap_base_addr = (priv->descriptor_map1 >> 12) & 0x00000FF0;
225
1.90k
  priv->descriptor_map2 = fu_struct_ifd_fdbar_get_descriptor_map2(st_fdbar);
226
1.90k
  priv->flash_mch_strap_base_addr = (priv->descriptor_map2 << 4) & 0x00000FF0;
227
228
  /* FCBA */
229
1.90k
  st_fcba = fu_struct_ifd_fcba_parse_stream(stream, priv->flash_component_base_addr, error);
230
1.90k
  if (st_fcba == NULL)
231
0
    return FALSE;
232
1.90k
  priv->components_rcd = fu_struct_ifd_fcba_get_flcomp(st_fcba);
233
1.90k
  priv->illegal_jedec = fu_struct_ifd_fcba_get_flill(st_fcba);
234
1.90k
  priv->illegal_jedec1 = fu_struct_ifd_fcba_get_flill1(st_fcba);
235
236
  /* FMBA */
237
1.90k
  if (!fu_input_stream_read_u32(stream,
238
1.90k
              priv->flash_master_base_addr + 0x0,
239
1.90k
              &priv->flash_master[1],
240
1.90k
              G_LITTLE_ENDIAN,
241
1.90k
              error))
242
0
    return FALSE;
243
1.90k
  if (!fu_input_stream_read_u32(stream,
244
1.90k
              priv->flash_master_base_addr + 0x4,
245
1.90k
              &priv->flash_master[2],
246
1.90k
              G_LITTLE_ENDIAN,
247
1.90k
              error))
248
0
    return FALSE;
249
1.90k
  if (!fu_input_stream_read_u32(stream,
250
1.90k
              priv->flash_master_base_addr + 0x8,
251
1.90k
              &priv->flash_master[3],
252
1.90k
              G_LITTLE_ENDIAN,
253
1.90k
              error))
254
0
    return FALSE;
255
256
  /* FRBA */
257
1.90k
  priv->flash_descriptor_regs = g_new0(guint32, priv->num_regions);
258
13.8k
  for (guint i = 0; i < priv->num_regions; i++) {
259
11.9k
    if (!fu_input_stream_read_u32(stream,
260
11.9k
                priv->flash_region_base_addr + (i * sizeof(guint32)),
261
11.9k
                &priv->flash_descriptor_regs[i],
262
11.9k
                G_LITTLE_ENDIAN,
263
11.9k
                error))
264
3
      return FALSE;
265
11.9k
  }
266
7.16k
  for (guint i = 0; i < priv->num_regions; i++) {
267
6.34k
    const gchar *freg_str = fu_ifd_region_to_string(i);
268
6.34k
    guint32 freg_base = FU_IFD_FREG_BASE(priv->flash_descriptor_regs[i]);
269
6.34k
    guint32 freg_limt = FU_IFD_FREG_LIMIT(priv->flash_descriptor_regs[i]);
270
6.34k
    guint32 freg_size;
271
6.34k
    g_autoptr(FuFirmware) img = NULL;
272
6.34k
    g_autoptr(FuInputStream) partial_stream = NULL;
273
274
    /* invalid - check before subtraction */
275
6.34k
    if (freg_base > freg_limt)
276
2.16k
      continue;
277
4.18k
    freg_size = (freg_limt - freg_base) + 1;
278
279
    /* create image */
280
4.18k
    g_debug("freg %s 0x%04x -> 0x%04x", freg_str, freg_base, freg_limt);
281
4.18k
    partial_stream = fu_partial_input_stream_new(stream2, freg_base, freg_size, error);
282
4.18k
    if (partial_stream == NULL) {
283
489
      g_prefix_error_literal(error, "failed to cut IFD image: ");
284
489
      return FALSE;
285
489
    }
286
287
    /* do not parse all the EFI volumes if we only care about the structure */
288
3.69k
    if (i == FU_IFD_REGION_BIOS &&
289
1.88k
        (flags & FU_FIRMWARE_PARSE_FLAG_ONLY_PARTITION_LAYOUT) == 0) {
290
1.88k
      img = fu_ifd_bios_new();
291
1.88k
    } else {
292
1.81k
      img = fu_ifd_image_new();
293
1.81k
    }
294
3.69k
    if (!fu_firmware_parse_stream(img,
295
3.69k
                partial_stream,
296
3.69k
                0x0,
297
3.69k
                flags | FU_FIRMWARE_PARSE_FLAG_NO_SEARCH,
298
3.69k
                error))
299
595
      return FALSE;
300
3.10k
    fu_firmware_set_addr(img, freg_base);
301
3.10k
    fu_firmware_set_idx(img, i);
302
3.10k
    if (freg_str != NULL)
303
2.84k
      fu_firmware_set_id(img, freg_str);
304
3.10k
    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.4k
    for (FuIfdRegion r = 1; r <= 3; r++) {
309
9.30k
      FuIfdAccess acc;
310
9.30k
      acc = fu_ifd_firmware_region_to_access(i,
311
9.30k
                     priv->flash_master[r],
312
9.30k
                     priv->new_layout);
313
9.30k
      fu_ifd_image_set_access(FU_IFD_IMAGE(img), r, acc);
314
9.30k
    }
315
3.10k
  }
316
317
  /* success */
318
817
  return TRUE;
319
1.90k
}
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
817
{
348
817
  FuIfdFirmware *self = FU_IFD_FIRMWARE(firmware);
349
817
  FuIfdFirmwarePrivate *priv = GET_PRIVATE(self);
350
817
  gsize bufsz_max = 0x0;
351
817
  g_autoptr(GByteArray) buf = g_byte_array_new();
352
817
  g_autoptr(FuStructIfdFcba) st_fcba = fu_struct_ifd_fcba_new();
353
817
  g_autoptr(FuStructIfdFdbar) st_fdbar = fu_struct_ifd_fdbar_new();
354
817
  g_autoptr(GHashTable) blobs = NULL;
355
817
  g_autoptr(FuFirmware) img_desc = NULL;
356
357
  /* if the descriptor does not exist, then add something plausible */
358
817
  img_desc = fu_firmware_get_image_by_idx(firmware, FU_IFD_REGION_DESC, NULL);
359
817
  if (img_desc == NULL) {
360
775
    g_autoptr(GByteArray) buf_desc = g_byte_array_new();
361
775
    g_autoptr(GBytes) blob_desc = NULL;
362
775
    fu_byte_array_set_size(buf_desc, FU_IFD_SIZE, 0x00);
363
364
    /* success */
365
775
    blob_desc = g_bytes_new(buf_desc->data, buf_desc->len);
366
775
    img_desc = fu_firmware_new_from_bytes(blob_desc);
367
775
    fu_firmware_set_addr(img_desc, 0x0);
368
775
    fu_firmware_set_idx(img_desc, FU_IFD_REGION_DESC);
369
775
    fu_firmware_set_id(img_desc, "desc");
370
775
    if (!fu_firmware_add_image(firmware, img_desc, error))
371
0
      return NULL;
372
775
  }
373
374
  /* generate ahead of time */
375
817
  blobs = g_hash_table_new_full(g_direct_hash,
376
817
              g_direct_equal,
377
817
              NULL,
378
817
              (GDestroyNotify)g_bytes_unref);
379
2.63k
  for (guint i = 0; i < priv->num_regions; i++) {
380
2.07k
    gsize image_end;
381
2.07k
    g_autoptr(FuFirmware) img = fu_firmware_get_image_by_idx(firmware, i, NULL);
382
2.07k
    g_autoptr(GBytes) blob = NULL;
383
384
2.07k
    if (img == NULL)
385
333
      continue;
386
1.73k
    blob = fu_firmware_write(img, error);
387
1.73k
    if (blob == NULL) {
388
251
      g_prefix_error(error, "failed to write %s: ", fu_firmware_get_id(img));
389
251
      return NULL;
390
251
    }
391
1.48k
    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.48k
    g_hash_table_insert(blobs, GUINT_TO_POINTER(i), g_bytes_ref(blob));
400
401
    /* check total size with overflow checking */
402
1.48k
    image_end = fu_firmware_get_addr(img);
403
1.48k
    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.48k
    bufsz_max = MAX(image_end, bufsz_max);
410
1.48k
  }
411
566
  fu_byte_array_set_size(buf, bufsz_max, 0x00);
412
413
  /* descriptor map */
414
566
  fu_struct_ifd_fdbar_set_descriptor_map0(st_fdbar, priv->descriptor_map0);
415
566
  fu_struct_ifd_fdbar_set_descriptor_map1(st_fdbar, priv->descriptor_map1);
416
566
  fu_struct_ifd_fdbar_set_descriptor_map2(st_fdbar, priv->descriptor_map2);
417
566
  if (!fu_memcpy_safe(buf->data,
418
566
          buf->len,
419
566
          0x0,
420
566
          st_fdbar->buf->data,
421
566
          st_fdbar->buf->len,
422
566
          0x0,
423
566
          st_fdbar->buf->len,
424
566
          error))
425
0
    return NULL;
426
427
  /* FCBA */
428
566
  fu_struct_ifd_fcba_set_flcomp(st_fcba, priv->components_rcd);
429
566
  fu_struct_ifd_fcba_set_flill(st_fcba, priv->illegal_jedec);
430
566
  fu_struct_ifd_fcba_set_flill1(st_fcba, priv->illegal_jedec1);
431
566
  if (!fu_memcpy_safe(buf->data,
432
566
          buf->len,
433
566
          priv->flash_component_base_addr,
434
566
          st_fcba->buf->data,
435
566
          st_fcba->buf->len,
436
566
          0x0,
437
566
          st_fcba->buf->len,
438
566
          error))
439
0
    return NULL;
440
441
  /* FRBA */
442
1.76k
  for (guint i = 0; i < priv->num_regions; i++) {
443
1.20k
    guint32 freg_base = 0x7FFF000;
444
1.20k
    guint32 freg_limt = 0x0;
445
1.20k
    guint32 flreg;
446
1.20k
    g_autoptr(FuFirmware) img = fu_firmware_get_image_by_idx(firmware, i, NULL);
447
1.20k
    if (img != NULL) {
448
1.12k
      GBytes *blob =
449
1.12k
          g_hash_table_lookup(blobs, GUINT_TO_POINTER(fu_firmware_get_idx(img)));
450
1.12k
      freg_base = fu_firmware_get_addr(img);
451
1.12k
      freg_limt = (freg_base + g_bytes_get_size(blob)) - 1;
452
1.12k
    }
453
1.20k
    flreg = ((freg_limt << 4) & 0xFFFF0000) | (freg_base >> 12);
454
1.20k
    g_debug("freg 0x%04x -> 0x%04x = 0x%08x", freg_base, freg_limt, flreg);
455
1.20k
    if (!fu_memwrite_uint32_safe(buf->data,
456
1.20k
               buf->len,
457
1.20k
               priv->flash_region_base_addr + (i * sizeof(guint32)),
458
1.20k
               flreg,
459
1.20k
               G_LITTLE_ENDIAN,
460
1.20k
               error))
461
2
      return NULL;
462
1.20k
  }
463
464
  /* write images at correct offsets */
465
1.19k
  for (guint i = 1; i < priv->num_regions; i++) {
466
631
    GBytes *blob;
467
631
    g_autoptr(FuFirmware) img = fu_firmware_get_image_by_idx(firmware, i, NULL);
468
631
    if (img == NULL)
469
74
      continue;
470
557
    blob = g_hash_table_lookup(blobs, GUINT_TO_POINTER(fu_firmware_get_idx(img)));
471
557
    if (!fu_memcpy_safe(buf->data,
472
557
            buf->len,
473
557
            fu_firmware_get_addr(img),
474
557
            g_bytes_get_data(blob, NULL),
475
557
            g_bytes_get_size(blob),
476
557
            0x0,
477
557
            g_bytes_get_size(blob),
478
557
            error))
479
0
      return NULL;
480
557
  }
481
482
  /* success */
483
564
  return g_steal_pointer(&buf);
484
564
}
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
1.98k
{
519
1.98k
  FuIfdFirmwarePrivate *priv = GET_PRIVATE(self);
520
521
  /* some good defaults */
522
1.98k
  priv->new_layout = TRUE;
523
1.98k
  priv->num_regions = 10;
524
1.98k
  priv->flash_region_base_addr = 0x40;
525
1.98k
  priv->flash_component_base_addr = 0x30;
526
1.98k
  priv->flash_master_base_addr = 0x80;
527
1.98k
  priv->flash_master[1] = 0x00A00F00;
528
1.98k
  priv->flash_master[2] = 0x00400D00;
529
1.98k
  priv->flash_master[3] = 0x00800900;
530
1.98k
  priv->flash_ich_strap_base_addr = 0x100;
531
1.98k
  priv->flash_mch_strap_base_addr = 0x300;
532
1.98k
}
533
534
static void
535
fu_ifd_firmware_finalize(GObject *object)
536
1.98k
{
537
1.98k
  FuIfdFirmware *self = FU_IFD_FIRMWARE(object);
538
1.98k
  FuIfdFirmwarePrivate *priv = GET_PRIVATE(self);
539
1.98k
  g_free(priv->flash_descriptor_regs);
540
1.98k
  G_OBJECT_CLASS(fu_ifd_firmware_parent_class)->finalize(object);
541
1.98k
}
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
}