blob: dfb8baac6675d0104de54d1dfb1119270964f0c4 [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2022 Google
*/
#include <common.h>
#include <emmc_partitions.h>
#include <tee.h>
#include <tee/optee.h>
#include <zircon_uboot/partition.h>
#include "optee_msg.h"
#include "optee_msg_supplicant.h"
#include "optee_private.h"
/*
* Read `length` bytes from `offset` of a designated raw partition into
* `buffer`. Buffer size is guaranteed to be >= `length`.
*/
static u32 do_read(u64 offset, u64 length, void *buffer)
{
zircon_partition *part = zircon_get_partition(MMC_SECURE_STORAGE_NAME);
if (!part) {
return TEE_ERROR_ITEM_NOT_FOUND;
}
if (!part->read) {
printf("Optee raw IO: no read implementation\n");
zircon_free_partition(part);
return TEE_ERROR_NOT_SUPPORTED;
}
// Boundary check will be performed in read(). The API supports unaligned
// read.
int res = part->read(part, offset, buffer, length);
if (res) {
printf("Optee raw IO: read failed. %d\n", res);
zircon_free_partition(part);
return TEE_ERROR_GENERIC;
}
zircon_free_partition(part);
return TEE_SUCCESS;
}
/*
* Write `length` bytes from `buffer` into a designated raw partition at
* `offset`. Buffer size is guaranteed to be >= `length`.
*/
static u32 do_write(u64 offset, u64 length, const void *buffer)
{
zircon_partition *part = zircon_get_partition(MMC_SECURE_STORAGE_NAME);
if (!part) {
return TEE_ERROR_ITEM_NOT_FOUND;
}
if (!part->write) {
printf("Optee raw IO: no write implementation\n");
zircon_free_partition(part);
return TEE_ERROR_NOT_SUPPORTED;
}
// Boundary check will be performed in write(). The API supports unaligned
// write.
int res = part->write(part, offset, buffer, length);
if (res) {
printf("Optee raw IO: write failed. %d\n", res);
zircon_free_partition(part);
return TEE_ERROR_GENERIC;
}
zircon_free_partition(part);
return TEE_SUCCESS;
}
void optee_suppl_cmd_raw_io(struct optee_msg_arg *arg)
{
u64 offset;
u64 length;
void *buffer;
u64 buffer_size;
/* The supplicant is part of the REE<>TEE communications stack. */
arg->ret_origin = TEE_ORIGIN_COMMS;
if (!(arg->num_params == 2 &&
arg->params[0].attr == OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)) {
arg->ret = TEE_ERROR_BAD_PARAMETERS;
return;
}
offset = arg->params[0].u.value.b;
length = arg->params[0].u.value.c;
buffer = (u8 *)arg->params[1].u.tmem.buf_ptr;
buffer_size = arg->params[1].u.tmem.size;
if (!(buffer && buffer_size > 0 && buffer_size >= length)) {
arg->ret = TEE_ERROR_BAD_PARAMETERS;
return;
}
switch (arg->params[0].u.value.a) {
case OPTEE_MRC_RAW_READ:
if (arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT) {
arg->ret = TEE_ERROR_BAD_PARAMETERS;
return;
}
arg->ret = do_read(offset, length, buffer);
break;
case OPTEE_MRC_RAW_WRITE:
if (arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_TMEM_INPUT) {
arg->ret = TEE_ERROR_BAD_PARAMETERS;
return;
}
arg->ret = do_write(offset, length, buffer);
break;
default:
arg->ret = TEE_ERROR_BAD_PARAMETERS;
break;
}
return;
}
#if defined(DEV_BUILD_CONFIG)
int optee_suppl_cmd_raw_io_wrapper(enum optee_suppl_cmd_raw_io_op op,
void *buffer, size_t offset, size_t length)
{
struct optee_suppl_cmd_raw_io_test_param {
struct optee_msg_arg arg;
struct optee_msg_param params[2];
} test_arg = {
.arg = {
.num_params = 2,
},
.params[0] = {
.attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT,
.u.value.b = offset,
.u.value.c = length,
},
.params[1] = {
.u.tmem.buf_ptr = (u64)buffer,
.u.tmem.size = length,
},
};
switch (op) {
case optee_suppl_cmd_raw_io_read:
test_arg.arg.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
test_arg.arg.params[0].u.value.a = OPTEE_MRC_RAW_READ;
break;
case optee_suppl_cmd_raw_io_write:
test_arg.arg.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
test_arg.arg.params[0].u.value.a = OPTEE_MRC_RAW_WRITE;
break;
default:
return -1;
}
optee_suppl_cmd_raw_io(&test_arg.arg);
return test_arg.arg.ret == TEE_SUCCESS ? 0 : -1;
}
#endif