diff options
Diffstat (limited to 'roms/skiboot/external/gard')
51 files changed, 1834 insertions, 0 deletions
diff --git a/roms/skiboot/external/gard/.gitignore b/roms/skiboot/external/gard/.gitignore new file mode 100644 index 000000000..7e8f83f20 --- /dev/null +++ b/roms/skiboot/external/gard/.gitignore @@ -0,0 +1,11 @@ +o +*.d +ccan +common +common-ast-sf-ctrl.c +common-io.h +gard +test/test.sh +libflash +make_version.sh +gard-*.tar diff --git a/roms/skiboot/external/gard/Makefile b/roms/skiboot/external/gard/Makefile new file mode 100644 index 000000000..e249cf846 --- /dev/null +++ b/roms/skiboot/external/gard/Makefile @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: Apache-2.0 +# This tool is a linux userland tool and should be completely stand alone +include rules.mk +GET_ARCH = ../../external/common/get_arch.sh +include ../../external/common/rules.mk + +all: links arch_links $(EXE) + +.PHONY: coverage +coverage: CFLAGS += -fprofile-arcs -ftest-coverage +coverage: check + +#Rebuild version.o so that the the version always matches +#what the test suite will get from ./make_version.sh +check: version.o all + @ln -sf ../../make_version.sh make_version.sh + @ln -sf ../../test/test.sh test/test.sh + @test/test-gard + +.PHONY: VERSION-always +.version: VERSION-always + @echo $(GARD_VERSION) > $@.tmp + @cmp -s $@ $@.tmp || cp $@.tmp $@ + @rm -f $@.tmp + +.PHONY: dist +#File is named $(GARD_VERSION).tar because the expectation is that gard- +#is always at the start of the verion. This remains consistent with skiboot +#version strings +dist: arch_links links .version + @find -L ../gard/ -iname '*.[ch]' -print0 | xargs -0 tar -rhf $(GARD_VERSION).tar + @tar --transform 's/Makefile.dist/Makefile/' -rhf $(GARD_VERSION).tar \ + ../gard/Makefile.dist ../gard/rules.mk \ + ../gard/.version ../gard/common/* + +clean: arch_clean + rm -f $(OBJS) $(EXE) *.o *.d .version .version.tmp + +distclean: clean + rm -f *.c~ *.h~ *.sh~ Makefile~ config.mk~ libflash/*.c~ libflash/*.h~ + rm -f libflash ccan common io.h version.c make_version.sh + rm -f gard-*.tar + diff --git a/roms/skiboot/external/gard/Makefile.dist b/roms/skiboot/external/gard/Makefile.dist new file mode 100644 index 000000000..e03ad230a --- /dev/null +++ b/roms/skiboot/external/gard/Makefile.dist @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +#Prevent make from trying to remake arch links symlinks +#which are fixed files now +ARCH_LINKS := + +GARD_VERSION := $(shell cat .version) + +include rules.mk +GET_ARCH = common/get_arch.sh +include common/rules.mk + +all: $(EXE) + +clean: + rm -f $(OBJS) *.o +distclean: clean + rm -f $(EXE) diff --git a/roms/skiboot/external/gard/config.h b/roms/skiboot/external/gard/config.h new file mode 100644 index 000000000..42aef6ddb --- /dev/null +++ b/roms/skiboot/external/gard/config.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * For CCAN + * + * Copyright 2015-2017 IBM Corp + */ + +#include <endian.h> +#include <byteswap.h> + +#define HAVE_TYPEOF 1 +#define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1 + +#ifndef HAVE_LITTLE_ENDIAN +#ifndef HAVE_BIG_ENDIAN +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define HAVE_LITTLE_ENDIAN 1 +#else +#define HAVE_BIG_ENDIAN 1 +#endif +#endif +#endif + +/* Keep -Wundef happy by defining whatever isn't on commandline to 0 */ +#if defined(HAVE_LITTLE_ENDIAN) && HAVE_LITTLE_ENDIAN +#define HAVE_BIG_ENDIAN 0 +#endif +#if defined(HAVE_BIG_ENDIAN) && HAVE_BIG_ENDIAN +#define HAVE_LITTLE_ENDIAN 0 +#endif + +#define HAVE_BYTESWAP_H 1 +#define HAVE_BSWAP_64 1 diff --git a/roms/skiboot/external/gard/gard.c b/roms/skiboot/external/gard/gard.c new file mode 100644 index 000000000..53a26d0e9 --- /dev/null +++ b/roms/skiboot/external/gard/gard.c @@ -0,0 +1,1017 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * Manipulate GARD records in the GARD partition + * + * Copyright 2013-2019 IBM Corp. + */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <dirent.h> +#include <limits.h> +#include <inttypes.h> +#include <ctype.h> + +#include <ccan/array_size/array_size.h> + +#include <mtd/mtd-abi.h> + +#include <getopt.h> + +#include <libflash/libflash.h> +#include <libflash/libffs.h> +#include <libflash/file.h> +#include <libflash/blocklevel.h> +#include <common/arch_flash.h> + +#include "gard.h" + +#define FDT_PATH "/proc/device-tree" +#define FDT_FSP_NODE FDT_PATH"/fsps" +#define FDT_ACTIVE_FLASH_PATH FDT_PATH"/chosen/ibm,system-flash" +#define SYSFS_MTD_PATH "/sys/class/mtd/" +#define FLASH_GARD_PART "GUARD" + +#define VPNOR_GARD_DIR "/media/pnor-prsv" +#define VPNOR_GARD_FILE VPNOR_GARD_DIR"/GUARD" + +/* Full gard version number (possibly includes gitid). */ +extern const char version[]; + + +#define __unused __attribute__((unused)) + +struct gard_ctx { + uint32_t f_size; + uint32_t f_pos; + + uint32_t gard_part_idx; + uint32_t gard_data_pos; + uint32_t gard_data_len; + + struct blocklevel_device *bl; + struct ffs_handle *ffs; +}; + +static void show_flash_err(int rc) +{ + switch (rc) { + case FFS_ERR_BAD_MAGIC: + fprintf(stderr, "libffs bad magic\n"); + break; + case FFS_ERR_BAD_VERSION: + fprintf(stderr, "libffs bad version\n"); + break; + case FFS_ERR_BAD_CKSUM: + fprintf(stderr, "libffs bad check sum\n"); + break; + case FFS_ERR_PART_NOT_FOUND: + fprintf(stderr, "libffs flash partition not found\n"); + break; + /* ------- */ + case FLASH_ERR_MALLOC_FAILED: + fprintf(stderr, "libflash malloc failed\n"); + break; + case FLASH_ERR_CHIP_UNKNOWN: + fprintf(stderr, "libflash unknown flash chip\n"); + break; + case FLASH_ERR_PARM_ERROR: + fprintf(stderr, "libflash parameter error\n"); + break; + case FLASH_ERR_ERASE_BOUNDARY: + fprintf(stderr, "libflash erase boundary error\n"); + break; + case FLASH_ERR_WREN_TIMEOUT: + fprintf(stderr, "libflash WREN timeout\n"); + break; + case FLASH_ERR_WIP_TIMEOUT: + fprintf(stderr, "libflash WIP timeout\n"); + break; + case FLASH_ERR_VERIFY_FAILURE: + fprintf(stderr, "libflash verification failure\n"); + break; + case FLASH_ERR_4B_NOT_SUPPORTED: + fprintf(stderr, "libflash 4byte mode not supported\n"); + break; + case FLASH_ERR_CTRL_CONFIG_MISMATCH: + fprintf(stderr, "libflash control config mismatch\n"); + break; + case FLASH_ERR_CHIP_ER_NOT_SUPPORTED: + fprintf(stderr, "libflash chip not supported\n"); + break; + case FLASH_ERR_CTRL_CMD_UNSUPPORTED: + fprintf(stderr, "libflash unsupported control command\n"); + break; + case FLASH_ERR_CTRL_TIMEOUT: + fprintf(stderr, "libflash control timeout\n"); + break; + case FLASH_ERR_ECC_INVALID: + fprintf(stderr, "libflash ecc invalid\n"); + break; + default: + fprintf(stderr, "A libflash/libffs error has occurred %d\n", rc); + } +} + +const struct chip_unit_desc *chip_units; +int chip_unit_count; + +static void set_chip_gen(const struct chip_unit_desc *c) +{ + chip_units = c; + chip_unit_count = 0; + + while (strcmp("LAST_IN_RANGE", c->desc)) { + chip_unit_count++; + c++; + } +} + +#ifdef __powerpc64__ +static void guess_chip_gen(void) +{ + /* + * Guesstimate what chip generation based on the PVR if we're running + * on ppc64. + */ + uint32_t pvr; + + /* grab the chip type from the PVR SPR */ + asm ("mfspr %0,0x11f" : "=r" (pvr)); + + switch (pvr >> 16) { + case 0x004b: /* murano */ + case 0x004c: /* naples */ + case 0x004d: /* venice */ + set_chip_gen(p8_chip_units); + return; + + case 0x004e: /* nimbus */ + case 0x004f: /* axone */ + set_chip_gen(p9_chip_units); + return; + + case 0x0080: /* power10 */ + set_chip_gen(p10_chip_units); + return; + + default: + fprintf(stderr, "Unsupported processor (pvr %#x)! Set the processor generation manually with -8, -9 or -0\n", pvr); + exit(1); + } +} +#else +static void guess_chip_gen(void) +{ +#ifdef ASSUME_P8 + set_chip_gen(p8_chip_units); +#else + set_chip_gen(p9_chip_units); +#endif +} +#endif + +static const char *target_type_to_str(int type) +{ + int i; + + for (i = 0; i < chip_unit_count; i++) + if (chip_units[i].type == type) + return chip_units[i].desc; + + return "UNKNOWN"; +} + +static int str_to_target_type(const char *path) +{ + int i, len; + + for (i = 0; i < chip_unit_count; i++) { + len = strlen(chip_units[i].desc); + + if (!strncasecmp(chip_units[i].desc, path, len)) + return chip_units[i].type; /* match! */ + } + + return -1; +} + +static const char *deconfig_reason_str(enum gard_reason reason) +{ + switch (reason) { + case GARD_NO_REASON: + return "None"; + case GARD_MANUAL: + return "Manual"; + case GARD_UNRECOVERABLE: + return "Unrecoverable"; + case GARD_FATAL: + return "Fatal"; + case GARD_PREDICTIVE: + return "Predictive"; + case GARD_POWER: + return "Power"; // What does this even mean? + case GARD_HYP: + return "Hypervisor"; + case GARD_RECONFIG: + return "Reconfig"; + default: + return "Unknown"; + } +}; + +static const char *path_type_to_str(enum path_type t) +{ + switch (t) { + case PATH_NA: + return "not applicable"; + case PATH_AFFINITY: + return "affinity"; + case PATH_PHYSICAL: + return "physical"; + case PATH_DEVICE: + return "device"; + case PATH_POWER: + return "power"; + } + return "Unknown"; +} + +/* + * NB: buffer is assumped to be MAX_PATH_SIZE + */ +static char *format_path(struct entity_path *path, char *buffer) +{ + int elements = path->type_size & PATH_ELEMENTS_MASK; + int i, offset = 0; + + for (i = 0; i < elements; i++) { + const struct path_element *e = &path->path_elements[i]; + + offset += sprintf(buffer + offset, "/%s%d", + target_type_to_str(e->target_type), + e->instance); + } + + return buffer; +} + +/* + * parses a Path string into the entity_path structured provided. + * + * str - In param, String to parse + * parsed - Out param, resultant entity_path + * + * e.g. + * + * "/Sys0/Node0/Proc1" -> { + * type_size = 0x23, + * + * path_element[0] = {0, 0} + * path_element[1] = {1, 0} + * path_element[2] = {2, 1} + * } + */ +static int parse_path(const char *str, struct entity_path *parsed) +{ + int unit_count = 0; + + memset(parsed, 0, sizeof(*parsed)); + + while (*str != '\0') { + int unit_id = str_to_target_type(++str); /* ++ skips the '/' */ + long instance; + char *end; + size_t len; + + if (unit_count > MAX_PATH_ELEMENTS - 1) { + fprintf(stderr, "Path has more than 10 components!\n"); + return -1; + } + + /* find the type Id of this component */ + if (unit_id < 0) { /* unknown unit, bail out */ + fprintf(stderr, "Unknown unit at: '%s'\n", str); + return -1; + } + + parsed->path_elements[unit_count].target_type = unit_id; + + /* now parse the instance # */ + len = strlen(target_type_to_str(unit_id)); + instance = strtol(str + len, &end, 10); + + if (!isdigit(*(str + len))) { + fprintf(stderr, "Missing instance number after '%s'\n", + str); + return -1; + } + + if (*end != '\0' && *end != '/') { + fprintf(stderr, "Unable to parse instance after '%s'\n", + str); + return -1; + } + + if (instance > 255 || instance < 0) { + fprintf(stderr, + "Instance %ld is invalid. Must be 0 to 255\n", + instance); + return -1; + } + parsed->path_elements[unit_count].instance = instance; + + str = end; + unit_count++; + } + + /* + * We assume the path is a physical path because every gard record I've + * seen so far uses them. We might need to fix this later on, but lets + * cross the bridge when we have to. + */ + parsed->type_size = (unit_count & 0xf) | + (PATH_PHYSICAL << PATH_TYPE_SHIFT); + + return 0; +} + +static struct gard_record blank_record; + +static bool is_valid_record(struct gard_record *g) +{ + return memcmp(&blank_record, g, sizeof(*g)); +} + +static int do_iterate(struct gard_ctx *ctx, + int (*func)(struct gard_ctx *ctx, int pos, + struct gard_record *gard, void *priv), + void *priv) +{ + int rc = 0; + unsigned int i; + struct gard_record gard, null_gard; + + memset(&null_gard, UINT_MAX, sizeof(gard)); + for (i = 0; i * sizeof(gard) < ctx->gard_data_len && rc == 0; i++) { + memset(&gard, 0, sizeof(gard)); + + rc = blocklevel_read(ctx->bl, ctx->gard_data_pos + (i * sizeof(gard)), + &gard, sizeof(gard)); + /* It isn't super clear what constitutes the end, this should do */ + if (rc || memcmp(&gard, &null_gard, sizeof(gard)) == 0) + break; + + rc = func(ctx, i, &gard, priv); + } + + return rc; +} + +/* + * read the next guard record into the supplied buffer (gard) + * + * returns the record id (nb: 1 based not zero) + * + */ +static int __gard_next(struct gard_ctx *ctx, int pos, struct gard_record *gard, int *rc) +{ + uint32_t offset = pos * sizeof(*gard); + + if (offset > ctx->gard_data_len) /* too big */ + return -1; + + /* you lose error handling information, *gruble* */ + memset(gard, 0, sizeof(*gard)); + *rc = blocklevel_read(ctx->bl, ctx->gard_data_pos + offset, + gard, sizeof(*gard)); + + if (!is_valid_record(gard)) + return -1; + + if (*rc) + return -1; + + return pos; +} + +#define for_each_gard(ctx, pos, gard, rc) \ + for (pos = __gard_next(ctx, 0, gard, rc); \ + pos >= 0; pos = __gard_next(ctx, ++pos, gard, rc)) + +static int count_records(struct gard_ctx *ctx) +{ + struct gard_record record; + int rc, pos, count = 0; + + for_each_gard(ctx, pos, &record, &rc) + count++; + + return rc ? rc : count; +} + +static int count_valid_records(struct gard_ctx *ctx) +{ + struct gard_record record; + int rc, pos, count = 0; + + for_each_gard(ctx, pos, &record, &rc) + count++; + + return rc ? rc : count; +} + +static size_t find_longest_path(struct gard_ctx *ctx) +{ + char scratch[MAX_PATH_SIZE]; + struct gard_record gard; + size_t len, longest = 0; + int rc, pos; + + for_each_gard(ctx, pos, &gard, &rc) { + len = strlen(format_path(&gard.target_id, scratch)); + if (len > longest) + longest = len; + } + + return longest; +} + +static void draw_ruler(char c, int size) +{ + int i; + + for (i = 0; i < size; i++) + putchar(c); + putchar('\n'); +} + +static int do_list(struct gard_ctx *ctx, int argc __attribute__((unused)), + char **argv __attribute__((unused))) +{ + /* This header matches the line formatting above in do_list_i() */ + const char *header = " ID | Error | Type | Path"; + size_t ruler_size; + char scratch[MAX_PATH_SIZE]; + struct gard_record gard; + int rc = 0, pos; + + /* No entries */ + if (count_valid_records(ctx) == 0) { + printf("No GARD entries to display\n"); + return 0; + } + + puts(header); + + ruler_size = strlen(header) + find_longest_path(ctx); + draw_ruler('-', ruler_size); + + for_each_gard(ctx, pos, &gard, &rc) { + printf(" %08x | %08x | %-10s | %s%s\n", + be32toh(gard.record_id), + be32toh(gard.errlog_eid), + deconfig_reason_str(gard.error_type), + format_path(&gard.target_id, scratch), + gard.record_id == 0xffffffff ? " *CLEARED*" : ""); + } + + draw_ruler('=', ruler_size); + + return rc; +} + +static int do_show_i(struct gard_ctx *ctx, int pos, struct gard_record *gard, void *priv) +{ + uint32_t id; + + (void)ctx; + (void)pos; + + if (!priv || !gard) + return -1; + + id = *(uint32_t *)priv; + + if (be32toh(gard->record_id) == id) { + unsigned int count, i; + + printf("Record ID: 0x%08x%s\n", id, id == 0xffffffff ? " *CLEARED*" : ""); + printf("========================\n"); + printf("Error ID: 0x%08x\n", be32toh(gard->errlog_eid)); + printf("Error Type: %s (0x%02x)\n", + deconfig_reason_str(gard->error_type), + gard->error_type); + printf("Path Type: %s\n", path_type_to_str(gard->target_id.type_size >> PATH_TYPE_SHIFT)); + count = gard->target_id.type_size & PATH_ELEMENTS_MASK; + for (i = 0; i < count && i < MAX_PATH_ELEMENTS; i++) + printf("%*c%s, Instance #%d\n", i + 1, '>', target_type_to_str(gard->target_id.path_elements[i].target_type), + gard->target_id.path_elements[i].instance); + } + + return 0; +} + +static int do_show(struct gard_ctx *ctx, int argc, char **argv) +{ + uint32_t id; + int rc; + + if (argc != 2) { + fprintf(stderr, "%s option requires a GARD record\n", argv[0]); + return -1; + } + + id = strtoul(argv[1], NULL, 16); + + rc = do_iterate(ctx, &do_show_i, &id); + + return rc; +} + +static int do_clear_i(struct gard_ctx *ctx, int pos, struct gard_record *gard, void *priv) +{ + int largest, rc = 0; + char *buf; + struct gard_record null_gard; + + if (!gard || !ctx || !priv) + return -1; + + /* Not this one */ + if (be32toh(gard->record_id) != *(uint32_t *)priv) + return 0; + + memset(&null_gard, 0xFF, sizeof(null_gard)); + + largest = count_records(ctx); + + printf("Clearing gard record 0x%08x...", be32toh(gard->record_id)); + + if (largest < 0 || pos > largest) { + /* Something went horribly wrong */ + fprintf(stderr, "largest index out of range %d\n", largest); + return -1; + } + + if (pos < largest) { + /* We're not clearing the last record, shift all the records up */ + int buf_len = ((largest - pos) * sizeof(struct gard_record)); + int buf_pos = ctx->gard_data_pos + ((pos + 1) * sizeof(struct gard_record)); + buf = malloc(buf_len); + if (!buf) + return -ENOMEM; + + rc = blocklevel_read(ctx->bl, buf_pos, buf, buf_len); + if (rc) { + free(buf); + fprintf(stderr, "Couldn't read from flash at 0x%08x for len 0x%08x\n", buf_pos, buf_len); + return rc; + } + + rc = blocklevel_smart_write(ctx->bl, buf_pos - sizeof(*gard), buf, buf_len); + free(buf); + if (rc) { + fprintf(stderr, "Couldn't write to flash at 0x%08x for len 0x%08x\n", + buf_pos - (int) sizeof(struct gard_record), buf_len); + return rc; + } + } + + /* Now wipe the last record */ + rc = blocklevel_smart_write(ctx->bl, ctx->gard_data_pos + (largest * sizeof(null_gard)), + &null_gard, sizeof(null_gard)); + printf("done\n"); + + return rc; +} + +static int reset_partition(struct gard_ctx *ctx) +{ + int no_ecc_len = (ctx->gard_data_len / 9) * 8; + struct gard_record *gard; + int rc = 0; + + gard = malloc(ctx->gard_data_len); + if (!gard) { + return FLASH_ERR_MALLOC_FAILED; + } + memset(gard, 0xFF, ctx->gard_data_len); + + rc = blocklevel_smart_erase(ctx->bl, ctx->gard_data_pos, ctx->gard_data_len); + if (rc) { + fprintf(stderr, "Couldn't erase the gard partition. Bailing out\n"); + goto out; + } + + rc = blocklevel_write(ctx->bl, ctx->gard_data_pos, gard, no_ecc_len); + if (rc) + fprintf(stderr, "Couldn't reset the entire gard partition. Bailing out\n"); + +out: + free(gard); + return rc; +} + +static int do_clear(struct gard_ctx *ctx, int argc, char **argv) +{ + int rc; + uint32_t id; + + if (argc != 2) { + fprintf(stderr, "%s option requires a GARD record or 'all'\n", argv[0]); + return -1; + } + + if (strncmp(argv[1], "all", strlen("all")) == 0) { + printf("Clearing the entire gard partition..."); + fflush(stdout); + rc = reset_partition(ctx); + printf("done\n"); + } else { + id = strtoul(argv[1], NULL, 16); + rc = do_iterate(ctx, do_clear_i, &id); + } + + return rc; +} + +static int do_create(struct gard_ctx *ctx, int argc, char **argv) +{ + int rc, pos, max_id = 0, last_pos = 0; + struct gard_record gard; + struct entity_path path; + + if (argc < 2) { + fprintf(stderr, "create requires path to gard\n"); + fprintf(stderr, "e.g.\n"); + fprintf(stderr, " /Sys0/Node0/Proc0\n"); + fprintf(stderr, " /Sys0/Node0/DIMM15\n"); + return -1; + } + + if (parse_path(argv[1], &path)) { + fprintf(stderr, "Unable to parse path\n"); + return -1; + } + + /* check if we already have a gard record applied to this path */ + for_each_gard(ctx, pos, &gard, &rc) { + if (!memcmp(&path, &gard.target_id, sizeof(path))) { + fprintf(stderr, + "Unit %s is already GARDed by record %#08x\n", + argv[1], be32toh(gard.record_id)); + return -1; + } + + /* + * Keep track of the largest record ID seen so far, + * we'll give the new record the max + 1 to ensure + * that it's unique + */ + if (be32toh(gard.record_id) > max_id) + max_id = be32toh(gard.record_id); + + last_pos++; + } + + /* do we have an empty record to write into? */ + if (!rc && !is_valid_record(&gard)) { + int offset = last_pos * sizeof(gard); + + memset(&gard, 0xff, sizeof(gard)); + + gard.record_id = be32toh(max_id + 1); + gard.error_type = GARD_MANUAL; + gard.target_id = path; + gard.errlog_eid = 0x0; + + if (offset > ctx->gard_data_len - sizeof(gard)) { + fprintf(stderr, "No space in GUARD for a new record\n"); + return -1; + } + + rc = blocklevel_smart_write(ctx->bl, + ctx->gard_data_pos + offset, &gard, sizeof(gard)); + } + + return rc; +} + +static int check_gard_partition(struct gard_ctx *ctx) +{ + int rc; + struct gard_record gard; + char msg[2]; + + if (ctx->gard_data_len == 0 || ctx->gard_data_len % sizeof(struct gard_record) != 0) + /* Just warn for now */ + fprintf(stderr, "The %s partition doesn't appear to be an exact multiple of" + "gard records in size: %zd vs %u (or partition is zero in length)\n", + FLASH_GARD_PART, sizeof(struct gard_record), ctx->gard_data_len); + + /* + * Attempt to read the first record, nothing can really operate if the + * first record is dead. There (currently) isn't a way to validate more + * than ECC correctness. + */ + rc = blocklevel_read(ctx->bl, ctx->gard_data_pos, &gard, sizeof(gard)); + if (rc == FLASH_ERR_ECC_INVALID) { + fprintf(stderr, "The data at the GUARD partition does not appear to be valid gard data\n"); + fprintf(stderr, "Clear the entire GUARD partition? [y/N]\n"); + if (fgets(msg, sizeof(msg), stdin) == NULL) { + fprintf(stderr, "Couldn't read from standard input\n"); + return -1; + } + if (msg[0] == 'y') { + rc = reset_partition(ctx); + if (rc) { + fprintf(stderr, "Couldn't reset the GUARD partition. Bailing out\n"); + return rc; + } + } + /* + * else leave rc as is so that the main bails out, not going to be + * able to do sensible anyway + */ + } + return rc; +} + +__attribute__ ((unused)) +static int do_nop(struct gard_ctx *ctx, int argc, char **argv) +{ + (void)ctx; + (void)argc; + fprintf(stderr, "Unimplemented action '%s'\n", argv[0]); + return EXIT_SUCCESS; +} + +struct { + const char *name; + const char *desc; + int (*fn)(struct gard_ctx *, int, char **); +} actions[] = { + { "list", "List current GARD records", do_list }, + { "show", "Show details of a GARD record", do_show }, + { "clear", "Clear GARD records", do_clear }, + { "create", "Create a GARD record", do_create }, +}; + +static void print_version(void) +{ + printf("Open-Power GARD tool %s\n", version); +} + +static void usage(const char *progname) +{ + unsigned int i; + + print_version(); + fprintf(stderr, "Usage: %s [-a -e -f <file> -p] <command> [<args>]\n\n", + progname); + fprintf(stderr, "-8 --p8\n"); + fprintf(stderr, "-9 --p9\n"); + fprintf(stderr, "-0 --p10\n\tSet the processor generation\n\n"); + fprintf(stderr, "-e --ecc\n\tForce reading/writing with ECC bytes.\n\n"); + fprintf(stderr, "-f --file <file>\n\tDon't search for MTD device," + " read from <file>.\n\n"); + fprintf(stderr, "-p --part\n\tUsed in conjunction with -f to specify" + " that just\n"); + fprintf(stderr, "\tthe GUARD partition is in <file> and libffs\n"); + fprintf(stderr, "\tshouldn't be used.\n\n"); + + + fprintf(stderr, "Where <command> is one of:\n\n"); + + for (i = 0; i < ARRAY_SIZE(actions); i++) { + fprintf(stderr, "\t%-7s\t%s\n", + actions[i].name, actions[i].desc); + } +} + +static bool is_fsp(void) +{ + return access(FDT_FSP_NODE, F_OK) == 0; +} + +static struct option global_options[] = { + { "file", required_argument, 0, 'f' }, + { "part", no_argument, 0, 'p' }, + { "ecc", no_argument, 0, 'e' }, + { "p8", no_argument, 0, '8' }, + { "p9", no_argument, 0, '9' }, + { "p10", no_argument, 0, '0' }, + { 0 }, +}; +static const char *global_optstring = "+ef:p890"; + +int main(int argc, char **argv) +{ + const char *action, *progname; + char *filename = NULL; + struct gard_ctx _ctx, *ctx; + uint64_t bl_size; + int rc, i = 0; + bool part = 0; + bool ecc = 0; + + progname = argv[0]; + + ctx = &_ctx; + memset(ctx, 0, sizeof(*ctx)); + memset(&blank_record, 0xff, sizeof(blank_record)); + + /* process global options */ + for (;;) { + int c; + + c = getopt_long(argc, argv, global_optstring, global_options, + NULL); + if (c == -1) + break; + switch (c) { + case 'e': + ecc = true; + break; + case 'f': + /* If they specify -f twice */ + free(filename); + + filename = strdup(optarg); + if (!filename) { + fprintf(stderr, "Out of memory\n"); + return EXIT_FAILURE; + } + break; + case 'p': + part = true; + break; + case '8': + set_chip_gen(p8_chip_units); + break; + case '9': + set_chip_gen(p9_chip_units); + break; + case '0': + set_chip_gen(p10_chip_units); + break; + case '?': + usage(progname); + rc = EXIT_FAILURE; + goto out_free; + } + } + + + if (is_fsp() && !filename) { + fprintf(stderr, "This is the OpenPower gard tool which does " + "not support FSP systems\n"); + return EXIT_FAILURE; + } + + + /* + * It doesn't make sense to specify that we have the gard partition but + * read from flash + */ + if (part && !filename) { + usage(progname); + fprintf(stderr, "-p only makes sense when used with -f!\n"); + return EXIT_FAILURE; + } + + /* do we have a command? */ + if (optind == argc) { + usage(progname); + rc = EXIT_FAILURE; + goto out_free; + } + + argc -= optind; + argv += optind; + action = argv[0]; + +#ifdef __arm__ + /* + * HACK: Look for a vPNOR GUARD file if we haven't been given anything + * explitly. If it exists then we can safely assume that: + * a) The host is a P9 + * b) The file is ECC protected + * c) The file is a bare partition. + * + * This is a stupid hack, but there's not other sane place for it. + * arch_init_flash() always looks for a FFS formatted PNOR when + * filename is NULL + */ + if (!filename) { + struct stat buf; + + if (!stat(VPNOR_GARD_FILE, &buf)) { + filename = strdup(VPNOR_GARD_FILE); + /* BUG: This ignores the command line settings */ + part = true; + ecc = true; + } else if (!stat(VPNOR_GARD_DIR, &buf)) { + printf(VPNOR_GARD_FILE" is missing. Nothing to do\n"); + return 0; + } + } +#endif + + if (!chip_units) + guess_chip_gen(); + + /* + * Force libflash to do flash accesses via the MTD. Direct mode is + * generally unsafe since it fiddles with the flash controller state + * underneath the kernel. Anyone who needs direct mode can use pflash + * instead. + */ + arch_flash_access(ctx->bl, PNOR_MTD); + + if (arch_flash_init(&(ctx->bl), filename, true)) { + /* Can fail for a few ways, most likely couldn't open MTD device */ + fprintf(stderr, "Can't open %s\n", filename ? filename : "MTD Device. Are you root?"); + rc = EXIT_FAILURE; + goto out_free; + } + + rc = blocklevel_get_info(ctx->bl, NULL, &bl_size, NULL); + if (rc) + goto out; + + if (bl_size > UINT_MAX) { + fprintf(stderr, "MTD device bigger than %i: size: %" PRIu64 "\n", + UINT_MAX, bl_size); + rc = EXIT_FAILURE; + goto out; + } + ctx->f_size = bl_size; + + if (!part) { + rc = ffs_init(0, ctx->f_size, ctx->bl, &ctx->ffs, 1); + if (rc) + goto out; + + rc = ffs_lookup_part(ctx->ffs, FLASH_GARD_PART, &ctx->gard_part_idx); + if (rc) + goto out; + + rc = ffs_part_info(ctx->ffs, ctx->gard_part_idx, NULL, &(ctx->gard_data_pos), + &(ctx->gard_data_len), NULL, NULL); + if (rc) + goto out; + } else { + if (ecc) { + rc = blocklevel_ecc_protect(ctx->bl, 0, ctx->f_size); + if (rc) + goto out; + } + + ctx->gard_data_pos = 0; + ctx->gard_data_len = ctx->f_size; + } + + rc = check_gard_partition(ctx); + if (rc) { + fprintf(stderr, "Does not appear to be sane gard data\n"); + goto out; + } + + for (i = 0; i < ARRAY_SIZE(actions); i++) { + if (!strcmp(actions[i].name, action)) { + rc = actions[i].fn(ctx, argc, argv); + break; + } + } + +out: + if (ctx->ffs) + ffs_close(ctx->ffs); + + file_exit_close(ctx->bl); + + if (i == ARRAY_SIZE(actions)) { + fprintf(stderr, "%s: '%s' isn't a valid command\n", progname, action); + usage(progname); + rc = EXIT_FAILURE; + goto out_free; + } + + if (rc > 0) { + show_flash_err(rc); + if (filename && rc == FFS_ERR_BAD_MAGIC) + fprintf(stderr, "Maybe you didn't give a full flash image file?\nDid you mean '--part'?\n"); + } + +out_free: + free(filename); + return rc; +} diff --git a/roms/skiboot/external/gard/gard.h b/roms/skiboot/external/gard/gard.h new file mode 100644 index 000000000..d59c2a0de --- /dev/null +++ b/roms/skiboot/external/gard/gard.h @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* Copyright 2013-2017 IBM Corp. + */ + +#include <stdint.h> + +#define MAX_PATH_ELEMENTS 10 +#define PATH_TYPE_SHIFT 4 +#define PATH_ELEMENTS_MASK (0x0F) + +/* + * Sourced from hostboot: src/include/usr/hwas/common/hwasCallout.H + */ +enum gard_reason { + GARD_NO_REASON = 0x0, + GARD_MANUAL = 0xD2, + GARD_UNRECOVERABLE = 0xE2, + GARD_FATAL = 0xE3, + GARD_PREDICTIVE = 0xE6, + GARD_POWER = 0xE9, + GARD_HYP = 0xEA, + GARD_RECONFIG = 0xEB, + + /* + * This should only occur if the GUARD partition isn't correctly + * programmed with ECC bits. + */ + GARD_VOID = 0xFF, +}; + +/* see src/include/usr/targeting/common/entitypath.H */ +enum path_type { + PATH_NA = 0x00, + PATH_AFFINITY = 0x01, + PATH_PHYSICAL = 0x02, + PATH_DEVICE = 0x03, + PATH_POWER = 0x04, +}; + +struct path_element { + uint8_t target_type; + uint8_t instance; +} __attribute__((packed)); + +struct entity_path { + /* First 4 bits are a path_type enum */ + /* Second 4 bits are the amount of path_elements */ + uint8_t type_size; + struct path_element path_elements[MAX_PATH_ELEMENTS]; + +} __attribute__((packed)); + +/* From hostboot: src/include/usr/hwas/common/deconfigGard.H:GardRecord */ +struct gard_record { + uint32_t record_id; + struct entity_path target_id; + uint8_t pad0[3]; /* compiler dependent padding */ + uint32_t errlog_eid; + uint8_t error_type; + uint8_t resource_recovery; + uint8_t pad1[6]; +} __attribute__((packed)); + +#define MAX_PATH_SIZE 420 + +struct chip_unit_desc { + int type; + const char *desc; +}; + +extern const struct chip_unit_desc *chip_units; +extern const struct chip_unit_desc p8_chip_units[]; +extern const struct chip_unit_desc p9_chip_units[]; +extern const struct chip_unit_desc p10_chip_units[]; diff --git a/roms/skiboot/external/gard/opal-gard.1 b/roms/skiboot/external/gard/opal-gard.1 new file mode 100644 index 000000000..65b214470 --- /dev/null +++ b/roms/skiboot/external/gard/opal-gard.1 @@ -0,0 +1,30 @@ +.TH opal-gard 1 "19 June 2015" +.SH NAME +opal-gard \- GUARD Partition manipulation tool for OpenPower hardware +.SH SYNOPSIS +\fBopal-gard\fP [ \-e | \-f \fIfile\fP | \-p ] +\fIcommand\fP +.SH DESCRIPTION +\fBopal-gard\fP allows reading of the GUARD partition on OpenPower hardware though the exposed mtd flash interface. The actual device (usually \fB/dev/mtd0\fR) is automatically detected. +.SS Options +\fB\-e, \-\-ecc\fP +Force reading/writing with ECC bytes. +.TP +\fB\-f, \-\-file\fP \fIfile\fR +Don't search for the \fB/dev/mtd\fR device, use \fIfile\fP instead. +.TP +.TP +\fB\-p, \-\-part\fP +Used in conjunction with \-f to specify that just the GUARD partition is in the \fIfile\fR and that libffs shouldn't be used. +.SS Commands +\fIcommand\fP +may be one of the following +.TP +\fBlist\fP +List current GARD records +.TP +\fBshow\fP +Show details of a GARD record +.TP +\fBclear\fP +Clear GARD records diff --git a/roms/skiboot/external/gard/rules.mk b/roms/skiboot/external/gard/rules.mk new file mode 100644 index 000000000..92ceb9bc0 --- /dev/null +++ b/roms/skiboot/external/gard/rules.mk @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +.DEFAULT_GOAL := all + +override CFLAGS += -O2 -Wall -Werror -Wno-stringop-truncation -I. +OBJS = version.o gard.o units.o +LIBFLASH_FILES := libflash.c libffs.c ecc.c blocklevel.c file.c +LIBFLASH_OBJS := $(addprefix libflash-, $(LIBFLASH_FILES:.c=.o)) +LIBFLASH_SRC := $(addprefix libflash/,$(LIBFLASH_FILES)) +CCAN_FILES := list.c +CCAN_OBJS := $(addprefix ccan-list-, $(CCAN_FILES:.c=.o)) +CCAN_SRC := $(addprefix ccan/list/,$(CCAN_FILES)) +OBJS += $(LIBFLASH_OBJS) $(CCAN_OBJS) +OBJS += common-arch_flash.o +EXE = opal-gard + +prefix = /usr/local/ +sbindir = $(prefix)/sbin +datadir = $(prefix)/share +mandir = $(datadir)/man + +#This will only be unset if we're running out of git tree, +#../../make_version.sh is garanteed to exist that way +GARD_VERSION ?= $(shell ../../make_version.sh $(EXE)) + +version.c: .version + @(if [ "a$(GARD_VERSION)" = "a" ]; then \ + echo "#error You need to set GARD_VERSION environment variable" > $@ ;\ + else \ + echo "const char version[] = \"$(GARD_VERSION)\";" ;\ + fi) > $@ + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBFLASH_SRC): | links +$(CCAN_SRC): | links + +$(LIBFLASH_OBJS): libflash-%.o : libflash/%.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(CCAN_OBJS): ccan-list-%.o: ccan/list/%.c + $(Q_CC)$(CC) $(CFLAGS) -c $< -o $@ + +$(EXE): $(OBJS) + $(CC) $(LDFLAGS) $(CFLAGS) $^ -o $@ + +install: all + install -D $(EXE) $(DESTDIR)$(sbindir)/$(EXE) + install -D -m 0644 $(EXE).1 $(DESTDIR)$(mandir)/man1/$(EXE).1 + + diff --git a/roms/skiboot/external/gard/test/add_test.sh b/roms/skiboot/external/gard/test/add_test.sh new file mode 100755 index 000000000..6523dffc6 --- /dev/null +++ b/roms/skiboot/external/gard/test/add_test.sh @@ -0,0 +1,67 @@ +#!/bin/bash -uex +# +# this is a really dumb script for auto-generating test cases from known good-data +# +# usage: ./add_test <pass|fail> <inputfile> <testname> [opal-gard subcommand] +# +# e.g. +# ./add_test.sh fail blank.bin create-bad-instance create /sys256 +# ./add_test.sh pass blank.bin create-normal create /sys0/node0/proc0 +# +# this will generate a test script file and writes the stdout/stderr of the command +# to the respective files. +# + +cd $(dirname $(realpath $0))/../ +echo $PWD + +if [ "$1" = "pass" ]; then + check='if [ "$?" -ne 0 ]; then' + test_type="pass" +else + check='if [ "$?" -eq 0 ]; then' + test_type="fails" +fi +shift + +file="test/files/$1" +if [ ! -f "$file" ]; then + echo "test file not found!" + exit 1; +fi +shift + +name="$1" +shift + +max="$(ls test/tests/ -1|sort -n | sed 's@\(..\).*@\1@' | tail -1 | sed s@^0*@@)" +num="$(printf %02d $((max + 1)))" + +echo "Adding: $num-$name" + +# where we will write the script file +script_file="test/tests/$num-$name" + +echo "making $num-$name: f=$script_file, normally $test_type, cmd='$*'" + +cat > $script_file <<EOF +#! /bin/sh + +run_binary "./opal-gard" "-9 -p -e -f $file $*" +$check + fail_test +fi + +diff_with_result + +pass_test +EOF + +# generate the .out and .err files +stdout_file="test/results/$num-$name.out" +stderr_file="test/results/$num-$name.err" + +test_input="$name-$num-input" +cp $file $test_input +./opal-gard -f $test_input -p -e $* 2>$stderr_file >$stdout_file +rm -f $test_input diff --git a/roms/skiboot/external/gard/test/files/blank.bin b/roms/skiboot/external/gard/test/files/blank.bin Binary files differnew file mode 100644 index 000000000..c6cc6b8c2 --- /dev/null +++ b/roms/skiboot/external/gard/test/files/blank.bin diff --git a/roms/skiboot/external/gard/test/files/data-p9.bin b/roms/skiboot/external/gard/test/files/data-p9.bin Binary files differnew file mode 100644 index 000000000..f2141657a --- /dev/null +++ b/roms/skiboot/external/gard/test/files/data-p9.bin diff --git a/roms/skiboot/external/gard/test/files/data1.bin b/roms/skiboot/external/gard/test/files/data1.bin Binary files differnew file mode 100644 index 000000000..aa5bf1437 --- /dev/null +++ b/roms/skiboot/external/gard/test/files/data1.bin diff --git a/roms/skiboot/external/gard/test/make-check-test b/roms/skiboot/external/gard/test/make-check-test new file mode 100755 index 000000000..6b9e5db88 --- /dev/null +++ b/roms/skiboot/external/gard/test/make-check-test @@ -0,0 +1 @@ +make -C external/gard/ check diff --git a/roms/skiboot/external/gard/test/results/00-list.err b/roms/skiboot/external/gard/test/results/00-list.err new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/skiboot/external/gard/test/results/00-list.err diff --git a/roms/skiboot/external/gard/test/results/00-list.out b/roms/skiboot/external/gard/test/results/00-list.out new file mode 100644 index 000000000..0e20b4aef --- /dev/null +++ b/roms/skiboot/external/gard/test/results/00-list.out @@ -0,0 +1,5 @@ + ID | Error | Type | Path +----------------------------------------------------------- + 00000001 | 90000015 | Predictive | /Sys0/Node0/Proc0 + 00000002 | 90000016 | Predictive | /Sys0/Node0/Membuf0 +=========================================================== diff --git a/roms/skiboot/external/gard/test/results/01-show_1.err b/roms/skiboot/external/gard/test/results/01-show_1.err new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/skiboot/external/gard/test/results/01-show_1.err diff --git a/roms/skiboot/external/gard/test/results/01-show_1.out b/roms/skiboot/external/gard/test/results/01-show_1.out new file mode 100644 index 000000000..60fcea264 --- /dev/null +++ b/roms/skiboot/external/gard/test/results/01-show_1.out @@ -0,0 +1,8 @@ +Record ID: 0x00000001 +======================== +Error ID: 0x90000015 +Error Type: Predictive (0xe6) +Path Type: physical +>Sys, Instance #0 + >Node, Instance #0 + >Proc, Instance #0 diff --git a/roms/skiboot/external/gard/test/results/02-usage.err b/roms/skiboot/external/gard/test/results/02-usage.err new file mode 100644 index 000000000..453fcf52f --- /dev/null +++ b/roms/skiboot/external/gard/test/results/02-usage.err @@ -0,0 +1,24 @@ +Usage: ./opal-gard [-a -e -f <file> -p] <command> [<args>] + +-8 --p8 +-9 --p9 +-0 --p10 + Set the processor generation + +-e --ecc + Force reading/writing with ECC bytes. + +-f --file <file> + Don't search for MTD device, read from <file>. + +-p --part + Used in conjunction with -f to specify that just + the GUARD partition is in <file> and libffs + shouldn't be used. + +Where <command> is one of: + + list List current GARD records + show Show details of a GARD record + clear Clear GARD records + create Create a GARD record diff --git a/roms/skiboot/external/gard/test/results/02-usage.out b/roms/skiboot/external/gard/test/results/02-usage.out new file mode 100644 index 000000000..c862167b4 --- /dev/null +++ b/roms/skiboot/external/gard/test/results/02-usage.out @@ -0,0 +1 @@ +Open-Power GARD tool VERSION diff --git a/roms/skiboot/external/gard/test/results/03-show_1-p9.err b/roms/skiboot/external/gard/test/results/03-show_1-p9.err new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/skiboot/external/gard/test/results/03-show_1-p9.err diff --git a/roms/skiboot/external/gard/test/results/03-show_1-p9.out b/roms/skiboot/external/gard/test/results/03-show_1-p9.out new file mode 100644 index 000000000..c9ae5b21c --- /dev/null +++ b/roms/skiboot/external/gard/test/results/03-show_1-p9.out @@ -0,0 +1,10 @@ +Record ID: 0x00000001 +======================== +Error ID: 0x90000007 +Error Type: Fatal (0xe3) +Path Type: physical +>Sys, Instance #0 + >Node, Instance #0 + >Proc, Instance #0 + >EQ, Instance #1 + >EX, Instance #0 diff --git a/roms/skiboot/external/gard/test/results/04-create-bad-instance.err b/roms/skiboot/external/gard/test/results/04-create-bad-instance.err new file mode 100644 index 000000000..2a8da501a --- /dev/null +++ b/roms/skiboot/external/gard/test/results/04-create-bad-instance.err @@ -0,0 +1,2 @@ +Instance 256 is invalid. Must be 0 to 255 +Unable to parse path diff --git a/roms/skiboot/external/gard/test/results/04-create-bad-instance.out b/roms/skiboot/external/gard/test/results/04-create-bad-instance.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/skiboot/external/gard/test/results/04-create-bad-instance.out diff --git a/roms/skiboot/external/gard/test/results/05-create-bad-unit.err b/roms/skiboot/external/gard/test/results/05-create-bad-unit.err new file mode 100644 index 000000000..aa1af82f5 --- /dev/null +++ b/roms/skiboot/external/gard/test/results/05-create-bad-unit.err @@ -0,0 +1,2 @@ +Unknown unit at: 'doesnt_exist0' +Unable to parse path diff --git a/roms/skiboot/external/gard/test/results/05-create-bad-unit.out b/roms/skiboot/external/gard/test/results/05-create-bad-unit.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/skiboot/external/gard/test/results/05-create-bad-unit.out diff --git a/roms/skiboot/external/gard/test/results/06-create-long-path.err b/roms/skiboot/external/gard/test/results/06-create-long-path.err new file mode 100644 index 000000000..f79a3bda9 --- /dev/null +++ b/roms/skiboot/external/gard/test/results/06-create-long-path.err @@ -0,0 +1,2 @@ +Path has more than 10 components! +Unable to parse path diff --git a/roms/skiboot/external/gard/test/results/06-create-long-path.out b/roms/skiboot/external/gard/test/results/06-create-long-path.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/skiboot/external/gard/test/results/06-create-long-path.out diff --git a/roms/skiboot/external/gard/test/results/07-create-slash.err b/roms/skiboot/external/gard/test/results/07-create-slash.err new file mode 100644 index 000000000..6fd687604 --- /dev/null +++ b/roms/skiboot/external/gard/test/results/07-create-slash.err @@ -0,0 +1,2 @@ +Unknown unit at: '' +Unable to parse path diff --git a/roms/skiboot/external/gard/test/results/07-create-slash.out b/roms/skiboot/external/gard/test/results/07-create-slash.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/skiboot/external/gard/test/results/07-create-slash.out diff --git a/roms/skiboot/external/gard/test/results/08-create-duplicate.err b/roms/skiboot/external/gard/test/results/08-create-duplicate.err new file mode 100644 index 000000000..4c4073953 --- /dev/null +++ b/roms/skiboot/external/gard/test/results/08-create-duplicate.err @@ -0,0 +1 @@ +Unit /Sys0/Node0/Membuf0 is already GARDed by record 0x000002 diff --git a/roms/skiboot/external/gard/test/results/08-create-duplicate.out b/roms/skiboot/external/gard/test/results/08-create-duplicate.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/skiboot/external/gard/test/results/08-create-duplicate.out diff --git a/roms/skiboot/external/gard/test/results/09-create-last-unit.err b/roms/skiboot/external/gard/test/results/09-create-last-unit.err new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/skiboot/external/gard/test/results/09-create-last-unit.err diff --git a/roms/skiboot/external/gard/test/results/09-create-last-unit.out b/roms/skiboot/external/gard/test/results/09-create-last-unit.out new file mode 100644 index 000000000..62cfcbbd0 --- /dev/null +++ b/roms/skiboot/external/gard/test/results/09-create-last-unit.out @@ -0,0 +1,4 @@ + ID | Error | Type | Path +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + 00000001 | 00000000 | Manual | /MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255 +================================================================================================================================================================ diff --git a/roms/skiboot/external/gard/test/results/10-clear-single.err b/roms/skiboot/external/gard/test/results/10-clear-single.err new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/skiboot/external/gard/test/results/10-clear-single.err diff --git a/roms/skiboot/external/gard/test/results/10-clear-single.out b/roms/skiboot/external/gard/test/results/10-clear-single.out new file mode 100644 index 000000000..904e61a56 --- /dev/null +++ b/roms/skiboot/external/gard/test/results/10-clear-single.out @@ -0,0 +1,7 @@ +Clearing the entire gard partition...done + ID | Error | Type | Path +--------------------------------------------------------- + 00000001 | 00000000 | Manual | /Sys0/Node0/Proc1 +========================================================= +Clearing gard record 0x00000001...done +No GARD entries to display diff --git a/roms/skiboot/external/gard/test/results/11-clear-first.err b/roms/skiboot/external/gard/test/results/11-clear-first.err new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/skiboot/external/gard/test/results/11-clear-first.err diff --git a/roms/skiboot/external/gard/test/results/11-clear-first.out b/roms/skiboot/external/gard/test/results/11-clear-first.out new file mode 100644 index 000000000..3b67689ce --- /dev/null +++ b/roms/skiboot/external/gard/test/results/11-clear-first.out @@ -0,0 +1,13 @@ +Clearing the entire gard partition...done + ID | Error | Type | Path +--------------------------------------------------------- + 00000001 | 00000000 | Manual | /Sys0/Node0/Proc0 + 00000002 | 00000000 | Manual | /Sys0/Node0/Proc1 +========================================================= +Clearing gard record 0x00000001...done + ID | Error | Type | Path +--------------------------------------------------------- + 00000002 | 00000000 | Manual | /Sys0/Node0/Proc1 +========================================================= +Clearing gard record 0x00000002...done +No GARD entries to display diff --git a/roms/skiboot/external/gard/test/test-gard b/roms/skiboot/external/gard/test/test-gard new file mode 100755 index 000000000..10da35156 --- /dev/null +++ b/roms/skiboot/external/gard/test/test-gard @@ -0,0 +1,5 @@ +#! /bin/sh + +. test/test.sh + +run_tests "test/tests/*" "test/results" diff --git a/roms/skiboot/external/gard/test/tests/00-list b/roms/skiboot/external/gard/test/tests/00-list new file mode 100644 index 000000000..982acb3d3 --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/00-list @@ -0,0 +1,10 @@ +#! /bin/sh + +run_binary "./opal-gard" "-p -e -8 -f test/files/data1.bin list" +if [ "$?" -ne 0 ] ; then + fail_test +fi + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/test/tests/01-show_1 b/roms/skiboot/external/gard/test/tests/01-show_1 new file mode 100644 index 000000000..48b779eb9 --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/01-show_1 @@ -0,0 +1,10 @@ +#! /bin/sh + +run_binary "./opal-gard" "-p -e -8 -f test/files/data1.bin show 1" +if [ "$?" -ne 0 ] ; then + fail_test +fi + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/test/tests/02-usage b/roms/skiboot/external/gard/test/tests/02-usage new file mode 100644 index 000000000..7ef3c04e6 --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/02-usage @@ -0,0 +1,17 @@ +#! /bin/sh + +# This test fails on FSP based system. Hence skip this test. +if [ -d "/proc/device-tree/fsps" ] ; then + return 0 +fi + +run_binary "./opal-gard" +if [ "$?" -ne 1 ] ; then + fail_test +fi + +strip_version_from_result "gard" + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/test/tests/03-show_1-p9 b/roms/skiboot/external/gard/test/tests/03-show_1-p9 new file mode 100644 index 000000000..2a7b91b7d --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/03-show_1-p9 @@ -0,0 +1,10 @@ +#! /bin/sh + +run_binary "./opal-gard" "-p -e -f test/files/data-p9.bin --p9 show 1" +if [ "$?" -ne 0 ] ; then + fail_test +fi + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/test/tests/04-create-bad-instance b/roms/skiboot/external/gard/test/tests/04-create-bad-instance new file mode 100644 index 000000000..f9070a3dc --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/04-create-bad-instance @@ -0,0 +1,10 @@ +#! /bin/sh + +run_binary "./opal-gard" "-p -e -8 -f test/files/blank.bin create /sys256" +if [ "$?" -eq 0 ]; then + fail_test +fi + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/test/tests/05-create-bad-unit b/roms/skiboot/external/gard/test/tests/05-create-bad-unit new file mode 100644 index 000000000..be60aed04 --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/05-create-bad-unit @@ -0,0 +1,10 @@ +#! /bin/sh + +run_binary "./opal-gard" "-p -e -f test/files/blank.bin create /doesnt_exist0" +if [ "$?" -eq 0 ]; then + fail_test +fi + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/test/tests/06-create-long-path b/roms/skiboot/external/gard/test/tests/06-create-long-path new file mode 100644 index 000000000..f3ffaabf6 --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/06-create-long-path @@ -0,0 +1,10 @@ +#! /bin/sh + +run_binary "./opal-gard" "-p -e -8 -f test/files/blank.bin create /sys0/sys0/sys0/sys0/sys0/sys0/sys0/sys0/sys0/sys0/sys0/sys0/" +if [ "$?" -eq 0 ]; then + fail_test +fi + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/test/tests/07-create-slash b/roms/skiboot/external/gard/test/tests/07-create-slash new file mode 100644 index 000000000..0e597e346 --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/07-create-slash @@ -0,0 +1,10 @@ +#! /bin/sh + +run_binary "./opal-gard" "-p -e -f test/files/blank.bin create /" +if [ "$?" -eq 0 ]; then + fail_test +fi + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/test/tests/08-create-duplicate b/roms/skiboot/external/gard/test/tests/08-create-duplicate new file mode 100644 index 000000000..fad5d3499 --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/08-create-duplicate @@ -0,0 +1,10 @@ +#! /bin/sh + +run_binary "./opal-gard" "-p -e -8 -f test/files/data1.bin create /Sys0/Node0/Membuf0" +if [ "$?" -eq 0 ]; then + fail_test +fi + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/test/tests/09-create-last-unit b/roms/skiboot/external/gard/test/tests/09-create-last-unit new file mode 100644 index 000000000..4d9b319cc --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/09-create-last-unit @@ -0,0 +1,16 @@ +#! /bin/sh + +cp test/files/blank.bin $DATA_DIR/input +run_binary "./opal-gard" "-9 -p -e -f $DATA_DIR/input create /MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255/MFREFCLK255" +if [ "$?" -ne 0 ]; then + fail_test +fi + +run_binary "./opal-gard" "-9 -p -e -f $DATA_DIR/input list" +if [ "$?" -ne 0 ]; then + fail_test +fi + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/test/tests/10-clear-single b/roms/skiboot/external/gard/test/tests/10-clear-single new file mode 100644 index 000000000..3a5f962ec --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/10-clear-single @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +DATA=$(mktemp) + +cleanup() { + rm -f $DATA +} + +trap cleanup EXIT + +dd if=/dev/zero of=$DATA bs=$((0x1000)) count=5 2>/dev/null + +run_binary "./opal-gard" "-p -e -f $DATA clear all" +run_binary "./opal-gard" "-p -e -f $DATA create /sys0/node0/proc1" +run_binary "./opal-gard" "-p -e -f $DATA list" +run_binary "./opal-gard" "-p -e -f $DATA clear 00000001" +run_binary "./opal-gard" "-p -e -f $DATA list" + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/test/tests/11-clear-first b/roms/skiboot/external/gard/test/tests/11-clear-first new file mode 100644 index 000000000..c59fcc8f0 --- /dev/null +++ b/roms/skiboot/external/gard/test/tests/11-clear-first @@ -0,0 +1,26 @@ +#!/bin/sh + +set -e + +DATA=$(mktemp) + +cleanup() { + rm -f $DATA +} + +trap cleanup EXIT + +dd if=/dev/zero of=$DATA bs=$((0x1000)) count=5 2>/dev/null + +run_binary "./opal-gard" "-p -e -f $DATA clear all" +run_binary "./opal-gard" "-p -e -f $DATA create /sys0/node0/proc0" +run_binary "./opal-gard" "-p -e -f $DATA create /sys0/node0/proc1" +run_binary "./opal-gard" "-p -e -f $DATA list" +run_binary "./opal-gard" "-p -e -f $DATA clear 00000001" +run_binary "./opal-gard" "-p -e -f $DATA list" +run_binary "./opal-gard" "-p -e -f $DATA clear 00000002" +run_binary "./opal-gard" "-p -e -f $DATA list" + +diff_with_result + +pass_test diff --git a/roms/skiboot/external/gard/units.c b/roms/skiboot/external/gard/units.c new file mode 100644 index 000000000..f3b435a3a --- /dev/null +++ b/roms/skiboot/external/gard/units.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * Each chip has a set of "units" that are detailed by the System MRW. Granted + * they're pretty much fixed for a given chip generation so hardcoding them here + * isn't a big deal. + * + * These tables we generated from obj/genfiles/errl/errludtarget.H. Which is + * generated as a part of the hostboot build process. Yeah that's about as + * dumb as it sounds, but whatever. + * + * Copyright 2017 IBM Corp + */ + +#include "gard.h" + +/* + * Notes: + * + * When formatting these as strings we print them into a buffer of MAX_PATH_SIZE + * Given there is a max path length of ten units MAX_PATH_SIZE might need a + * bump is we start using very detailed unit description strings. + */ + +const struct chip_unit_desc p8_chip_units[] = { + {0x00, "NA"}, + {0x01, "Sys"}, + {0x02, "Node"}, + {0x03, "DIMM"}, + {0x04, "Membuf"}, + {0x05, "Proc"}, + {0x06, "EX"}, + {0x07, "Core"}, + {0x08, "L2"}, + {0x09, "L3"}, + {0x0A, "L4"}, + {0x0B, "MCS"}, + {0x0D, "MBA"}, + {0x0E, "XBUS"}, + {0x0F, "ABUS"}, + {0x10, "PCI"}, + {0x11, "DPSS"}, + {0x12, "APSS"}, + {0x13, "OCC"}, + {0x14, "PSI"}, + {0x15, "FSP"}, + {0x16, "PNOR"}, + {0x17, "OSC"}, + {0x18, "TODCLK"}, + {0x19, "CONTROL_NODE"}, + {0x1A, "OSCREFCLK"}, + {0x1B, "OSCPCICLK"}, + {0x1C, "REFCLKENDPT"}, + {0x1D, "PCICLKENDPT"}, + {0x1E, "NX"}, + {0x1F, "PORE"}, + {0x20, "PCIESWITCH"}, + {0x21, "CAPP"}, + {0x22, "FSI"}, + {0x23, "TPM"}, + {0x24, "SP"}, + {0x25, "UART"}, + {0x26, "PS"}, + {0x27, "FAN"}, + {0x28, "VRM"}, + {0x29, "USB"}, + {0x2A, "ETH"}, + {0x2B, "PANEL"}, + {0x2C, "TEST_FAIL"}, + {0x2D, "LAST_IN_RANGE"} +}; + +const struct chip_unit_desc p9_chip_units[] = { + {0x00, "NA"}, + {0x01, "Sys"}, + {0x02, "Node"}, + {0x03, "DIMM"}, + {0x04, "Membuf"}, + {0x05, "Proc"}, + {0x06, "EX"}, + {0x07, "Core"}, + {0x08, "L2"}, + {0x09, "L3"}, + {0x0A, "L4"}, + {0x0B, "MCS"}, + /* a hole! */ + {0x0D, "MBA"}, + {0x0E, "XBUS"}, + {0x0F, "ABUS"}, + {0x10, "PCI"}, + {0x11, "DPSS"}, + {0x12, "APSS"}, + {0x13, "OCC"}, + {0x14, "PSI"}, + {0x15, "FSP"}, + {0x16, "PNOR"}, + {0x17, "OSC"}, + {0x18, "TODCLK"}, + {0x19, "CONTROL_NODE"}, + {0x1A, "OSCREFCLK"}, + {0x1B, "OSCPCICLK"}, + {0x1C, "REFCLKENDPT"}, + {0x1D, "PCICLKENDPT"}, + {0x1E, "NX"}, + {0x1F, "PORE"}, + {0x20, "PCIESWITCH"}, + {0x21, "CAPP"}, + {0x22, "FSI"}, + {0x23, "EQ"}, + {0x24, "MCA"}, + {0x25, "MCBIST"}, + {0x26, "MI"}, + {0x27, "DMI"}, + {0x28, "OBUS"}, + {0x2A, "SBE"}, + {0x2B, "PPE"}, + {0x2C, "PERV"}, + {0x2D, "PEC"}, + {0x2E, "PHB"}, + {0x2F, "SYSREFCLKENDPT"}, + {0x30, "MFREFCLKENDPT"}, + {0x31, "TPM"}, + {0x32, "SP"}, + {0x33, "UART"}, + {0x34, "PS"}, + {0x35, "FAN"}, + {0x36, "VRM"}, + {0x37, "USB"}, + {0x38, "ETH"}, + {0x39, "PANEL"}, + {0x3A, "BMC"}, + {0x3B, "FLASH"}, + {0x3C, "SEEPROM"}, + {0x3D, "TMP"}, + {0x3E, "GPIO_EXPANDER"}, + {0x3F, "POWER_SEQUENCER"}, + {0x40, "RTC"}, + {0x41, "FANCTLR"}, + {0x42, "OBUS_BRICK"}, + {0x43, "NPU"}, + {0x44, "MC"}, + {0x45, "TEST_FAIL"}, + {0x46, "MFREFCLK"}, + {0x47, "SMPGROUP"}, + {0x48, "OMI"}, + {0x49, "MCC"}, + {0x4A, "OMIC"}, + {0x4B, "OCMB_CHIP"}, + {0x4C, "MEM_PORT"}, + {0x4D, "I2C_MUX"}, + {0x4E, "PMIC"}, + {0x4F, "LAST_IN_RANGE"}, +}; + +const struct chip_unit_desc p10_chip_units[] = { + {0x00, "NA"}, + {0x01, "Sys"}, + {0x02, "Node"}, + {0x03, "DIMM"}, + {0x04, "Membuf"}, + {0x05, "Proc"}, + {0x06, "EX"}, + {0x07, "Core"}, + {0x08, "L2"}, + {0x09, "L3"}, + {0x0A, "L4"}, + {0x0B, "MCS"}, + /* a hole! */ + {0x0D, "MBA"}, + {0x0E, "XBUS"}, + {0x0F, "ABUS"}, + {0x10, "PCI"}, + {0x11, "DPSS"}, + {0x12, "APSS"}, + {0x13, "OCC"}, + {0x14, "PSI"}, + {0x15, "FSP"}, + {0x16, "PNOR"}, + {0x17, "OSC"}, + {0x18, "TODCLK"}, + {0x19, "CONTROL_NODE"}, + {0x1A, "OSCREFCLK"}, + {0x1B, "OSCPCICLK"}, + {0x1C, "REFCLKENDPT"}, + {0x1D, "PCICLKENDPT"}, + {0x1E, "NX"}, + {0x1F, "PORE"}, + {0x20, "PCIESWITCH"}, + {0x21, "CAPP"}, + {0x22, "FSI"}, + {0x23, "EQ"}, + {0x24, "MCA"}, + {0x25, "MCBIST"}, + {0x26, "MI"}, + {0x27, "DMI"}, + {0x28, "OBUS"}, + {0x2A, "SBE"}, + {0x2B, "PPE"}, + {0x2C, "PERV"}, + {0x2D, "PEC"}, + {0x2E, "PHB"}, + {0x2F, "SYSREFCLKENDPT"}, + {0x30, "MFREFCLKENDPT"}, + {0x31, "TPM"}, + {0x32, "SP"}, + {0x33, "UART"}, + {0x34, "PS"}, + {0x35, "FAN"}, + {0x36, "VRM"}, + {0x37, "USB"}, + {0x38, "ETH"}, + {0x39, "PANEL"}, + {0x3A, "BMC"}, + {0x3B, "FLASH"}, + {0x3C, "SEEPROM"}, + {0x3D, "TMP"}, + {0x3E, "GPIO_EXPANDER"}, + {0x3F, "POWER_SEQUENCER"}, + {0x40, "RTC"}, + {0x41, "FANCTLR"}, + {0x42, "OBUS_BRICK"}, + {0x43, "NPU"}, + {0x44, "MC"}, + {0x45, "TEST_FAIL"}, + {0x46, "MFREFCLK"}, + {0x47, "SMPGROUP"}, + {0x48, "OMI"}, + {0x49, "MCC"}, + {0x4A, "OMIC"}, + {0x4B, "OCMB_CHIP"}, + {0x4C, "MEM_PORT"}, + {0x4D, "I2C_MUX"}, + {0x4E, "PMIC"}, + {0x4F, "NMMU"}, + {0x50, "PAU"}, + {0x51, "IOHS"}, + {0x52, "PAUC"}, + {0x53, "FC"}, + {0x54, "LPCREFCLKENDPT"}, + {0x55, "GENERIC_I2C_DEVICE"}, + {0x56, "LAST_IN_RANGE"}, +}; + |