blob: d9b5907c75331366c6d2f5b97f4657b4ed4fd6dd [file] [log] [blame]
/** @file
SVSM TPM communication
Copyright (C) 2024 James.Bottomley@HansenPartnership.com
Copyright (C) 2024 IBM Corporation
Copyright (C) 2024 Red Hat
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/AmdSvsmLib.h>
#include <Library/PcdLib.h>
#include "Tpm2Svsm.h"
/**
Platform commands (MSSIM commands) can be sent through the
SVSM_VTPM_CMD operation. Each command can have its own
request and response structures.
**/
#define TPM_SEND_COMMAND 8
#pragma pack(1)
typedef struct _TPM2_SEND_CMD_REQ {
UINT32 Cmd;
UINT8 Locality;
UINT32 BufSize;
UINT8 Buf[];
} TPM2_SEND_CMD_REQ;
typedef struct _TPM2_SEND_CMD_RESP {
UINT32 Size;
UINT8 Buf[];
} TPM2_SEND_CMD_RESP;
#pragma pack()
/* Max req/resp buffer size */
#define TPM_PLATFORM_MAX_BUFFER 4096
typedef union {
TPM2_SEND_CMD_REQ req;
TPM2_SEND_CMD_RESP resp;
} SVSM_TPM_CMD_BUFFER;
STATIC_ASSERT (sizeof (SVSM_TPM_CMD_BUFFER) <= TPM_PLATFORM_MAX_BUFFER, "SVSM_TPM_CMD_BUFFER too large");
/**
Probe the SVSM vTPM for TPM_SEND_COMMAND support. The
TPM_SEND_COMMAND platform command can be used to execute a
TPM command and get the result.
@retval TRUE TPM_SEND_COMMAND is supported.
@retval FALSE TPM_SEND_COMMAND is not supported.
**/
BOOLEAN
Tpm2SvsmQueryTpmSendCmd (
VOID
)
{
UINT64 PlatformCmdBitmap;
UINT64 TpmSendMask;
PlatformCmdBitmap = 0;
TpmSendMask = 1 << TPM_SEND_COMMAND;
if (!AmdSvsmVtpmQuery (&PlatformCmdBitmap, NULL)) {
return FALSE;
}
return ((PlatformCmdBitmap & TpmSendMask) == TpmSendMask) ? TRUE : FALSE;
}
/**
Send a TPM command to the SVSM vTPM and return the TPM response.
@param[in] BufferIn It should contain the marshaled
TPM command.
@param[in] SizeIn Size of the TPM command.
@param[out] BufferOut It will contain the marshaled
TPM response.
@param[in, out] SizeOut Size of the BufferOut; it will also
be used to return the size of the
TPM response
@retval EFI_SUCCESS Operation completed successfully.
@retval EFI_INVALID_PARAMETER Buffer not provided.
@retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
@retval EFI_DEVICE_ERROR Unexpected device behavior.
@retval EFI_OUT_OF_RESOURCES Out of memory when allocating internal buffer.
@retval EFI_UNSUPPORTED Unsupported TPM version
**/
EFI_STATUS
Tpm2SvsmTpmSendCommand (
IN UINT8 *BufferIn,
IN UINT32 SizeIn,
OUT UINT8 *BufferOut,
IN OUT UINT32 *SizeOut
)
{
STATIC SVSM_TPM_CMD_BUFFER *Buffer = NULL;
if ((SizeIn == 0) || !BufferIn || !SizeOut || !BufferOut) {
return EFI_INVALID_PARAMETER;
}
if (SizeIn > TPM_PLATFORM_MAX_BUFFER - sizeof (TPM2_SEND_CMD_REQ)) {
return EFI_BUFFER_TOO_SMALL;
}
if (Buffer == NULL) {
STATIC_ASSERT (sizeof (UINT64) >= sizeof (UINTN), "Pointer size larger than 64bit");
Buffer = (SVSM_TPM_CMD_BUFFER *)(UINTN)PcdGet64 (PcdSvsmVTpmBufferPtr);
if (Buffer == NULL) {
Buffer = (SVSM_TPM_CMD_BUFFER *)AllocatePages (EFI_SIZE_TO_PAGES (TPM_PLATFORM_MAX_BUFFER));
if (Buffer == NULL) {
DEBUG ((DEBUG_ERROR, "Unable to allocate SVSM vTPM buffer: %r", EFI_OUT_OF_RESOURCES));
return EFI_OUT_OF_RESOURCES;
}
PcdSet64S (PcdSvsmVTpmBufferPtr, (UINTN)(VOID *)Buffer);
}
}
Buffer->req.Cmd = TPM_SEND_COMMAND;
Buffer->req.Locality = 0;
Buffer->req.BufSize = SizeIn;
CopyMem (Buffer->req.Buf, BufferIn, SizeIn);
if (!AmdSvsmVtpmCmd ((UINT8 *)Buffer)) {
return EFI_DEVICE_ERROR;
}
if (Buffer->resp.Size > TPM_PLATFORM_MAX_BUFFER - sizeof (TPM2_SEND_CMD_RESP)) {
return EFI_DEVICE_ERROR;
}
if (Buffer->resp.Size > *SizeOut) {
return EFI_BUFFER_TOO_SMALL;
}
CopyMem (BufferOut, Buffer->resp.Buf, Buffer->resp.Size);
*SizeOut = Buffer->resp.Size;
return EFI_SUCCESS;
}