Coverage Report

Created: 2026-05-30 06:50

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