/* UUID of the stmm PTA */ staticconststruct tee_client_device_id tee_stmm_efi_id_table[] = {
{PTA_STMM_UUID},
{}
};
staticint tee_ctx_match(struct tee_ioctl_version_data *ver, constvoid *data)
{ /* currently only OP-TEE is supported as a communication path */ if (ver->impl_id == TEE_IMPL_ID_OPTEE) return 1; else return 0;
}
/** * tee_mm_communicate() - Pass a buffer to StandaloneMM running in TEE * * @comm_buf: locally allocated communication buffer * @dsize: buffer size * Return: status code
*/ static efi_status_t tee_mm_communicate(void *comm_buf, size_t dsize)
{
size_t buf_size; struct efi_mm_communicate_header *mm_hdr; struct tee_ioctl_invoke_arg arg; struct tee_param param[4]; struct tee_shm *shm = NULL; int rc;
switch (param[1].u.value.a) { case ARM_SVC_SPM_RET_SUCCESS: return EFI_SUCCESS;
case ARM_SVC_SPM_RET_INVALID_PARAMS: return EFI_INVALID_PARAMETER;
case ARM_SVC_SPM_RET_DENIED: return EFI_ACCESS_DENIED;
case ARM_SVC_SPM_RET_NO_MEMORY: return EFI_OUT_OF_RESOURCES;
default: return EFI_ACCESS_DENIED;
}
}
/** * mm_communicate() - Adjust the communication buffer to StandAlonneMM and send * it to TEE * * @comm_buf: locally allocated communication buffer, buffer should * be enough big to have some headers and payload * @payload_size: payload size * Return: status code
*/ static efi_status_t mm_communicate(u8 *comm_buf, size_t payload_size)
{
size_t dsize;
efi_status_t ret; struct efi_mm_communicate_header *mm_hdr; struct smm_variable_communicate_header *var_hdr;
/** * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the * header data. * * @dptr: pointer address to store allocated buffer * @payload_size: payload size * @func: standAloneMM function number * Return: pointer to corresponding StandAloneMM function buffer or NULL
*/ staticvoid *setup_mm_hdr(u8 **dptr, size_t payload_size, size_t func)
{ const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID; struct efi_mm_communicate_header *mm_hdr; struct smm_variable_communicate_header *var_hdr;
u8 *comm_buf;
/* In the init function we initialize max_buffer_size with * get_max_payload(). So skip the test if max_buffer_size is initialized * StandAloneMM will perform similar checks and drop the buffer if it's * too long
*/ if (max_buffer_size &&
max_buffer_size < (MM_COMMUNICATE_HEADER_SIZE +
MM_VARIABLE_COMMUNICATE_SIZE + payload_size)) { return NULL;
}
comm_buf = alloc_pages_exact(COMM_BUF_SIZE(payload_size),
GFP_KERNEL | __GFP_ZERO); if (!comm_buf) return NULL;
ret = mm_communicate(comm_buf, payload_size); if (ret != EFI_SUCCESS) goto out;
/* Make sure the buffer is big enough for storing variables */ if (var_payload->size < MM_VARIABLE_ACCESS_HEADER_SIZE + 0x20) {
ret = EFI_DEVICE_ERROR; goto out;
}
*size = var_payload->size; /* * There seems to be a bug in EDK2 miscalculating the boundaries and * size checks, so deduct 2 more bytes to fulfill this requirement. Fix * it up here to ensure backwards compatibility with older versions * (cf. StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c. * sizeof (EFI_MM_COMMUNICATE_HEADER) instead the size minus the * flexible array member). * * size is guaranteed to be > 2 due to checks on the beginning.
*/
*size -= 2;
out:
free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size)); return ret;
}
ret = mm_communicate(comm_buf, payload_size); /* * Currently only R/O property is supported in StMM. * Variables that are not set to R/O will not set the property in StMM * and the call will return EFI_NOT_FOUND. We are setting the * properties to 0x0 so checking against that is enough for the * EFI_NOT_FOUND case.
*/ if (ret == EFI_NOT_FOUND)
ret = EFI_SUCCESS; if (ret != EFI_SUCCESS) goto out;
memcpy(var_property, &smm_property->property, sizeof(*var_property));
ret = mm_communicate(comm_buf, payload_size); if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) /* Update with reported data size for trimmed case */
*data_size = var_acc->data_size; if (ret != EFI_SUCCESS) goto out;
ret = get_property_int(name, name_size, vendor, &var_property); if (ret != EFI_SUCCESS) goto out;
ret = mm_communicate(comm_buf, payload_size); if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { /* Update with reported data size for trimmed case */
*name_size = var_getnext->name_size;
} if (ret != EFI_SUCCESS) goto out;
/* * Allocate the buffer early, before switching to RW (if needed) * so we won't need to account for any failures in reading/setting * the properties, if the allocation fails
*/
var_acc = setup_mm_hdr(&comm_buf, payload_size,
SMM_VARIABLE_FUNCTION_SET_VARIABLE); if (!var_acc) return EFI_DEVICE_ERROR;
/* * The API has the ability to override RO flags. If no RO check was * requested switch the variable to RW for the duration of this call
*/
ret = get_property_int(name, name_size, vendor, &var_property); if (ret != EFI_SUCCESS) {
dev_err(pvt_data.dev, "Getting variable property failed\n"); goto out;
}
if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) {
ret = EFI_WRITE_PROTECTED; goto out;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ilias Apalodimas ");
MODULE_AUTHOR("Masahisa Kojima ");
MODULE_DESCRIPTION("TEE based EFI runtime variable service driver");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.