arch/arm64: Support FEAT_CCIDX
[coreboot2.git] / util / supermicro / smcbiosinfo / smcbiosinfo.c
blob6a27ba7a773b661d43282c728e8b6160737fd99c
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <stdint.h>
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <getopt.h>
11 #include <errno.h>
12 #include <stdarg.h>
14 /* Place the following struct somewhere in the ROM: */
15 struct SMC_BIOS_Update {
16 uint8_t magic0[4]; // always 0xaa00b1ed
17 char magic1[4]; // always $FID
18 uint8_t magic2[2]; // always 0x7804
19 uint8_t space0; // always zero
20 // SMCinfotool doesn't care for the first letter
21 // The BMC webinterface does.
22 char boardid[9]; // "100000000"
23 uint8_t space1[15]; // unknown data
24 uint8_t space2; // always 0x1f
25 char ukn_majorVer[2];// unknown
26 uint8_t space3; // always zero
27 char ukn_minorVer[2];// unknown
28 uint8_t space4; // always zero
29 char majorVer[3]; // BIOS major version
30 char minorVer[2]; // BIOS minor version
31 uint8_t space5; // always zero
32 uint16_t year; // year
33 uint8_t month; // month
34 uint8_t day; // day
35 uint32_t space6; // unknown data
36 uint8_t space7; // all ones
37 char str[15]; // "SUPERMSMCI--MB1"
38 uint8_t space8[3]; // always zero
39 uint64_t space9[6]; // all ones
40 } __packed;
42 static const char *optstring = "b:i:o:h";
44 static struct option long_options[] = {
45 {"boardid", required_argument, 0, 'b' },
46 {"input", required_argument, 0, 'i' },
47 {"output", required_argument, 0, 'o' },
48 {"help", no_argument, 0, 'h' },
51 static void usage(void)
53 printf("smcbiosinfo: Create BIOSInfo for BMC BIOS updates\n");
54 printf("Usage: smcbiosinfo [options] -i build.h -b <boardid> -o <filename>\n");
55 printf("-b | --boardid <ID> The board ID assigned by SMC\n");
56 printf("-i | --input <FILE> The build.h file to parse\n");
57 printf("-o | --output <FILE> The file to generate\n");
58 printf("-h | --help Print this help\n");
61 static int bcd2int(int hex)
63 if (hex > 0xff)
64 return -1;
65 return ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F);
68 static char *get_line(char *fn, char *match)
70 ssize_t read;
71 char *line = NULL;
72 char *ret = NULL;
73 size_t len = 0;
75 FILE *fp = fopen(fn, "r");
76 if (fp == NULL) {
77 fprintf(stderr, "E: Couldn't open file '%s'\n", fn);
78 return NULL;
81 while ((read = getline(&line, &len, fp)) != -1) {
82 if (strstr(line, match) != NULL) {
83 ret = strdup(strstr(line, match) + strlen(match));
84 break;
88 if (!ret)
89 fprintf(stderr, "E: %s not found in %s\n", match, fn);
91 fclose(fp);
92 return ret;
95 static int get_line_as_int(char *fn, char *match, int bcd)
97 int ret = -1;
98 char *s = get_line(fn, match);
99 if (s && strlen(s) > 0) {
100 char *endptr;
101 ret = strtol(s, &endptr, 0);
102 if (*endptr != '\0' && *endptr != '\n') {
103 fprintf(stderr, "E: Couldn't parse number for key '%s'\n", match);
104 return -1;
106 if (bcd)
107 ret = bcd2int(ret);
108 free(s);
109 } else {
110 fprintf(stderr, "E: Got invalid line for key '%s'\n", match);
113 return ret;
116 int main(int argc, char **argv)
118 int c;
119 int ret = 1;
120 char *filename = NULL;
121 char *inputfilename = NULL;
122 char *boardid = NULL;
123 int num;
125 while (1) {
126 int optindex = 0;
128 c = getopt_long(argc, argv, optstring, long_options, &optindex);
130 if (c == -1)
131 break;
133 switch (c) {
134 case 'b':
135 boardid = strdup(optarg);
136 break;
137 case 'i':
138 inputfilename = strdup(optarg);
139 break;
140 case 'o':
141 filename = strdup(optarg);
142 break;
143 case 'h':
144 ret = 0; /* fallthrough */
145 case '?':
146 usage();
147 goto out;
148 default:
149 break;
153 if (!inputfilename) {
154 fprintf(stderr, "E: Must specify build.h filename\n");
155 goto out;
157 if (!filename) {
158 fprintf(stderr, "E: Must specify a destination filename\n");
159 goto out;
162 if (!boardid || strlen(boardid) == 0) {
163 fprintf(stderr, "E: Board ID must be set\n");
164 goto out;
166 if (strlen(boardid) > 8) {
167 fprintf(stderr, "E: Board ID must be less than 8 characters\n");
168 goto out;
171 // generate the table
173 struct SMC_BIOS_Update sbu = {
174 {0xed, 0xb1, 0x00, 0xaa},
175 "$FID",
176 {0x04, 0x78},
177 0, // space
178 "100000000", // boardid
179 {}, // unknown data
180 0x1f, // space
181 "05", // unknown data
182 0, // zero
183 "06", // unknown data
184 0, // zero
185 "000", // major
186 "00", // minor
187 0, // zero
188 0, // year
189 0, // month
190 0, //day
191 0, // unknown data
192 0xff, // space
193 "SUPERMSMCI--MB1",
194 {0, 0, 0}, // all zero
195 {~0, ~0, ~0, ~0, ~0, ~0}, // all ones
198 num = get_line_as_int(inputfilename, "COREBOOT_MAJOR_VERSION", 0);
199 if (num < 0)
200 goto out;
202 if (num < 999) {
203 char tmp[4];
204 snprintf(tmp, sizeof(tmp), "%03d", num);
205 memcpy(&sbu.majorVer, &tmp, sizeof(sbu.majorVer));
206 } else {
207 fprintf(stderr, "E: Unsupported coreboot major version\n");
208 goto out;
211 num = get_line_as_int(inputfilename, "COREBOOT_MINOR_VERSION", 0);
212 if (num < 0)
213 goto out;
215 if (num < 99) {
216 char tmp[3];
217 snprintf(tmp, sizeof(tmp), "%02d", num);
218 memcpy(&sbu.minorVer, &tmp, sizeof(sbu.minorVer));
219 } else {
220 fprintf(stderr, "E: Unsupported coreboot minor version\n");
221 goto out;
224 num = get_line_as_int(inputfilename, "COREBOOT_BUILD_YEAR_BCD", 1);
225 if (num < 0)
226 goto out;
227 sbu.year = 2000 + num;
229 num = get_line_as_int(inputfilename, "COREBOOT_BUILD_MONTH_BCD", 1);
230 if (num < 0)
231 goto out;
232 sbu.month = num;
234 num = get_line_as_int(inputfilename, "COREBOOT_BUILD_DAY_BCD", 1);
235 if (num < 0)
236 goto out;
237 sbu.day = num;
239 memcpy(&sbu.boardid[1], boardid, strlen(boardid));
241 // write the table
242 FILE *fd = fopen(filename, "wb");
243 if (!fd) {
244 fprintf(stderr, "E: %s open failed: %s\n", filename, strerror(errno));
245 goto out;
248 if (fwrite(&sbu, 1, sizeof(sbu), fd) != sizeof(sbu)) {
249 fprintf(stderr, "E: %s write failed: %s\n", filename, strerror(errno));
250 fclose(fd);
251 goto out;
254 if (fclose(fd)) {
255 fprintf(stderr, "E: %s close failed: %s\n", filename, strerror(errno));
256 goto out;
259 ret = 0;
260 out:
261 if (ret > 0)
262 fprintf(stderr, "E: Error creating '%s'\n", filename);
264 free(filename);
266 exit(ret);
268 return 0;