target/arm: Define an IDAU interface

In v8M, the Implementation Defined Attribution Unit (IDAU) is
a small piece of hardware typically implemented in the SoC
which provides board or SoC specific security attribution
information for each address that the CPU performs MPU/SAU
checks on. For QEMU, we model this with a QOM interface which
is implemented by the board or SoC object and connected to
the CPU using a link property.

This commit defines the new interface class, adds the link
property to the CPU object, and makes the SAU checking
code call the IDAU interface if one is present.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20180220180325.29818-5-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2018-03-02 10:45:36 +00:00
parent 891f3bc37f
commit 181962fd69
4 changed files with 104 additions and 3 deletions

View File

@ -19,6 +19,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "target/arm/idau.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "cpu.h" #include "cpu.h"
@ -688,6 +689,13 @@ static void arm_cpu_post_init(Object *obj)
} }
} }
if (arm_feature(&cpu->env, ARM_FEATURE_M_SECURITY)) {
object_property_add_link(obj, "idau", TYPE_IDAU_INTERFACE, &cpu->idau,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
}
qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property, qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property,
&error_abort); &error_abort);
} }
@ -1821,11 +1829,18 @@ static const TypeInfo arm_cpu_type_info = {
.class_init = arm_cpu_class_init, .class_init = arm_cpu_class_init,
}; };
static const TypeInfo idau_interface_type_info = {
.name = TYPE_IDAU_INTERFACE,
.parent = TYPE_INTERFACE,
.class_size = sizeof(IDAUInterfaceClass),
};
static void arm_cpu_register_types(void) static void arm_cpu_register_types(void)
{ {
const ARMCPUInfo *info = arm_cpus; const ARMCPUInfo *info = arm_cpus;
type_register_static(&arm_cpu_type_info); type_register_static(&arm_cpu_type_info);
type_register_static(&idau_interface_type_info);
while (info->name) { while (info->name) {
cpu_register(info); cpu_register(info);

View File

@ -694,6 +694,9 @@ struct ARMCPU {
/* MemoryRegion to use for secure physical accesses */ /* MemoryRegion to use for secure physical accesses */
MemoryRegion *secure_memory; MemoryRegion *secure_memory;
/* For v8M, pointer to the IDAU interface provided by board/SoC */
Object *idau;
/* 'compatible' string for this CPU for Linux device trees */ /* 'compatible' string for this CPU for Linux device trees */
const char *dtb_compatible; const char *dtb_compatible;

View File

@ -1,4 +1,5 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "target/arm/idau.h"
#include "trace.h" #include "trace.h"
#include "cpu.h" #include "cpu.h"
#include "internals.h" #include "internals.h"
@ -9741,19 +9742,32 @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address,
*/ */
ARMCPU *cpu = arm_env_get_cpu(env); ARMCPU *cpu = arm_env_get_cpu(env);
int r; int r;
bool idau_exempt = false, idau_ns = true, idau_nsc = true;
int idau_region = IREGION_NOTVALID;
/* TODO: implement IDAU */ if (cpu->idau) {
IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(cpu->idau);
IDAUInterface *ii = IDAU_INTERFACE(cpu->idau);
iic->check(ii, address, &idau_region, &idau_exempt, &idau_ns,
&idau_nsc);
}
if (access_type == MMU_INST_FETCH && extract32(address, 28, 4) == 0xf) { if (access_type == MMU_INST_FETCH && extract32(address, 28, 4) == 0xf) {
/* 0xf0000000..0xffffffff is always S for insn fetches */ /* 0xf0000000..0xffffffff is always S for insn fetches */
return; return;
} }
if (v8m_is_sau_exempt(env, address, access_type)) { if (idau_exempt || v8m_is_sau_exempt(env, address, access_type)) {
sattrs->ns = !regime_is_secure(env, mmu_idx); sattrs->ns = !regime_is_secure(env, mmu_idx);
return; return;
} }
if (idau_region != IREGION_NOTVALID) {
sattrs->irvalid = true;
sattrs->iregion = idau_region;
}
switch (env->sau.ctrl & 3) { switch (env->sau.ctrl & 3) {
case 0: /* SAU.ENABLE == 0, SAU.ALLNS == 0 */ case 0: /* SAU.ENABLE == 0, SAU.ALLNS == 0 */
break; break;
@ -9790,7 +9804,15 @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address,
} }
} }
/* TODO when we support the IDAU then it may override the result here */ /* The IDAU will override the SAU lookup results if it specifies
* higher security than the SAU does.
*/
if (!idau_ns) {
if (sattrs->ns || (!idau_nsc && sattrs->nsc)) {
sattrs->ns = false;
sattrs->nsc = idau_nsc;
}
}
break; break;
} }
} }

61
target/arm/idau.h Normal file
View File

@ -0,0 +1,61 @@
/*
* QEMU ARM CPU -- interface for the Arm v8M IDAU
*
* Copyright (c) 2018 Linaro Ltd
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see
* <http://www.gnu.org/licenses/gpl-2.0.html>
*
* In the v8M architecture, the IDAU is a small piece of hardware
* typically implemented in the SoC which provides board or SoC
* specific security attribution information for each address that
* the CPU performs MPU/SAU checks on. For QEMU, we model this with a
* QOM interface which is implemented by the board or SoC object and
* connected to the CPU using a link property.
*/
#ifndef TARGET_ARM_IDAU_H
#define TARGET_ARM_IDAU_H
#include "qom/object.h"
#define TYPE_IDAU_INTERFACE "idau-interface"
#define IDAU_INTERFACE(obj) \
INTERFACE_CHECK(IDAUInterface, (obj), TYPE_IDAU_INTERFACE)
#define IDAU_INTERFACE_CLASS(class) \
OBJECT_CLASS_CHECK(IDAUInterfaceClass, (class), TYPE_IDAU_INTERFACE)
#define IDAU_INTERFACE_GET_CLASS(obj) \
OBJECT_GET_CLASS(IDAUInterfaceClass, (obj), TYPE_IDAU_INTERFACE)
typedef struct IDAUInterface {
Object parent;
} IDAUInterface;
#define IREGION_NOTVALID -1
typedef struct IDAUInterfaceClass {
InterfaceClass parent;
/* Check the specified address and return the IDAU security information
* for it by filling in iregion, exempt, ns and nsc:
* iregion: IDAU region number, or IREGION_NOTVALID if not valid
* exempt: true if address is exempt from security attribution
* ns: true if the address is NonSecure
* nsc: true if the address is NonSecure-callable
*/
void (*check)(IDAUInterface *ii, uint32_t address, int *iregion,
bool *exempt, bool *ns, bool *nsc);
} IDAUInterfaceClass;
#endif