mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-26 14:55:16 +00:00
feat(drtm): add a few DRTM DMA protection APIs
Added DRTM DMA protections APIs, and called them during the DLME launch and DRTM SMC handling. Change-Id: I29e7238c04e2ca9f26600276c5c05bff5387789e Signed-off-by: Manish V Badarkhe <Manish.Badarkhe@arm.com>
This commit is contained in:
parent
1436e37dcb
commit
2b13a98599
4 changed files with 245 additions and 2 deletions
|
@ -14,9 +14,30 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <common/debug.h>
|
#include <common/debug.h>
|
||||||
|
#include <drivers/arm/smmu_v3.h>
|
||||||
#include "drtm_dma_prot.h"
|
#include "drtm_dma_prot.h"
|
||||||
|
#include "drtm_main.h"
|
||||||
|
#include "drtm_remediation.h"
|
||||||
#include <plat/common/platform.h>
|
#include <plat/common/platform.h>
|
||||||
|
#include <smccc_helpers.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ________________________ LAUNCH success ________________________
|
||||||
|
* | Initial | -------------------> | Prot engaged |
|
||||||
|
* |````````````````````````| |````````````````````````|
|
||||||
|
* | request.type == NONE | | request.type != NONE |
|
||||||
|
* | | <------------------- | |
|
||||||
|
* `________________________' UNPROTECT_MEM `________________________'
|
||||||
|
*
|
||||||
|
* Transitions that are not shown correspond to ABI calls that do not change
|
||||||
|
* state and result in an error being returned to the caller.
|
||||||
|
*/
|
||||||
|
static struct dma_prot active_prot = {
|
||||||
|
.type = PROTECT_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Version-independent type. */
|
||||||
|
typedef struct drtm_dl_dma_prot_args_v1 struct_drtm_dl_dma_prot_args;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function checks that platform supports complete DMA protection.
|
* This function checks that platform supports complete DMA protection.
|
||||||
|
@ -59,3 +80,184 @@ bool drtm_dma_prot_init(void)
|
||||||
|
|
||||||
return must_init_fail;
|
return must_init_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks that the DMA protection arguments are valid and that the given
|
||||||
|
* protected regions are covered by DMA protection.
|
||||||
|
*/
|
||||||
|
enum drtm_retc drtm_dma_prot_check_args(const struct_drtm_dl_dma_prot_args *a,
|
||||||
|
int a_dma_prot_type,
|
||||||
|
drtm_mem_region_t p)
|
||||||
|
{
|
||||||
|
switch ((enum dma_prot_type)a_dma_prot_type) {
|
||||||
|
case PROTECT_MEM_ALL:
|
||||||
|
if (a->dma_prot_table_paddr || a->dma_prot_table_size) {
|
||||||
|
ERROR("DRTM: invalid launch due to inconsistent"
|
||||||
|
" DMA protection arguments\n");
|
||||||
|
return MEM_PROTECT_INVALID;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Full DMA protection ought to ensure that the DLME and NWd
|
||||||
|
* DCE regions are protected, no further checks required.
|
||||||
|
*/
|
||||||
|
return SUCCESS;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ERROR("DRTM: invalid launch due to unsupported DMA protection type\n");
|
||||||
|
return MEM_PROTECT_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum drtm_retc drtm_dma_prot_engage(const struct_drtm_dl_dma_prot_args *a,
|
||||||
|
int a_dma_prot_type)
|
||||||
|
{
|
||||||
|
const uintptr_t *smmus;
|
||||||
|
size_t num_smmus = 0;
|
||||||
|
|
||||||
|
if (active_prot.type != PROTECT_NONE) {
|
||||||
|
ERROR("DRTM: launch denied as previous DMA protection"
|
||||||
|
" is still engaged\n");
|
||||||
|
return DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a_dma_prot_type == PROTECT_NONE) {
|
||||||
|
return SUCCESS;
|
||||||
|
/* Only PROTECT_MEM_ALL is supported currently. */
|
||||||
|
} else if (a_dma_prot_type != PROTECT_MEM_ALL) {
|
||||||
|
ERROR("%s(): unimplemented DMA protection type\n", __func__);
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Engage SMMUs in accordance with the request we have previously received.
|
||||||
|
* Only PROTECT_MEM_ALL is implemented currently.
|
||||||
|
*/
|
||||||
|
plat_enumerate_smmus(&smmus, &num_smmus);
|
||||||
|
for (const uintptr_t *smmu = smmus; smmu < smmus+num_smmus; smmu++) {
|
||||||
|
/*
|
||||||
|
* TODO: Invalidate SMMU's Stage-1 and Stage-2 TLB entries. This ensures
|
||||||
|
* that any outstanding device transactions are completed, see Section
|
||||||
|
* 3.21.1, specification IHI_0070_C_a for an approximate reference.
|
||||||
|
*/
|
||||||
|
int rc = smmuv3_ns_set_abort_all(*smmu);
|
||||||
|
if (rc != 0) {
|
||||||
|
ERROR("DRTM: SMMU at PA 0x%lx failed to engage DMA protection"
|
||||||
|
" rc=%d\n", *smmu, rc);
|
||||||
|
return INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Restrict DMA from the GIC.
|
||||||
|
*
|
||||||
|
* Full DMA protection may be achieved as follows:
|
||||||
|
*
|
||||||
|
* With a GICv3:
|
||||||
|
* - Set GICR_CTLR.EnableLPIs to 0, for each GICR;
|
||||||
|
* GICR_CTLR.RWP == 0 must be the case before finishing, for each GICR.
|
||||||
|
* - Set GITS_CTLR.Enabled to 0;
|
||||||
|
* GITS_CTLR.Quiescent == 1 must be the case before finishing.
|
||||||
|
*
|
||||||
|
* In addition, with a GICv4:
|
||||||
|
* - Set GICR_VPENDBASER.Valid to 0, for each GICR;
|
||||||
|
* GICR_CTLR.RWP == 0 must be the case before finishing, for each GICR.
|
||||||
|
*
|
||||||
|
* Alternatively, e.g. if some bit values cannot be changed at runtime,
|
||||||
|
* this procedure should return an error if the LPI Pending and
|
||||||
|
* Configuration tables overlap the regions being protected.
|
||||||
|
*/
|
||||||
|
|
||||||
|
active_prot.type = a_dma_prot_type;
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Undo what has previously been done in drtm_dma_prot_engage(), or enter
|
||||||
|
* remediation if it is not possible.
|
||||||
|
*/
|
||||||
|
enum drtm_retc drtm_dma_prot_disengage(void)
|
||||||
|
{
|
||||||
|
const uintptr_t *smmus;
|
||||||
|
size_t num_smmus = 0;
|
||||||
|
const char *err_str = "cannot undo PROTECT_MEM_ALL SMMU config";
|
||||||
|
|
||||||
|
if (active_prot.type == PROTECT_NONE) {
|
||||||
|
return SUCCESS;
|
||||||
|
/* Only PROTECT_MEM_ALL is supported currently. */
|
||||||
|
} else if (active_prot.type != PROTECT_MEM_ALL) {
|
||||||
|
ERROR("%s(): unimplemented DMA protection type\n", __func__);
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For PROTECT_MEM_ALL, undo the SMMU configuration for "abort all" mode
|
||||||
|
* done during engage().
|
||||||
|
*/
|
||||||
|
/* Simply enter remediation for now. */
|
||||||
|
(void)smmus;
|
||||||
|
(void)num_smmus;
|
||||||
|
drtm_enter_remediation(1ULL, err_str);
|
||||||
|
|
||||||
|
/* TODO: Undo GIC DMA restrictions. */
|
||||||
|
|
||||||
|
active_prot.type = PROTECT_NONE;
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t drtm_unprotect_mem(void *ctx)
|
||||||
|
{
|
||||||
|
enum drtm_retc ret;
|
||||||
|
|
||||||
|
switch (active_prot.type) {
|
||||||
|
case PROTECT_NONE:
|
||||||
|
ERROR("DRTM: invalid UNPROTECT_MEM, no DMA protection has"
|
||||||
|
" previously been engaged\n");
|
||||||
|
ret = DENIED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROTECT_MEM_ALL:
|
||||||
|
/*
|
||||||
|
* UNPROTECT_MEM is a no-op for PROTECT_MEM_ALL: DRTM must not touch
|
||||||
|
* the NS SMMU as it is expected that the DLME has configured it.
|
||||||
|
*/
|
||||||
|
active_prot.type = PROTECT_NONE;
|
||||||
|
|
||||||
|
ret = SUCCESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = drtm_dma_prot_disengage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SMC_RET1(ctx, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drtm_dma_prot_serialise_table(uint8_t *dst, size_t *size_out)
|
||||||
|
{
|
||||||
|
if (active_prot.type == PROTECT_NONE) {
|
||||||
|
return;
|
||||||
|
} else if (active_prot.type != PROTECT_MEM_ALL) {
|
||||||
|
ERROR("%s(): unimplemented DMA protection type\n", __func__);
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct __packed descr_table_1 {
|
||||||
|
drtm_memory_region_descriptor_table_t header;
|
||||||
|
drtm_mem_region_t regions[1];
|
||||||
|
} prot_table = {
|
||||||
|
.header = {
|
||||||
|
.revision = 1,
|
||||||
|
.num_regions = sizeof(((struct descr_table_1 *)NULL)->regions) /
|
||||||
|
sizeof(((struct descr_table_1 *)NULL)->regions[0])
|
||||||
|
},
|
||||||
|
.regions = {
|
||||||
|
{.region_address = 0, PAGES_AND_TYPE(UINT64_MAX, 0x3)},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(dst, &prot_table, sizeof(prot_table));
|
||||||
|
*size_out = sizeof(prot_table);
|
||||||
|
}
|
||||||
|
|
|
@ -8,15 +8,43 @@
|
||||||
#define DRTM_DMA_PROT_H
|
#define DRTM_DMA_PROT_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <plat/common/platform.h>
|
||||||
|
#include <services/drtm_svc.h>
|
||||||
|
|
||||||
struct __packed drtm_dl_dma_prot_args_v1 {
|
struct __packed drtm_dl_dma_prot_args_v1 {
|
||||||
uint64_t dma_prot_table_paddr;
|
uint64_t dma_prot_table_paddr;
|
||||||
uint64_t dma_prot_table_size;
|
uint64_t dma_prot_table_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Values for DRTM_PROTECT_MEMORY */
|
||||||
|
enum dma_prot_type {
|
||||||
|
PROTECT_NONE = -1,
|
||||||
|
PROTECT_MEM_ALL = 0,
|
||||||
|
PROTECT_MEM_REGION = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dma_prot {
|
||||||
|
enum dma_prot_type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DRTM_MEM_REGION_PAGES_AND_TYPE(pages, type) \
|
||||||
|
(((uint64_t)(pages) & (((uint64_t)1 << 52) - 1)) \
|
||||||
|
| (((uint64_t)(type) & 0x7) << 52))
|
||||||
|
|
||||||
|
#define PAGES_AND_TYPE(pages, type) \
|
||||||
|
.region_size_type = DRTM_MEM_REGION_PAGES_AND_TYPE(pages, type)
|
||||||
|
|
||||||
/* Opaque / encapsulated type. */
|
/* Opaque / encapsulated type. */
|
||||||
typedef struct drtm_dl_dma_prot_args_v1 drtm_dl_dma_prot_args_v1_t;
|
typedef struct drtm_dl_dma_prot_args_v1 drtm_dl_dma_prot_args_v1_t;
|
||||||
|
|
||||||
bool drtm_dma_prot_init(void);
|
bool drtm_dma_prot_init(void);
|
||||||
|
enum drtm_retc drtm_dma_prot_check_args(const drtm_dl_dma_prot_args_v1_t *a,
|
||||||
|
int a_dma_prot_type,
|
||||||
|
drtm_mem_region_t p);
|
||||||
|
enum drtm_retc drtm_dma_prot_engage(const drtm_dl_dma_prot_args_v1_t *a,
|
||||||
|
int a_dma_prot_type);
|
||||||
|
enum drtm_retc drtm_dma_prot_disengage(void);
|
||||||
|
uint64_t drtm_unprotect_mem(void *ctx);
|
||||||
|
void drtm_dma_prot_serialise_table(uint8_t *dst, size_t *size_out);
|
||||||
|
|
||||||
#endif /* DRTM_DMA_PROT_H */
|
#endif /* DRTM_DMA_PROT_H */
|
||||||
|
|
|
@ -358,6 +358,7 @@ static enum drtm_retc drtm_dl_check_args(uint64_t x1,
|
||||||
static uint64_t drtm_dynamic_launch(uint64_t x1, void *handle)
|
static uint64_t drtm_dynamic_launch(uint64_t x1, void *handle)
|
||||||
{
|
{
|
||||||
enum drtm_retc ret = SUCCESS;
|
enum drtm_retc ret = SUCCESS;
|
||||||
|
enum drtm_retc dma_prot_ret;
|
||||||
struct_drtm_dl_args args;
|
struct_drtm_dl_args args;
|
||||||
|
|
||||||
/* Ensure that only boot PE is powered on */
|
/* Ensure that only boot PE is powered on */
|
||||||
|
@ -380,6 +381,17 @@ static uint64_t drtm_dynamic_launch(uint64_t x1, void *handle)
|
||||||
SMC_RET1(handle, ret);
|
SMC_RET1(handle, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Engage the DMA protections. The launch cannot proceed without the DMA
|
||||||
|
* protections due to potential TOC/TOU vulnerabilities w.r.t. the DLME
|
||||||
|
* region (and to the NWd DCE region).
|
||||||
|
*/
|
||||||
|
ret = drtm_dma_prot_engage(&args.dma_prot_args,
|
||||||
|
DL_ARGS_GET_DMA_PROT_TYPE(&args));
|
||||||
|
if (ret != SUCCESS) {
|
||||||
|
SMC_RET1(handle, ret);
|
||||||
|
}
|
||||||
|
|
||||||
SMC_RET1(handle, ret);
|
SMC_RET1(handle, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,7 +509,7 @@ uint64_t drtm_smc_handler(uint32_t smc_fid,
|
||||||
|
|
||||||
case ARM_DRTM_SVC_UNPROTECT_MEM:
|
case ARM_DRTM_SVC_UNPROTECT_MEM:
|
||||||
INFO("DRTM service handler: unprotect mem\n");
|
INFO("DRTM service handler: unprotect mem\n");
|
||||||
SMC_RET1(handle, SMC_OK);
|
return drtm_unprotect_mem(handle);
|
||||||
break; /* not reached */
|
break; /* not reached */
|
||||||
|
|
||||||
case ARM_DRTM_SVC_DYNAMIC_LAUNCH:
|
case ARM_DRTM_SVC_DYNAMIC_LAUNCH:
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#define DRTM_PAGE_SIZE (4 * (1 << 10))
|
#define DRTM_PAGE_SIZE (4 * (1 << 10))
|
||||||
#define DRTM_PAGE_SIZE_STR "4-KiB"
|
#define DRTM_PAGE_SIZE_STR "4-KiB"
|
||||||
|
|
||||||
|
#define DL_ARGS_GET_DMA_PROT_TYPE(a) (((a)->features >> 3) & 0x7U)
|
||||||
#define DL_ARGS_GET_PCR_SCHEMA(a) (((a)->features >> 1) & 0x3U)
|
#define DL_ARGS_GET_PCR_SCHEMA(a) (((a)->features >> 1) & 0x3U)
|
||||||
#define DL_ARGS_GET_DLME_ENTRY_POINT(a) \
|
#define DL_ARGS_GET_DLME_ENTRY_POINT(a) \
|
||||||
(((a)->dlme_paddr + (a)->dlme_img_off + (a)->dlme_img_ep_off))
|
(((a)->dlme_paddr + (a)->dlme_img_off + (a)->dlme_img_ep_off))
|
||||||
|
|
Loading…
Add table
Reference in a new issue