root/drivers/platform/x86/hp/hp-bioscfg/surestart-attributes.c
// SPDX-License-Identifier: GPL-2.0
/*
 * Functions corresponding to sure start object type attributes under
 * BIOS for use with hp-bioscfg driver
 *
 * Copyright (c) 2022 HP Development Company, L.P.
 */

#include "bioscfg.h"
#include <linux/types.h>

/* Maximum number of log entries supported when log entry size is 16
 * bytes. This value is calculated by dividing 4096 (page size) by
 * log entry size.
 */
#define LOG_MAX_ENTRIES         254

/*
 * Current Log entry size. This value size will change in the
 * future. The driver reads a total of 128 bytes for each log entry
 * provided by BIOS but only the first 16 bytes are used/read.
 */
#define LOG_ENTRY_SIZE          16

/*
 * audit_log_entry_count_show - Reports the number of
 *                              existing audit log entries available
 *                              to be read
 */
static ssize_t audit_log_entry_count_show(struct kobject *kobj,
                                          struct kobj_attribute *attr, char *buf)
{
        int ret;
        u32 count = 0;

        ret = hp_wmi_perform_query(HPWMI_SURESTART_GET_LOG_COUNT,
                                   HPWMI_SURESTART,
                                   &count, 1, sizeof(count));

        if (ret < 0)
                return ret;

        return sysfs_emit(buf, "%d,%d,%d\n", count, LOG_ENTRY_SIZE,
                          LOG_MAX_ENTRIES);
}

/*
 * audit_log_entries_show() - Return all entries found in log file
 */
static ssize_t audit_log_entries_show(struct kobject *kobj,
                                      struct kobj_attribute *attr, char *buf)
{
        int ret;
        int i;
        u32 count = 0;
        u8 audit_log_buffer[128];

        // Get the number of event logs
        ret = hp_wmi_perform_query(HPWMI_SURESTART_GET_LOG_COUNT,
                                   HPWMI_SURESTART,
                                   &count, 1, sizeof(count));

        if (ret < 0)
                return ret;

        /*
         * The show() api will not work if the audit logs ever go
         * beyond 4KB
         */
        if (count * LOG_ENTRY_SIZE > PAGE_SIZE)
                return -EIO;

        /*
         * We are guaranteed the buffer is 4KB so today all the event
         * logs will fit
         */
        for (i = 0; i < count; i++) {
                audit_log_buffer[0] = i + 1;

                /*
                 * read audit log entry at a time. 'buf' input value
                 * provides the audit log entry to be read. On
                 * input, Byte 0 = Audit Log entry number from
                 * beginning (1..254)
                 * Entry number 1 is the newest entry whereas the
                 * highest entry number (number of entries) is the
                 * oldest entry.
                 */
                ret = hp_wmi_perform_query(HPWMI_SURESTART_GET_LOG,
                                           HPWMI_SURESTART,
                                           audit_log_buffer, 1, 128);

                if (ret < 0 || (LOG_ENTRY_SIZE * i) > PAGE_SIZE) {
                        /*
                         * Encountered a failure while reading
                         * individual logs. Only a partial list of
                         * audit log will be returned.
                         */
                        break;
                } else {
                        memcpy(buf, audit_log_buffer, LOG_ENTRY_SIZE);
                        buf += LOG_ENTRY_SIZE;
                }
        }

        return i * LOG_ENTRY_SIZE;
}

static struct kobj_attribute sure_start_audit_log_entry_count = __ATTR_RO(audit_log_entry_count);
static struct kobj_attribute sure_start_audit_log_entries = __ATTR_RO(audit_log_entries);

static struct attribute *sure_start_attrs[] = {
        &sure_start_audit_log_entry_count.attr,
        &sure_start_audit_log_entries.attr,
        NULL
};

static const struct attribute_group sure_start_attr_group = {
        .attrs = sure_start_attrs,
};

void hp_exit_sure_start_attributes(void)
{
        sysfs_remove_group(bioscfg_drv.sure_start_attr_kobj,
                           &sure_start_attr_group);
}

int hp_populate_sure_start_data(struct kobject *attr_name_kobj)
{
        bioscfg_drv.sure_start_attr_kobj = attr_name_kobj;
        return sysfs_create_group(attr_name_kobj, &sure_start_attr_group);
}