blob: 0fa198a27d3fc3cbfa79826ca59800885ba14e63 [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
// Copyright 2022 IBM Corp.
#define pr_fmt(fmt) "PLDM: " fmt
#include <opal.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <libpldm/bios.h>
#include <libpldm/bios_table.h>
#include "pldm.h"
/*
* PLDM_BIOS_STRING_TABLE = 0
* pldmtool bios GetBIOSTable -t 0
* pldmtool: Tx: 08 01 80 03 01 00 00 00 00 01 00
* ...
* "60": "hb_lid_ids",
* ...
*/
static void *bios_string_table;
static size_t bios_string_length;
/*
* PLDM_BIOS_ATTR_TABLE = 1
* pldmtool bios GetBIOSTable -t 1
* pldmtool: Tx: 08 01 80 03 01 00 00 00 00 01 01
*
* {
* "AttributeHandle": 8,
* "AttributeNameHandle": "60(hb_lid_ids)",
* "AttributeType": "BIOSString",
* "StringType": "0x01",
* "MinimumStringLength": 0,
* "MaximumStringLength": 1024,
* "DefaultStringLength": 0,
* "DefaultString": ""
* },
*/
static void *bios_attr_table;
static size_t bios_attr_length;
/*
* PLDM_BIOS_ATTR_VAL_TABLE = 2
* pldmtool bios GetBIOSTable -t 2
* pldmtool: Tx: 08 01 80 03 01 00 00 00 00 01 02
*
* {
* "AttributeHandle": 8,
* "AttributeType": "BIOSString",
* "CurrentStringLength": 616,
* "CurrentString": "ATTR_PERM=81e00663,ATTR_TMP=81e00664, ...
* NVRAM=81e0066b,...,pnor.toc=NA"
* }, ...
*/
static void *bios_val_table;
static size_t bios_val_length;
static bool bios_ready;
static void bios_init_complete(bool success)
{
/* Read not successful, error out and free the buffer */
if (!success) {
bios_ready = false;
if (bios_string_table != NULL) {
free(bios_string_table);
bios_string_length = 0;
}
if (bios_attr_table != NULL) {
free(bios_attr_table);
bios_attr_length = 0;
}
if (bios_val_table != NULL) {
free(bios_val_table);
bios_val_length = 0;
}
return;
}
/* Mark ready */
bios_ready = true;
}
/*
* Send/receive a PLDM GetBIOSTable request message
*/
static int get_bios_table_req(enum pldm_bios_table_types table_type,
void **bios_table, size_t *bios_length)
{
size_t data_size = PLDM_MSG_SIZE(struct pldm_get_bios_table_req);
size_t response_len, payload_len, bios_table_offset;
uint8_t completion_code, transfer_flag;
struct pldm_tx_data *tx = NULL;
uint32_t next_transfer_handle;
int rc = OPAL_SUCCESS;
void *response_msg;
struct pldm_get_bios_table_req bios_table_req = {
.transfer_handle = 0, /* (0 if transfer op is FIRSTPART) */
.transfer_op_flag = PLDM_GET_FIRSTPART,
.table_type = table_type
};
prlog(PR_DEBUG, "%s - table type: %d\n", __func__, table_type);
/* Encode the bios table request */
tx = zalloc(sizeof(struct pldm_tx_data) + data_size);
if (!tx)
return OPAL_NO_MEM;
tx->data_size = data_size;
rc = encode_get_bios_table_req(
DEFAULT_INSTANCE_ID,
bios_table_req.transfer_handle,
bios_table_req.transfer_op_flag,
bios_table_req.table_type,
(struct pldm_msg *)tx->data);
if (rc != PLDM_SUCCESS) {
prlog(PR_ERR, "Encode GetBIOSTableReq Error, type: %d, rc: %d\n",
table_type, rc);
free(tx);
return OPAL_PARAMETER;
}
/* Send and get the response message bytes */
rc = pldm_requester_queue_and_wait(tx, &response_msg, &response_len);
if (rc) {
prlog(PR_ERR, "Communication Error, req: GetBIOSTableReq, rc: %d\n", rc);
free(tx);
return rc;
}
/* Decode the message */
payload_len = response_len - sizeof(struct pldm_msg_hdr);
rc = decode_get_bios_table_resp(
response_msg,
payload_len,
&completion_code,
&next_transfer_handle,
&transfer_flag,
&bios_table_offset);
if (rc != PLDM_SUCCESS || completion_code != PLDM_SUCCESS) {
prlog(PR_ERR, "Decode GetBIOSTableResp Error, rc: %d, cc: %d\n",
rc, completion_code);
rc = OPAL_PARAMETER;
goto out;
}
/* we do not support multipart transfer */
if ((next_transfer_handle != PLDM_GET_NEXTPART) ||
(transfer_flag != PLDM_START_AND_END)) {
prlog(PR_ERR, "Transfert GetBIOSTable not complete "
"transfer_hndl: %d, transfer_flag: %d\n",
next_transfer_handle,
transfer_flag);
}
*bios_length = payload_len - bios_table_offset;
*bios_table = zalloc(*bios_length);
if (!bios_table) {
prlog(PR_ERR, "failed to allocate bios table (size: 0x%lx)\n",
*bios_length);
rc = OPAL_NO_MEM;
goto out;
}
memcpy(*bios_table,
((struct pldm_msg *)response_msg)->payload + bios_table_offset,
*bios_length);
out:
free(tx);
free(response_msg);
return rc;
}
int pldm_bios_init(void)
{
int rc;
/* BIOS String Table is a BIOS table that contains all the BIOS
* strings including attribute names, and pre-configured strings
* used in representing the values of the attributes.
* Each string in the BIOS String Table has an associated unique
* handle.
*/
rc = get_bios_table_req(PLDM_BIOS_STRING_TABLE,
&bios_string_table, &bios_string_length);
if (rc)
goto err;
/* BIOS Attribute Table is a BIOS table that contains attribute
* name handles, attribute types, type-specific metadata,
* type-specific possible values (if any), and default values.
*/
rc = get_bios_table_req(PLDM_BIOS_ATTR_TABLE,
&bios_attr_table, &bios_attr_length);
if (rc)
goto err;
/* BIOS Attribute Value Table is a BIOS table that contains all
* the current values of the BIOS attributes and settings.
* Each entry in this table contains the attribute handle, the
* attribute type, and current values.
*/
rc = get_bios_table_req(PLDM_BIOS_ATTR_VAL_TABLE,
&bios_val_table, &bios_val_length);
if (rc)
goto err;
bios_init_complete(true);
prlog(PR_DEBUG, "%s - done\n", __func__);
return OPAL_SUCCESS;
err:
bios_init_complete(false);
return rc;
}