Coverage Report

Created: 2025-08-24 07:10

/src/fwupd/libfwupdplugin/fu-acpi-table.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2023 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-acpi-table-struct.h"
10
#include "fu-acpi-table.h"
11
#include "fu-common.h"
12
#include "fu-input-stream.h"
13
14
/**
15
 * FuAcpiTable:
16
 *
17
 * An generic ACPI table.
18
 *
19
 * See also: [class@FuFirmware]
20
 */
21
22
typedef struct {
23
  guint8 revision;
24
  gchar *oem_id;
25
  gchar *oem_table_id;
26
  guint32 oem_revision;
27
} FuAcpiTablePrivate;
28
29
G_DEFINE_TYPE_WITH_PRIVATE(FuAcpiTable, fu_acpi_table, FU_TYPE_FIRMWARE)
30
31
0
#define GET_PRIVATE(o) (fu_acpi_table_get_instance_private(o))
32
33
static void
34
fu_acpi_table_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn)
35
0
{
36
0
  FuAcpiTable *self = FU_ACPI_TABLE(firmware);
37
0
  FuAcpiTablePrivate *priv = GET_PRIVATE(self);
38
0
  fu_xmlb_builder_insert_kx(bn, "revision", priv->revision);
39
0
  fu_xmlb_builder_insert_kv(bn, "oem_id", priv->oem_id);
40
0
  fu_xmlb_builder_insert_kv(bn, "oem_table_id", priv->oem_table_id);
41
0
  fu_xmlb_builder_insert_kx(bn, "oem_revision", priv->oem_revision);
42
0
}
43
44
/**
45
 * fu_acpi_table_get_revision:
46
 * @self: a #FuAcpiTable
47
 *
48
 * Gets the revision of the table.
49
 *
50
 * Returns: integer, default 0x0
51
 *
52
 * Since: 1.8.11
53
 **/
54
guint8
55
fu_acpi_table_get_revision(FuAcpiTable *self)
56
0
{
57
0
  FuAcpiTablePrivate *priv = GET_PRIVATE(self);
58
0
  g_return_val_if_fail(FU_IS_ACPI_TABLE(self), G_MAXUINT8);
59
0
  return priv->revision;
60
0
}
61
62
/**
63
 * fu_acpi_table_get_oem_id:
64
 * @self: a #FuAcpiTable
65
 *
66
 * Gets an optional OEM ID.
67
 *
68
 * Returns: a string, or %NULL
69
 *
70
 * Since: 1.8.11
71
 **/
72
const gchar *
73
fu_acpi_table_get_oem_id(FuAcpiTable *self)
74
0
{
75
0
  FuAcpiTablePrivate *priv = GET_PRIVATE(self);
76
0
  g_return_val_if_fail(FU_IS_ACPI_TABLE(self), NULL);
77
0
  return priv->oem_id;
78
0
}
79
80
/**
81
 * fu_acpi_table_get_oem_table_id:
82
 * @self: a #FuAcpiTable
83
 *
84
 * Gets an optional OEM table ID.
85
 *
86
 * Returns: a string, or %NULL
87
 *
88
 * Since: 1.8.11
89
 **/
90
const gchar *
91
fu_acpi_table_get_oem_table_id(FuAcpiTable *self)
92
0
{
93
0
  FuAcpiTablePrivate *priv = GET_PRIVATE(self);
94
0
  g_return_val_if_fail(FU_IS_ACPI_TABLE(self), NULL);
95
0
  return priv->oem_table_id;
96
0
}
97
98
/**
99
 * fu_acpi_table_get_oem_revision:
100
 * @self: a #FuAcpiTable
101
 *
102
 * Gets the OEM revision.
103
 *
104
 * Returns: integer, default 0x0
105
 *
106
 * Since: 1.8.11
107
 **/
108
guint32
109
fu_acpi_table_get_oem_revision(FuAcpiTable *self)
110
0
{
111
0
  FuAcpiTablePrivate *priv = GET_PRIVATE(self);
112
0
  g_return_val_if_fail(FU_IS_ACPI_TABLE(self), G_MAXUINT32);
113
0
  return priv->oem_revision;
114
0
}
115
116
static gboolean
117
fu_acpi_table_parse(FuFirmware *firmware,
118
        GInputStream *stream,
119
        FuFirmwareParseFlags flags,
120
        GError **error)
121
0
{
122
0
  FuAcpiTable *self = FU_ACPI_TABLE(firmware);
123
0
  FuAcpiTablePrivate *priv = GET_PRIVATE(self);
124
0
  gsize streamsz = 0;
125
0
  guint32 length;
126
0
  g_autofree gchar *id = NULL;
127
0
  g_autoptr(FuStructAcpiTable) st = NULL;
128
129
  /* parse */
130
0
  st = fu_struct_acpi_table_parse_stream(stream, 0x0, error);
131
0
  if (st == NULL)
132
0
    return FALSE;
133
0
  id = fu_struct_acpi_table_get_signature(st);
134
0
  fu_firmware_set_id(FU_FIRMWARE(self), id);
135
0
  priv->revision = fu_struct_acpi_table_get_revision(st);
136
0
  priv->oem_id = fu_struct_acpi_table_get_oem_id(st);
137
0
  priv->oem_table_id = fu_struct_acpi_table_get_oem_table_id(st);
138
0
  priv->oem_revision = fu_struct_acpi_table_get_oem_revision(st);
139
140
  /* length */
141
0
  length = fu_struct_acpi_table_get_length(st);
142
0
  if (!fu_input_stream_size(stream, &streamsz, error))
143
0
    return FALSE;
144
0
  if (length > streamsz || length < st->len) {
145
0
    g_set_error(error,
146
0
          FWUPD_ERROR,
147
0
          FWUPD_ERROR_INVALID_DATA,
148
0
          "table length not valid: got 0x%x but expected 0x%x",
149
0
          (guint)streamsz,
150
0
          (guint)length);
151
0
    return FALSE;
152
0
  }
153
0
  fu_firmware_set_size(firmware, length);
154
155
  /* checksum */
156
0
  if ((flags & FU_FIRMWARE_PARSE_FLAG_IGNORE_CHECKSUM) == 0) {
157
0
    guint8 checksum_actual = 0;
158
0
    if (!fu_input_stream_compute_sum8(stream, &checksum_actual, error))
159
0
      return FALSE;
160
0
    if (checksum_actual != 0x0) {
161
0
      guint8 checksum = fu_struct_acpi_table_get_checksum(st);
162
0
      g_set_error(error,
163
0
            FWUPD_ERROR,
164
0
            FWUPD_ERROR_INTERNAL,
165
0
            "CRC failed, expected 0x%02x, got 0x%02x",
166
0
            (guint)checksum - checksum_actual,
167
0
            checksum);
168
0
      return FALSE;
169
0
    }
170
0
  }
171
172
  /* success */
173
0
  return TRUE;
174
0
}
175
176
static void
177
fu_acpi_table_init(FuAcpiTable *self)
178
0
{
179
0
  fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_HAS_CHECKSUM);
180
0
}
181
182
static void
183
fu_acpi_table_finalize(GObject *object)
184
0
{
185
0
  FuAcpiTable *self = FU_ACPI_TABLE(object);
186
0
  FuAcpiTablePrivate *priv = GET_PRIVATE(self);
187
0
  g_free(priv->oem_table_id);
188
0
  g_free(priv->oem_id);
189
0
  G_OBJECT_CLASS(fu_acpi_table_parent_class)->finalize(object);
190
0
}
191
192
static void
193
fu_acpi_table_class_init(FuAcpiTableClass *klass)
194
0
{
195
0
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
196
0
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
197
0
  object_class->finalize = fu_acpi_table_finalize;
198
0
  firmware_class->parse = fu_acpi_table_parse;
199
0
  firmware_class->export = fu_acpi_table_export;
200
0
}
201
202
/**
203
 * fu_acpi_table_new:
204
 *
205
 * Creates a new #FuFirmware
206
 *
207
 * Since: 1.8.11
208
 **/
209
FuFirmware *
210
fu_acpi_table_new(void)
211
0
{
212
0
  return FU_FIRMWARE(g_object_new(FU_TYPE_ACPI_TABLE, NULL));
213
0
}