Coverage Report

Created: 2026-01-22 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/systemd/src/fundamental/chid-fundamental.c
Line
Count
Source
1
/* SPDX-License-Identifier: BSD-3-Clause */
2
3
/*
4
 * Based on Nikita Travkin's dtbloader implementation.
5
 * Copyright (c) 2024 Nikita Travkin <nikita@trvn.ru>
6
 *
7
 * https://github.com/TravMurav/dtbloader/blob/main/src/chid.c
8
 */
9
10
/*
11
 * Based on Linaro dtbloader implementation.
12
 * Copyright (c) 2019, Linaro. All rights reserved.
13
 *
14
 * https://github.com/aarch64-laptops/edk2/blob/dtbloader-app/EmbeddedPkg/Application/ConfigTableLoader/CHID.c
15
 */
16
17
#if SD_BOOT
18
#  include "efi-string.h"
19
#  include "util.h"
20
#else
21
#  include <byteswap.h>
22
#  include <string.h>
23
#  include <utf8.h>
24
0
#define strlen16 char16_strlen
25
#endif
26
27
#include "chid-fundamental.h"
28
#include "macro-fundamental.h"
29
#include "memory-util-fundamental.h"
30
#include "sha1-fundamental.h"
31
32
static void get_chid(
33
                const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX],
34
                uint32_t mask,
35
0
                EFI_GUID *ret_chid) {
36
37
0
        assert(mask != 0);
38
0
        assert(ret_chid);
39
40
0
        struct sha1_ctx ctx = {};
41
0
        sha1_init_ctx(&ctx);
42
43
0
        static const EFI_GUID namespace = { UINT32_C(0x12d8ff70), UINT16_C(0x7f4c), UINT16_C(0x7d4c), {} }; /* Swapped to BE */
44
0
        sha1_process_bytes(&namespace, sizeof(namespace), &ctx);
45
46
0
        for (ChidSmbiosFields i = 0; i < _CHID_SMBIOS_FIELDS_MAX; i++) {
47
0
                if (!FLAGS_SET(mask, UINT32_C(1) << i))
48
0
                        continue;
49
50
0
                if (!smbios_fields[i]) {
51
                        /* If some SMBIOS field is missing, don't generate the CHID, as per spec */
52
0
                        memzero(ret_chid, sizeof(EFI_GUID));
53
0
                        return;
54
0
                }
55
56
0
                if (i > 0)
57
0
                        sha1_process_bytes(L"&", 2, &ctx);
58
59
0
                sha1_process_bytes(smbios_fields[i], strlen16(smbios_fields[i]) * sizeof(char16_t), &ctx);
60
0
        }
61
62
0
        uint8_t hash[SHA1_DIGEST_SIZE];
63
0
        sha1_finish_ctx(&ctx, hash);
64
65
0
        assert_cc(sizeof(hash) >= sizeof(*ret_chid));
66
0
        memcpy(ret_chid, hash, sizeof(*ret_chid));
67
68
        /* Convert the resulting CHID back to little-endian: */
69
0
        ret_chid->Data1 = bswap_32(ret_chid->Data1);
70
0
        ret_chid->Data2 = bswap_16(ret_chid->Data2);
71
0
        ret_chid->Data3 = bswap_16(ret_chid->Data3);
72
73
        /* set specific bits according to RFC4122 Section 4.1.3 */
74
0
        ret_chid->Data3 = (ret_chid->Data3 & 0x0fff) | (5 << 12);
75
0
        ret_chid->Data4[0] = (ret_chid->Data4[0] & UINT8_C(0x3f)) | UINT8_C(0x80);
76
0
}
77
78
const uint32_t chid_smbios_table[CHID_TYPES_MAX] = {
79
        [0] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
80
              (UINT32_C(1) << CHID_SMBIOS_FAMILY) |
81
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
82
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) |
83
              (UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) |
84
              (UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) |
85
              (UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) |
86
              (UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR),
87
88
        [1] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
89
              (UINT32_C(1) << CHID_SMBIOS_FAMILY) |
90
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
91
              (UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) |
92
              (UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) |
93
              (UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) |
94
              (UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR),
95
96
        [2] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
97
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
98
              (UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) |
99
              (UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) |
100
              (UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) |
101
              (UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR),
102
103
        [3] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
104
              (UINT32_C(1) << CHID_SMBIOS_FAMILY) |
105
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
106
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) |
107
              (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) |
108
              (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
109
110
        [4] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
111
              (UINT32_C(1) << CHID_SMBIOS_FAMILY) |
112
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
113
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU),
114
115
        [5] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
116
              (UINT32_C(1) << CHID_SMBIOS_FAMILY) |
117
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME),
118
119
        [6] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
120
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) |
121
              (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) |
122
              (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
123
124
        [7] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
125
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU),
126
127
        [8] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
128
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
129
              (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) |
130
              (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
131
132
        [9] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
133
              (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME),
134
135
        [10] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
136
               (UINT32_C(1) << CHID_SMBIOS_FAMILY) |
137
               (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) |
138
               (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
139
140
        [11] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
141
               (UINT32_C(1) << CHID_SMBIOS_FAMILY),
142
143
        [12] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
144
               (UINT32_C(1) << CHID_SMBIOS_ENCLOSURE_TYPE),
145
146
        [13] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
147
               (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) |
148
               (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
149
150
        [14] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER),
151
152
        /* Extra non-standard CHIDs */
153
154
        [EXTRA_CHID_BASE + 0] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
155
                                (UINT32_C(1) << CHID_SMBIOS_FAMILY) |
156
                                (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME)|
157
                                (UINT32_C(1) << CHID_EDID_PANEL),
158
159
        [EXTRA_CHID_BASE + 1] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
160
                                (UINT32_C(1) << CHID_SMBIOS_FAMILY) |
161
                                (UINT32_C(1) << CHID_EDID_PANEL),
162
163
        [EXTRA_CHID_BASE + 2] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
164
                                (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) |
165
                                (UINT32_C(1) << CHID_EDID_PANEL),
166
};
167
168
0
void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]) {
169
0
        assert(smbios_fields);
170
0
        assert(ret_chids);
171
172
0
        for (size_t i = 0; i < CHID_TYPES_MAX; i++) {
173
0
                if (chid_smbios_table[i] == 0) {
174
0
                        memzero(&ret_chids[i], sizeof(EFI_GUID));
175
0
                        continue;
176
0
                }
177
178
0
                get_chid(smbios_fields, chid_smbios_table[i], &ret_chids[i]);
179
0
        }
180
0
}