/src/fwupd/libfwupdplugin/fu-efi-common.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 | | #include "config.h" |
8 | | |
9 | | #include "fu-common.h" |
10 | | #include "fu-efi-common.h" |
11 | | #include "fu-efi-section.h" |
12 | | #include "fu-input-stream.h" |
13 | | #include "fu-partial-input-stream.h" |
14 | | |
15 | | /** |
16 | | * fu_efi_guid_to_name: |
17 | | * @guid: A lowercase GUID string, e.g. `8c8ce578-8a3d-4f1c-9935-896185c32dd3` |
18 | | * |
19 | | * Converts a GUID to the known nice name. |
20 | | * |
21 | | * Returns: identifier string, or %NULL if unknown |
22 | | * |
23 | | * Since: 1.6.2 |
24 | | **/ |
25 | | const gchar * |
26 | | fu_efi_guid_to_name(const gchar *guid) |
27 | 17.5k | { |
28 | 17.5k | if (g_strcmp0(guid, FU_EFI_VOLUME_GUID_FFS1) == 0) |
29 | 0 | return "Volume:Ffs1"; |
30 | 17.5k | if (g_strcmp0(guid, FU_EFI_VOLUME_GUID_FFS2) == 0) |
31 | 63 | return "Volume:Ffs2"; |
32 | 17.4k | if (g_strcmp0(guid, FU_EFI_VOLUME_GUID_FFS3) == 0) |
33 | 0 | return "Volume:Ffs3"; |
34 | 17.4k | if (g_strcmp0(guid, FU_EFI_VOLUME_GUID_NVRAM_EVSA) == 0) |
35 | 11.0k | return "Volume:NvramEvsa"; |
36 | 6.39k | if (g_strcmp0(guid, FU_EFI_VOLUME_GUID_NVRAM_NVAR) == 0) |
37 | 0 | return "Volume:NvramNvar"; |
38 | 6.39k | if (g_strcmp0(guid, FU_EFI_VOLUME_GUID_NVRAM_EVSA2) == 0) |
39 | 0 | return "Volume:NvramEvsa2"; |
40 | 6.39k | if (g_strcmp0(guid, FU_EFI_VOLUME_GUID_APPLE_BOOT) == 0) |
41 | 0 | return "Volume:AppleBoot"; |
42 | 6.39k | if (g_strcmp0(guid, FU_EFI_VOLUME_GUID_PFH1) == 0) |
43 | 0 | return "Volume:Pfh1"; |
44 | 6.39k | if (g_strcmp0(guid, FU_EFI_VOLUME_GUID_PFH2) == 0) |
45 | 0 | return "Volume:Pfh2"; |
46 | 6.39k | if (g_strcmp0(guid, FU_EFI_VOLUME_GUID_HP_FS) == 0) |
47 | 0 | return "Volume:HpFs"; |
48 | 6.39k | if (g_strcmp0(guid, FU_EFI_FILE_GUID_FV_IMAGE) == 0) |
49 | 0 | return "File:FvImage"; |
50 | 6.39k | if (g_strcmp0(guid, FU_EFI_FILE_GUID_MICROCODE) == 0) |
51 | 0 | return "File:Microcode"; |
52 | 6.39k | if (g_strcmp0(guid, FU_EFI_FILE_GUID_BIOS_GUARD) == 0) |
53 | 0 | return "File:BiosGuard"; |
54 | 6.39k | if (g_strcmp0(guid, FU_EFI_SECTION_GUID_LZMA_COMPRESS) == 0) |
55 | 0 | return "Section:LzmaCompress"; |
56 | 6.39k | if (g_strcmp0(guid, FU_EFI_SECTION_GUID_TIANO_COMPRESS) == 0) |
57 | 0 | return "Section:TianoCompress"; |
58 | 6.39k | if (g_strcmp0(guid, FU_EFI_SECTION_GUID_SMBIOS_TABLE) == 0) |
59 | 0 | return "Section:SmbiosTable"; |
60 | 6.39k | if (g_strcmp0(guid, FU_EFI_SECTION_GUID_ESRT_TABLE) == 0) |
61 | 0 | return "Section:EsrtTable"; |
62 | 6.39k | if (g_strcmp0(guid, FU_EFI_SECTION_GUID_ACPI1_TABLE) == 0) |
63 | 0 | return "Section:Acpi1Table"; |
64 | 6.39k | if (g_strcmp0(guid, FU_EFI_SECTION_GUID_ACPI2_TABLE) == 0) |
65 | 0 | return "Section:Acpi2Table"; |
66 | 6.39k | return NULL; |
67 | 6.39k | } |
68 | | |
69 | | /** |
70 | | * fu_efi_parse_sections: |
71 | | * @firmware: #FuFirmware |
72 | | * @stream: a #GInputStream |
73 | | * @flags: #FuFirmwareParseFlags |
74 | | * @error: (nullable): optional return location for an error |
75 | | * |
76 | | * Parses a UEFI section. |
77 | | * |
78 | | * Returns: %TRUE for success |
79 | | * |
80 | | * Since: 2.0.0 |
81 | | **/ |
82 | | gboolean |
83 | | fu_efi_parse_sections(FuFirmware *firmware, |
84 | | GInputStream *stream, |
85 | | gsize offset, |
86 | | FuFirmwareParseFlags flags, |
87 | | GError **error) |
88 | 8.20k | { |
89 | 8.20k | gsize streamsz = 0; |
90 | | |
91 | 8.20k | if (!fu_input_stream_size(stream, &streamsz, error)) |
92 | 0 | return FALSE; |
93 | 30.5k | while (offset < streamsz) { |
94 | 25.2k | g_autoptr(FuFirmware) img = fu_efi_section_new(); |
95 | 25.2k | g_autoptr(GInputStream) partial_stream = NULL; |
96 | | |
97 | | /* parse maximum payload */ |
98 | 25.2k | partial_stream = |
99 | 25.2k | fu_partial_input_stream_new(stream, offset, streamsz - offset, error); |
100 | 25.2k | if (partial_stream == NULL) { |
101 | 0 | g_prefix_error_literal(error, "failed to cut payload: "); |
102 | 0 | return FALSE; |
103 | 0 | } |
104 | 25.2k | if (!fu_firmware_parse_stream(img, |
105 | 25.2k | partial_stream, |
106 | 25.2k | 0x0, |
107 | 25.2k | flags | FU_FIRMWARE_PARSE_FLAG_NO_SEARCH, |
108 | 25.2k | error)) { |
109 | 2.88k | g_prefix_error(error, |
110 | 2.88k | "failed to parse section of size 0x%x: ", |
111 | 2.88k | (guint)streamsz); |
112 | 2.88k | return FALSE; |
113 | 2.88k | } |
114 | | |
115 | | /* invalid */ |
116 | 22.3k | if (fu_firmware_get_size(img) == 0) { |
117 | 0 | g_set_error_literal(error, |
118 | 0 | FWUPD_ERROR, |
119 | 0 | FWUPD_ERROR_INVALID_DATA, |
120 | 0 | "section had zero size"); |
121 | 0 | return FALSE; |
122 | 0 | } |
123 | | |
124 | 22.3k | fu_firmware_set_offset(img, offset); |
125 | 22.3k | if (!fu_firmware_add_image(firmware, img, error)) |
126 | 71 | return FALSE; |
127 | | |
128 | | /* next! */ |
129 | 22.3k | offset += fu_common_align_up(fu_firmware_get_size(img), FU_FIRMWARE_ALIGNMENT_4); |
130 | 22.3k | } |
131 | | |
132 | | /* success */ |
133 | 5.25k | return TRUE; |
134 | 8.20k | } |
135 | | |
136 | | /** |
137 | | * fu_efi_timestamp_export: |
138 | | * @st: a #FuStructEfiTime |
139 | | * @bn: a #XbBuilderNode |
140 | | * |
141 | | * Exports an `EFI_TIME` to XML. |
142 | | * |
143 | | * Since: 2.0.17 |
144 | | **/ |
145 | | void |
146 | | fu_efi_timestamp_export(FuStructEfiTime *st, XbBuilderNode *bn) |
147 | 0 | { |
148 | 0 | if (fu_struct_efi_time_get_year(st) != 0) |
149 | 0 | fu_xmlb_builder_insert_kx(bn, "year", fu_struct_efi_time_get_year(st)); |
150 | 0 | if (fu_struct_efi_time_get_month(st) != 0) |
151 | 0 | fu_xmlb_builder_insert_kx(bn, "month", fu_struct_efi_time_get_month(st)); |
152 | 0 | if (fu_struct_efi_time_get_day(st) != 0) |
153 | 0 | fu_xmlb_builder_insert_kx(bn, "day", fu_struct_efi_time_get_day(st)); |
154 | 0 | if (fu_struct_efi_time_get_hour(st) != 0) |
155 | 0 | fu_xmlb_builder_insert_kx(bn, "hour", fu_struct_efi_time_get_hour(st)); |
156 | 0 | if (fu_struct_efi_time_get_minute(st) != 0) |
157 | 0 | fu_xmlb_builder_insert_kx(bn, "minute", fu_struct_efi_time_get_minute(st)); |
158 | 0 | if (fu_struct_efi_time_get_second(st) != 0) |
159 | 0 | fu_xmlb_builder_insert_kx(bn, "second", fu_struct_efi_time_get_second(st)); |
160 | 0 | } |
161 | | |
162 | | /** |
163 | | * fu_efi_timestamp_build: |
164 | | * @st: a #FuStructEfiTime |
165 | | * @n: a #XbNode |
166 | | * |
167 | | * Imports an `EFI_TIME` from XML. |
168 | | * |
169 | | * Since: 2.0.17 |
170 | | **/ |
171 | | void |
172 | | fu_efi_timestamp_build(FuStructEfiTime *st, XbNode *n) |
173 | 0 | { |
174 | 0 | guint64 tmp; |
175 | |
|
176 | 0 | tmp = xb_node_query_text_as_uint(n, "year", NULL); |
177 | 0 | if (tmp != G_MAXUINT64) |
178 | 0 | fu_struct_efi_time_set_year(st, tmp); |
179 | 0 | tmp = xb_node_query_text_as_uint(n, "month", NULL); |
180 | 0 | if (tmp != G_MAXUINT64) |
181 | 0 | fu_struct_efi_time_set_month(st, tmp); |
182 | 0 | tmp = xb_node_query_text_as_uint(n, "day", NULL); |
183 | 0 | if (tmp != G_MAXUINT64) |
184 | 0 | fu_struct_efi_time_set_day(st, tmp); |
185 | 0 | tmp = xb_node_query_text_as_uint(n, "hour", NULL); |
186 | 0 | if (tmp != G_MAXUINT64) |
187 | 0 | fu_struct_efi_time_set_hour(st, tmp); |
188 | 0 | tmp = xb_node_query_text_as_uint(n, "minute", NULL); |
189 | 0 | if (tmp != G_MAXUINT64) |
190 | 0 | fu_struct_efi_time_set_minute(st, tmp); |
191 | 0 | tmp = xb_node_query_text_as_uint(n, "second", NULL); |
192 | 0 | if (tmp != G_MAXUINT64) |
193 | 0 | fu_struct_efi_time_set_second(st, tmp); |
194 | 0 | } |