blob: 07ab98996cfb6f9ea43867866a7680b19a6d8ad7 [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
/* Copyright 2020 IBM Corp. */
#include <skiboot.h>
#include "secboot_tpm.h"
/* Offset into the SECBOOT PNOR partition to write "TPMNV" data */
static size_t fakenv_offset = sizeof(struct secboot);
struct fake_tpmnv {
struct {
struct secboot_header header;
char vars[2048]; // Hardcode the size to 2048 for now
} vars;
struct tpmnv_control control;
int defined[2];
} __attribute__((packed));
static struct fake_tpmnv fakenv;
static int tpm_ready;
static inline void *nv_index_address(int index)
{
switch (index) {
case SECBOOT_TPMNV_VARS_INDEX:
return &fakenv.vars;
case SECBOOT_TPMNV_CONTROL_INDEX:
return &fakenv.control;
default:
return 0;
}
}
static int tpm_init(void)
{
int rc;
if (tpm_ready)
return 0;
rc = flash_secboot_read(&fakenv, fakenv_offset, sizeof(struct fake_tpmnv));
if (rc)
return rc;
tpm_ready = 1;
return 0;
}
static int fakenv_read(TPMI_RH_NV_INDEX nvIndex, void *buf,
size_t bufsize, uint16_t off)
{
if (tpm_init())
return OPAL_INTERNAL_ERROR;
memcpy(buf, nv_index_address(nvIndex) + off, bufsize);
return 0;
}
static int fakenv_write(TPMI_RH_NV_INDEX nvIndex, void *buf,
size_t bufsize, uint16_t off)
{
if (tpm_init())
return OPAL_INTERNAL_ERROR;
memcpy(nv_index_address(nvIndex) + off, buf, bufsize);
/* Just write the whole NV struct for now */
return flash_secboot_write(fakenv_offset, &fakenv, sizeof(struct fake_tpmnv));
}
static int fakenv_definespace(TPMI_RH_NV_INDEX nvIndex, uint16_t dataSize)
{
if (tpm_init())
return OPAL_INTERNAL_ERROR;
(void) dataSize;
switch (nvIndex) {
case SECBOOT_TPMNV_VARS_INDEX:
fakenv.defined[0] = 1;
return 0;
case SECBOOT_TPMNV_CONTROL_INDEX:
fakenv.defined[1] = 1;
return 0;
}
return OPAL_INTERNAL_ERROR;
}
static int fakenv_writelock(TPMI_RH_NV_INDEX nvIndex)
{
if (tpm_init())
return OPAL_INTERNAL_ERROR;
(void) nvIndex;
return 0;
}
static int fakenv_get_defined_indices(TPMI_RH_NV_INDEX **indices, size_t *count)
{
if (tpm_init())
return OPAL_INTERNAL_ERROR;
*indices = zalloc(sizeof(fakenv.defined));
if (*indices == NULL)
return OPAL_NO_MEM;
*count = 0;
if (fakenv.defined[0]) {
*indices[0] = SECBOOT_TPMNV_VARS_INDEX;
(*count)++;
}
if (fakenv.defined[1]) {
*indices[1] = SECBOOT_TPMNV_CONTROL_INDEX;
(*count)++;
}
return 0;
}
static int fakenv_undefinespace(TPMI_RH_NV_INDEX index)
{
if (tpm_init())
return OPAL_INTERNAL_ERROR;
switch (index) {
case SECBOOT_TPMNV_VARS_INDEX:
fakenv.defined[0] = 0;
memset(&fakenv.vars, 0, sizeof(fakenv.vars));
return 0;
case SECBOOT_TPMNV_CONTROL_INDEX:
fakenv.defined[1] = 0;
memset(&fakenv.control, 0, sizeof(fakenv.control));
return 0;
}
return -1;
}
static int fakenv_readpublic(TPMI_RH_NV_INDEX index, TPMS_NV_PUBLIC *nv_public,
TPM2B_NAME *nv_name)
{
if (tpm_init())
return OPAL_INTERNAL_ERROR;
(void) nv_public;
switch (index) {
case SECBOOT_TPMNV_VARS_INDEX:
memcpy(&nv_name->t.name, tpmnv_vars_name, sizeof(tpmnv_vars_name));
break;
case SECBOOT_TPMNV_CONTROL_INDEX:
memcpy(&nv_name->t.name, tpmnv_control_name, sizeof(tpmnv_control_name));
break;
default:
return OPAL_INTERNAL_ERROR;
}
return 0;
}
struct tpmnv_ops_s tpmnv_ops = {
.read = fakenv_read,
.write = fakenv_write,
.writelock = fakenv_writelock,
.definespace = fakenv_definespace,
.getindices = fakenv_get_defined_indices,
.undefinespace = fakenv_undefinespace,
.readpublic = fakenv_readpublic,
};