/src/fwupd/libfwupdplugin/fu-ifd-image.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2021 Richard Hughes <richard@hughsie.com> |
3 | | * |
4 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | | */ |
6 | | |
7 | | #include "config.h" |
8 | | |
9 | | #include "fu-byte-array.h" |
10 | | #include "fu-common.h" |
11 | | #include "fu-ifd-image.h" |
12 | | |
13 | | /** |
14 | | * FuIfdImage: |
15 | | * |
16 | | * An Intel Flash Descriptor image, e.g. BIOS. |
17 | | * |
18 | | * See also: [class@FuFirmware] |
19 | | */ |
20 | | |
21 | | typedef struct { |
22 | | FuIfdAccess access[FU_IFD_REGION_MAX]; |
23 | | } FuIfdImagePrivate; |
24 | | |
25 | | G_DEFINE_TYPE_WITH_PRIVATE(FuIfdImage, fu_ifd_image, FU_TYPE_FIRMWARE) |
26 | 21.4k | #define GET_PRIVATE(o) (fu_ifd_image_get_instance_private(o)) |
27 | | |
28 | | static void |
29 | | fu_ifd_image_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn) |
30 | 0 | { |
31 | 0 | FuIfdImage *self = FU_IFD_IMAGE(firmware); |
32 | 0 | FuIfdImagePrivate *priv = GET_PRIVATE(self); |
33 | 0 | for (guint i = 0; i < FU_IFD_REGION_MAX; i++) { |
34 | 0 | if (priv->access[i] == FU_IFD_ACCESS_NONE) |
35 | 0 | continue; |
36 | 0 | xb_builder_node_insert_text(bn, |
37 | 0 | "access", |
38 | 0 | fu_ifd_access_to_string(priv->access[i]), |
39 | 0 | "region", |
40 | 0 | fu_ifd_region_to_string(i), |
41 | 0 | NULL); |
42 | 0 | } |
43 | 0 | } |
44 | | |
45 | | /** |
46 | | * fu_ifd_image_set_access: |
47 | | * @self: a #FuIfdImage |
48 | | * @region: a #FuIfdRegion, e.g. %FU_IFD_REGION_BIOS |
49 | | * @access: a #FuIfdAccess, e.g. %FU_IFD_ACCESS_NONE |
50 | | * |
51 | | * Sets the access control for a specific reason. |
52 | | * |
53 | | * Since: 1.6.2 |
54 | | **/ |
55 | | void |
56 | | fu_ifd_image_set_access(FuIfdImage *self, FuIfdRegion region, FuIfdAccess access) |
57 | 21.4k | { |
58 | 21.4k | FuIfdImagePrivate *priv = GET_PRIVATE(self); |
59 | 21.4k | g_return_if_fail(FU_IS_IFD_IMAGE(self)); |
60 | 21.4k | g_return_if_fail(region < FU_IFD_REGION_MAX); |
61 | 21.4k | priv->access[region] = access; |
62 | 21.4k | } |
63 | | |
64 | | /** |
65 | | * fu_ifd_image_get_access: |
66 | | * @self: a #FuIfdImage |
67 | | * @region: a #FuIfdRegion, e.g. %FU_IFD_REGION_BIOS |
68 | | * |
69 | | * Gets the access control for a specific reason. |
70 | | * |
71 | | * Returns: a #FuIfdAccess, e.g. %FU_IFD_ACCESS_NONE |
72 | | * |
73 | | * Since: 1.6.2 |
74 | | **/ |
75 | | FuIfdAccess |
76 | | fu_ifd_image_get_access(FuIfdImage *self, FuIfdRegion region) |
77 | 0 | { |
78 | 0 | FuIfdImagePrivate *priv = GET_PRIVATE(self); |
79 | 0 | g_return_val_if_fail(FU_IS_IFD_IMAGE(self), FU_IFD_ACCESS_NONE); |
80 | 0 | g_return_val_if_fail(region < FU_IFD_REGION_MAX, FU_IFD_ACCESS_NONE); |
81 | 0 | return priv->access[region]; |
82 | 0 | } |
83 | | |
84 | | static GByteArray * |
85 | | fu_ifd_image_write(FuFirmware *firmware, GError **error) |
86 | 774 | { |
87 | 774 | g_autoptr(GByteArray) buf = g_byte_array_new(); |
88 | 774 | g_autoptr(GPtrArray) images = fu_firmware_get_images(firmware); |
89 | | |
90 | | /* sanity check */ |
91 | 774 | if (fu_firmware_get_alignment(firmware) > FU_FIRMWARE_ALIGNMENT_1M) { |
92 | 0 | g_set_error(error, |
93 | 0 | FWUPD_ERROR, |
94 | 0 | FWUPD_ERROR_INVALID_FILE, |
95 | 0 | "alignment invalid, got 0x%02x", |
96 | 0 | fu_firmware_get_alignment(firmware)); |
97 | 0 | return NULL; |
98 | 0 | } |
99 | | |
100 | | /* add each volume */ |
101 | 774 | if (images->len > 0) { |
102 | 2.32k | for (guint i = 0; i < images->len; i++) { |
103 | 2.16k | FuFirmware *img = g_ptr_array_index(images, i); |
104 | 2.16k | g_autoptr(GBytes) bytes = fu_firmware_write(img, error); |
105 | 2.16k | if (bytes == NULL) |
106 | 106 | return NULL; |
107 | 2.05k | fu_byte_array_append_bytes(buf, bytes); |
108 | 2.05k | } |
109 | 500 | } else { |
110 | 500 | g_autoptr(GBytes) bytes = NULL; |
111 | 500 | bytes = fu_firmware_get_bytes_with_patches(firmware, error); |
112 | 500 | if (bytes == NULL) |
113 | 500 | return NULL; |
114 | 0 | fu_byte_array_append_bytes(buf, bytes); |
115 | 0 | } |
116 | | |
117 | | /* align up */ |
118 | 168 | fu_byte_array_set_size(buf, |
119 | 168 | fu_common_align_up(buf->len, fu_firmware_get_alignment(firmware)), |
120 | 168 | 0x00); |
121 | | |
122 | | /* success */ |
123 | 168 | return g_steal_pointer(&buf); |
124 | 774 | } |
125 | | |
126 | | static void |
127 | | fu_ifd_image_init(FuIfdImage *self) |
128 | 7.46k | { |
129 | 7.46k | fu_firmware_set_alignment(FU_FIRMWARE(self), FU_FIRMWARE_ALIGNMENT_4K); |
130 | 7.46k | } |
131 | | |
132 | | static void |
133 | | fu_ifd_image_class_init(FuIfdImageClass *klass) |
134 | 1 | { |
135 | 1 | FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass); |
136 | 1 | firmware_class->export = fu_ifd_image_export; |
137 | 1 | firmware_class->write = fu_ifd_image_write; |
138 | 1 | } |
139 | | |
140 | | /** |
141 | | * fu_ifd_image_new: |
142 | | * |
143 | | * Creates a new #FuFirmware |
144 | | * |
145 | | * Since: 1.6.2 |
146 | | **/ |
147 | | FuFirmware * |
148 | | fu_ifd_image_new(void) |
149 | 5.71k | { |
150 | 5.71k | return FU_FIRMWARE(g_object_new(FU_TYPE_IFD_IMAGE, NULL)); |
151 | 5.71k | } |