arm: Don't panic when checking coprocessor read/write permissions
Instructions that use the coprocessor interface check the current program status to determine whether the current context has the priviledges to read from/write to the coprocessor. Some modes allow the execution of coprocessor instructions, some others do not allow it, while some other modes are unexpected (e.g., executing an AArch32 instruction while being in an AArch64 mode). Previously we would unconditionally trigger a panic if we were in an unexpected mode. This change removes the panic and replaces it with an Undefined Instruction fault that triggers if and when a coprocessor instruction commits in an unexpected mode. This allows speculative coprocessor instructions from unexpected modes to execute but prevents them from gettting committed. Change-Id: If2776d5bae2471cdbaf76d0e1ae655f501bfbf01 Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-by: Rekai Gonzalez Alberquilla <rekai.gonzalezalberquilla@arm.com> Reviewed-on: https://gem5-review.googlesource.com/2281 Maintainer: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-by: Weiping Liao <weipingliao@google.com>
This commit is contained in:
parent
4b164f8382
commit
3384caf0fe
3 changed files with 70 additions and 31 deletions
|
@ -1,6 +1,6 @@
|
||||||
// -*- mode:c++ -*-
|
// -*- mode:c++ -*-
|
||||||
|
|
||||||
// Copyright (c) 2010-2013 ARM Limited
|
// Copyright (c) 2010-2013,2017 ARM Limited
|
||||||
// All rights reserved
|
// All rights reserved
|
||||||
//
|
//
|
||||||
// The license below extends only to copyright in the software and shall
|
// The license below extends only to copyright in the software and shall
|
||||||
|
@ -814,7 +814,9 @@ let {{
|
||||||
|
|
||||||
mrc14code = '''
|
mrc14code = '''
|
||||||
MiscRegIndex miscReg = (MiscRegIndex) xc->tcBase()->flattenMiscIndex(op1);
|
MiscRegIndex miscReg = (MiscRegIndex) xc->tcBase()->flattenMiscIndex(op1);
|
||||||
if (!canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase())) {
|
bool can_read, undefined;
|
||||||
|
std::tie(can_read, undefined) = canReadCoprocReg(miscReg, Scr, Cpsr);
|
||||||
|
if (!can_read || undefined) {
|
||||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||||
mnemonic);
|
mnemonic);
|
||||||
}
|
}
|
||||||
|
@ -836,7 +838,9 @@ let {{
|
||||||
|
|
||||||
mcr14code = '''
|
mcr14code = '''
|
||||||
MiscRegIndex miscReg = (MiscRegIndex) xc->tcBase()->flattenMiscIndex(dest);
|
MiscRegIndex miscReg = (MiscRegIndex) xc->tcBase()->flattenMiscIndex(dest);
|
||||||
if (!canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase())) {
|
bool can_write, undefined;
|
||||||
|
std::tie(can_write, undefined) = canWriteCoprocReg(miscReg, Scr, Cpsr);
|
||||||
|
if (undefined || !can_write) {
|
||||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||||
mnemonic);
|
mnemonic);
|
||||||
}
|
}
|
||||||
|
@ -861,12 +865,13 @@ let {{
|
||||||
xc->tcBase()->flattenMiscIndex(preFlatOp1);
|
xc->tcBase()->flattenMiscIndex(preFlatOp1);
|
||||||
bool hypTrap = mcrMrc15TrapToHyp(miscReg, Hcr, Cpsr, Scr, Hdcr, Hstr,
|
bool hypTrap = mcrMrc15TrapToHyp(miscReg, Hcr, Cpsr, Scr, Hdcr, Hstr,
|
||||||
Hcptr, imm);
|
Hcptr, imm);
|
||||||
bool canRead = canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
bool can_read, undefined;
|
||||||
|
std::tie(can_read, undefined) = canReadCoprocReg(miscReg, Scr, Cpsr);
|
||||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||||
// the register is accessable, in other modes we trap if only if the register
|
// the register is accessable, in other modes we trap if only if the register
|
||||||
// IS accessable.
|
// IS accessable.
|
||||||
if (!canRead && !(hypTrap && !inUserMode(Cpsr) && !inSecureState(Scr, Cpsr))) {
|
if (undefined || (!can_read && !(hypTrap && !inUserMode(Cpsr) &&
|
||||||
|
!inSecureState(Scr, Cpsr)))) {
|
||||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||||
mnemonic);
|
mnemonic);
|
||||||
}
|
}
|
||||||
|
@ -891,12 +896,14 @@ let {{
|
||||||
xc->tcBase()->flattenMiscIndex(preFlatDest);
|
xc->tcBase()->flattenMiscIndex(preFlatDest);
|
||||||
bool hypTrap = mcrMrc15TrapToHyp(miscReg, Hcr, Cpsr, Scr, Hdcr, Hstr,
|
bool hypTrap = mcrMrc15TrapToHyp(miscReg, Hcr, Cpsr, Scr, Hdcr, Hstr,
|
||||||
Hcptr, imm);
|
Hcptr, imm);
|
||||||
bool canWrite = canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
bool can_write, undefined;
|
||||||
|
std::tie(can_write, undefined) = canWriteCoprocReg(miscReg, Scr, Cpsr);
|
||||||
|
|
||||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||||
// the register is accessable, in other modes we trap if only if the register
|
// the register is accessable, in other modes we trap if only if the register
|
||||||
// IS accessable.
|
// IS accessable.
|
||||||
if (!canWrite & !(hypTrap & !inUserMode(Cpsr) & !inSecureState(Scr, Cpsr))) {
|
if (undefined || (!can_write && !(hypTrap && !inUserMode(Cpsr) &&
|
||||||
|
!inSecureState(Scr, Cpsr)))) {
|
||||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||||
mnemonic);
|
mnemonic);
|
||||||
}
|
}
|
||||||
|
@ -920,12 +927,13 @@ let {{
|
||||||
MiscRegIndex miscReg = (MiscRegIndex)
|
MiscRegIndex miscReg = (MiscRegIndex)
|
||||||
xc->tcBase()->flattenMiscIndex(preFlatOp1);
|
xc->tcBase()->flattenMiscIndex(preFlatOp1);
|
||||||
bool hypTrap = mcrrMrrc15TrapToHyp(miscReg, Cpsr, Scr, Hstr, Hcr, imm);
|
bool hypTrap = mcrrMrrc15TrapToHyp(miscReg, Cpsr, Scr, Hstr, Hcr, imm);
|
||||||
bool canRead = canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
bool can_read, undefined;
|
||||||
|
std::tie(can_read, undefined) = canReadCoprocReg(miscReg, Scr, Cpsr);
|
||||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||||
// the register is accessable, in other modes we trap if only if the register
|
// the register is accessable, in other modes we trap if only if the register
|
||||||
// IS accessable.
|
// IS accessable.
|
||||||
if (!canRead && !(hypTrap && !inUserMode(Cpsr) && !inSecureState(Scr, Cpsr))) {
|
if (undefined || (!can_read && !(hypTrap && !inUserMode(Cpsr) &&
|
||||||
|
!inSecureState(Scr, Cpsr)))) {
|
||||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||||
mnemonic);
|
mnemonic);
|
||||||
}
|
}
|
||||||
|
@ -949,12 +957,14 @@ let {{
|
||||||
MiscRegIndex miscReg = (MiscRegIndex)
|
MiscRegIndex miscReg = (MiscRegIndex)
|
||||||
xc->tcBase()->flattenMiscIndex(preFlatDest);
|
xc->tcBase()->flattenMiscIndex(preFlatDest);
|
||||||
bool hypTrap = mcrrMrrc15TrapToHyp(miscReg, Cpsr, Scr, Hstr, Hcr, imm);
|
bool hypTrap = mcrrMrrc15TrapToHyp(miscReg, Cpsr, Scr, Hstr, Hcr, imm);
|
||||||
bool canWrite = canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
bool can_write, undefined;
|
||||||
|
std::tie(can_write, undefined) = canWriteCoprocReg(miscReg, Scr, Cpsr);
|
||||||
|
|
||||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||||
// the register is accessable, in other modes we trap if only if the register
|
// the register is accessable, in other modes we trap if only if the register
|
||||||
// IS accessable.
|
// IS accessable.
|
||||||
if (!canWrite & !(hypTrap & !inUserMode(Cpsr) & !inSecureState(Scr, Cpsr))) {
|
if (undefined || (!can_write && !(hypTrap && !inUserMode(Cpsr) &&
|
||||||
|
!inSecureState(Scr, Cpsr)))) {
|
||||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||||
mnemonic);
|
mnemonic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010-2013, 2015-2016 ARM Limited
|
* Copyright (c) 2010-2013, 2015-2017 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -41,6 +41,8 @@
|
||||||
|
|
||||||
#include "arch/arm/miscregs.hh"
|
#include "arch/arm/miscregs.hh"
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include "arch/arm/isa.hh"
|
#include "arch/arm/isa.hh"
|
||||||
#include "base/misc.hh"
|
#include "base/misc.hh"
|
||||||
#include "cpu/thread_context.hh"
|
#include "cpu/thread_context.hh"
|
||||||
|
@ -1967,11 +1969,12 @@ decodeCP15Reg64(unsigned crm, unsigned opc1)
|
||||||
return MISCREG_CP15_UNIMPL;
|
return MISCREG_CP15_UNIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
std::tuple<bool, bool>
|
||||||
canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc)
|
canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr)
|
||||||
{
|
{
|
||||||
bool secure = !scr.ns;
|
bool secure = !scr.ns;
|
||||||
bool canRead;
|
bool canRead = false;
|
||||||
|
bool undefined = false;
|
||||||
|
|
||||||
switch (cpsr.mode) {
|
switch (cpsr.mode) {
|
||||||
case MODE_USER:
|
case MODE_USER:
|
||||||
|
@ -1995,18 +1998,19 @@ canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc)
|
||||||
canRead = miscRegInfo[reg][MISCREG_HYP_RD];
|
canRead = miscRegInfo[reg][MISCREG_HYP_RD];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unrecognized mode setting in CPSR.\n");
|
undefined = true;
|
||||||
}
|
}
|
||||||
// can't do permissions checkes on the root of a banked pair of regs
|
// can't do permissions checkes on the root of a banked pair of regs
|
||||||
assert(!miscRegInfo[reg][MISCREG_BANKED]);
|
assert(!miscRegInfo[reg][MISCREG_BANKED]);
|
||||||
return canRead;
|
return std::make_tuple(canRead, undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
std::tuple<bool, bool>
|
||||||
canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc)
|
canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr)
|
||||||
{
|
{
|
||||||
bool secure = !scr.ns;
|
bool secure = !scr.ns;
|
||||||
bool canWrite;
|
bool canWrite = false;
|
||||||
|
bool undefined = false;
|
||||||
|
|
||||||
switch (cpsr.mode) {
|
switch (cpsr.mode) {
|
||||||
case MODE_USER:
|
case MODE_USER:
|
||||||
|
@ -2030,11 +2034,11 @@ canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc)
|
||||||
canWrite = miscRegInfo[reg][MISCREG_HYP_WR];
|
canWrite = miscRegInfo[reg][MISCREG_HYP_WR];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unrecognized mode setting in CPSR.\n");
|
undefined = true;
|
||||||
}
|
}
|
||||||
// can't do permissions checkes on the root of a banked pair of regs
|
// can't do permissions checkes on the root of a banked pair of regs
|
||||||
assert(!miscRegInfo[reg][MISCREG_BANKED]);
|
assert(!miscRegInfo[reg][MISCREG_BANKED]);
|
||||||
return canWrite;
|
return std::make_tuple(canWrite, undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010-2016 ARM Limited
|
* Copyright (c) 2010-2017 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -44,6 +44,7 @@
|
||||||
#define __ARCH_ARM_MISCREGS_HH__
|
#define __ARCH_ARM_MISCREGS_HH__
|
||||||
|
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include "base/bitunion.hh"
|
#include "base/bitunion.hh"
|
||||||
#include "base/compiler.hh"
|
#include "base/compiler.hh"
|
||||||
|
@ -1847,13 +1848,37 @@ namespace ArmISA
|
||||||
EndBitUnion(CPTR)
|
EndBitUnion(CPTR)
|
||||||
|
|
||||||
|
|
||||||
// Checks read access permissions to coproc. registers
|
/**
|
||||||
bool canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr,
|
* Check for permission to read coprocessor registers.
|
||||||
ThreadContext *tc);
|
*
|
||||||
|
* Checks whether an instruction at the current program mode has
|
||||||
|
* permissions to read the coprocessor registers. This function
|
||||||
|
* returns whether the check is undefined and if not whether the
|
||||||
|
* read access is permitted.
|
||||||
|
*
|
||||||
|
* @param the misc reg indicating the coprocessor
|
||||||
|
* @param the SCR
|
||||||
|
* @param the CPSR
|
||||||
|
* @return a tuple of booleans: can_read, undefined
|
||||||
|
*/
|
||||||
|
std::tuple<bool, bool> canReadCoprocReg(MiscRegIndex reg, SCR scr,
|
||||||
|
CPSR cpsr);
|
||||||
|
|
||||||
// Checks write access permissions to coproc. registers
|
/**
|
||||||
bool canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr,
|
* Check for permission to write coprocessor registers.
|
||||||
ThreadContext *tc);
|
*
|
||||||
|
* Checks whether an instruction at the current program mode has
|
||||||
|
* permissions to write the coprocessor registers. This function
|
||||||
|
* returns whether the check is undefined and if not whether the
|
||||||
|
* write access is permitted.
|
||||||
|
*
|
||||||
|
* @param the misc reg indicating the coprocessor
|
||||||
|
* @param the SCR
|
||||||
|
* @param the CPSR
|
||||||
|
* @return a tuple of booleans: can_write, undefined
|
||||||
|
*/
|
||||||
|
std::tuple<bool, bool> canWriteCoprocReg(MiscRegIndex reg, SCR scr,
|
||||||
|
CPSR cpsr);
|
||||||
|
|
||||||
// Checks read access permissions to AArch64 system registers
|
// Checks read access permissions to AArch64 system registers
|
||||||
bool canReadAArch64SysReg(MiscRegIndex reg, SCR scr, CPSR cpsr,
|
bool canReadAArch64SysReg(MiscRegIndex reg, SCR scr, CPSR cpsr,
|
||||||
|
|
Loading…
Reference in a new issue