Coverage Report

Created: 2026-01-10 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/plugins/cros-ec/fu-cros-ec-firmware.c
Line
Count
Source
1
/*
2
 * Copyright 2020 Benson Leung <bleung@chromium.org>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
#include "config.h"
8
9
#include "fu-cros-ec-common.h"
10
#include "fu-cros-ec-firmware.h"
11
12
#define MAXSECTIONS 2
13
14
struct _FuCrosEcFirmware {
15
  FuFmapFirmware parent_instance;
16
  GPtrArray *sections;
17
};
18
19
12.0k
G_DEFINE_TYPE(FuCrosEcFirmware, fu_cros_ec_firmware, FU_TYPE_FMAP_FIRMWARE)
20
12.0k
21
12.0k
gboolean
22
12.0k
fu_cros_ec_firmware_pick_sections(FuCrosEcFirmware *self, guint32 writeable_offset, GError **error)
23
12.0k
{
24
0
  gboolean found = FALSE;
25
26
0
  for (gsize i = 0; i < self->sections->len; i++) {
27
0
    FuCrosEcFirmwareSection *section = g_ptr_array_index(self->sections, i);
28
0
    guint32 offset = section->offset;
29
30
0
    if (offset != writeable_offset)
31
0
      continue;
32
33
0
    section->ustatus = FU_CROS_EC_FIRMWARE_UPGRADE_STATUS_NEEDED;
34
0
    found = TRUE;
35
0
  }
36
37
0
  if (!found) {
38
0
    g_set_error(error,
39
0
          FWUPD_ERROR,
40
0
          FWUPD_ERROR_INVALID_DATA,
41
0
          "no writable section found with offset: 0x%x",
42
0
          writeable_offset);
43
0
    return FALSE;
44
0
  }
45
46
  /* success */
47
0
  return TRUE;
48
0
}
49
50
GPtrArray *
51
fu_cros_ec_firmware_get_needed_sections(FuCrosEcFirmware *self, GError **error)
52
0
{
53
0
  g_autoptr(GPtrArray) needed_sections = g_ptr_array_new();
54
55
0
  for (guint i = 0; i < self->sections->len; i++) {
56
0
    FuCrosEcFirmwareSection *section = g_ptr_array_index(self->sections, i);
57
0
    if (section->ustatus != FU_CROS_EC_FIRMWARE_UPGRADE_STATUS_NEEDED)
58
0
      continue;
59
0
    g_ptr_array_add(needed_sections, section);
60
0
  }
61
0
  if (needed_sections->len == 0) {
62
0
    g_set_error_literal(error,
63
0
            FWUPD_ERROR,
64
0
            FWUPD_ERROR_INVALID_DATA,
65
0
            "no needed sections");
66
0
    return NULL;
67
0
  }
68
69
  /* success */
70
0
  return g_steal_pointer(&needed_sections);
71
0
}
72
73
gboolean
74
fu_cros_ec_firmware_ensure_version(FuCrosEcFirmware *self, GError **error)
75
0
{
76
0
  for (gsize i = 0; i < self->sections->len; i++) {
77
0
    gboolean rw = FALSE;
78
0
    FuCrosEcFirmwareSection *section = g_ptr_array_index(self->sections, i);
79
0
    const gchar *fmap_name;
80
0
    const gchar *fmap_fwid_name;
81
0
    g_autoptr(FuCrosEcVersion) version = NULL;
82
0
    g_autoptr(FuFirmware) img = NULL;
83
0
    g_autoptr(FuFirmware) fwid_img = NULL;
84
0
    g_autoptr(GBytes) payload_bytes = NULL;
85
0
    g_autoptr(GBytes) fwid_bytes = NULL;
86
87
0
    if (g_strcmp0(section->name, "RO") == 0) {
88
0
      fmap_name = "EC_RO";
89
0
      fmap_fwid_name = "RO_FRID";
90
0
    } else if (g_strcmp0(section->name, "RW") == 0) {
91
0
      rw = TRUE;
92
0
      fmap_name = "EC_RW";
93
0
      fmap_fwid_name = "RW_FWID";
94
0
    } else {
95
0
      g_set_error_literal(error,
96
0
              FWUPD_ERROR,
97
0
              FWUPD_ERROR_INVALID_DATA,
98
0
              "incorrect section name");
99
0
      return FALSE;
100
0
    }
101
102
0
    img = fu_firmware_get_image_by_id(FU_FIRMWARE(self), fmap_name, error);
103
0
    if (img == NULL) {
104
0
      g_prefix_error(error, "%s image not found: ", fmap_name);
105
0
      return FALSE;
106
0
    }
107
108
0
    fwid_img = fu_firmware_get_image_by_id(FU_FIRMWARE(self), fmap_fwid_name, error);
109
0
    if (fwid_img == NULL) {
110
0
      g_prefix_error(error, "%s image not found: ", fmap_fwid_name);
111
0
      return FALSE;
112
0
    }
113
0
    fwid_bytes = fu_firmware_write(fwid_img, error);
114
0
    if (fwid_bytes == NULL) {
115
0
      g_prefix_error(error, "unable to get bytes from %s: ", fmap_fwid_name);
116
0
      return FALSE;
117
0
    }
118
0
    if (!fu_memcpy_safe((guint8 *)section->raw_version,
119
0
            FU_FMAP_FIRMWARE_STRLEN,
120
0
            0x0,
121
0
            g_bytes_get_data(fwid_bytes, NULL),
122
0
            g_bytes_get_size(fwid_bytes),
123
0
            0x0,
124
0
            g_bytes_get_size(fwid_bytes),
125
0
            error))
126
0
      return FALSE;
127
128
0
    payload_bytes = fu_firmware_write(img, error);
129
0
    if (payload_bytes == NULL) {
130
0
      g_prefix_error(error, "unable to get bytes from %s: ", fmap_name);
131
0
      return FALSE;
132
0
    }
133
0
    section->offset = fu_firmware_get_addr(img);
134
0
    section->size = g_bytes_get_size(payload_bytes);
135
0
    fu_firmware_set_version(img, section->raw_version);
136
0
    section->image_idx = fu_firmware_get_idx(img);
137
138
0
    version = fu_cros_ec_version_parse(section->raw_version, error);
139
0
    if (version == NULL) {
140
0
      g_prefix_error(error,
141
0
               "failed parsing firmware's version: %32s: ",
142
0
               section->raw_version);
143
0
      return FALSE;
144
0
    }
145
146
0
    if (rw) {
147
0
      g_autoptr(FuCrosEcVersion) version_rw = NULL;
148
0
      version_rw = fu_cros_ec_version_parse(section->raw_version, error);
149
0
      if (version_rw == NULL) {
150
0
        g_prefix_error(error,
151
0
                 "failed parsing firmware's version: %32s: ",
152
0
                 section->raw_version);
153
0
        return FALSE;
154
0
      }
155
0
      fu_firmware_set_version(FU_FIRMWARE(self), version_rw->triplet);
156
0
    }
157
0
  }
158
159
  /* success */
160
0
  return TRUE;
161
0
}
162
163
static void
164
fu_cros_ec_firmware_init(FuCrosEcFirmware *self)
165
6.04k
{
166
6.04k
  FuCrosEcFirmwareSection *section;
167
168
6.04k
  self->sections = g_ptr_array_new_with_free_func(g_free);
169
6.04k
  section = g_new0(FuCrosEcFirmwareSection, 1);
170
6.04k
  section->name = "RO";
171
6.04k
  g_ptr_array_add(self->sections, section);
172
6.04k
  section = g_new0(FuCrosEcFirmwareSection, 1);
173
6.04k
  section->name = "RW";
174
6.04k
  g_ptr_array_add(self->sections, section);
175
176
6.04k
  fu_firmware_add_image_gtype(FU_FIRMWARE(self), FU_TYPE_FIRMWARE);
177
6.04k
}
178
179
static void
180
fu_cros_ec_firmware_finalize(GObject *object)
181
6.04k
{
182
6.04k
  FuCrosEcFirmware *self = FU_CROS_EC_FIRMWARE(object);
183
6.04k
  g_ptr_array_free(self->sections, TRUE);
184
6.04k
  G_OBJECT_CLASS(fu_cros_ec_firmware_parent_class)->finalize(object);
185
6.04k
}
186
187
static void
188
fu_cros_ec_firmware_class_init(FuCrosEcFirmwareClass *klass)
189
1
{
190
1
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
191
1
  object_class->finalize = fu_cros_ec_firmware_finalize;
192
1
}
193
194
FuFirmware *
195
fu_cros_ec_firmware_new(void)
196
0
{
197
0
  return g_object_new(FU_TYPE_CROS_EC_FIRMWARE, NULL);
198
0
}