[PATCH] [V2] opal: mtd: Add OPAL MTD Validation
Colin Ian King
colin.king at canonical.com
Tue Aug 30 17:40:09 UTC 2016
On 30/08/16 18:36, Deb McLemore wrote:
> Hi Colin,
>
> See replies in line and some follow-up clarifications.
>
> On 08/30/2016 12:24 PM, Colin Ian King wrote:
>> Thanks deb,
>>
>> I've re-reviewed the patch and it builds OK w/o any static analysis
>> issues too. However, I have just a couple of minor nit-picks;
>> apologies, I should have spotted those on the first review.
>>
>> Colin
>>
>> On 30/08/16 17:49, Deb McLemore wrote:
>>> Check that the MTD system device for OPAL is properly setup.
>>>
>>> Signed-off-by: Deb McLemore <debmc at linux.vnet.ibm.com>
>>> ---
>>> configure.ac | 2 +
>>> src/Makefile.am | 1 +
>>> src/opal/mtd_info.c | 379
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>> 3 files changed, 382 insertions(+)
>>> create mode 100644 src/opal/mtd_info.c
>>>
>>> diff --git a/configure.ac b/configure.ac
>>> index e3e7512..042d45b 100644
>>> --- a/configure.ac
>>> +++ b/configure.ac
>>> @@ -64,7 +64,9 @@
>>> AC_CHECK_HEADERS([glib.h])
>>> AC_CHECK_HEADERS([gio/gio.h])
>>> AC_CHECK_HEADERS([asm/opal-prd.h])
>>> + AC_CHECK_HEADERS([mtd/mtd-abi.h])
>>> AM_CONDITIONAL([HAVE_ASM_OPAL_PRD_H], [test
>>> "x$ac_cv_header_asm_opal_prd_h" = "xyes"])
>>> + AM_CONDITIONAL([HAVE_MTD_ABI_H], [test
>>> "x$ac_cv_header_mtd_abi_h" = "xyes"])
>>> #AC_CHECK_LIB(pcre, pcre_compile)
>>> AC_SEARCH_LIBS([fdt_check_header], [fdt], [
>>> AC_DEFINE([HAVE_LIBFDT], [1], [Define if we have libfdt])
>>> diff --git a/src/Makefile.am b/src/Makefile.am
>>> index 137a429..eeef7a8 100644
>>> --- a/src/Makefile.am
>>> +++ b/src/Makefile.am
>>> @@ -134,6 +134,7 @@ fwts_SOURCES = main.c \
>>> kernel/olog/olog.c \
>>> kernel/oops/oops.c \
>>> kernel/version/version.c \
>>> + opal/mtd_info.c \
>>> opal/prd_info.c \
>>> pci/aspm/aspm.c \
>>> pci/crs/crs.c \
>>> diff --git a/src/opal/mtd_info.c b/src/opal/mtd_info.c
>>> new file mode 100644
>>> index 0000000..edb25fa
>>> --- /dev/null
>>> +++ b/src/opal/mtd_info.c
>>> @@ -0,0 +1,379 @@
>>> +/*
>>> + * Copyright (C) 2010-2016 Canonical
>>> + * Some of this work - Copyright (C) 2016 IBM
>>> + *
>>> + * 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; either version 2
>>> + * of the License, or (at your option) any later version.
>>> + *
>>> + * 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.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with this program; if not, write to the Free Software
>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>>> 02110-1301, USA.
>>> + *
>>> + */
>>> +
>>> +#define _GNU_SOURCE /* added for asprintf */
>>> +#include <fcntl.h>
>>> +#include <sys/ioctl.h>
>>> +#include <stdio.h>
>>> +
>>> +#include "fwts.h"
>>> +
>>> +#ifdef HAVE_MTD_MTD_ABI_H
>>> +#include <mtd/mtd-abi.h>
>>> +#endif
>>> +
>>> +#ifdef HAVE_LIBFDT
>>> +#include <libfdt.h>
>>> +#endif
>>> +
>>> +#define FDT_FLASH_PATH "/proc/device-tree/chosen/ibm,system-flash"
>>> +#define SYSFS_MTD_PATH "/sys/class/mtd"
>>> +
>>> +bool mtd_present(int fwts_mtd_flags, char *mtd_devnode)
>>> +{
>>> + return !access(mtd_devnode, fwts_mtd_flags);
>>> +}
>>> +
>>> +int mtd_hdr_query(fwts_framework *fw, char *mtd_devnode) {
>>> +
>>> + /* snippet from skiboot libflash/ffs.h */
>>> + struct ffs_hdr {
>>> + char magic[8];
>>> + };
>>> + int fd = 0;
>>> + ssize_t bytes_read = 0;
>>> + struct ffs_hdr mtd_hdr;
>>> +
>>> + if ((fd = open(mtd_devnode, O_RDONLY)) < 0) {
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL MTD Info",
>>> + "Cannot get data from MTD device '%s'.",
>>> + mtd_devnode);
>>> + return FWTS_ERROR;
>>> + }
>>> +
>>> + bytes_read = read(fd, &mtd_hdr, sizeof(mtd_hdr) );
>>> +
>>> + if (bytes_read >= 4) {
>>> + /* FFS_MAGIC from skiboot libflash/ffs.h */
>>> + if (strncmp(mtd_hdr.magic, "PART", 4) == 0) {
>>> + fwts_log_info(fw,
>>> + "MTD device '%s' header eye-catcher 'PART'"
>>> + " verified.\n", mtd_devnode);
>>> + } else {
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
>>> + "OPAL MTD Info",
>>> + "MTD device '%s' header eye-catcher 'PART'"
>>> + " not able to be"
>>> + " verified. Check the system setup.\n",
>>> + mtd_devnode);
>>> + close(fd);
>>> + return FWTS_ERROR;
>>> + }
>>> + } else {
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL MTD Info",
>>> + "MTD device '%s' header was unable to be read."
>>> + " Cannot validate the integrity of the MTD."
>>> + " Check the system setup.\n",
>>> + mtd_devnode);
>>> + close(fd);
>>> + return FWTS_ERROR;
>>> + }
>>> +
>>> + close(fd);
>>> + return FWTS_OK;
>>> +}
>>> +
>>> +int mtd_dev_query(fwts_framework *fw, char *mtd_devnode)
>>> +{
>>> +
>>> +#ifdef HAVE_MTD_MTD_ABI_H
>>> + int fd = 0;
>>> + int fwts_mtd_flags = 0;
>>> + struct mtd_info_user mtd_info;
>>> +#endif
>>> +
>>> + if (!mtd_present(R_OK | W_OK, mtd_devnode)) {
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL MTD Info",
>>> + "Cannot read or write to MTD device '%s'"
>>> + " check your user privileges.", mtd_devnode);
>>> + return FWTS_ERROR;
>>> + } else {
>>> + fwts_log_info(fw, "MTD device '%s' is verified"
>>> + " and %s is read/write in the file system, the"
>>> + " MTD device itself will be checked later,"
>>> + " see MTD Flags.",
>>> + mtd_devnode, mtd_devnode);
>>> + }
>>> +
>>> +#ifdef HAVE_MTD_MTD_ABI_H
>>> + if (strstr(mtd_devnode, "ro")) {
>>> + fwts_mtd_flags = O_RDONLY;
>>> + } else {
>>> + fwts_mtd_flags = O_RDWR;
>>> + }
>>> +
>>> + if ((fd = open(mtd_devnode, fwts_mtd_flags)) < 0) {
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL MTD Info",
>>> + "Cannot get data from '%s'"
>>> + " device interface.", mtd_devnode);
>>> + return FWTS_ERROR;
>>> + }
>>> +
>>> + if (ioctl(fd, MEMGETINFO, &mtd_info)) {
>>> + close(fd);
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL MTD Info",
>>> + "Cannot get data from '%s'"
>>> + " device interface.", mtd_devnode);
>>> + return FWTS_ERROR;
>>> + } else {
>>> + fwts_log_info(fw, "MTD device '%s' attributes follow:"
>>> + " MTD Type=%u (3=MTD_NORFLASH),"
>>> + " MTD Flags=%u (1024=MTD_WRITEABLE),"
>>> + " MTD total size=%u bytes,"
>>> + " MTD erase size=%u bytes,"
>>> + " MTD write size=%u,"
>>> + " MTD oob size=%u",
>>> + mtd_devnode,
>>> + mtd_info.type,
>>> + mtd_info.flags,
>>> + mtd_info.size,
>>> + mtd_info.erasesize,
>>> + mtd_info.writesize,
>>> + mtd_info.oobsize);
>>> + close(fd);
>>> + return FWTS_OK;
>>> + }
>>> +}
>>> +#else
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
>>> + "OPAL MTD Info",
>>> + "MTD Info unable to be retrieved"
>>> + " for '%s' due to lack of "
>>> + "mtd-abi.h, check your "
>>> + "configuration and rebuild.",
>>> + mtd_devnode);
>>> + return FWTS_ERROR;
>>> +}
>>> +#endif
>>> +
>>> +static int mtd_info_test1(fwts_framework *fw)
>>> +{
>>> + char fdt_node_path[PATH_MAX];
>>> + int count, i, fd;
>>> + ssize_t bytes = 0, bytes_read = 0;
>>> + struct dirent **namelist;
>>> +
>>> + fd = open(FDT_FLASH_PATH, O_RDONLY);
>>> + if (fd < 0) {
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
>>> + "OPAL MTD Info",
>>> + "Failed to open the path %s."
>>> + " Check the installation"
>>> + " for the path %s.\n",
>>> + FDT_FLASH_PATH,
>>> + FDT_FLASH_PATH);
>>> + return FWTS_ERROR;
>>> + }
>>> + bytes_read = read(fd, fdt_node_path, sizeof(fdt_node_path));
>> do we expect bytes_read to be sizeof(fdt_node_path) if successful too?
> On success, bytes_read will be the number of bytes actually read
yup, and should that be sizeof(fdt_node_path)? if so, it may be worth
checking for that.
>>> + if (bytes_read < 0) {
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
>>> + "OPAL MTD Info",
>>> + "Failed to get the FDT info."
>>> + " Check the installation "
>>> + "for the path %s.\n",
>>> + FDT_FLASH_PATH);
>>> + close(fd);
>>> + return FWTS_ERROR;
>>> + }
>>> + close(fd);
>>> + fwts_log_info(fw, "MTD Info validated FDT of '%s'.",
>>> + fdt_node_path);
>>> +
>>> + count = scandir(SYSFS_MTD_PATH, &namelist, NULL, alphasort);
>>> + if (count < 0) {
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
>>> + "OPAL MTD Info",
>>> + "Scan for MTD '%s' unable to find any "
>>> + "candidates. Check the installation "
>>> + "for the MTD device config.",
>>> + SYSFS_MTD_PATH);
>>> + }
>>> +
>>> + bytes = 0;
>>> +
>>> + fwts_log_nl(fw);
>>> + fwts_log_info(fw, "STARTING checks of MTD devices");
>>> + fwts_log_nl(fw);
>>> +
>>> + for (i = 0; i < count; i++) {
>>> + struct dirent *dirent;
>>> + char *sys_device_path; /* /sys/class/device/mtdx */
>>> + char *mtd_device_path; /* /dev/mtdx */
>>> + char *driver_path;
>>> + char fdt_node_path_tmp[PATH_MAX];
>>> + char mtd_driver_path[PATH_MAX];
>>> +
>>> + memset(fdt_node_path_tmp, 0, sizeof(fdt_node_path_tmp));
>>> + memset(mtd_driver_path, 0, sizeof(mtd_driver_path));
>>> +
>>> + dirent = namelist[i];
>>> +
>>> + if (dirent->d_name[0] == '.' || bytes ||
>>> + asprintf(&sys_device_path,
>>> + "%s/%s/device/of_node",
>>> + SYSFS_MTD_PATH, dirent->d_name) < 0) {
>>> + /* asprintf must be last condition so when it */
>>> + /* evaluates sys_device_path gets allocated */
>>> + free(namelist[i]);
>>> + continue;
>>> + }
>>> +
>>> + bytes = readlink(sys_device_path, fdt_node_path_tmp,
>>> + sizeof(fdt_node_path_tmp) - 1);
>>> + free(sys_device_path);
>>> + if (bytes < 0) {
>>> + /* if mtd system flash does not have an FDT node */
>>> + /* just continue */
>> minor nitpick, can the two comments above be indented by 1 tab
> Done
>>
>>> + free(namelist[i]);
>>> + /* reset the bytes to continue */
>>> + bytes = 0;
>>> + continue;
>>> + }
>>> + fdt_node_path_tmp[bytes] = '\0';
>>> +
>>> + if (strstr(fdt_node_path_tmp, fdt_node_path)) {
>>> + bytes = asprintf(&mtd_device_path, "/dev/%s",
>>> + dirent->d_name);
>>> + if (bytes < 0) {
>>> + free(namelist[i]);
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
>>> + "OPAL MTD Info",
>>> + "Failed to get the device path."
>>> + " Check the installation for the"
>>> + " path '/dev/%s'.",
>>> + dirent->d_name);
>>> + continue;
>>> + }
>>> + mtd_device_path[bytes] = '\0';
>>> + bytes = 0;
>>> + if (asprintf(&driver_path,
>>> + "%s/%s/device/driver",
>>> + SYSFS_MTD_PATH, dirent->d_name) < 0) {
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
>>> + "OPAL MTD Info",
>>> + "Failed to get the MTD Path."
>>> + " Check the installation "
>>> + "for the path '%s/%s/device/driver'.",
>>> + SYSFS_MTD_PATH,
>>> + dirent->d_name);
>>> + free(mtd_device_path);
>>> + continue;
>>> + }
>>> + bytes = readlink(driver_path, mtd_driver_path,
>>> + sizeof(mtd_driver_path) -1);
>>> + if (bytes < 0) {
>>> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
>>> + "OPAL MTD Info",
>>> + "Failed to get the MTD drive path."
>>> + " Check the installation for the "
>>> + "path %s.",
>>> + driver_path);
>>> + free(mtd_device_path);
>>> + free(driver_path);
>>> + continue;
>>> + } else {
>>> + mtd_driver_path[bytes] = '\0';
>>> + bytes = 0;
>>> + free(driver_path);
>>> + }
>>> +
>>> + if (strstr(mtd_driver_path, "powernv_flash")) {
>>> + if (!strstr(mtd_device_path, "ro")) {
>>> + if (mtd_dev_query(fw,
>>> + mtd_device_path)) {
>>> + /* failures logged in subroutine */
>>> + free(mtd_device_path);
>>> + continue;
>>> + }
>>> + if (mtd_hdr_query(fw,
>>> + mtd_device_path)) {
>>> + /* failures logged in subroutine */
>>> + free(mtd_device_path);
>>> + continue;
>>> + }
>>> + fwts_log_nl(fw);
>> minor nitpick - the above has the indentation from what I can tell.
> Can you clarify this comment, not sure what is requested ?
>>
>>> + }
>>> + free(mtd_device_path);
>>> + }
>>> + }
>>> +
>>> + free(namelist[i]);
>>> + }
>>> + free(namelist);
>>> +
>>> + fwts_log_info(fw, "ENDING checks of MTD devices");
>>> + fwts_log_nl(fw);
>>> +
>>> + fwts_passed(fw, "OPAL MTD info passed.");
>>> +
>>> + return FWTS_OK;
>>> +}
>>> +
>>> +static int mtd_info_init(fwts_framework *fw)
>>> +{
>>> + if (fw->fdt) {
>>> +#ifdef HAVE_LIBFDT
>>> + int node;
>>> + /* perform some FDT validation */
>>> + node = fdt_path_offset(fw->fdt,
>>> + "/ibm,opal/nvram");
>>> + if (node >= 0) {
>>> + if (!fdt_node_check_compatible(fw->fdt, node,
>>> + "ibm,opal-nvram")) {
>>> + fwts_log_info(fw,
>>> + "MTD Info initialization validated"
>>> + " FDT for 'ibm,opal-nvram'.");
>>> + return FWTS_OK;
>>> + } else {
>>> + return FWTS_SKIP;
>>> + }
>>> + }
>>> +#endif
>>> + } else {
>>> + fwts_log_info(fw, "The OPAL MTD device tree node is not"
>>> + " able to be detected so skipping the mtd_info"
>>> + " test. There may be tools missing such as"
>>> + " libfdt-dev or dtc, check that the packages"
>>> + " are installed and re-build if needed."
>>> + " If this condition persists try running the"
>>> + " dt_base test to further diagnose. If dt_base"
>>> + " test is not available this is probably a"
>>> + " setup problem.");
>>> + return FWTS_SKIP;
>>> + }
>>> +
>>> + /* only run test when fdt node is confirmed */
>>> + return FWTS_SKIP;
>>> +}
>>> +
>>> +static fwts_framework_minor_test mtd_info_tests[] = {
>>> + { mtd_info_test1, "OPAL MTD Info" },
>>> + { NULL, NULL }
>>> +};
>>> +
>>> +static fwts_framework_ops mtd_info_ops = {
>>> + .description = "OPAL MTD Info",
>>> + .init = mtd_info_init,
>>> + .minor_tests = mtd_info_tests
>>> +};
>>> +
>>> +FWTS_REGISTER_FEATURES("mtd_info", &mtd_info_ops, FWTS_TEST_ANYTIME,
>>> + FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV,
>>> + FWTS_FW_FEATURE_DEVICETREE);
>>>
>
More information about the fwts-devel
mailing list