coreboot-kgpe-d16/util/supermicro/smcbiosinfo/smcbiosinfo.c
Patrick Georgi 02363b5e46 treewide: Move "is part of the coreboot project" line in its own comment
That makes it easier to identify "license only" headers (because they
are now license only)

Script line used for that:
  perl -i -p0e 's|/\*.*\n.*This file is part of the coreboot project.*\n.*\*|/* This file is part of the coreboot project. */\n/*|' # ...filelist...

Change-Id: I2280b19972e37c36d8c67a67e0320296567fa4f6
Signed-off-by: Patrick Georgi <pgeorgi@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41065
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
Reviewed-by: HAOUAS Elyes <ehaouas@noos.fr>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
2020-05-06 22:20:28 +00:00

281 lines
6.4 KiB
C

/* This file is part of the coreboot project. */
/*
* Copyright (C) 2019 9elements Agency GmbH <patrick.rudolph@9elements.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#include <errno.h>
#include <stdarg.h>
/* Place the following struct somewhere in the ROM: */
struct SMC_BIOS_Update {
uint8_t magic0[4]; // always 0xaa00b1ed
char magic1[4]; // always $FID
uint8_t magic2[2]; // always 0x7804
uint8_t space0; // always zero
// SMCinfotool doesn't care for the first letter
// The BMC webinterface does.
char boardid[9]; // "100000000"
uint8_t space1[15]; // unknown data
uint8_t space2; // always 0x1f
char ukn_majorVer[2];// unknown
uint8_t space3; // always zero
char ukn_minorVer[2];// unknown
uint8_t space4; // always zero
char majorVer[3]; // BIOS major version
char minorVer[2]; // BIOS minor version
uint8_t space5; // always zero
uint16_t year; // year
uint8_t month; // month
uint8_t day; // day
uint32_t space6; // unknown data
uint8_t space7; // all ones
char str[15]; // "SUPERMSMCI--MB1"
uint8_t space8[3]; // always zero
uint64_t space9[6]; // all ones
} __packed;
static const char *optstring = "b:i:o:h";
static struct option long_options[] = {
{"boardid", required_argument, 0, 'b' },
{"input", required_argument, 0, 'i' },
{"output", required_argument, 0, 'o' },
{"help", no_argument, 0, 'h' },
};
static void usage(void)
{
printf("smcbiosinfo: Create BIOSInfo for BMC BIOS updates\n");
printf("Usage: smcbiosinfo [options] -i build.h -b <boardid> -o <filename>\n");
printf("-b | --boardid <ID> The board ID assigned by SMC\n");
printf("-i | --input <FILE> The build.h file to parse\n");
printf("-o | --output <FILE> The file to generate\n");
printf("-h | --help Print this help\n");
}
static int bcd2int(int hex)
{
if (hex > 0xff)
return -1;
return ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F);
}
static char *get_line(char *fn, char *match)
{
ssize_t read;
char *line = NULL;
char *ret = NULL;
size_t len = 0;
FILE *fp = fopen(fn, "r");
if (fp == NULL) {
fprintf(stderr, "E: Couldn't open file '%s'\n", fn);
return NULL;
}
while ((read = getline(&line, &len, fp)) != -1) {
if (strstr(line, match) != NULL) {
ret = strdup(strstr(line, match) + strlen(match));
break;
}
}
if (!ret)
fprintf(stderr, "E: %s not found in %s\n", match, fn);
fclose(fp);
return ret;
}
static int get_line_as_int(char *fn, char *match, int bcd)
{
int ret = -1;
char *s = get_line(fn, match);
if (s && strlen(s) > 0) {
char *endptr;
ret = strtol(s, &endptr, 0);
if (*endptr != '\0' && *endptr != '\n') {
fprintf(stderr, "E: Couldn't parse number for key '%s'\n", match);
return -1;
}
if (bcd)
ret = bcd2int(ret);
free(s);
} else {
fprintf(stderr, "E: Got invalid line for key '%s'\n", match);
}
return ret;
}
int main(int argc, char **argv)
{
int c;
int ret = 1;
char *filename = NULL;
char *inputfilename = NULL;
char *boardid = NULL;
int num;
while (1) {
int optindex = 0;
c = getopt_long(argc, argv, optstring, long_options, &optindex);
if (c == -1)
break;
switch (c) {
case 'b':
boardid = strdup(optarg);
break;
case 'i':
inputfilename = strdup(optarg);
break;
case 'o':
filename = strdup(optarg);
break;
case 'h':
ret = 0; /* fallthrough */
case '?':
usage();
goto out;
default:
break;
}
}
if (!inputfilename) {
fprintf(stderr, "E: Must specify build.h filename\n");
goto out;
}
if (!filename) {
fprintf(stderr, "E: Must specify a destination filename\n");
goto out;
}
if (!boardid || strlen(boardid) == 0) {
fprintf(stderr, "E: Board ID must be set\n");
goto out;
}
if (strlen(boardid) > 8) {
fprintf(stderr, "E: Board ID must be less than 8 characters\n");
goto out;
}
// generate the table
struct SMC_BIOS_Update sbu = {
{0xed, 0xb1, 0x00, 0xaa},
"$FID",
{0x04, 0x78},
0, // space
"100000000", // boardid
{}, // unknown data
0x1f, // space
"05", // unknown data
0, // zero
"06", // unknown data
0, // zero
"000", // major
"00", // minor
0, // zero
0, // year
0, // month
0, //day
0, // unknown data
0xff, // space
"SUPERMSMCI--MB1",
{0, 0, 0}, // all zero
{~0, ~0, ~0, ~0, ~0, ~0}, // all ones
};
num = get_line_as_int(inputfilename, "COREBOOT_MAJOR_VERSION", 0);
if (num < 0)
goto out;
if (num < 999) {
char tmp[4];
snprintf(tmp, sizeof(tmp), "%03d", num);
memcpy(&sbu.majorVer, &tmp, sizeof(sbu.majorVer));
} else {
fprintf(stderr, "E: Unsupported coreboot major version\n");
goto out;
}
num = get_line_as_int(inputfilename, "COREBOOT_MINOR_VERSION", 0);
if (num < 0)
goto out;
if (num < 99) {
char tmp[3];
snprintf(tmp, sizeof(tmp), "%02d", num);
memcpy(&sbu.minorVer, &tmp, sizeof(sbu.minorVer));
} else {
fprintf(stderr, "E: Unsupported coreboot minor version\n");
goto out;
}
num = get_line_as_int(inputfilename, "COREBOOT_BUILD_YEAR_BCD", 1);
if (num < 0)
goto out;
sbu.year = 2000 + num;
num = get_line_as_int(inputfilename, "COREBOOT_BUILD_MONTH_BCD", 1);
if (num < 0)
goto out;
sbu.month = num;
num = get_line_as_int(inputfilename, "COREBOOT_BUILD_DAY_BCD", 1);
if (num < 0)
goto out;
sbu.day = num;
memcpy(&sbu.boardid[1], boardid, strlen(boardid));
// write the table
FILE *fd = fopen(filename, "wb");
if (!fd) {
fprintf(stderr, "E: %s open failed: %s\n", filename, strerror(errno));
goto out;
}
if (fwrite(&sbu, 1, sizeof(sbu), fd) != sizeof(sbu)) {
fprintf(stderr, "E: %s write failed: %s\n", filename, strerror(errno));
fclose(fd);
goto out;
}
if (fclose(fd)) {
fprintf(stderr, "E: %s close failed: %s\n", filename, strerror(errno));
goto out;
}
ret = 0;
out:
if (ret > 0)
fprintf(stderr, "E: Error creating '%s'\n", filename);
free(filename);
exit(ret);
return 0;
}