root/usr/src/test/util-tests/tests/smbios/smbios_test_pinfo.c
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2019 Robert Mustacchi
 * Copyright 2021 Oxide Computer Company
 */

/*
 * Tests for SMBIOS type 44 - SMB_TYPE_PROCESSOR_INFO and the per-CPU type
 * follow ups.
 */

#include "smbios_test.h"

static uint16_t smbios_pinfo_phandle = 0x1;
static uint64_t smbios_pinfo_isa = 0x4010d;
static uint8_t smbios_pinfo_hartid[16];
static uint8_t smbios_pinfo_vendid[16];
static uint8_t smbios_pinfo_archid[16];
static uint8_t smbios_pinfo_machid[16];
static uint8_t smbios_pinfo_metdi[16];
static uint8_t smbios_pinfo_mitdi[16];

boolean_t
smbios_test_pinfo_mktable_amd64(smbios_test_table_t *table)
{
        smb_processor_info_t pi;

        pi.smbpai_hdr.smbh_type = SMB_TYPE_PROCESSOR_INFO;
        pi.smbpai_hdr.smbh_len = sizeof (smb_processor_info_t);
        pi.smbpai_proc = htole16(smbios_pinfo_phandle);
        pi.smbpai_len = 0;
        pi.smbpai_type = SMB_PROCINFO_T_AMD64;

        (void) smbios_test_table_append(table, &pi, sizeof (pi));
        smbios_test_table_append_eot(table);

        return (B_TRUE);
}

boolean_t
smbios_test_pinfo_verify_amd64(smbios_hdl_t *hdl)
{
        smbios_struct_t sp;
        smbios_processor_info_t pinfo;
        smbios_processor_info_riscv_t rv;
        boolean_t ret = B_TRUE;

        if (smbios_lookup_type(hdl, SMB_TYPE_PROCESSOR_INFO, &sp) == -1) {
                warnx("failed to lookup SMBIOS processor additional "
                    "information: %s", smbios_errmsg(smbios_errno(hdl)));
                return (B_FALSE);
        }

        if (smbios_info_processor_info(hdl, sp.smbstr_id, &pinfo) != 0) {

                warnx("failed to get SMBIOS processor additional "
                    "information: %s", smbios_errmsg(smbios_errno(hdl)));
                return (B_FALSE);
        }

        if (pinfo.smbpi_processor != smbios_pinfo_phandle) {
                warnx("processor handle incorrect, found 0x%" _PRIxID,
                    pinfo.smbpi_processor);
                ret = B_FALSE;
        }

        if (pinfo.smbpi_ptype != SMB_PROCINFO_T_AMD64) {
                warnx("processor type incorrect, found 0x%x",
                    pinfo.smbpi_ptype);
                ret = B_FALSE;
        }

        if (strcmp(smbios_processor_info_type_desc(pinfo.smbpi_ptype),
            "X64 (x86-64, Intel64, AMD64, EMT64)") != 0) {
                warnx("processor type incorrect, found %s",
                    smbios_processor_info_type_desc(pinfo.smbpi_ptype));
                ret = B_FALSE;
        }

        if (smbios_info_processor_riscv(hdl, sp.smbstr_id, &rv) != -1) {
                warnx("accidentally got riscv info on non-riscv handle");
                ret = B_FALSE;
        }

        if (smbios_errno(hdl) != ESMB_TYPE) {
                warnx("encountered wrong errno for RISC-V info, found: 0x%x",
                    smbios_errno(hdl));
                ret = B_FALSE;
        }

        return (ret);
}

boolean_t
smbios_test_pinfo_mktable_riscv(smbios_test_table_t *table)
{
        smb_processor_info_t pi;
        smb_processor_info_riscv_t rv;

        pi.smbpai_hdr.smbh_type = SMB_TYPE_PROCESSOR_INFO;
        pi.smbpai_hdr.smbh_len = sizeof (smb_processor_info_t) +
            sizeof (smb_processor_info_riscv_t);
        pi.smbpai_proc = htole16(smbios_pinfo_phandle);
        pi.smbpai_len = sizeof (smb_processor_info_riscv_t);
        pi.smbpai_type = SMB_PROCINFO_T_RV64;

        (void) smbios_test_table_append(table, &pi, sizeof (pi));

        rv.smbpairv_vers = 1;
        rv.smbpairv_len = sizeof (smb_processor_info_riscv_t);
        arc4random_buf(smbios_pinfo_hartid, sizeof (smbios_pinfo_hartid));
        bcopy(smbios_pinfo_hartid, rv.smbpairv_hartid,
            sizeof (smbios_pinfo_hartid));
        rv.smbpairv_boot = 1;
        arc4random_buf(smbios_pinfo_vendid, sizeof (smbios_pinfo_vendid));
        bcopy(smbios_pinfo_vendid, rv.smbpairv_vendid,
            sizeof (smbios_pinfo_vendid));
        arc4random_buf(smbios_pinfo_archid, sizeof (smbios_pinfo_archid));
        bcopy(smbios_pinfo_archid, rv.smbpairv_archid,
            sizeof (smbios_pinfo_archid));
        arc4random_buf(smbios_pinfo_machid, sizeof (smbios_pinfo_machid));
        bcopy(smbios_pinfo_machid, rv.smbpairv_machid,
            sizeof (smbios_pinfo_machid));
        rv.smbpairv_boot = 1;
        rv.smbpairv_isa = htole64(smbios_pinfo_isa);
        rv.smbpairv_privlvl = SMB_RV_PRIV_M | SMB_RV_PRIV_S;
        arc4random_buf(smbios_pinfo_metdi, sizeof (smbios_pinfo_metdi));
        bcopy(smbios_pinfo_metdi, rv.smbpairv_metdi,
            sizeof (smbios_pinfo_metdi));
        arc4random_buf(smbios_pinfo_mitdi, sizeof (smbios_pinfo_mitdi));
        bcopy(smbios_pinfo_mitdi, rv.smbpairv_mitdi,
            sizeof (smbios_pinfo_mitdi));
        rv.smbpairv_xlen = SMB_RV_WIDTH_64B;
        rv.smbpairv_mxlen = SMB_RV_WIDTH_64B;
        rv.smbpairv_sxlen = SMB_RV_WIDTH_128B;
        rv.smbpairv_uxlen = SMB_RV_WIDTH_32B;

        smbios_test_table_append_raw(table, &rv, sizeof (rv));
        smbios_test_table_append_eot(table);

        return (B_TRUE);
}

static void
smbios_test_pinfo_id_mismatch(uint8_t *act, uint8_t *exp)
{
        uint_t i;
        (void) fprintf(stderr, "found:    ");
        for (i = 0; i < 16; i++) {
                (void) fprintf(stderr, " %02x", act[i]);
        }
        (void) fprintf(stderr, "\nexpected: ");
        for (i = 0; i < 16; i++) {
                (void) fprintf(stderr, " %02x", exp[i]);
        }
        (void) fprintf(stderr, "\n");
}

boolean_t
smbios_test_pinfo_verify_riscv(smbios_hdl_t *hdl)
{
        smbios_struct_t sp;
        smbios_processor_info_t pinfo;
        smbios_processor_info_riscv_t rv;
        boolean_t ret = B_TRUE;

        if (smbios_lookup_type(hdl, SMB_TYPE_PROCESSOR_INFO, &sp) == -1) {
                warnx("failed to lookup SMBIOS processor additional "
                    "information: %s", smbios_errmsg(smbios_errno(hdl)));
                return (B_FALSE);
        }

        if (smbios_info_processor_info(hdl, sp.smbstr_id, &pinfo) != 0) {
                warnx("failed to get SMBIOS processor additional "
                    "information: %s", smbios_errmsg(smbios_errno(hdl)));
                return (B_FALSE);
        }

        if (pinfo.smbpi_processor != smbios_pinfo_phandle) {
                warnx("processor handle incorrect, found 0x%" _PRIxID,
                    pinfo.smbpi_processor);
                ret = B_FALSE;
        }

        if (pinfo.smbpi_ptype != SMB_PROCINFO_T_RV64) {
                warnx("processor type incorrect, found 0x%x",
                    pinfo.smbpi_ptype);
                ret = B_FALSE;
        }

        if (strcmp(smbios_processor_info_type_desc(pinfo.smbpi_ptype),
            "64-bit RISC-V (RV64)") != 0) {
                warnx("processor type incorrect, found %s",
                    smbios_processor_info_type_desc(pinfo.smbpi_ptype));
                ret = B_FALSE;
        }

        if (smbios_info_processor_riscv(hdl, sp.smbstr_id, &rv) != 0) {

                warnx("failed to get SMBIOS processor additional "
                    "information for RISC-V: %s",
                    smbios_errmsg(smbios_errno(hdl)));
                return (B_FALSE);
        }

        if (bcmp(rv.smbpirv_hartid, smbios_pinfo_hartid,
            sizeof (smbios_pinfo_hartid)) != 0) {
                warnx("RISC-V hart id's don't match");
                smbios_test_pinfo_id_mismatch(rv.smbpirv_hartid,
                    smbios_pinfo_hartid);
                ret = B_FALSE;
        }

        if (bcmp(rv.smbpirv_vendid, smbios_pinfo_vendid,
            sizeof (smbios_pinfo_vendid)) != 0) {
                warnx("RISC-V vend id's don't match");
                smbios_test_pinfo_id_mismatch(rv.smbpirv_vendid,
                    smbios_pinfo_vendid);
                ret = B_FALSE;
        }

        if (bcmp(rv.smbpirv_archid, smbios_pinfo_archid,
            sizeof (smbios_pinfo_archid)) != 0) {
                warnx("RISC-V arch id's don't match");
                smbios_test_pinfo_id_mismatch(rv.smbpirv_archid,
                    smbios_pinfo_archid);
                ret = B_FALSE;
        }

        if (bcmp(rv.smbpirv_machid, smbios_pinfo_machid,
            sizeof (smbios_pinfo_machid)) != 0) {
                warnx("RISC-V mach id's don't match");
                smbios_test_pinfo_id_mismatch(rv.smbpirv_machid,
                    smbios_pinfo_machid);
                ret = B_FALSE;
        }

        if (bcmp(rv.smbpirv_metdi, smbios_pinfo_metdi,
            sizeof (smbios_pinfo_metdi)) != 0) {
                warnx("RISC-V METDI don't match");
                smbios_test_pinfo_id_mismatch(rv.smbpirv_metdi,
                    smbios_pinfo_metdi);
                ret = B_FALSE;
        }

        if (bcmp(rv.smbpirv_mitdi, smbios_pinfo_mitdi,
            sizeof (smbios_pinfo_mitdi)) != 0) {
                warnx("RISC-V METDI don't match");
                smbios_test_pinfo_id_mismatch(rv.smbpirv_mitdi,
                    smbios_pinfo_mitdi);
                ret = B_FALSE;
        }

        if (rv.smbpirv_isa != smbios_pinfo_isa) {
                warnx("RISC-V ISA mismatch");
                ret = B_FALSE;
        }

        if (rv.smbpirv_privlvl != (SMB_RV_PRIV_M | SMB_RV_PRIV_S)) {
                warnx("RISC-V privilege level mismatch, found: 0x%x",
                    rv.smbpirv_privlvl);
                ret = B_FALSE;
        }

        if (rv.smbpirv_xlen != SMB_RV_WIDTH_64B) {
                warnx("RISC-V xlen mismatch, found: 0x%x", rv.smbpirv_xlen);
                ret = B_FALSE;
        }

        if (rv.smbpirv_mxlen != SMB_RV_WIDTH_64B) {
                warnx("RISC-V mxlen mismatch, found: 0x%x", rv.smbpirv_mxlen);
                ret = B_FALSE;
        }

        if (rv.smbpirv_sxlen != SMB_RV_WIDTH_128B) {
                warnx("RISC-V sxlen mismatch, found: 0x%x", rv.smbpirv_sxlen);
                ret = B_FALSE;
        }

        if (rv.smbpirv_uxlen != SMB_RV_WIDTH_32B) {
                warnx("RISC-V uxlen mismatch, found: 0x%x", rv.smbpirv_uxlen);
                ret = B_FALSE;
        }

        /*
         * Finally, use this to spot check several of the different RISC-V
         * strings.
         */
        if (strcmp(smbios_riscv_priv_desc(SMB_RV_PRIV_M), "Machine Mode") !=
            0) {
                warnx("SMB_RV_PRIV_M string desc mismatch, found %s",
                    smbios_riscv_priv_desc(SMB_RV_PRIV_M));
                ret = B_FALSE;
        }

        if (strcmp(smbios_riscv_priv_name(SMB_RV_PRIV_U), "SMB_RV_PRIV_U") !=
            0) {
                warnx("SMB_RV_PRIV_U string name mismatch, found %s",
                    smbios_riscv_priv_name(SMB_RV_PRIV_U));
                ret = B_FALSE;
        }

        if (strcmp(smbios_riscv_width_desc(SMB_RV_WIDTH_64B), "64-bit") !=
            0) {
                warnx("SMB_RV_WIDTH_64B string desc mismatch, found %s",
                    smbios_riscv_width_desc(SMB_RV_WIDTH_64B));
                ret = B_FALSE;
        }

        if (strcmp(smbios_riscv_width_desc(SMB_RV_WIDTH_128B), "128-bit") !=
            0) {
                warnx("SMB_RV_WIDTH_128B string desc mismatch, found %s",
                    smbios_riscv_width_desc(SMB_RV_WIDTH_128B));
                ret = B_FALSE;
        }

        if (strcmp(smbios_riscv_isa_desc(SMB_RV_ISA_A), "Atomic") != 0) {
                warnx("SMB_RV_ISA_A string desc mismatch, found %s",
                    smbios_riscv_isa_desc(SMB_RV_ISA_A));
                ret = B_FALSE;
        }

        if (strcmp(smbios_riscv_isa_desc(SMB_RV_ISA_C), "Compressed") != 0) {
                warnx("SMB_RV_ISA_C string desc mismatch, found %s",
                    smbios_riscv_isa_desc(SMB_RV_ISA_C));
                ret = B_FALSE;
        }

        if (strcmp(smbios_riscv_isa_desc(SMB_RV_ISA_Q),
            "Quad-precision floating-point") != 0) {
                warnx("SMB_RV_ISA_Q string desc mismatch, found %s",
                    smbios_riscv_isa_desc(SMB_RV_ISA_Q));
                ret = B_FALSE;
        }

        if (strcmp(smbios_riscv_isa_name(SMB_RV_ISA_A), "SMB_RV_ISA_A") != 0) {
                warnx("SMB_RV_ISA_A string name mismatch, found %s",
                    smbios_riscv_isa_name(SMB_RV_ISA_A));
                ret = B_FALSE;
        }

        if (strcmp(smbios_riscv_isa_name(SMB_RV_ISA_C), "SMB_RV_ISA_C") != 0) {
                warnx("SMB_RV_ISA_Q string name mismatch, found %s",
                    smbios_riscv_isa_name(SMB_RV_ISA_C));
                ret = B_FALSE;
        }

        if (strcmp(smbios_riscv_isa_name(SMB_RV_ISA_Q), "SMB_RV_ISA_Q") != 0) {
                warnx("SMB_RV_ISA_Q string name mismatch, found %s",
                    smbios_riscv_isa_name(SMB_RV_ISA_Q));
                ret = B_FALSE;
        }

        return (ret);
}

/*
 * This shows having an invalid table length.
 */
boolean_t
smbios_test_pinfo_mktable_invlen1(smbios_test_table_t *table)
{
        smb_processor_info_t pi;

        pi.smbpai_hdr.smbh_type = SMB_TYPE_PROCESSOR_INFO;
        pi.smbpai_hdr.smbh_len = 2;
        pi.smbpai_proc = htole16(smbios_pinfo_phandle);
        pi.smbpai_len = 0;
        pi.smbpai_type = SMB_PROCINFO_T_AMD64;

        (void) smbios_test_table_append(table, &pi, sizeof (pi));
        smbios_test_table_append_eot(table);

        return (B_TRUE);
}

/*
 * This sets the internal length of the additional processor information data to
 * go beyond the length of the basic structure.
 */
boolean_t
smbios_test_pinfo_mktable_invlen2(smbios_test_table_t *table)
{
        smb_processor_info_t pi;
        smb_processor_info_riscv_t rv;

        pi.smbpai_hdr.smbh_type = SMB_TYPE_PROCESSOR_INFO;
        pi.smbpai_hdr.smbh_len = sizeof (smb_processor_info_t);
        pi.smbpai_proc = htole16(smbios_pinfo_phandle);
        pi.smbpai_len = sizeof (smb_processor_info_riscv_t);
        pi.smbpai_type = SMB_PROCINFO_T_RV64;

        (void) smbios_test_table_append(table, &pi, sizeof (pi));

        arc4random_buf(&rv, sizeof (rv));
        rv.smbpairv_vers = 1;
        rv.smbpairv_len = sizeof (smb_processor_info_riscv_t);

        smbios_test_table_append_raw(table, &rv, sizeof (rv));
        smbios_test_table_append_eot(table);

        return (B_TRUE);
}

/*
 * This verifies that we can detect a header length that doesn't properly
 * contain both the risc-v and base structure.
 */
boolean_t
smbios_test_pinfo_mktable_invlen3(smbios_test_table_t *table)
{
        smb_processor_info_t pi;
        smb_processor_info_riscv_t rv;

        pi.smbpai_hdr.smbh_type = SMB_TYPE_PROCESSOR_INFO;
        pi.smbpai_hdr.smbh_len = sizeof (smb_processor_info_t);
        pi.smbpai_proc = htole16(smbios_pinfo_phandle);
        pi.smbpai_len = 0;
        pi.smbpai_type = SMB_PROCINFO_T_RV64;

        (void) smbios_test_table_append(table, &pi, sizeof (pi));

        arc4random_buf(&rv, sizeof (rv));
        rv.smbpairv_vers = 1;
        rv.smbpairv_len = sizeof (smb_processor_info_riscv_t);

        smbios_test_table_append_raw(table, &rv, sizeof (rv));
        smbios_test_table_append_eot(table);

        return (B_TRUE);
}

/*
 * This verifies that we can detect an inner risc-v additional processor
 * information section that declares its size to be beyond the header of the
 * structure.
 */
boolean_t
smbios_test_pinfo_mktable_invlen4(smbios_test_table_t *table)
{
        smb_processor_info_t pi;
        smb_processor_info_riscv_t rv;

        pi.smbpai_hdr.smbh_type = SMB_TYPE_PROCESSOR_INFO;
        pi.smbpai_hdr.smbh_len = sizeof (smb_processor_info_t) +
            sizeof (smb_processor_info_riscv_t);
        pi.smbpai_proc = htole16(smbios_pinfo_phandle);
        pi.smbpai_len = sizeof (smb_processor_info_riscv_t);
        pi.smbpai_type = SMB_PROCINFO_T_RV64;

        (void) smbios_test_table_append(table, &pi, sizeof (pi));

        arc4random_buf(&rv, sizeof (rv));
        rv.smbpairv_vers = 1;
        rv.smbpairv_len = sizeof (smb_processor_info_riscv_t) * 2;

        smbios_test_table_append_raw(table, &rv, sizeof (rv));
        smbios_test_table_append_eot(table);

        return (B_TRUE);
}
static boolean_t
smbios_test_pinfo_verify_badtable(smbios_hdl_t *hdl, int smberr,
    boolean_t valid_pinfo)
{
        smbios_struct_t sp;
        smbios_processor_info_t pinfo;
        smbios_processor_info_riscv_t rv;
        boolean_t ret = B_TRUE;

        if (smbios_lookup_type(hdl, SMB_TYPE_PROCESSOR_INFO, &sp) == -1) {
                warnx("failed to lookup SMBIOS processor additional "
                    "information: %s", smbios_errmsg(smbios_errno(hdl)));
                return (B_FALSE);
        }

        if (!valid_pinfo) {
                if (smbios_info_processor_info(hdl, sp.smbstr_id, &pinfo) !=
                    -1) {
                        warnx("accidentally parsed invalid processor "
                            "additional information as valid");
                        ret = B_FALSE;
                }

                if (smbios_errno(hdl) != smberr) {
                        warnx("encountered wrong error for processor info, "
                            "found: 0x%x", smbios_errno(hdl));
                        ret = B_FALSE;
                }
        } else {
                if (smbios_info_processor_info(hdl, sp.smbstr_id, &pinfo) !=
                    0) {
                        warnx("failed to get SMBIOS processor additional "
                            "information: %s",
                            smbios_errmsg(smbios_errno(hdl)));
                        ret = B_FALSE;
                }
        }

        if (smbios_info_processor_riscv(hdl, sp.smbstr_id, &rv) != -1) {
                warnx("accidentally got riscv info on invalid handle");
                ret = B_FALSE;
        }

        if (smbios_errno(hdl) != smberr) {
                warnx("encountered wrong error for amd64 info, found: 0x%x",
                    smbios_errno(hdl));
                ret = B_FALSE;
        }

        return (ret);
}

boolean_t
smbios_test_pinfo_verify_invlen1(smbios_hdl_t *hdl)
{
        return (smbios_test_pinfo_verify_badtable(hdl, ESMB_SHORT, B_FALSE));
}

boolean_t
smbios_test_pinfo_verify_invlen2(smbios_hdl_t *hdl)
{
        return (smbios_test_pinfo_verify_badtable(hdl, ESMB_CORRUPT, B_FALSE));
}

boolean_t
smbios_test_pinfo_verify_invlen3(smbios_hdl_t *hdl)
{
        return (smbios_test_pinfo_verify_badtable(hdl, ESMB_SHORT, B_TRUE));
}

boolean_t
smbios_test_pinfo_verify_invlen4(smbios_hdl_t *hdl)
{
        return (smbios_test_pinfo_verify_badtable(hdl, ESMB_CORRUPT, B_TRUE));
}

boolean_t
smbios_test_pinfo_verify_badtype(smbios_hdl_t *hdl)
{
        smbios_struct_t sp;
        smbios_processor_info_t pinfo;
        smbios_processor_info_riscv_t rv;
        boolean_t ret = B_TRUE;

        if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
                warnx("failed to lookup SMBIOS memory device information: %s",
                    smbios_errmsg(smbios_errno(hdl)));
                return (B_FALSE);
        }

        if (smbios_info_processor_info(hdl, sp.smbstr_id, &pinfo) != -1) {
                warnx("accidentally parsed invalid processor additional "
                    "information as valid");
                ret = B_FALSE;
        }

        if (smbios_errno(hdl) != ESMB_TYPE) {
                warnx("encountered wrong error for processor info, found: 0x%x",
                    smbios_errno(hdl));
                ret = B_FALSE;
        }

        if (smbios_info_processor_riscv(hdl, sp.smbstr_id, &rv) != -1) {
                warnx("accidentally got riscv info on invalid handle");
                ret = B_FALSE;
        }

        if (smbios_errno(hdl) != ESMB_TYPE) {
                warnx("encountered wrong error for processor info, found: 0x%x",
                    smbios_errno(hdl));
                ret = B_FALSE;
        }

        return (ret);
}