Coverage Report

Created: 2025-07-01 07:09

/src/fwupd/libfwupdplugin/fu-efi-section.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2020 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
40.1k
#define G_LOG_DOMAIN "FuEfiSection"
8
9
#include "config.h"
10
11
#include "fu-byte-array.h"
12
#include "fu-common.h"
13
#include "fu-efi-common.h"
14
#include "fu-efi-lz77-decompressor.h"
15
#include "fu-efi-section.h"
16
#include "fu-efi-struct.h"
17
#include "fu-efi-volume.h"
18
#include "fu-input-stream.h"
19
#include "fu-lzma-common.h"
20
#include "fu-partial-input-stream.h"
21
#include "fu-string.h"
22
23
/**
24
 * FuEfiSection:
25
 *
26
 * A UEFI firmware section.
27
 *
28
 * See also: [class@FuFirmware]
29
 */
30
31
typedef struct {
32
  guint8 type;
33
  gchar *user_interface;
34
} FuEfiSectionPrivate;
35
36
G_DEFINE_TYPE_WITH_PRIVATE(FuEfiSection, fu_efi_section, FU_TYPE_FIRMWARE)
37
155k
#define GET_PRIVATE(o) (fu_efi_section_get_instance_private(o))
38
39
static void
40
fu_efi_section_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn)
41
0
{
42
0
  FuEfiSection *self = FU_EFI_SECTION(firmware);
43
0
  FuEfiSectionPrivate *priv = GET_PRIVATE(self);
44
45
0
  fu_xmlb_builder_insert_kx(bn, "type", priv->type);
46
0
  if (priv->user_interface != NULL)
47
0
    fu_xmlb_builder_insert_kv(bn, "user_interface", priv->user_interface);
48
0
  if (flags & FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG) {
49
0
    fu_xmlb_builder_insert_kv(bn,
50
0
            "name",
51
0
            fu_efi_guid_to_name(fu_firmware_get_id(firmware)));
52
0
    fu_xmlb_builder_insert_kv(bn,
53
0
            "type_name",
54
0
            fu_efi_section_type_to_string(priv->type));
55
0
  }
56
0
}
57
58
static gboolean
59
fu_efi_section_parse_volume_image(FuEfiSection *self,
60
          GInputStream *stream,
61
          FuFirmwareParseFlags flags,
62
          GError **error)
63
1.34k
{
64
1.34k
  g_autoptr(FuFirmware) img = fu_efi_volume_new();
65
1.34k
  if (!fu_firmware_parse_stream(img,
66
1.34k
              stream,
67
1.34k
              0x0,
68
1.34k
              flags | FU_FIRMWARE_PARSE_FLAG_NO_SEARCH,
69
1.34k
              error)) {
70
1.24k
    return FALSE;
71
1.24k
  }
72
98
  fu_firmware_add_image(FU_FIRMWARE(self), img);
73
98
  return TRUE;
74
1.34k
}
75
76
static gboolean
77
fu_efi_section_parse_lzma_sections(FuEfiSection *self,
78
           GInputStream *stream,
79
           FuFirmwareParseFlags flags,
80
           GError **error)
81
0
{
82
0
  g_autoptr(GBytes) blob = NULL;
83
0
  g_autoptr(GBytes) blob_uncomp = NULL;
84
0
  g_autoptr(GInputStream) stream_uncomp = NULL;
85
86
  /* parse all sections */
87
0
  blob = fu_input_stream_read_bytes(stream, 0, G_MAXSIZE, NULL, error);
88
0
  if (blob == NULL)
89
0
    return FALSE;
90
0
  blob_uncomp = fu_lzma_decompress_bytes(blob, 128 * 1024 * 1024, error);
91
0
  if (blob_uncomp == NULL) {
92
0
    g_prefix_error(error, "failed to decompress: ");
93
0
    return FALSE;
94
0
  }
95
0
  stream_uncomp = g_memory_input_stream_new_from_bytes(blob_uncomp);
96
0
  if (!fu_efi_parse_sections(FU_FIRMWARE(self), stream_uncomp, 0, flags, error)) {
97
0
    g_prefix_error(error, "failed to parse sections: ");
98
0
    return FALSE;
99
0
  }
100
0
  return TRUE;
101
0
}
102
103
static gboolean
104
fu_efi_section_parse_user_interface(FuEfiSection *self,
105
            GInputStream *stream,
106
            FuFirmwareParseFlags flags,
107
            GError **error)
108
1.07k
{
109
1.07k
  FuEfiSectionPrivate *priv = GET_PRIVATE(self);
110
1.07k
  g_autoptr(GByteArray) buf = NULL;
111
112
1.07k
  if (priv->user_interface != NULL) {
113
0
    g_set_error(error,
114
0
          FWUPD_ERROR,
115
0
          FWUPD_ERROR_INTERNAL,
116
0
          "UI already set as %s for section",
117
0
          priv->user_interface);
118
0
    return FALSE;
119
0
  }
120
1.07k
  buf = fu_input_stream_read_byte_array(stream, 0x0, G_MAXSIZE, NULL, error);
121
1.07k
  if (buf == NULL)
122
6
    return FALSE;
123
1.06k
  priv->user_interface = fu_utf16_to_utf8_byte_array(buf, G_LITTLE_ENDIAN, error);
124
1.06k
  if (priv->user_interface == NULL)
125
69
    return FALSE;
126
998
  return TRUE;
127
1.06k
}
128
129
static gboolean
130
fu_efi_section_parse_version(FuEfiSection *self,
131
           GInputStream *stream,
132
           FuFirmwareParseFlags flags,
133
           GError **error)
134
1.36k
{
135
1.36k
  guint16 version_raw = 0;
136
1.36k
  g_autofree gchar *version = NULL;
137
1.36k
  g_autoptr(GByteArray) buf = NULL;
138
139
1.36k
  if (!fu_input_stream_read_u16(stream, 0x0, &version_raw, G_LITTLE_ENDIAN, error)) {
140
7
    g_prefix_error(error, "failed to read raw version: ");
141
7
    return FALSE;
142
7
  }
143
1.35k
  fu_firmware_set_version_raw(FU_FIRMWARE(self), version_raw);
144
1.35k
  buf = fu_input_stream_read_byte_array(stream, sizeof(guint16), G_MAXSIZE, NULL, error);
145
1.35k
  if (buf == NULL) {
146
13
    g_prefix_error(error, "failed to read version buffer: ");
147
13
    return FALSE;
148
13
  }
149
1.34k
  version = fu_utf16_to_utf8_byte_array(buf, G_LITTLE_ENDIAN, error);
150
1.34k
  if (version == NULL) {
151
23
    g_prefix_error(error, "failed to convert to UTF-16: ");
152
23
    return FALSE;
153
23
  }
154
1.32k
  fu_firmware_set_version(FU_FIRMWARE(self), version); /* nocheck:set-version */
155
1.32k
  return TRUE;
156
1.34k
}
157
158
static gboolean
159
fu_efi_section_parse_compression_sections(FuEfiSection *self,
160
            GInputStream *stream,
161
            FuFirmwareParseFlags flags,
162
            GError **error)
163
3.46k
{
164
3.46k
  g_autoptr(GByteArray) st = NULL;
165
3.46k
  st = fu_struct_efi_section_compression_parse_stream(stream, 0x0, error);
166
3.46k
  if (st == NULL)
167
27
    return FALSE;
168
3.43k
  if (fu_struct_efi_section_compression_get_compression_type(st) ==
169
3.43k
      FU_EFI_COMPRESSION_TYPE_NOT_COMPRESSED) {
170
679
    if (!fu_efi_parse_sections(FU_FIRMWARE(self), stream, st->len, flags, error)) {
171
378
      g_prefix_error(error, "failed to parse sections: ");
172
378
      return FALSE;
173
378
    }
174
2.75k
  } else {
175
2.75k
    g_autoptr(FuFirmware) lz77_decompressor = fu_efi_lz77_decompressor_new();
176
2.75k
    g_autoptr(GInputStream) lz77_stream = NULL;
177
2.75k
    if (!fu_firmware_parse_stream(lz77_decompressor, stream, st->len, flags, error))
178
1.27k
      return FALSE;
179
1.48k
    lz77_stream = fu_firmware_get_stream(lz77_decompressor, error);
180
1.48k
    if (lz77_stream == NULL)
181
0
      return FALSE;
182
1.48k
    if (!fu_efi_parse_sections(FU_FIRMWARE(self), lz77_stream, 0, flags, error)) {
183
643
      g_prefix_error(error, "failed to parse sections: ");
184
643
      return FALSE;
185
643
    }
186
1.48k
  }
187
1.14k
  return TRUE;
188
3.43k
}
189
190
static const gchar *
191
fu_efi_section_freeform_subtype_guid_to_string(const gchar *guid)
192
302
{
193
302
  struct {
194
302
    const gchar *guid;
195
302
    const gchar *str;
196
302
  } freeform_guids[] = {
197
302
      {"00781ca1-5de3-405f-abb8-379c3c076984", "AmiRomLayoutGuid"},
198
302
      {"20feebde-e739-420e-ae31-77e2876508c0", "IntelRstOprom"},
199
302
      {"224d6eb4-307f-45ba-9dc3-fe9fc6b38148", "IntelEntRaidController"},
200
302
      {"2ebe0275-6458-4af9-91ed-d3f4edb100aa", "SignOn"},
201
302
      {"380b6b4f-1454-41f2-a6d3-61d1333e8cb4", "IntelGop"},
202
302
      {"50339d20-c90a-4bb2-9aff-d8a11b23bc15", "I219?Oprom"},
203
302
      {"88a15a4f-977d-4682-b17c-da1f316c1f32", "RomLayout"},
204
302
      {"9bec7109-6d7a-413a-8e4b-019ced0503e1", "AmiBoardInfoSectionGuid"},
205
302
      {"ab56dc60-0057-11da-a8db-000102eee626", "?BuildData"},
206
302
      {"c5a4306e-e247-4ecd-a9d8-5b1985d3dcda", "?Oprom"},
207
302
      {"c9352cc3-a354-44e5-8776-b2ed8dd781ec", "IntelEntRaidController"},
208
302
      {"d46346ca-82a1-4cde-9546-77c86f893888", "?Oprom"},
209
302
      {"e095affe-d4cd-4289-9b48-28f64e3d781d", "IntelRstOprom"},
210
302
      {"fe612b72-203c-47b1-8560-a66d946eb371", "setupdata"},
211
302
      {NULL, NULL},
212
302
  };
213
4.53k
  for (guint i = 0; freeform_guids[i].guid != NULL; i++) {
214
4.22k
    if (g_strcmp0(guid, freeform_guids[i].guid) == 0)
215
0
      return freeform_guids[i].str;
216
4.22k
  }
217
302
  return NULL;
218
302
}
219
220
static gboolean
221
fu_efi_section_parse_freeform_subtype_guid(FuEfiSection *self,
222
             GInputStream *stream,
223
             FuFirmwareParseFlags flags,
224
             GError **error)
225
323
{
226
323
  const gchar *guid_ui;
227
323
  g_autofree gchar *guid_str = NULL;
228
323
  g_autoptr(GByteArray) st = NULL;
229
230
323
  st = fu_struct_efi_section_freeform_subtype_guid_parse_stream(stream, 0x0, error);
231
323
  if (st == NULL)
232
21
    return FALSE;
233
234
  /* no idea */
235
302
  guid_str = fwupd_guid_to_string(fu_struct_efi_section_freeform_subtype_guid_get_guid(st),
236
302
          FWUPD_GUID_FLAG_MIXED_ENDIAN);
237
302
  guid_ui = fu_efi_section_freeform_subtype_guid_to_string(guid_str);
238
302
  if (guid_ui != NULL) {
239
0
    g_debug("ignoring FREEFORM_SUBTYPE_GUID %s [%s]", guid_str, guid_ui);
240
0
    return TRUE;
241
0
  }
242
302
  g_debug("unknown FREEFORM_SUBTYPE_GUID %s", guid_str);
243
302
  return TRUE;
244
302
}
245
246
static gboolean
247
fu_efi_section_parse(FuFirmware *firmware,
248
         GInputStream *stream,
249
         FuFirmwareParseFlags flags,
250
         GError **error)
251
48.6k
{
252
48.6k
  FuEfiSection *self = FU_EFI_SECTION(firmware);
253
48.6k
  FuEfiSectionPrivate *priv = GET_PRIVATE(self);
254
48.6k
  gsize offset = 0;
255
48.6k
  gsize streamsz = 0;
256
48.6k
  guint32 size;
257
48.6k
  g_autoptr(GByteArray) st = NULL;
258
48.6k
  g_autoptr(GInputStream) partial_stream = NULL;
259
260
  /* parse */
261
48.6k
  st = fu_struct_efi_section_parse_stream(stream, offset, error);
262
48.6k
  if (st == NULL)
263
199
    return FALSE;
264
265
  /* use extended size */
266
48.4k
  if (fu_struct_efi_section_get_size(st) == 0xFFFFFF) {
267
1.30k
    fu_struct_efi_section_unref(st);
268
1.30k
    st = fu_struct_efi_section2_parse_stream(stream, offset, error);
269
1.30k
    if (st == NULL)
270
23
      return FALSE;
271
1.28k
    size = fu_struct_efi_section2_get_extended_size(st);
272
47.1k
  } else {
273
47.1k
    size = fu_struct_efi_section_get_size(st);
274
47.1k
  }
275
48.3k
  if (size < FU_STRUCT_EFI_SECTION_SIZE) {
276
432
    g_set_error(error,
277
432
          FWUPD_ERROR,
278
432
          FWUPD_ERROR_INTERNAL,
279
432
          "invalid section size, got 0x%x",
280
432
          (guint)size);
281
432
    return FALSE;
282
432
  }
283
284
  /* sanity check */
285
47.9k
  if (!fu_input_stream_size(stream, &streamsz, error))
286
0
    return FALSE;
287
47.9k
  if (size > streamsz) {
288
408
    g_set_error(error,
289
408
          FWUPD_ERROR,
290
408
          FWUPD_ERROR_INTERNAL,
291
408
          "invalid section size, got 0x%x from stream of size 0x%x",
292
408
          (guint)size,
293
408
          (guint)streamsz);
294
408
    return FALSE;
295
408
  }
296
297
  /* name */
298
47.5k
  priv->type = fu_struct_efi_section_get_type(st);
299
47.5k
  if (priv->type == FU_EFI_SECTION_TYPE_GUID_DEFINED) {
300
7.29k
    g_autofree gchar *guid_str = NULL;
301
7.29k
    g_autoptr(GByteArray) st_def = NULL;
302
7.29k
    st_def = fu_struct_efi_section_guid_defined_parse_stream(stream, st->len, error);
303
7.29k
    if (st_def == NULL)
304
23
      return FALSE;
305
7.27k
    guid_str = fwupd_guid_to_string(fu_struct_efi_section_guid_defined_get_name(st_def),
306
7.27k
            FWUPD_GUID_FLAG_MIXED_ENDIAN);
307
7.27k
    fu_firmware_set_id(firmware, guid_str);
308
7.27k
    if (fu_struct_efi_section_guid_defined_get_offset(st_def) < st_def->len) {
309
18
      g_set_error(error,
310
18
            FWUPD_ERROR,
311
18
            FWUPD_ERROR_INTERNAL,
312
18
            "invalid section size, got 0x%x",
313
18
            (guint)fu_struct_efi_section_guid_defined_get_offset(st_def));
314
18
      return FALSE;
315
18
    }
316
7.25k
    offset += fu_struct_efi_section_guid_defined_get_offset(st_def) - st->len;
317
7.25k
  }
318
319
  /* create blob */
320
47.5k
  offset += st->len;
321
47.5k
  partial_stream = fu_partial_input_stream_new(stream, offset, size - offset, error);
322
47.5k
  if (partial_stream == NULL) {
323
1
    g_prefix_error(error, "failed to cut data: ");
324
1
    return FALSE;
325
1
  }
326
47.5k
  fu_firmware_set_offset(firmware, offset);
327
47.5k
  fu_firmware_set_size(firmware, size);
328
47.5k
  if (!fu_firmware_set_stream(firmware, partial_stream, error))
329
101
    return FALSE;
330
331
  /* nested volume */
332
47.4k
  if (priv->type == FU_EFI_SECTION_TYPE_VOLUME_IMAGE) {
333
1.34k
    if (!fu_efi_section_parse_volume_image(self, partial_stream, flags, error)) {
334
1.24k
      g_prefix_error(error, "failed to parse nested volume: ");
335
1.24k
      return FALSE;
336
1.24k
    }
337
46.0k
  } else if (priv->type == FU_EFI_SECTION_TYPE_GUID_DEFINED &&
338
46.0k
       g_strcmp0(fu_firmware_get_id(firmware), FU_EFI_SECTION_GUID_LZMA_COMPRESS) ==
339
7.25k
           0) {
340
0
    if (!fu_efi_section_parse_lzma_sections(self, partial_stream, flags, error)) {
341
0
      g_prefix_error(error, "failed to parse lzma section: ");
342
0
      return FALSE;
343
0
    }
344
46.0k
  } else if (priv->type == FU_EFI_SECTION_TYPE_GUID_DEFINED &&
345
46.0k
       g_strcmp0(fu_firmware_get_id(firmware),
346
7.25k
           "ced4eac6-49f3-4c12-a597-fc8c33447691") == 0) {
347
37
    g_debug("ignoring %s [0x%x] EFI section as self test",
348
37
      fu_efi_section_type_to_string(priv->type),
349
37
      priv->type);
350
46.0k
  } else if (priv->type == FU_EFI_SECTION_TYPE_GUID_DEFINED) {
351
7.21k
    g_warning("no idea how to decompress encapsulation section of type %s",
352
7.21k
        fu_firmware_get_id(firmware));
353
38.8k
  } else if (priv->type == FU_EFI_SECTION_TYPE_USER_INTERFACE) {
354
1.07k
    if (!fu_efi_section_parse_user_interface(self, partial_stream, flags, error)) {
355
75
      g_prefix_error(error, "failed to parse user interface: ");
356
75
      return FALSE;
357
75
    }
358
37.7k
  } else if (priv->type == FU_EFI_SECTION_TYPE_VERSION) {
359
1.36k
    if (!fu_efi_section_parse_version(self, partial_stream, flags, error)) {
360
43
      g_prefix_error(error, "failed to parse version: ");
361
43
      return FALSE;
362
43
    }
363
36.3k
  } else if (priv->type == FU_EFI_SECTION_TYPE_COMPRESSION) {
364
3.46k
    if (!fu_efi_section_parse_compression_sections(self,
365
3.46k
                     partial_stream,
366
3.46k
                     flags,
367
3.46k
                     error)) {
368
2.31k
      g_prefix_error(error, "failed to parse compression: ");
369
2.31k
      return FALSE;
370
2.31k
    }
371
32.9k
  } else if (priv->type == FU_EFI_SECTION_TYPE_FREEFORM_SUBTYPE_GUID) {
372
323
    if (!fu_efi_section_parse_freeform_subtype_guid(self,
373
323
                partial_stream,
374
323
                flags,
375
323
                error)) {
376
21
      g_prefix_error(error, "failed to parse compression: ");
377
21
      return FALSE;
378
21
    }
379
32.5k
  } else if (priv->type == FU_EFI_SECTION_TYPE_PEI_DEPEX ||
380
32.5k
       priv->type == FU_EFI_SECTION_TYPE_DXE_DEPEX ||
381
32.5k
       priv->type == FU_EFI_SECTION_TYPE_MM_DEPEX ||
382
32.5k
       priv->type == FU_EFI_SECTION_TYPE_PE32 || priv->type == FU_EFI_SECTION_TYPE_TE ||
383
32.5k
       priv->type == FU_EFI_SECTION_TYPE_RAW) {
384
11.0k
    g_debug("ignoring %s [0x%x] EFI section",
385
11.0k
      fu_efi_section_type_to_string(priv->type),
386
11.0k
      priv->type);
387
21.5k
  } else {
388
21.5k
    g_warning("no idea how to parse %s [0x%x] EFI section",
389
21.5k
        fu_efi_section_type_to_string(priv->type),
390
21.5k
        priv->type);
391
21.5k
  }
392
393
  /* success */
394
43.6k
  return TRUE;
395
47.4k
}
396
397
static GByteArray *
398
fu_efi_section_write(FuFirmware *firmware, GError **error)
399
8.24k
{
400
8.24k
  FuEfiSection *self = FU_EFI_SECTION(firmware);
401
8.24k
  FuEfiSectionPrivate *priv = GET_PRIVATE(self);
402
8.24k
  g_autoptr(GByteArray) buf = fu_struct_efi_section_new();
403
8.24k
  g_autoptr(GBytes) blob = NULL;
404
405
  /* simple blob for now */
406
8.24k
  blob = fu_firmware_get_bytes_with_patches(firmware, error);
407
8.24k
  if (blob == NULL)
408
349
    return NULL;
409
410
  /* header */
411
7.89k
  if (priv->type == FU_EFI_SECTION_TYPE_GUID_DEFINED) {
412
1.69k
    fwupd_guid_t guid = {0x0};
413
1.69k
    g_autoptr(GByteArray) st_def = fu_struct_efi_section_guid_defined_new();
414
1.69k
    if (!fwupd_guid_from_string(fu_firmware_get_id(firmware),
415
1.69k
              &guid,
416
1.69k
              FWUPD_GUID_FLAG_MIXED_ENDIAN,
417
1.69k
              error))
418
0
      return NULL;
419
1.69k
    fu_struct_efi_section_guid_defined_set_name(st_def, &guid);
420
1.69k
    fu_struct_efi_section_guid_defined_set_offset(st_def, buf->len + st_def->len);
421
1.69k
    g_byte_array_append(buf, st_def->data, st_def->len);
422
1.69k
  }
423
7.89k
  fu_struct_efi_section_set_type(buf, priv->type);
424
7.89k
  fu_struct_efi_section_set_size(buf, buf->len + g_bytes_get_size(blob));
425
426
  /* blob */
427
7.89k
  fu_byte_array_append_bytes(buf, blob);
428
7.89k
  return g_steal_pointer(&buf);
429
7.89k
}
430
431
static gboolean
432
fu_efi_section_build(FuFirmware *firmware, XbNode *n, GError **error)
433
0
{
434
0
  FuEfiSection *self = FU_EFI_SECTION(firmware);
435
0
  FuEfiSectionPrivate *priv = GET_PRIVATE(self);
436
0
  const gchar *str;
437
0
  guint64 tmp;
438
439
  /* simple properties */
440
0
  tmp = xb_node_query_text_as_uint(n, "type", NULL);
441
0
  if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8)
442
0
    priv->type = tmp;
443
0
  str = xb_node_query_text(n, "user_interface", NULL);
444
0
  if (str != NULL) {
445
0
    if (priv->user_interface != NULL) {
446
0
      g_set_error(error,
447
0
            FWUPD_ERROR,
448
0
            FWUPD_ERROR_INTERNAL,
449
0
            "UI already set as %s for section",
450
0
            priv->user_interface);
451
0
      return FALSE;
452
0
    }
453
0
    priv->user_interface = g_strdup(str);
454
0
  }
455
456
  /* success */
457
0
  return TRUE;
458
0
}
459
460
static void
461
fu_efi_section_init(FuEfiSection *self)
462
48.6k
{
463
48.6k
  FuEfiSectionPrivate *priv = GET_PRIVATE(self);
464
48.6k
  priv->type = FU_EFI_SECTION_TYPE_RAW;
465
48.6k
  fu_firmware_set_images_max(FU_FIRMWARE(self),
466
48.6k
           g_getenv("FWUPD_FUZZER_RUNNING") != NULL ? 10 : 2000);
467
48.6k
  fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_NO_AUTO_DETECTION);
468
  //  fu_firmware_set_alignment (FU_FIRMWARE (self), FU_FIRMWARE_ALIGNMENT_8);
469
48.6k
  g_type_ensure(FU_TYPE_EFI_VOLUME);
470
48.6k
}
471
472
static void
473
fu_efi_section_finalize(GObject *object)
474
48.6k
{
475
48.6k
  FuEfiSection *self = FU_EFI_SECTION(object);
476
48.6k
  FuEfiSectionPrivate *priv = GET_PRIVATE(self);
477
48.6k
  g_free(priv->user_interface);
478
48.6k
  G_OBJECT_CLASS(fu_efi_section_parent_class)->finalize(object);
479
48.6k
}
480
481
static void
482
fu_efi_section_class_init(FuEfiSectionClass *klass)
483
2
{
484
2
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
485
2
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
486
2
  object_class->finalize = fu_efi_section_finalize;
487
2
  firmware_class->parse = fu_efi_section_parse;
488
2
  firmware_class->write = fu_efi_section_write;
489
2
  firmware_class->build = fu_efi_section_build;
490
2
  firmware_class->export = fu_efi_section_export;
491
2
}
492
493
/**
494
 * fu_efi_section_new:
495
 *
496
 * Creates a new #FuFirmware
497
 *
498
 * Since: 2.0.0
499
 **/
500
FuFirmware *
501
fu_efi_section_new(void)
502
48.6k
{
503
48.6k
  return FU_FIRMWARE(g_object_new(FU_TYPE_EFI_SECTION, NULL));
504
48.6k
}