| (old) | htmldiff from- | (new) |
This page displays common pseudocode functions shared by many pages
// AArch32_EncodePARLD()
// =====================
// Returns 64-bit format PAR on address translation instruction.
func AArch32_EncodePARLD(addrdesc : AddressDescriptor, ss : SecurityState)
begin
PAR()[63:0] = Zeros{64};
if !IsFault(addrdesc) then
var ns : bit;
if ss == SS_NonSecure then
ns = ARBITRARY : bit;
elsif addrdesc.paddress.paspace == PAS_Secure then
ns = '0';
else
ns = '1';
end;
PAR().F = '0';
PAR().SH = ReportedPARShareability(PAREncodeShareability(addrdesc.memattrs));
PAR().NS = ns;
PAR()[10] = ImpDefBit("Non-Faulting PAR"); // IMPDEF
PAR().LPAE = '1';
PAR().PA = addrdesc.paddress.address[39:12];
PAR().ATTR = ReportedPARAttrs(EncodePARAttrs(addrdesc.memattrs));
else
PAR().F = '1';
PAR().FST = AArch32_PARFaultStatusLD(addrdesc.fault);
PAR().S2WLK = if addrdesc.fault.s2fs1walk then '1' else '0';
PAR().FSTAGE = if addrdesc.fault.secondstage then '1' else '0';
PAR().LPAE = '1';
PAR()[63:48] = ImpDefBits{16}("Faulting PAR"); // IMPDEF
end;
return;
end;
// AArch32_EncodePARSD() // ===================== // Returns 32-bit format PAR on address translation instruction. func AArch32_EncodePARSD(addrdesc_in : AddressDescriptor, supersection : bit, ss : SecurityState) begin PAR()[31:0] = Zeros{32}; var addrdesc : AddressDescriptor = addrdesc_in; if !IsFault(addrdesc) then if (addrdesc.memattrs.memtype == MemType_Device || (addrdesc.memattrs.inner.attrs == MemAttr_NC && addrdesc.memattrs.outer.attrs == MemAttr_NC)) then addrdesc.memattrs.shareability = Shareability_OSH; end; var ns : bit; if ss == SS_NonSecure then ns = ARBITRARY : bit; elsif addrdesc.paddress.paspace == PAS_Secure then ns = '0'; else ns = '1'; end; let sh : bits(2) = (if addrdesc.memattrs.shareability != Shareability_NSH then '01' else '00'); PAR().F = '0'; PAR().SS = supersection; PAR().Outer = AArch32_ReportedOuterAttrs(AArch32_PAROuterAttrs(addrdesc.memattrs)); PAR().Inner = AArch32_ReportedInnerAttrs(AArch32_PARInnerAttrs(addrdesc.memattrs)); PAR().SH = ReportedPARShareability(sh); PAR()[8] = ImpDefBit("Non-Faulting PAR"); // IMPDEF PAR().NS = ns; PAR().NOS = if addrdesc.memattrs.shareability == Shareability_OSH then '0' else '1'; PAR().LPAE = '0'; PAR().PA = addrdesc.paddress.address[39:12]; else PAR().F = '1'; PAR().FST = AArch32_PARFaultStatusSD(addrdesc.fault); PAR().LPAE = '0'; PAR()[31:16] = ImpDefBits{16}("Faulting PAR"); // IMPDEF end; return; end;
// AArch32_VCRMatch()
// ==================
func AArch32_VCRMatch(vaddress : bits(32)) => boolean
begin
var match : boolean;
if UsingAArch32() && ELUsingAArch32(EL1) && PSTATE.EL != PSTATE.EL != EL2 then
// Each bit position in this string corresponds to a bit in DBGVCR and an exception vector.
var match_word : bits(32) = Zeros{};
let ss : SecurityState = CurrentSecurityState();
if vaddress[31:5] == ExcVectorBase()[31:5] then
if HaveEL(EL3) && ss == SS_NonSecure then
match_word[UInt(vaddress[4:2]) + 24] = '1'; // Non-secure vectors
else
match_word[UInt(vaddress[4:2]) + 0] = '1'; // Secure vectors (or no EL3)
end;
end;
if (HaveEL(EL3) && ELUsingAArch32(EL3) && vaddress[31:5] == MVBAR()[31:5] &&
ss == SS_Secure) then
match_word[UInt(vaddress[4:2]) + 8] = '1'; // Monitor vectors
end;
// Mask out bits not corresponding to vectors.
var mask : bits(32);
if !HaveEL(EL3) then
mask = '00000000'::'00000000'::'00000000'::'11011110'; // DBGVCR[31:8] are RES0
elsif !ELUsingAArch32(EL3) then
mask = '11011110'::'00000000'::'00000000'::'11011110'; // DBGVCR[15:8] are RES0
else
mask = '11011110'::'00000000'::'11011100'::'11011110';
end;
match_word = match_word AND DBGVCR() AND mask;
match = !IsZero(match_word);
// Check for UNPREDICTABLE case - match on Prefetch Abort and Data Abort vectors
if !IsZero(match_word[28:27,12:11,4:3]) && DebugTarget() == PSTATE.EL() == PSTATE.EL then
match = ConstrainUnpredictableBool(Unpredictable_VCMATCHDAPA);
end;
if !IsZero(vaddress[1:0]) && match then
match = ConstrainUnpredictableBool(Unpredictable_VCMATCHHALF);
end;
else
match = FALSE;
end;
return match;
end;
// AArch32_WatchpointByteMatch()
// =============================
func AArch32_WatchpointByteMatch(n : integer, vaddress : bits(32)) => boolean
begin
let dbgtop : integer{} = 31;
let cmpbottom : integer{} = if DBGWVR(n)[2] == '1' then 2 else 3; // Word or doubleword
var bottom = cmpbottom;
let select : integer{} = UInt(vaddress[cmpbottom-1:0]);
var byte_select_match : boolean = (DBGWCR(n).BAS[select] != '0');
var mask : integer{} = UInt(DBGWCR(n).MASK);
// If DBGWCR(n).MASK is a nonzero value and DBGWCR(n).BAS is not set to '11111111', or
// DBGWCR(n).BAS specifies a non-contiguous set of bytes behavior is CONSTRAINED
// UNPREDICTABLE.
if mask > 0 && !IsOnes(DBGWCR(n).BAS) then
byte_select_match = ConstrainUnpredictableBool(Unpredictable_WPMASKANDBAS);
else
let LSB : bits(8) = (DBGWCR(n).BAS AND NOT(DBGWCR(n).BAS - 1));
let MSB : bits(8) = (DBGWCR(n).BAS + LSB);
if !IsZero(MSB AND (MSB - 1)) then // Not contiguous
byte_select_match = ConstrainUnpredictableBool(Unpredictable_WPBASCONTIGUOUS);
bottom = 3; // For the whole doubleword
end;
end;
// If the address mask is set to a reserved value, the behavior is CONSTRAINED UNPREDICTABLE.
if mask > 0 && mask <= 2 then
var c : Constraint;
var unpred_mask : integer;
(c, unpred_maskmask) = ( ConstrainUnpredictableInteger(3, 31, Unpredictable_RESWPMASK);
assert)
as c IN {(Constraint, integer{0..31}));
assert c IN {Constraint_DISABLED, Constraint_NONE, Constraint_UNKNOWN};
case c of
when Constraint_DISABLED => return FALSE; // Disabled
when Constraint_NONE => mask = 0; // No masking
// Otherwise the value returned by ConstrainUnpredictableInteger is a not-reserved value
otherwise => mask = unpred_mask as integer{3..31};
end;
end;
let cmpmsb : integer{} = dbgtop;
let cmplsb : integer{} = if mask > bottom then mask else bottom;
let bottombit : integer{} = bottom;
var WVR_match : boolean = (vaddress[cmpmsb:cmplsb] == DBGWVR(n)[cmpmsb:cmplsb]);
if mask > bottom then
// If masked bits of DBGWVR(n) are not zero, the behavior is CONSTRAINED UNPREDICTABLE.
if WVR_match && !IsZero(DBGWVR(n)[cmplsb-1:bottombit]) then
WVR_match = ConstrainUnpredictableBool(Unpredictable_WPMASKEDBITS);
end;
end;
return (WVR_match && byte_select_match);
end;
// AArch32_ReportDataAbort()
// =========================
// Report syndrome information for aborts taken to modes other than Hyp mode.
func AArch32_ReportDataAbort(route_to_monitor : boolean, fault : FaultRecord)
begin
var long_format : boolean;
if route_to_monitor && CurrentSecurityState() != SS_Secure then
long_format = ((TTBCR_S().EAE == '1') ||
(IsExternalSyncAbort(fault) && ((PSTATE.EL ==PSTATE.EL == EL2 || TTBCR().EAE == '1') ||
(fault.secondstage && (ImpDefBool(
"Report abort using Long-descriptor format")))));"))))));
else
long_format = TTBCR().EAE == '1';
end;
var syndrome : bits(32) = AArch32_CommonFaultStatus(fault, long_format);
// bits of syndrome that are not common to I and D side
if fault.accessdesc.acctype IN {AccessType_DC, AccessType_IC, AccessType_AT} then
syndrome[13] = '1'; // CM
syndrome[11] = '1'; // WnR
else
syndrome[11] = if fault.write then '1' else '0'; // WnR
end;
if !long_format then
syndrome[7:4] = fault.domain; // Domain
end;
if fault.accessdesc.acctype == AccessType_IC then
var i_syndrome : bits(32);
if (!long_format &&
ImpDefBool("Report I-cache maintenance fault in IFSR")) then
i_syndrome = syndrome;
syndrome[10,3:0] = EncodeSDFSC(Fault_ICacheMaint, 1);
else
i_syndrome = ARBITRARY : bits(32);
end;
if route_to_monitor then
IFSR_S() = i_syndrome;
else
IFSR() = i_syndrome;
end;
end;
if route_to_monitor then
DFSR_S() = syndrome;
DFAR_S() = fault.vaddress[31:0];
else
DFSR() = syndrome;
DFAR() = fault.vaddress[31:0];
end;
return;
end;
// AArch32_ReportPrefetchAbort()
// =============================
// Report syndrome information for aborts taken to modes other than Hyp mode.
func AArch32_ReportPrefetchAbort(route_to_monitor : boolean, fault : FaultRecord)
begin
// The encoding used in the IFSR can be Long-descriptor format or Short-descriptor format.
// Normally, the current translation table format determines the format. For an abort from
// Non-secure state to Monitor mode, the IFSR uses the Long-descriptor format if any of the
// following applies:
// * The Secure TTBCR.EAE is set to 1.
// * It is taken from Hyp mode.
// * It is taken from EL1 or EL0, and the Non-secure TTBCR.EAE is set to 1.
var long_format : boolean = FALSE;
if route_to_monitor && CurrentSecurityState() != SS_Secure then
long_format = TTBCR_S().EAE == '1' || PSTATE.EL == PSTATE.EL == EL2 || TTBCR().EAE == '1';
else
long_format = TTBCR().EAE == '1';
end;
let fsr : bits(32) = AArch32_CommonFaultStatus(fault, long_format);
if route_to_monitor then
IFSR_S() = fsr;
IFAR_S() = fault.vaddress[31:0];
else
IFSR() = fsr;
IFAR() = fault.vaddress[31:0];
end;
return;
end;
// AArch32_TakePhysicalFIQException()
// ==================================
func AArch32_TakePhysicalFIQException()
begin
// Check if routed to AArch64 state
var route_to_aarch64 : boolean = PSTATE.EL == PSTATE.EL == EL0 && !ELUsingAArch32(EL1);
if !route_to_aarch64 && EL2Enabled() && !ELUsingAArch32(EL2) then
route_to_aarch64 = HCR_EL2().TGE == '1' || (HCR_EL2().FMO == '1' && !IsInHost());
end;
if !route_to_aarch64 then
route_to_aarch64 =&& EffectiveSCR_EL3_FIQHaveEL() == '1';
end;
if route_to_aarch64 then AArch64_TakePhysicalFIQException(); end;
let route_to_monitor : boolean =( EL3) && !ELUsingAArch32(EL3) then
route_to_aarch64 = SCR_EL3().FIQ == '1';
end;
if route_to_aarch64 then AArch64_TakePhysicalFIQException(); end;
let route_to_monitor : boolean = HaveEL(EL3) && SCR().FIQ == '1';
let route_to_hyp : boolean = (PSTATE.EL IN {PSTATE.EL IN {EL0, EL1} && EL2Enabled() &&
(HCR().TGE == '1' || HCR().FMO == '1'));
let preferred_exception_return : bits(32) = ThisInstrAddr{}();
let vect_offset : integer = 0x1C;
let lr_offset : integer = 4;
if route_to_monitor then
AArch32_EnterMonitorMode(preferred_exception_return, lr_offset, vect_offset);
elsif PSTATE.EL() &&
(HCR().TGE == '1' || HCR().FMO == '1'));
let preferred_exception_return : bits(32) = ThisInstrAddr{}();
let vect_offset : integer = 0x1C;
let lr_offset : integer = 4;
if route_to_monitor then
AArch32_EnterMonitorMode(preferred_exception_return, lr_offset, vect_offset);
elsif PSTATE.EL == EL2 || route_to_hyp then
let except : ExceptionRecord = ExceptionSyndrome(Exception_FIQ);
AArch32_EnterHypMode(except, preferred_exception_return, vect_offset);
else
AArch32_EnterMode(M32_FIQ, preferred_exception_return, lr_offset, vect_offset);
end;
end;
// AArch32_TakePhysicalIRQException()
// ==================================
// Take an enabled physical IRQ exception.
func AArch32_TakePhysicalIRQException()
begin
// Check if routed to AArch64 state
var route_to_aarch64 : boolean = PSTATE.EL == PSTATE.EL == EL0 && !ELUsingAArch32(EL1);
if !route_to_aarch64 && EL2Enabled() && !ELUsingAArch32(EL2) then
route_to_aarch64 = HCR_EL2().TGE == '1' || (HCR_EL2().IMO == '1' && !IsInHost());
end;
if !route_to_aarch64 then
route_to_aarch64 =&& EffectiveSCR_EL3_IRQHaveEL() == '1';
end;
if route_to_aarch64 then AArch64_TakePhysicalIRQException(); end;
let route_to_monitor : boolean =( EL3) && !ELUsingAArch32(EL3) then
route_to_aarch64 = SCR_EL3().IRQ == '1';
end;
if route_to_aarch64 then AArch64_TakePhysicalIRQException(); end;
let route_to_monitor : boolean = HaveEL(EL3) && SCR().IRQ == '1';
let route_to_hyp : boolean = (PSTATE.EL IN {PSTATE.EL IN {EL0, EL1} && EL2Enabled() &&
(HCR().TGE == '1' || HCR().IMO == '1'));
let preferred_exception_return : bits(32) = ThisInstrAddr{}();
let vect_offset : integer = 0x18;
let lr_offset : integer = 4;
if route_to_monitor then
AArch32_EnterMonitorMode(preferred_exception_return, lr_offset, vect_offset);
elsif PSTATE.EL() &&
(HCR().TGE == '1' || HCR().IMO == '1'));
let preferred_exception_return : bits(32) = ThisInstrAddr{}();
let vect_offset : integer = 0x18;
let lr_offset : integer = 4;
if route_to_monitor then
AArch32_EnterMonitorMode(preferred_exception_return, lr_offset, vect_offset);
elsif PSTATE.EL == EL2 || route_to_hyp then
let except : ExceptionRecord = ExceptionSyndrome(Exception_IRQ);
AArch32_EnterHypMode(except, preferred_exception_return, vect_offset);
else
AArch32_EnterMode(M32_IRQ, preferred_exception_return, lr_offset, vect_offset);
end;
end;
// AArch32_TakeVirtualFIQException()
// =================================
func AArch32_TakeVirtualFIQException()
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL0, EL1} && EL2Enabled();
if ELUsingAArch32(EL2) then // Virtual IRQ enabled if TGE==0 and FMO==1
assert HCR().TGE == '0' && HCR().FMO == '1';
else
assert HCR_EL2().TGE == '0' && HCR_EL2().FMO == '1';
end;
// Check if routed to AArch64 state
if PSTATE.EL) then // Virtual IRQ enabled if TGE==0 and FMO==1
assert HCR().TGE == '0' && HCR().FMO == '1';
else
assert HCR_EL2().TGE == '0' && HCR_EL2().FMO == '1';
end;
// Check if routed to AArch64 state
if PSTATE.EL == EL0 && !ELUsingAArch32(EL1) then AArch64_TakeVirtualFIQException(); end;
let preferred_exception_return : bits(32)=) = ThisInstrAddr{}();
let vect_offset : integer = 0x1C;
let lr_offset : integer = 4;
AArch32_EnterMode(M32_FIQ, preferred_exception_return, lr_offset, vect_offset);
end;
// AArch32_ExceptionClass()
// ========================
// Returns the Exception Class and Instruction Length fields to be reported in HSR
func AArch32_ExceptionClass(exceptype : Exception) => (integer,bit)
begin
var il_is_valid : boolean = TRUE;
var ec : integer;
case exceptype of
when Exception_Uncategorized => ec = 0x00; il_is_valid = FALSE;
when Exception_WFxTrap => ec = 0x01;
when Exception_CP15RTTrap => ec = 0x03;
when Exception_CP15RRTTrap => ec = 0x04;
when Exception_CP14RTTrap => ec = 0x05;
when Exception_CP14DTTrap => ec = 0x06;
when Exception_AdvSIMDFPAccessTrap => ec = 0x07;
when Exception_FPIDTrap => ec = 0x08;
when Exception_PACTrap => ec = 0x09;
when Exception_GPC => ec = 0x1E;
when Exception_CP14RRTTrap => ec = 0x0C;
when Exception_BranchTarget => ec = 0x0D;
when Exception_IllegalState => ec = 0x0E; il_is_valid = FALSE;
when Exception_SupervisorCall => ec = 0x11;
when Exception_HypervisorCall => ec = 0x12;
when Exception_MonitorCall => ec = 0x13;
when Exception_InstructionAbort =>
ec = if PSTATE.EL == PSTATE.EL == EL2 then 0x21 else 0x20;
il_is_valid = FALSE;
when Exception_PCAlignment => ec = 0x22; il_is_valid = FALSE;
when Exception_DataAbort => ec = if PSTATE.EL == PSTATEEL2.ELthen ==0x25 else 0x24;
when EL2Exception_NV2DataAbort then=> ec = 0x25 else 0x24;
when Exception_FPTrappedException => ec = 0x28;
when Exception_Profiling => ec = 0x3D;
otherwise => unreachable;
end;
var il : bit;
if il_is_valid then
il = if ThisInstrLength() == 32 then '1' else '0';
else
il = '1';
end;
return (ec,il);
end;
// AArch32_TakeReset()
// ===================
// Reset into AArch32 state
func AArch32_TakeReset(cold_reset : boolean)
begin
assert !HaveAArch64();
// Enter the highest implemented Exception level in AArch32 state
if HaveEL(EL3) then
AArch32_WriteMode(M32_Svc);
SCR().NS = '0'; // Secure state
elsif HaveEL(EL2) then
AArch32_WriteMode(M32_Hyp);
else
AArch32_WriteMode(M32_Svc);
end;
// Reset System registers in the coproc=0b111x encoding space
// and other system components
AArch32_ResetControlRegisters(cold_reset);
FPEXC().EN = '0';
// Reset all other PSTATE fields, including instruction set and endianness according to the
// SCTLR values produced by the above call to ResetControlRegisters()
PSTATE.[A,I,F] = '111'; // All asynchronous exceptions masked
PSTATE.IT = '00000000'; // IT block state reset
if
PSTATE.IT = '00000000'; // IT block state reset
if HaveEL(EL2) && !HaveEL(EL3) then
PSTATE.T = HSCTLR().TE; // Instruction set: TE=0:A32, TE=1:T32. PSTATE.J is RES0.
PSTATE.E = HSCTLR().EE; // Endianness: EE=0: little-endian, EE=1: big-endian.
else
PSTATE.T = SCTLR().TE; // Instruction set: TE=0:A32, TE=1:T32. PSTATE.J is RES0.
PSTATE.E = SCTLR().EE; // Endianness: EE=0: little-endian, EE=1: big-endian.
end;
PSTATE.IL = '0'; // Clear Illegal Execution state bit
// All registers, bits and fields not reset by the above pseudocode or by the BranchTo() call
// below are UNKNOWN bitstrings after reset. In particular, the return information registers
// R14 or ELR_hyp and SPSR have UNKNOWN values, so that it
// is impossible to return from a reset in an architecturally defined way.
AArch32_ResetGeneralRegisters();
if IsFeatureImplemented(FEAT_SME) || IsFeatureImplemented(FEAT_SVE) then
ResetSVERegisters();
else
AArch32_ResetSIMDFPRegisters();
end;
AArch32_ResetSpecialRegisters();
ResetExternalDebugRegisters(cold_reset);
var rv : bits(32); // IMPLEMENTATION DEFINED reset vector
if
PSTATE.T = HSCTLR().TE; // Instruction set: TE=0:A32, TE=1:T32. PSTATE.J is RES0.
PSTATE.E = HSCTLR().EE; // Endianness: EE=0: little-endian, EE=1: big-endian.
else
PSTATE.T = SCTLR().TE; // Instruction set: TE=0:A32, TE=1:T32. PSTATE.J is RES0.
PSTATE.E = SCTLR().EE; // Endianness: EE=0: little-endian, EE=1: big-endian.
end;
PSTATE.IL = '0'; // Clear Illegal Execution state bit
// All registers, bits and fields not reset by the above pseudocode or by the BranchTo() call
// below are UNKNOWN bitstrings after reset. In particular, the return information registers
// R14 or ELR_hyp and SPSR have UNKNOWN values, so that it
// is impossible to return from a reset in an architecturally defined way.
AArch32_ResetGeneralRegisters();
if IsFeatureImplemented(FEAT_SME) || IsFeatureImplemented(FEAT_SVE) then
ResetSVERegisters();
else
AArch32_ResetSIMDFPRegisters();
end;
AArch32_ResetSpecialRegisters();
ResetExternalDebugRegisters(cold_reset);
var rv : bits(32); // IMPLEMENTATION DEFINED reset vector
if HaveEL(EL3) then
if MVBAR()[0] == '1' then // Reset vector in MVBAR
rv = MVBAR()[31:1]::'0';
else
rv = ImpDefBits{32}("reset vector address");
end;
else
rv = RVBAR()[31:1]::'0';
end;
// The reset vector must be correctly aligned
assert rv[0] == '0' && (PSTATE.T) then
if MVBAR()[0] == '1' then // Reset vector in MVBAR
rv = MVBAR()[31:1]::'0';
else
rv = ImpDefBits{32}("reset vector address");
end;
else
rv = RVBAR()[31:1]::'0';
end;
// The reset vector must be correctly aligned
assert rv[0] == '0' && (PSTATE.T == '1' || rv[1] == '0');
let branch_conditional : boolean = FALSE;
EDPRSR().R = '0'; // Leaving Reset State.
BranchTo{32}(rv, BranchType_RESET, branch_conditional);
end;
// AArch32_TakeSMCException()
// ==========================
func AArch32_TakeSMCException()
begin
assert HaveEL(EL3) && ELUsingAArch32(EL3);
AArch32_ITAdvance();
HSAdvance();
SSAdvance();
let preferred_exception_return : bits(32) = NextInstrAddr{}();
let vect_offset : integer{} = 0x08;
let lr_offset : integer{} = 0;
AArch32_EnterMonitorMode(preferred_exception_return, lr_offset, vect_offset);
end;
// AArch32_EnterHypMode()
// ======================
// Take an exception to Hyp mode.
noreturn func AArch32_EnterHypMode(except : ExceptionRecord, preferred_exception_return : bits(32),
vect_offset : integer)
begin
SynchronizeContext();
assert HaveEL(EL2) && CurrentSecurityState() == SS_NonSecure && ELUsingAArch32(EL2);
if Halted() then
AArch32_EnterHypModeInDebugState(except);
end;
let spsr : bits(32) = GetPSRFromPSTATE{}(AArch32_NonDebugState);
if ! except.exceptype IN {Exception_IRQ, Exception_FIQ} then
AArch32_ReportHypEntry(except);
end;
AArch32_WriteMode(M32_Hyp);
SPSR_curr() = spsr;
ELR_hyp() = preferred_exception_return;
PSTATE.T = HSCTLR().TE; // PSTATE.J is RES0
PSTATE.SS = '0';
if !
PSTATE.T = HSCTLR().TE; // PSTATE.J is RES0
PSTATE.SS = '0';
if !HaveEL(EL3) then
PSTATE.A = '1';
PSTATE.I = '1';
PSTATE.F = '1';
else
if
PSTATE.A = '1';
PSTATE.I = '1';
PSTATE.F = '1';
else
if ELUsingAArch32(EL3) then
if SCR().EA == '0' then PSTATE.A = '1'; end;
if SCR().IRQ == '0' then PSTATE.I = '1'; end;
if SCR().FIQ == '0' then PSTATE.F = '1'; end;
else
if SCR_EL3().EA == '0' then PSTATE.A = '1'; end;
if EffectiveSCR_EL3_IRQ() == '0' then PSTATE.I = '1'; end;
if EffectiveSCR_EL3_FIQ() == '0' then PSTATE.F = '1'; end;
end;
end;
PSTATE.E = HSCTLR().EE;
PSTATE.IL = '0';
PSTATE.IT = '00000000';
if IsFeatureImplemented(FEAT_SSBS) then PSTATE.SSBS) then
if SCR().EA == '0' then PSTATE.A = '1'; end;
if SCR().IRQ == '0' then PSTATE.I = '1'; end;
if SCR().FIQ == '0' then PSTATE.F = '1'; end;
else
if SCR_EL3().EA == '0' then PSTATE.A = '1'; end;
if SCR_EL3().IRQ == '0' then PSTATE.I = '1'; end;
if SCR_EL3().FIQ == '0' then PSTATE.F = '1'; end;
end;
end;
PSTATE.E = HSCTLR().EE;
PSTATE.IL = '0';
PSTATE.IT = '00000000';
if IsFeatureImplemented(FEAT_SSBS) then PSTATE.SSBS = HSCTLR().DSSBS; end;
let branch_conditional : boolean = FALSE;
BranchTo{32}(HVBAR()[31:5]::vect_offset[4:0], BranchType_EXCEPTION, branch_conditional);
CheckExceptionCatch(TRUE); // Check for debug event on exception entry
EndOfInstruction();
end;
// Mem_with_type
// =============
accessor Mem_with_type{size : integer{8, 16, 32, 64}}(address : bits(32),
accdesc_in : AccessDescriptor
) <=> value_in : bits(size)
begin
// Perform a read of 'size' bits. The access byte order is reversed for a big-endian access.
// Instruction fetches would call AArch32_MemSingle directly.
getter
let bytes : integer{} = size DIV 8;
var accdesc : AccessDescriptor = accdesc_in;
var value : bits(size);
// Check alignment on size of element accessed, not overall access size
var aligned : boolean;
if accdesc.ispair then
let halfalignment : integer{} = (sizeif DIVaccdesc.ispair 2)then asbytes integer{32};
alignedDIV =2 IsAlignedSize(address,else halfbytes;
var DIV 8);
else
aligned : boolean = IsAlignedSize(address, bytesalignment);
end;
if !aligned && AArch32_UnalignedAccessFaults(accdesc) then
let fault : FaultRecord = AlignmentFault(accdesc, ZeroExtend{64}(address));
AArch32_Abort(fault);
end;
if aligned then
value = AArch32_MemSingle{size}(address, accdesc, aligned);
else
assert bytes > 1;
value[7:0] = AArch32_MemSingle{8}(address, accdesc, aligned);
// For subsequent bytes, if they cross to a new translation page which assigns
// Device memory type, it is CONSTRAINED UNPREDICTABLE whether an unaligned access
// will generate an Alignment Fault.
let c : Constraint = ConstrainUnpredictable(Unpredictable_DEVPAGE2);
assert c IN {Constraint_FAULT, Constraint_NONE};
if c == Constraint_NONE then aligned = TRUE; end;
for i = 1 to bytes-1 do
value[i*:8] = AArch32_MemSingle{8}(address+i, accdesc, aligned);
end;
end;
if BigEndian(accdesc.acctype) then
value = BigEndianReverse{size}(value);
end;
return value;
end;
// Perform a write of 'size' bits. The byte order is reversed for a big-endian access.
setter
let bytes : integer{} = size DIV 8;
var value : bits(size) = value_in;
var accdesc : AccessDescriptor = accdesc_in;
// Check alignment on size of element accessed, not overall access size
var aligned : boolean;
if accdesc.ispair then
let halfalignment : integer{} = (sizeif DIVaccdesc.ispair 2)then asbytes integer{32};
alignedDIV =2 IsAlignedSize(address,else halfbytes;
var DIV 8);
else
aligned : boolean = IsAlignedSize(address, bytesalignment);
end;
if !aligned && AArch32_UnalignedAccessFaults(accdesc) then
let fault : FaultRecord = AlignmentFault(accdesc, ZeroExtend{64}(address));
AArch32_Abort(fault);
end;
if BigEndian(accdesc.acctype) then
value = BigEndianReverse{size}(value);
end;
if aligned then
AArch32_MemSingle{size}(address, accdesc, aligned) = value;
else
assert bytes > 1;
AArch32_MemSingle{8}(address, accdesc, aligned) = value[7:0];
// For subsequent bytes, if they cross to a new translation page which assigns
// Device memory type, it is CONSTRAINED UNPREDICTABLE whether an unaligned access
// will generate an Alignment Fault.
let c : Constraint = ConstrainUnpredictable(Unpredictable_DEVPAGE2);
assert c IN {Constraint_FAULT, Constraint_NONE};
if c == Constraint_NONE then aligned = TRUE; end;
for i = 1 to bytes-1 do
AArch32_MemSingle{8}(address+i, accdesc, aligned) = value[i*:8];
end;
end;
return;
end;
end;
// AArch32_WriteModeByInstr()
// ==========================
// Function for dealing with writes to PSTATE.M from an AArch32 instruction, and ensuring that
// illegal state changes are correctly flagged in PSTATE.IL.
func AArch32_WriteModeByInstr(mode : bits(5))
begin
var (valid,el) : (boolean, bits(2)) = ELFromM32(mode);
// 'valid' is set to FALSE if' mode' is invalid for this implementation or the current value
// of SCR.NS/SCR_EL3.NS. Additionally, it is illegal for an instruction to write 'mode' to
// PSTATE.EL if it would result in any of:
// * A change to a mode that would cause entry to a higher Exception level.
if UInt(el) > UInt(PSTATE.EL) then
valid = FALSE;
end;
// * A change to or from Hyp mode.
if (PSTATE.M ==PSTATE.EL) then
valid = FALSE;
end;
// * A change to or from Hyp mode.
if (PSTATE.M == M32_Hyp || mode == M32_Hyp) && PSTATE.M != mode then
valid = FALSE;
end;
// * When EL2 is implemented, the value of HCR.TGE is '1', a change to a Non-secure EL1 mode.
if (PSTATE.M == PSTATE.M != mode then
valid = FALSE;
end;
// * When EL2 is implemented, the value of HCR.TGE is '1', a change to a Non-secure EL1 mode.
if (PSTATE.M == M32_Monitor && HaveEL(EL2) && el == EL1 && SCR().NS == '1'
&& HCR().TGE == '1') then
valid = FALSE;
end;
if !valid then
PSTATE.IL&& SCR().NS == '1'
&& HCR().TGE == '1') then
valid = FALSE;
end;
if !valid then
PSTATE.IL = '1';
else
AArch32_WriteMode(mode);
end;
end;
// AArch32_DTLBI_ALL()
// ===================
// Invalidate all data TLB entries for the indicated translation regime with the
// the indicated security state for all TLBs within the indicated broadcast domain.
// Invalidation applies to all applicable stage 1 and stage 2 entries.
func AArch32_DTLBI_ALL(security : SecurityState, regime : Regime, broadcast_inbroadcast : Broadcast,
attr_inattr : TLBIMemAttr)
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var attr : TLBIMemAttr = attr_in;
let broadcast : Broadcast = AArch32_EffectiveBroadcast(broadcast_in);
if ExcludeXS() then
attr = TLBI_ExcludeXS;
end;};
var r : TLBIRecord;
r.op = TLBIOp_DALL;
r.from_aarch64 = FALSE;
r.security = security;
r.regime = regime;
r.level = TLBILevel_Any;
r.attr = attr;
TLBI(r);
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch32_DTLBI_ASID()
// ====================
// Invalidate all data TLB stage 1 entries matching the indicated VMID (where regime supports)
// and ASID in the parameter Rt in the indicated translation regime with the
// indicated security state for all TLBs within the indicated broadcast domain.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch32_DTLBI_ASID(security : SecurityState, regime : Regime, vmid : bits(16),
broadcast_inbroadcast : Broadcast, attr_inattr : TLBIMemAttr, Rt : bits(32))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var attr : TLBIMemAttr = attr_in;
let broadcast : Broadcast = AArch32_EffectiveBroadcast(broadcast_in);
if ExcludeXS() then
attr = TLBI_ExcludeXS;
end;};
var r : TLBIRecord;
r.op = TLBIOp_DASID;
r.from_aarch64 = FALSE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = TLBILevel_Any;
r.attr = attr;
r.asid = Zeros{8} :: Rt[7:0];
TLBI(r);
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch32_DTLBI_VA()
// ==================
// Invalidate by VA all stage 1 data TLB entries in the indicated broadcast domain
// matching the indicated VMID and ASID (where regime supports VMID, ASID) in the indicated regime
// with the indicated security state.
// ASID, VA and related parameters are derived from Rt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch32_DTLBI_VA(security : SecurityState, regime : Regime, vmid : bits(16),
broadcast_inbroadcast : Broadcast, level : TLBILevel, attr_inattr : TLBIMemAttr,
Rt : bits(32))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var attr : TLBIMemAttr = attr_in;
let broadcast : Broadcast = AArch32_EffectiveBroadcast(broadcast_in);
if ExcludeXS() then
attr = TLBI_ExcludeXS;
end;};
var r : TLBIRecord;
r.op = TLBIOp_DVA;
r.from_aarch64 = FALSE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = level;
r.attr = attr;
r.asid = Zeros{8} :: Rt[7:0];
r.address = Zeros{32} :: Rt[31:12] :: Zeros{12};
TLBI(r);
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch32_EffectiveBroadcastAArch32_ITLBI_ALL()
// ===============================================
// Invalidate all instruction TLB entries for the indicated translation regime with the
// the indicated security state for all TLBs within the indicated broadcast domain.
// Invalidation applies to all applicable stage 1 and stage 2 entries.
func AArch32_ITLBI_ALL(security : AArch32_EffectiveBroadcast(broadcast_in, regime : BroadcastRegime), =>broadcast : Broadcast
begin
var broadcast,
attr : BroadcastTLBIMemAttr =)
begin
assert broadcast_in;
ifPSTATE.EL IN { PSTATEEL3.EL !=, EL2, EL1 then return broadcast; end;};
ifvar (broadcastr ==: Broadcast_NSHTLBIRecord && ((;
r.op =ELUsingAArch32TLBIOp_IALL(;
r.from_aarch64 = FALSE;
r.security = security;
r.regime = regime;
r.level =EL2TLBILevel_Any);
r.attr = &&attr;
TLBI(r);
if HCR().FBbroadcast == '1') ||
(!!=ELUsingAArch32Broadcast_NSH(EL2) && HCR_EL2().FB == '1'))) then
broadcast = Broadcast_ForcedISHthen BroadcastTLBI(broadcast, r); end;
end;
return broadcast;
end;
// AArch32_ITLBI_ALLAArch32_ITLBI_ASID()
// =======================================
// Invalidate all instruction TLB stage 1 entries formatching the indicated translationVMID
// (where regime withsupports) and ASID in the parameter Rt in the indicated translation
// regime with the indicated security state for all TLBs within the indicated broadcast domain.
// InvalidationNote: applies to all applicable stage 1 and stage 2 entries.combined entries are in the scope of this operation.
func AArch32_ITLBI_ALLAArch32_ITLBI_ASID(security : SecurityState, regime : Regime, broadcast_invmid : bits(16),
broadcast : Broadcast,
attr_in attr : TLBIMemAttr), Rt : bits(32))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var attrr : TLBIMemAttrTLBIRecord ;
r.op = attr_in;
let broadcast : BroadcastTLBIOp_IASID ;
r.from_aarch64 = FALSE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = AArch32_EffectiveBroadcastUseVMID(broadcast_in);
if ExcludeXS() then
attr = TLBI_ExcludeXS;
end;
var r : TLBIRecord;
r.op = TLBIOp_IALL;
r.from_aarch64 = FALSE;
r.security = security;
r.regime = (regime;);
r.level = TLBILevel_Any;
r.attr = attr;
r.asid = Zeros{8} :: Rt[7:0];
TLBI(r);
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch32_ITLBI_ASIDAArch32_ITLBI_VA()
// ======================================
// Invalidate allby instructionVA TLBall stage 1 instruction TLB entries matchingin the indicated VMIDbroadcast domain
// (wherematching regimethe supports)indicated VMID and ASID in(where theregime parametersupports RtVMID, ASID) in the indicated translationregime
// regime with the indicated security statestate.
// forASID, allVA TLBsand withinrelated theparameters indicatedare broadcastderived domain.from Rt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch32_ITLBI_ASIDAArch32_ITLBI_VA(security : SecurityState, regime : Regime, vmid : bits(16),
broadcast_in
broadcast : Broadcast, attr_inlevel : TLBILevel, attr : TLBIMemAttr, Rt : bits(32))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var attrr : TLBIMemAttr = attr_in;
let broadcast : Broadcast = AArch32_EffectiveBroadcast(broadcast_in);
if ExcludeXS() then
attr = TLBI_ExcludeXS;
end;
var r : TLBIRecord;
r.op = TLBIOp_IASIDTLBIOp_IVA;
r.from_aarch64 = FALSE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = TLBILevel_Any(regime);
r.level = level;
r.attr = attr;
r.asid = Zeros{8} :: Rt[7:0];
r.address = Zeros{32} :: Rt[31:12] :: Zeros{12};
TLBI(r);
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch32_ITLBI_VA() // ================== // Invalidate by VA all stage 1 instruction TLB entries in the indicated broadcast domain // matching the indicated VMID and ASID (where regime supports VMID, ASID) in the indicated regime // with the indicated security state. // ASID, VA and related parameters are derived from Rt. // Note: stage 1 and stage 2 combined entries are in the scope of this operation. func AArch32_ITLBI_VA(security : SecurityState, regime : Regime, vmid : bits(16), broadcast_in : Broadcast, level : TLBILevel, attr_in : TLBIMemAttr, Rt : bits(32)) begin assert PSTATE.EL IN {EL3, EL2, EL1}; var attr : TLBIMemAttr = attr_in; let broadcast : Broadcast = AArch32_EffectiveBroadcast(broadcast_in); if ExcludeXS() then attr = TLBI_ExcludeXS; end; var r : TLBIRecord; r.op = TLBIOp_IVA; r.from_aarch64 = FALSE; r.security = security; r.regime = regime; r.vmid = vmid; r.use_vmid = UseVMID(regime); r.level = level; r.attr = attr; r.asid = Zeros{8} :: Rt[7:0]; r.address = Zeros{32} :: Rt[31:12] :: Zeros{12}; TLBI(r); if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end; return; end;
// AArch32_TLBI_ASID()
// ===================
// Invalidate all stage 1 entries matching the indicated VMID (where regime supports)
// and ASID in the parameter Rt in the indicated translation regime with the
// indicated security state for all TLBs within the indicated broadcast domain.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch32_TLBI_ASID(security : SecurityState, regime : Regime, vmid : bits(16),
broadcast_inbroadcast : Broadcast, attr_inattr : TLBIMemAttr, Rt : bits(32))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var attr : TLBIMemAttr = attr_in;
let broadcast : Broadcast = AArch32_EffectiveBroadcast(broadcast_in);
if ExcludeXS() then
attr = TLBI_ExcludeXS;
end;};
var r : TLBIRecord;
r.op = TLBIOp_ASID;
r.from_aarch64 = FALSE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = TLBILevel_Any;
r.attr = attr;
r.asid = Zeros{8} :: Rt[7:0];
TLBI(r);
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch32_TLBI_VA()
// =================
// Invalidate by VA all stage 1 TLB entries in the indicated broadcast domain
// matching the indicated VMID and ASID (where regime supports VMID, ASID) in the indicated regime
// with the indicated security state.
// ASID, VA and related parameters are derived from Rt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch32_TLBI_VA(security : SecurityState, regime : Regime, vmid : bits(16),
broadcast_inbroadcast : Broadcast, level : TLBILevel, attr_inattr : TLBIMemAttr,
Rt : bits(32))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var attr : TLBIMemAttr = attr_in;
let broadcast : Broadcast = AArch32_EffectiveBroadcast(broadcast_in);
if ExcludeXS() then
attr = TLBI_ExcludeXS;
end;};
var r : TLBIRecord;
r.op = TLBIOp_VA;
r.from_aarch64 = FALSE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = level;
r.attr = attr;
r.asid = Zeros{8} :: Rt[7:0];
r.address = Zeros{32} :: Rt[31:12] :: Zeros{12};
TLBI(r);
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch32_TLBI_VAA()
// ==================
// Invalidate by VA all stage 1 TLB entries in the indicated broadcast domain
// matching the indicated VMID (where regime supports VMID) and all ASID in the indicated regime
// with the indicated security state.
// VA and related parameters are derived from Rt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch32_TLBI_VAA(security : SecurityState, regime : Regime, vmid : bits(16),
broadcast_inbroadcast : Broadcast, level : TLBILevel, attr_inattr : TLBIMemAttr,
Rt : bits(32))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var attr : TLBIMemAttr = attr_in;
let broadcast : Broadcast = AArch32_EffectiveBroadcast(broadcast_in);
if ExcludeXS() then
attr = TLBI_ExcludeXS;
end;};
var r : TLBIRecord;
r.op = TLBIOp_VAA;
r.from_aarch64 = FALSE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = level;
r.attr = attr;
r.address = Zeros{32} :: Rt[31:12] :: Zeros{12};
TLBI(r);
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch32_TLBI_VMALL()
// ====================
// Invalidate all stage 1 entries for the indicated translation regime with the
// the indicated security state for all TLBs within the indicated broadcast
// domain that match the indicated VMID (where applicable).
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
// Note: stage 2 only entries are not in the scope of this operation.
func AArch32_TLBI_VMALL(security : SecurityState, regime : Regime, vmid : bits(16),
broadcast_inbroadcast : Broadcast, attr_inattr : TLBIMemAttr)
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var attr : TLBIMemAttr = attr_in;
let broadcast : Broadcast = AArch32_EffectiveBroadcast(broadcast_in);
if ExcludeXS() then
attr = TLBI_ExcludeXS;
end;};
var r : TLBIRecord;
r.op = TLBIOp_VMALL;
r.from_aarch64 = FALSE;
r.security = security;
r.regime = regime;
r.level = TLBILevel_Any;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.attr = attr;
TLBI(r);
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch32_IC()
// ============
// Perform Instruction Cache Operation.
func AArch32_IC(opscope : CacheOpScope)
begin
let regval : bits(32) = ARBITRARY : bits(32);
AArch32_IC(regval, opscope);
end;
// AArch32_IC()
// ============
// Perform Instruction Cache Operation.
func AArch32_IC(regval : bits(32), opscope : CacheOpScope)
begin
var cache : CacheRecord;
cache.acctype = AccessType_IC;
cache.cachetype = CacheType_Instruction;
cache.cacheop = CacheOp_Invalidate;
cache.opscope = opscope;
cache.security = SecurityStateAtEL(PSTATE.EL);
if opscope IN {PSTATE.EL);
if opscope IN {CacheOpScope_ALLU, CacheOpScope_ALLUIS} then
if (opscope == CacheOpScope_ALLUIS ||then
cache.shareability =
AArch32_EffectiveBroadcast(Broadcast_NSH) == Broadcast_ForcedISH) then
cache.shareability = Shareability_ISH;
else
cache.shareability = Shareability_NSH;
end;
cache.regval = ZeroExtend{64}(regval);
CACHE_OP(cache);
else
assert opscope == CacheOpScope_PoU;
if EL2Enabled() then
if PSTATE.EL IN { PSTATE.EL IN {EL0, EL1} then
cache.is_vmid_valid = TRUE;
cache.vmid = VMID();
else
cache.is_vmid_valid = FALSE;
end;
else
cache.is_vmid_valid = FALSE;
end;
if PSTATE.EL();
else
cache.is_vmid_valid = FALSE;
end;
else
cache.is_vmid_valid = FALSE;
end;
if PSTATE.EL == EL0 then
cache.is_asid_valid = TRUE;
cache.asid = ASID();
else
cache.is_asid_valid = FALSE;
end;
cache.shareability = Shareability_NSH;
cache.vaddress = ZeroExtend{64}(regval);
let size : integer = 0;
let aligned : boolean = TRUE;
let accdesc : AccessDescriptor = CreateAccDescIC(cache);
let memaddrdesc : AddressDescriptor = AArch32_TranslateAddress(regval, accdesc, aligned,
size);
if IsFault(memaddrdesc) then
AArch32_Abort(memaddrdesc.fault);
end;
cache.paddress = memaddrdesc.paddress;
CACHE_OP(cache);
end;
return;
end;
// AArch32_MAIRAttr()
// ==================
// Retrieve the memory attribute encoding indexed in the given MAIR
func AArch32_MAIRAttr(index : integer, mair : bits(64))MAIRType) => bits(8)
begin
assert (index < 8);
return mair[index*:8];
end;
// BRBEDebugStateExit()
// ====================
// Called to write Debug state exit branch record when BRBE is active.
func BRBEDebugStateExit(target_address : bits(64))
begin
if BranchRecordAllowed(PSTATE.EL) then
// Debug state is a prohibited region, therefore ccu=1, cc=0, source_address=0
let branch_type : bits(6) = '111001';
let ccu : bit = '1';
let cc : bits(14) = Zeros{};
let el : bits(2) = PSTATE.EL;
let mispredict : bit = '0';
UpdateBranchRecordBuffer(ccu, cc, branch_type, el, mispredict,
'01', Zeros{64}, target_address);
PMUEvent(PMU_EVENT_BRB_FILTRATE);
end;
return;
end;PSTATE.EL) then
// Debug state is a prohibited region, therefore ccu=1, cc=0, source_address=0
let branch_type : bits(6) = '111001';
let ccu : bit = '1';
let cc : bits(14) = Zeros{14};
let el : bits(2) = PSTATE.EL;
let mispredict : bit = '0';
UpdateBranchRecordBuffer(ccu, cc, branch_type, el, mispredict,
'01', Zeros{64}, target_address);
PMUEvent(PMU_EVENT_BRB_FILTRATE);
end;
return;
end;
// BranchEncCycleCount()
// =====================
// The first return result is '1' if either of the following is true, and '0' otherwise:
// - This is the first Branch record after the PE exited a Prohibited Region.
// - This is the first Branch record after cycle counting has been enabled.
// If the first return return is '0', the second return result is the encoded cycle count
// since the last branch.
// The format of this field uses a mantissa and exponent to express the cycle count value.
// - bits[7:0] indicate the mantissa M.
// - bits[13:8] indicate the exponent E.
// The cycle count is expressed using the following function:
// cycle_count = (if IsZero(E) then UInt(M) else UInt('1'::M::Zeros{(UInt(E)-1})))))
// A value of all ones in both the mantissa and exponent indicates the cycle count value
// exceeded the size of the cycle counter.
// If the cycle count is not known, the second return result is zero.
func BranchEncCycleCount() => (bit, bits(14))
begin
var cc : integer = BranchRawCycleCount();
if !BRBCycleCountingEnabled() || FirstBranchAfterProhibited() then
return ('1', Zeros{14});
end;
// The format of this field uses a mantissa and exponent to express the cycle count value.
// - bits[7:0] indicate the mantissa M.
// - bits[13:8] indicate the exponent E.
// The cycle count is expressed using the following function:
// cycle_count = (if IsZero(E) then UInt(M) else UInt('1'::M::Zeros{(UInt(E)-1}))))
// A value of all ones in both the mantissa and exponent indicates the cycle count value
// exceeded the size of the cycle counter.
var E : bits(6);
var M : bits(8);
if cc < 2^8 then
E = Zeros{6};
M = cc[7:0];
elsif cc >= 2^20 then
E = Ones{6};
M = Ones{8};
else
E = 1[5:0];
while cc >= 2^9 looplimit 11 do
E = E + 1;
cc = cc DIVRM 2;
end;
M = cc[7:0];
end;
return ('0', E::M);
end;
// AArch64_BreakpointValueMatch()
// ==============================
// Returns breakpoint type to indicate the type of breakpoint and a boolean to indicate
// whether the breakpoint matched successfully. For Address Mismatch breakpoints, the
// returned boolean is the inverted result. If the breakpoint type return value is Inactive,
// then the boolean result is FALSE.
func AArch64_BreakpointValueMatch(n_in : integer, vaddress : bits(64),
linked_to : boolean, isbreakpnt : boolean,
from_linking_enabled : boolean
) => (BreakpointType, boolean) recurselimit 2
begin
// "n_in" is the identity of the breakpoint unit to match against.
// "vaddress" is the current instruction address, ignored if linked_to is TRUE and for Context
// matching breakpoints.
// "linked_to" is TRUE if this is a call from StateMatch for linking.
// "isbreakpnt" TRUE is this is a call from BreakpointMatch or from StateMatch for a
// linked breakpoint or from BreakpointValueMatch for a linked breakpoint with linking enabled.
// "from_linking_enabled" is TRUE if this is a call from BreakpointValueMatch for a linked
// breakpoint with linking enabled.
var n : integer = n_in;
var c : Constraint;
var dbgtype : bits(5);
// If a non-existent breakpoint then it is CONSTRAINED UNPREDICTABLE whether this gives
// no match or the breakpoint is mapped to another UNKNOWN implemented breakpoint.
if n >= NumBreakpointsImplemented() then
(c, n) = ConstrainUnpredictableInteger(0, NumBreakpointsImplemented() - 1,
Unpredictable_BPNOTIMPL);
assert c IN {Constraint_DISABLED, Constraint_UNKNOWN};
if c == Constraint_DISABLED then return (BreakpointType_Inactive, FALSE); end;
end;
// If this breakpoint is not enabled, it cannot generate a match.
// (This could also happen on a call from StateMatch for linking).
if !IsBreakpointEnabled(n) then return (BreakpointType_Inactive, FALSE); end;
// If BT is set to a reserved type, behaves either as disabled or as a not-reserved type.
if IsFeatureImplemented(FEAT_ABLE) then
dbgtype = DBGBCR_EL1(n).[BT2,BT];
else
dbgtype = '0' :: DBGBCR_EL1(n).BT;
end;
(c, dbgtype) = AArch64_ReservedBreakpointType(n, dbgtype);
if c == Constraint_DISABLED then return (BreakpointType_Inactive, FALSE); end;
// Otherwise the value returned by ConstrainUnpredictableBits must be a not-reserved value
// Determine what to compare against.
let match_addr : boolean = (dbgtype == 'x0x0x');
let mismatch : boolean = (dbgtype == 'x010x');
let match_vmid : boolean = (dbgtype == 'x10xx');
let match_cid : boolean = (dbgtype == 'x001x');
let match_cid1 : boolean = (dbgtype IN {'x101x', 'xx11x'});
let match_cid2 : boolean = (dbgtype == 'x11xx');
let linking_enabled : boolean = (dbgtype IN {'xxx11', 'x1xx1', '1xxxx'});
// If this is a call from StateMatch, return FALSE if the breakpoint is not
// programmed with linking enabled.
if linked_to && !linking_enabled then
return (BreakpointType_Inactive, FALSE);
end;
// If called from BreakpointMatch return FALSE for breakpoint with linking enabled.
if !linked_to && linking_enabled then
return (BreakpointType_Inactive, FALSE);
end;
let linked : boolean = (dbgtype == 'x0x01');
if from_linking_enabled then // A breakpoint with linking enabled has called this function.
assert linked_to && isbreakpnt;
if linked then
// A breakpoint with linking enabled is linked to a linked breakpoint. This is
// architecturally UNPREDICTABLE, but treated as disabled in the pseudo code to
// avoid potential recursion in BreakpointValueMatch().
return (BreakpointType_Inactive, FALSE);
end;
end;
// If a linked breakpoint is linked to an address matching breakpoint,
// the behavior is CONSTRAINED UNPREDICTABLE.
if linked_to && match_addr && isbreakpnt then
if !ConstrainUnpredictableBool(Unpredictable_BPLINKEDADDRMATCH) then
return (BreakpointType_Inactive, FALSE);
end;
end;
// A breakpoint programmed for address mismatch does not match in AArch32 state.
if mismatch && UsingAArch32() then
return (BreakpointType_Inactive, FALSE);
end;
var bvr_match : boolean = FALSE;
var bxvr_match : boolean = FALSE;
var bp_type : BreakpointType;
var mask : integer{0..31};
if IsFeatureImplemented(FEAT_BWE) then
mask = UInt(DBGBCR_EL1(n).MASK);
// If the mask is set to a reserved value, the behavior is CONSTRAINED UNPREDICTABLE.
if mask IN {1, 2} then
var unpred_mask : integer;
(c, unpred_maskmask) = (ConstrainUnpredictableInteger(3, 31, Unpredictable_RESBPMASK);)
as (Constraint, integer{3..31}));
assert c IN {Constraint_DISABLED, Constraint_NONE, Constraint_UNKNOWN};
case c of
when Constraint_DISABLED => return (BreakpointType_Inactive, FALSE); // Disabled
when Constraint_NONE => mask = 0; // No masking
// Otherwise the value returned by ConstrainUnpredictableBits must
// be a not-reserved value.
otherwise => mask = unpred_mask as integer{3..31};
end;
end;
if mask != 0 then
// When DBGBCR_EL1(n).MASK is a valid nonzero value, the behavior is
// CONSTRAINED UNPREDICTABLE if any of the following are true:
// - DBGBCR_EL1(n).[BT2,BT] is programmed for a Context matching breakpoint.
// - DBGBCR_EL1(n).BAS is not '1111' and AArch32 is supported at EL0.
if ((match_cid || match_cid1 || match_cid2) ||
(DBGBCR_EL1(n).BAS != '1111' && HaveAArch32())) then
if !ConstrainUnpredictableBool(Unpredictable_BPMASK) then
return (BreakpointType_Inactive, FALSE);
end;
end;
else
// A stand-alone mismatch of a single address is not supported.
if mismatch then
return (BreakpointType_Inactive, FALSE);
end;
end;
else
mask = 0;
end;
// Do the comparison.
if match_addr then
var byte_select_match : boolean;
let byte : integer = UInt(vaddress[1:0]);
if HaveAArch32() then
// T32 instructions can be executed at EL0 in an AArch64 translation regime.
assert byte IN {0,2}; // "vaddress" is halfword aligned
byte_select_match = (DBGBCR_EL1(n).BAS[byte] == '1');
else
assert byte == 0; // "vaddress" is word aligned
byte_select_match = TRUE; // DBGBCR_EL1(n).BAS[byte] is RES1
end;
// When FEAT_LVA3 is not implemented, if the DBGBVR_EL1(n).RESS field bits are not a
// sign extension of the MSB of DBGBVR_EL1(n).VA, it is UNPREDICTABLE whether they
// appear to be included in the match.
// If 'vaddress' is outside of the current virtual address space, then the access
// generates a Translation fault.
let dbgtop : AddressSize = DebugAddrTop();
let unpredictable_ress : boolean = (dbgtop < 55 && !IsOnes(DBGBVR_EL1(n)[63:dbgtop]) &&
!IsZero(DBGBVR_EL1(n)[63:dbgtop]) &&
ConstrainUnpredictableBool(Unpredictable_DBGxVR_RESS));
let cmpmsb : integer{} = if unpredictable_ress then 63 else dbgtop;
let cmplsb : integer{} = if mask > 2 then mask else 2;
bvr_match = ((vaddress[cmpmsb:cmplsb] == DBGBVR_EL1(n)[cmpmsb:cmplsb]) &&
byte_select_match);
if mask > 2 then
// If masked bits of DBGBVR_EL1(n) are not zero, the behavior
// is CONSTRAINED UNPREDICTABLE.
let masktop : integer{} = mask - 1;
if bvr_match && !IsZero(DBGBVR_EL1(n)[masktop:2]) then
bvr_match = ConstrainUnpredictableBool(Unpredictable_BPMASKEDBITS);
end;
end;
elsif match_cid then
if IsInHost() then
bvr_match = (CONTEXTIDR_EL2()[31:0] == DBGBVR_EL1(n)[31:0]);
else
bvr_match = (PSTATE.EL IN {EL0, EL1} && CONTEXTIDR_EL1()[31:0] == DBGBVR_EL1(n)[31:0]);
end;
elsif match_cid1 then
bvr_match = (PSTATE.EL IN {EL0, EL1} && !IsInHost() &&
CONTEXTIDR_EL1()[31:0] == DBGBVR_EL1(n)[31:0]);
end;
if match_vmid then
let vmid : bits(16) = VMID();
var bvr_vmid : bits(16);
if !IsFeatureImplemented(FEAT_VMID16) || VTCR_EL2().VS == '0' then
bvr_vmid = ZeroExtend{16}(DBGBVR_EL1(n)[39:32]);
else
bvr_vmid = DBGBVR_EL1(n)[47:32];
end;
bxvr_match = (PSTATE.EL IN {EL0, EL1} && EL2Enabled() && !IsInHost() && vmid == bvr_vmid);
elsif match_cid2 then
bxvr_match = (PSTATE.EL != EL3 && EL2Enabled() &&
DBGBVR_EL1(n)[63:32] == CONTEXTIDR_EL2()[31:0]);
end;
let bvr_match_valid : boolean = (match_addr || match_cid || match_cid1);
let bxvr_match_valid : boolean = (match_vmid || match_cid2);
var value_match : boolean = ((!bxvr_match_valid || bxvr_match) &&
(!bvr_match_valid || bvr_match));
// A watchpoint might be linked to a linked address matching breakpoint with linking enabled,
// which is in turn linked to a context matching breakpoint.
if linked_to && linked then
// If called from StateMatch and breakpoint is a linked breakpoint then it must be a
// watchpoint that is linked to an address matching breakpoint which is linked to a
// context matching breakpoint.
assert !isbreakpnt && match_addr && IsFeatureImplemented(FEAT_ABLE);
let lbnx : bits(2) = (if IsFeatureImplemented(FEAT_Debugv8p9) then DBGBCR_EL1(n).LBNX
else '00');
let linked_linked_n : integer{} = UInt(lbnx :: DBGBCR_EL1(n).LBN);
var linked_value_match : boolean;
let linked_vaddress = ARBITRARY : bits(64);
let linked_linked_to = TRUE;
let linked_isbreakpnt = TRUE;
let linked_from_linking_enabled = TRUE;
(bp_type, linked_value_match) = AArch64_BreakpointValueMatch(linked_linked_n,
linked_vaddress,
linked_linked_to,
linked_isbreakpnt,
linked_from_linking_enabled);
value_match = value_match && linked_value_match;
end;
if match_addr && !mismatch then
bp_type = BreakpointType_AddrMatch;
elsif match_addr && mismatch then
bp_type = BreakpointType_AddrMismatch;
elsif match_vmid || match_cid || match_cid1 || match_cid2 then
bp_type = BreakpointType_CtxtMatch;
else
unreachable;
end;
return (bp_type, value_match);
end;
var inst_addr_executedsync_counter_overflowed : bits(64);boolean;
varinst_addr_executed : bits(64);
// CheckMDCR_EL3_NSPBTrap()
// ========================
// Check if the register access is trappable by MDCR_EL3.[MDCR_EL3().[NSPBE, NSPB]
func CheckMDCR_EL3_NSPBTrap() => boolean
begin
var state_bits : bits(3);
var reserved : boolean;
(state_bits, reserved) = EffectiveMDCR_EL3_NSPB();
return ((reserved && ConstrainUnpredictableBool(Unpredictable_RESERVEDNSxB_Trap)) ||
state_bits[0] == '0' || state_bits[1] != SCR_EL3().NS ||
(IsFeatureImplemented(FEAT_RME) && state_bits[2] != SCR_EL3().NSE));
end; EffectiveSCR_EL3_NS() ||
(IsFeatureImplemented(FEAT_RME) && state_bits[2] != EffectiveSCR_EL3_NSE()));
end;
// EffectiveMDCR_EL3_NSPB()
// ========================
// Return the Effective value of MDCR_EL3.[MDCR_EL3().[NSPBE, NSPB] field and whether it is a reserved value.
readonly func EffectiveMDCR_EL3_NSPB() => (bits(3), boolean)
begin
var state_bits : bits(3);
var reserved : boolean = FALSE;
if IsFeatureImplemented(FEAT_RME) then
state_bits = MDCR_EL3().[NSPBE, NSPB];
if state_bits == '10x' || (!IsFeatureImplemented(FEAT_Secure) && state_bits == '00x') then
// Reserved value
reserved = TRUE;
(-, state_bits) = ConstrainUnpredictableBits{3}(Unpredictable_RESERVEDNSxB);
end;
else
state_bits = '0' :: MDCR_EL3().NSPB;
end;
return (state_bits, reserved);
end;
// SPEEvent()
// ==========
// Called when a PMU event is generated by the sampled structure.
// Sets appropriate bit in SPESampleStorage.events.
func SPEEvent(pmuevent : bits(16))
begin
if !SPESampleInFlight then
return;
end;
case pmuevent of
when PMU_EVENT_DSNP_HIT_RD =>
if IsFeatureImplemented(FEAT_SPEv1p4) then
SPESampleEvents[23] = '1'; // Snoop hit
end;
when {PMU_EVENT_L1D_LFB_HIT_RD, PMU_EVENT_L2D_LFB_HIT_RD,
PMU_EVENT_L3D_LFB_HIT_RD, PMU_EVENT_LL_LFB_HIT_RD} =>
if IsFeatureImplemented(FEAT_SPEv1p4) then
SPESampleEvents[22] = '1'; // Recent fetch
end;
when {PMU_EVENT_L1D_CACHE_HITM_RD, PMU_EVENT_L2D_CACHE_HITM_RD,
PMU_EVENT_L3D_CACHE_HITM_RD, PMU_EVENT_LL_CACHE_HITM_RD}PMU_EVENT_L2D_LFB_HIT_RD =>
if IsFeatureImplemented(FEAT_SPEv1p4) then
SPESampleEvents[2122] = '1'; // ModifiedRecent fetch
end;
when PMU_EVENT_L2D_CACHE_LMISS_RDPMU_EVENT_L3D_LFB_HIT_RD =>
if IsFeatureImplemented(FEAT_SPEv1p4) then
SPESampleEvents[2022] = '1'; // L2Recent missfetch
end;
when PMU_EVENT_L2D_CACHE_RDPMU_EVENT_LL_LFB_HIT_RD =>
if IsFeatureImplemented(FEAT_SPEv1p4) then
SPESampleEvents[1922] = '1'; // L2Recent accessfetch
end;
when PMU_EVENT_SVE_PRED_EMPTY_SPECPMU_EVENT_L1D_CACHE_HITM_RD =>
if IsFeatureImplemented(FEAT_SPEv1p1FEAT_SPEv1p4) then
SPESampleEvents[1821] = '1'; // Empty predicateModified
end;
when PMU_EVENT_SVE_PRED_NOT_FULL_SPECPMU_EVENT_L2D_CACHE_HITM_RD =>
if IsFeatureImplemented(FEAT_SPEv1p1FEAT_SPEv1p4) then
SPESampleEvents[1721] = '1'; // Partial predicateModified
end;
when PMU_EVENT_LDST_ALIGN_LATPMU_EVENT_L3D_CACHE_HITM_RD =>
if IsFeatureImplemented(FEAT_SPEv1p1FEAT_SPEv1p4) then
SPESampleEvents[1121] = '1'; // MisalignedModified
end;
when PMU_EVENT_REMOTE_ACCESSPMU_EVENT_LL_CACHE_HITM_RD =>
if IsFeatureImplemented(FEAT_SPEv1p4) then SPESampleEvents[1021] = '1'; // Remote accessModified
end;
when PMU_EVENT_LL_CACHE_MISSPMU_EVENT_L2D_CACHE_LMISS_RD =>
if IsFeatureImplemented(FEAT_SPEv1p4) then SPESampleEvents[920] = '1'; // LLCL2 miss
end;
when PMU_EVENT_LL_CACHEPMU_EVENT_L2D_CACHE_RD =>
if IsFeatureImplemented(FEAT_SPEv1p4) then SPESampleEvents[819] = '1'; // LLCL2 access
end;
when PMU_EVENT_BR_MIS_PREDPMU_EVENT_SVE_PRED_EMPTY_SPEC =>
if IsFeatureImplemented(FEAT_SPEv1p1) then SPESampleEvents[718] = '1'; // MispredictedEmpty predicate
end;
when PMU_EVENT_BR_MIS_PRED_RETIREDPMU_EVENT_SVE_PRED_NOT_FULL_SPEC =>
if IsFeatureImplemented(FEAT_SPEv1p1) then SPESampleEvents[717] = '1'; // NotPartial takenpredicate
end;
when PMU_EVENT_DTLB_WALKPMU_EVENT_LDST_ALIGN_LAT =>
if IsFeatureImplemented(FEAT_SPEv1p1) then SPESampleEvents[511] = '1'; // TLB walkMisaligned
end;
when PMU_EVENT_L1D_TLBPMU_EVENT_REMOTE_ACCESS => SPESampleEvents[410] = '1'; // TLBRemote access
when PMU_EVENT_L1D_CACHE_REFILLPMU_EVENT_LL_CACHE_MISS =>
if !IsFeatureImplemented(FEAT_SPEv1p4) then
SPESampleEvents[39] = '1'; // L1LLC refill
end;miss
when PMU_EVENT_L1D_CACHE_LMISS_RDPMU_EVENT_LL_CACHE =>
if IsFeatureImplemented(FEAT_SPEv1p4) then
SPESampleEvents[38] = '1'; // L1LLC miss
end;access
when PMU_EVENT_L1D_CACHEPMU_EVENT_BR_MIS_PRED => SPESampleEvents[27] = '1'; // L1 accessMispredicted
when PMU_EVENT_INST_RETIREDPMU_EVENT_BR_MIS_PRED_RETIRED => SPESampleEvents[17] = '1'; // RetireNot taken
when PMU_EVENT_EXC_TAKENPMU_EVENT_DTLB_WALK => SPESampleEvents[05] = '1'; // ExceptionTLB walk
otherwisewhen PMU_EVENT_L1D_TLB => return;
end;
return;
end;SPESampleEvents[4] = '1'; // TLB access
when PMU_EVENT_L1D_CACHE_REFILL =>
if !IsFeatureImplemented(FEAT_SPEv1p4) then
SPESampleEvents[3] = '1'; // L1 refill
end;
when PMU_EVENT_L1D_CACHE_LMISS_RD =>
if IsFeatureImplemented(FEAT_SPEv1p4) then
SPESampleEvents[3] = '1'; // L1 miss
end;
when PMU_EVENT_L1D_CACHE => SPESampleEvents[2] = '1'; // L1 access
when PMU_EVENT_INST_RETIRED => SPESampleEvents[1] = '1'; // Retire
when PMU_EVENT_EXC_TAKEN => SPESampleEvents[0] = '1'; // Exception
otherwise => return;
end;
return;
end;
// AArch64_TakeExceptionInDebugState()
// ===================================
// Take an exception in Debug state to an Exception level using AArch64.
noreturn func AArch64_TakeExceptionInDebugState(target_el : bits(2), exception_in : ExceptionRecord)
begin
assert HaveEL(target_el) && !ELUsingAArch32(target_el) && UInt(target_el) >= UInt(PSTATE.EL);
assert target_el !=PSTATE.EL);
assert target_el != EL3 || EDSCR().SDD == '0';
var except : ExceptionRecord = exception_in;
var sync_errors : boolean;
if IsFeatureImplemented(FEAT_IESB) then
sync_errors = SCTLR_EL(target_el).IESB == '1';
if IsFeatureImplemented(FEAT_DoubleFault) then
sync_errors = sync_errors || (SCR_EL3().[EA,NMEA] == '11' && target_el == EL3);
end;
// The Effective value of SCTLR[].IESB might be zero in Debug state.
if !ConstrainUnpredictableBool(Unpredictable_IESBinDebug) then
sync_errors = FALSE;
end;
else
sync_errors = FALSE;
end;
if !IsFeatureImplemented(FEAT_ExS) || SCTLR_EL(target_el).EIS == '1' then
// Synchronize the context, including Instruction Fetch Barrier effect
SynchronizeContext();
end;
// If coming from AArch32 state, the top parts of the X()[] registers might be set to zero
let from_32 : boolean = UsingAArch32();
if from_32 then AArch64_MaybeZeroRegisterUppers(); end;
if from_32 && IsFeatureImplemented(FEAT_SME) && PSTATE.SM == '1' then
ResetSVEState();
else
MaybeZeroSVEUppers(target_el);
end;
AArch64_ReportException(except, target_el);
if IsFeatureImplemented(FEAT_GCS) then
PSTATE.EXLOCK = '0'; // Effective value of GCSCR_ELx.EXLOCKEN is 0 in Debug state
end;
PSTATE.EL = target_el;
PSTATE.nRW = '0';
PSTATE.SP = '1'; PSTATE.SM == '1' then
ResetSVEState();
else
MaybeZeroSVEUppers(target_el);
end;
AArch64_ReportException(except, target_el);
if IsFeatureImplemented(FEAT_GCS) then
PSTATE.EXLOCK = '0'; // Effective value of GCSCR_ELx.EXLOCKEN is 0 in Debug state
end;
PSTATE.EL = target_el;
PSTATE.nRW = '0';
PSTATE.SP = '1';
SPSR_ELx() = ARBITRARY : bits(64);
ELR_ELx() = ARBITRARY : bits(64);
// PSTATE.[SS,D,A,I,F] are not observable and ignored in Debug state, so behave as if UNKNOWN.
PSTATE.[SS,D,A,I,F] = ARBITRARY : bits(5);
if IsFeatureImplemented(FEAT_SSBS) then PSTATE.SSBS = ARBITRARY : bit; end;
if IsFeatureImplemented(FEAT_EBEP) then PSTATE.PM = ARBITRARY : bit; end;
if IsFeatureImplemented(FEAT_SEBEP) then PSTATE.PPEND = '0'; end;
if IsFeatureImplemented(FEAT_MTE) then PSTATE.TCO = '1'; end;
PSTATE.IL = '0';
if IsFeatureImplemented(FEAT_UAO) then PSTATE.UAO = '0'; end;
if IsFeatureImplemented(FEAT_UINJ) then PSTATE.UINJ = '0'; end;
if IsFeatureImplemented(FEAT_PAuth_LR) then PSTATE.PACM = '0'; end;
if (IsFeatureImplemented(FEAT_PAN) && (PSTATE.EL == PSTATE.SSBS = ARBITRARY : bit; end;
if IsFeatureImplemented(FEAT_EBEP) then PSTATE.PM = ARBITRARY : bit; end;
if IsFeatureImplemented(FEAT_SEBEP) then PSTATE.PPEND = '0'; end;
if IsFeatureImplemented(FEAT_MTE) then PSTATE.TCO = '1'; end;
PSTATE.IL = '0';
if IsFeatureImplemented(FEAT_UAO) then PSTATE.UAO = '0'; end;
if IsFeatureImplemented(FEAT_UINJ) then PSTATE.UINJ = '0'; end;
if IsFeatureImplemented(FEAT_PAuth_LR) then PSTATE.PACM = '0'; end;
if (IsFeatureImplemented(FEAT_PAN) && (PSTATE.EL == EL1 ||
(PSTATE.EL ==PSTATE.EL == EL2 && ELIsInHost(EL0))) &&
SCTLR_ELx().SPAN == '0') then
PSTATE.PAN = '1';
end;
if from_32 then // Coming from AArch32
PSTATE.IT = '00000000';
PSTATE.T = '0'; // PSTATE.J is RES0
end;
if IsFeatureImplemented(FEAT_BTI) then PSTATE.BTYPE().SPAN == '0') then
PSTATE.PAN = '1';
end;
if from_32 then // Coming from AArch32
PSTATE.IT = '00000000';
PSTATE.T = '0'; // PSTATE.J is RES0
end;
if IsFeatureImplemented(FEAT_BTI) then PSTATE.BTYPE = '00'; end;
DLR_EL0() = ARBITRARY : bits(64);
DSPSR_EL0() = ARBITRARY : bits(64);
EDSCR().ERR = '1';
UpdateEDSCRFields(); // Update EDSCR PE state flags.
if sync_errors then
SynchronizeErrors();
end;
EndOfInstruction();
end;
// AArch64_WatchpointByteMatch()
// =============================
func AArch64_WatchpointByteMatch(n : integer, vaddress : bits(64)) => boolean
begin
let dbgtop : AddressSize = DebugAddrTop();
let cmpbottom : integer{} = if DBGWVR_EL1(n)[2] == '1' then 2 else 3;// Word or doubleword
var bottom : integer{} = cmpbottom;
let select : integer{} = UInt(vaddress[cmpbottom-1:0]);
var byte_select_match : boolean = (DBGWCR_EL1(n).BAS[select] != '0');
var mask : integer{} = UInt(DBGWCR_EL1(n).MASK);
// If DBGWCR_EL1(n).MASK is a nonzero value and DBGWCR_EL1(n).BAS is not set to '11111111', or
// DBGWCR_EL1(n).BAS specifies a non-contiguous set of bytes behavior is CONSTRAINED
// UNPREDICTABLE.
if mask > 0 && !IsOnes(DBGWCR_EL1(n).BAS) then
byte_select_match = ConstrainUnpredictableBool(Unpredictable_WPMASKANDBAS);
else
let LSB : bits(8) = (DBGWCR_EL1(n).BAS AND NOT(DBGWCR_EL1(n).BAS - 1));
let MSB : bits(8) = (DBGWCR_EL1(n).BAS + LSB);
if !IsZero(MSB AND (MSB - 1)) then // Not contiguous
byte_select_match = ConstrainUnpredictableBool(Unpredictable_WPBASCONTIGUOUS);
bottom = 3; // For the whole doubleword
end;
end;
// If the address mask is set to a reserved value, the behavior is CONSTRAINED UNPREDICTABLE.
if mask > 0 && mask <= 2 then
var c : Constraint;
var unpred_mask : integer;
(c, unpred_maskmask) = (ConstrainUnpredictableInteger(3, 31, Unpredictable_RESWPMASK);)
as (Constraint, integer{0..31}));
assert c IN {Constraint_DISABLED, Constraint_NONE, Constraint_UNKNOWN};
case c of
when Constraint_DISABLED => return FALSE; // Disabled
when Constraint_NONE => mask = 0; // No masking
// Otherwise the value returned by ConstrainUnpredictableInteger is a not-reserved value
otherwise => mask = unpred_mask as integer{3..31};
end;
end;
// When FEAT_LVA3 is not implemented, if the DBGWVR_EL1(n).RESS field bits are not a
// sign extension of the MSB of DBGWVR_EL1(n).VA, it is UNPREDICTABLE whether they
// appear to be included in the match.
let unpredictable_ress : boolean = (dbgtop < 55 && !IsOnes(DBGWVR_EL1(n)[63:dbgtop]) &&
!IsZero(DBGWVR_EL1(n)[63:dbgtop]) &&
ConstrainUnpredictableBool(Unpredictable_DBGxVR_RESS));
let cmpmsb : integer{} = if unpredictable_ress then 63 else dbgtop;
let cmplsb : integer{} = if mask > bottom then mask else bottom;
let bottombit : integer{} = bottom;
var WVR_match : boolean = (vaddress[cmpmsb:cmplsb] == DBGWVR_EL1(n)[cmpmsb:cmplsb]);
if mask > bottom then
// If masked bits of DBGWVR_EL1(n) are not zero, the behavior is CONSTRAINED UNPREDICTABLE.
if WVR_match && !IsZero(DBGWVR_EL1(n)[cmplsb-1:bottombit]) then
WVR_match = ConstrainUnpredictableBool(Unpredictable_WPMASKEDBITS);
end;
end;
return (WVR_match && byte_select_match);
end;
// AArch64_TakePhysicalFIQException()
// ==================================
func AArch64_TakePhysicalFIQException()
begin
let route_to_el3 : boolean = EffectiveSCR_EL3_FIQHaveEL() == '1';
let route_to_el2 : boolean = (PSTATEEL3.EL) && SCR_EL3().FIQ == '1';
let route_to_el2 : boolean = (PSTATE.EL IN {EL0, EL1} && EL2Enabled() &&
(HCR_EL2().TGE == '1' || HCR_EL2().FMO == '1'));
let preferred_exception_return : bits(64) = ThisInstrAddr{}();
let vect_offset : integer = 0x100;
let except : ExceptionRecord = ExceptionSyndrome(Exception_FIQ);
if route_to_el3 then
AArch64_TakeException(EL3, except, preferred_exception_return, vect_offset);
elsif PSTATE.EL == PSTATE.EL == EL2 || route_to_el2 then
assert PSTATE.EL != PSTATE.EL != EL3;
AArch64_TakeException(EL2, except, preferred_exception_return, vect_offset);
else
assert PSTATE.EL, except, preferred_exception_return, vect_offset);
else
assert PSTATE.EL IN {EL0, EL1};
AArch64_TakeException(EL1, except, preferred_exception_return, vect_offset);
end;
end;
// AArch64_TakePhysicalIRQException()
// ==================================
// Take an enabled physical IRQ exception.
func AArch64_TakePhysicalIRQException()
begin
let route_to_el3 : boolean = EffectiveSCR_EL3_IRQHaveEL() == '1';
let route_to_el2 : boolean = (PSTATEEL3.EL) && SCR_EL3().IRQ == '1';
let route_to_el2 : boolean = (PSTATE.EL IN {EL0, EL1} && EL2Enabled() &&
(HCR_EL2().TGE == '1' || HCR_EL2().IMO == '1'));
let preferred_exception_return : bits(64) = ThisInstrAddr{}();
let vect_offset : integer = 0x80;
let except : ExceptionRecord = ExceptionSyndrome(Exception_IRQ);
if route_to_el3 then
AArch64_TakeException(EL3, except, preferred_exception_return, vect_offset);
elsif PSTATE.EL == PSTATE.EL == EL2 || route_to_el2 then
assert PSTATE.EL != PSTATE.EL != EL3;
AArch64_TakeException(EL2, except, preferred_exception_return, vect_offset);
else
assert PSTATE.EL, except, preferred_exception_return, vect_offset);
else
assert PSTATE.EL IN {EL0, EL1};
AArch64_TakeException(EL1, except, preferred_exception_return, vect_offset);
end;
end;
// AArch64_TakeException()
// =======================
// Take an exception to an Exception level using AArch64.
noreturn func AArch64_TakeException(target_el : bits(2), exception_in : ExceptionRecord,
preferred_exception_return : bits(64), vect_offset_in : integer)
begin
assert HaveEL(target_el) && !ELUsingAArch32(target_el) && UInt(target_el) >= UInt(PSTATE.EL);
ifPSTATE.EL);
if Halted() then
AArch64_TakeExceptionInDebugState(target_el, exception_in);
end;
var except : ExceptionRecord = exception_in;
var sync_errors : boolean;
var iesb_req : boolean;
if IsFeatureImplemented(FEAT_IESB) then
sync_errors = SCTLR_EL(target_el).IESB == '1';
if IsFeatureImplemented(FEAT_DoubleFault) then
sync_errors = sync_errors || (SCR_EL3().[EA,NMEA] == '11' && target_el == EL3);
end;
if sync_errors && InsertIESBBeforeException(target_el) then
SynchronizeErrors();
if except.exceptype != Exception_SError then
iesb_req = FALSE;
sync_errors = FALSE;
TakeUnmaskedPhysicalSErrorInterrupts(iesb_req);
end;
end;
else
sync_errors = FALSE;
end;
var brbe_source_allowed : boolean = FALSE;
var brbe_source_address : bits(64) = Zeros{};
if IsFeatureImplemented(FEAT_BRBE) then
brbe_source_allowed = BranchRecordAllowed(PSTATE.EL);
brbe_source_address = preferred_exception_return;
end;
if !IsFeatureImplemented(FEAT_ExS) ||PSTATE.EL);
brbe_source_address = preferred_exception_return;
end;
if !IsFeatureImplemented(FEAT_ExS) || SCTLR_EL(target_el).EIS == '1' then
// Synchronize the context, including Instruction Fetch Barrier effect
SynchronizeContext();
elsif !(except.exceptype == Exception_SoftwareBreakpoint ||
(except.exceptype IN {Exception_SupervisorCall,
Exception_HypervisorCall,
Exception_MonitorCall} &&
!except.trappedsyscallinst)) then
InstructionFetchBarrier();
end;
// If coming from AArch32 state, the top parts of the X()[] registers might be set to zero
let from_32 : boolean = UsingAArch32();
if from_32 then AArch64_MaybeZeroRegisterUppers(); end;
if from_32 && IsFeatureImplemented(FEAT_SME) && PSTATE.SM == '1' then
ResetSVEState();
else
MaybeZeroSVEUppers(target_el);
end;
var vect_offset : integer = vect_offset_in;
if UInt(target_el) > UInt(PSTATE.EL) then
var lower_32 : boolean;
if target_el == PSTATE.SM == '1' then
ResetSVEState();
else
MaybeZeroSVEUppers(target_el);
end;
var vect_offset : integer = vect_offset_in;
if UInt(target_el) > UInt(PSTATE.EL) then
var lower_32 : boolean;
if target_el == EL3 then
if EL2Enabled() then
lower_32 = ELUsingAArch32(EL2);
else
lower_32 = ELUsingAArch32(EL1);
end;
elsif IsInHost() && PSTATE.EL == PSTATE.EL == EL0 && target_el == EL2 then
lower_32 = ELUsingAArch32(EL0);
else
lower_32 = ELUsingAArch32(target_el - 1);
end;
vect_offset = vect_offset + (if lower_32 then 0x600 else 0x400);
elsif PSTATE.SP == '1' then
vect_offset = vect_offset + 0x200;
end;
var spsr : bits(64) = GetPSRFromPSTATE{}( PSTATE.SP == '1' then
vect_offset = vect_offset + 0x200;
end;
assert vect_offset < 2048;
let vect_base : bits(64) = VBAR_EL(target_el)[63:11]::Zeros{11};
let target_vector : bits(64) = vect_base + vect_offset;
var spsr : bits(64) = GetPSRFromPSTATE{}(AArch64_NonDebugState);
if PSTATE.EL == PSTATE.EL == EL1 && target_el == EL1 && EL2Enabled() then
if EffectiveHCR_EL2_NVx() IN {'x01', '111'} then
spsr[3:2] = '10';
end;
end;
if IsFeatureImplemented(FEAT_BTI) && !UsingAArch32() then
var zero_btype : boolean;
// SPSR_ELx[].BTYPE is only guaranteed valid for these exception types
if except.exceptype IN {Exception_SError, Exception_IRQ, Exception_FIQ,
Exception_SoftwareStep, Exception_PCAlignment,
Exception_InstructionAbort, Exception_Breakpoint,
Exception_VectorCatch, Exception_SoftwareBreakpoint,
Exception_IllegalState, Exception_BranchTarget} then
zero_btype = FALSE;
else
zero_btype = ConstrainUnpredictableBool(Unpredictable_ZEROBTYPE);
end;
if zero_btype then spsr[11:10] = '00'; end;
end;
if (IsFeatureImplemented(FEAT_NV2) &&
except.exceptype == Exception_NV2DataAbort && target_el == EL3) then
// External aborts are configured to be taken to EL3
except.exceptype = Exception_DataAbort;
end;
if ! except.exceptype IN {Exception_IRQ, Exception_FIQ} then
AArch64_ReportException(except, target_el);
end;
if IsFeatureImplemented(FEAT_BRBE) then
BRBEException(except,let brbe_source_allowed,brbe_target_address brbe_source_address,
target_vector,: target_el, except.trappedsyscallinst);
end;
if IsFeatureImplementedbits(FEAT_GCS64) then
if= PSTATEVBAR_EL.EL(target_el)[63:11]::vect_offset[10:0];
BRBEException(except, brbe_source_allowed, brbe_source_address,
brbe_target_address, target_el,
except.trappedsyscallinst);
end;
if IsFeatureImplemented(FEAT_GCS) then
if PSTATE.EL == target_el then
if GetCurrentEXLOCKEN() then
PSTATE.EXLOCK = '1';
else
PSTATE.EXLOCK = '0';
end;
else
PSTATE.EXLOCK = '0';
end;
end;
PSTATE.EL = target_el;
PSTATE.nRW = '0';
PSTATE.SP = '1';
PSTATE.EXLOCK = '1';
else
PSTATE.EXLOCK = '0';
end;
else
PSTATE.EXLOCK = '0';
end;
end;
PSTATE.EL = target_el;
PSTATE.nRW = '0';
PSTATE.SP = '1';
SPSR_ELx() = spsr;
ELR_ELx() = preferred_exception_return;
PSTATE.SS = '0';
if IsFeatureImplemented(FEAT_SSBS) then PSTATE.SSBS =
PSTATE.SS = '0';
if IsFeatureImplemented(FEAT_SSBS) then PSTATE.SSBS = SCTLR_ELx().DSSBS; end;
if IsFeatureImplemented(FEAT_EBEP) then PSTATE.PM = '1'; end;
if IsFeatureImplemented(FEAT_SEBEP) then
PSTATE.PPEND = '0'; PSTATE.PM = '1'; end;
if IsFeatureImplemented(FEAT_SEBEP) then
PSTATE.PPEND = '0';
ShouldSetPPEND = FALSE;
end;
if IsFeatureImplemented(FEAT_NMI) then
PSTATE.ALLINT = NOT
PSTATE.ALLINT = NOT SCTLR_ELx().SPINTMASK;
end;
PSTATE.[D,A,I,F] = '1111';
if IsFeatureImplemented(FEAT_MTE) then PSTATE.TCO = '1'; end;
PSTATE.IL = '0';
if IsFeatureImplemented(FEAT_UAO) then PSTATE.UAO = '0'; end;
if IsFeatureImplemented(FEAT_UINJ) then PSTATE.UINJ = '0'; end;
if IsFeatureImplemented(FEAT_PAuth_LR) then PSTATE.PACM = '0'; end;
if (IsFeatureImplemented(FEAT_PAN) && (PSTATE.EL == PSTATE.TCO = '1'; end;
PSTATE.IL = '0';
if IsFeatureImplemented(FEAT_UAO) then PSTATE.UAO = '0'; end;
if IsFeatureImplemented(FEAT_UINJ) then PSTATE.UINJ = '0'; end;
if IsFeatureImplemented(FEAT_PAuth_LR) then PSTATE.PACM = '0'; end;
if (IsFeatureImplemented(FEAT_PAN) && (PSTATE.EL == EL1 ||
(PSTATE.EL ==PSTATE.EL == EL2 && ELIsInHost(EL0))) &&
SCTLR_ELx().SPAN == '0') then
PSTATE.PAN = '1';
end;
if from_32 then // Coming from AArch32
PSTATE.IT = '00000000';
PSTATE.T = '0'; // PSTATE.J is RES0
end;
if IsFeatureImplemented(FEAT_BTI) then PSTATE.BTYPE = '00'; end;
let branch_conditional : boolean = FALSE;
BranchTo{64}(
PSTATEVBAR_ELx.PAN = '1';
end;
if from_32 then // Coming from AArch32
PSTATE.IT = '00000000';
PSTATE.T = '0'; // PSTATE.J is RES0
end;
if IsFeatureImplemented(FEAT_BTI) then PSTATE.BTYPE = '00'; end;
let branch_conditional ()[63: boolean = FALSE;
BranchTo{64}(target_vector,11]::vect_offset[10:0], BranchType_EXCEPTION, branch_conditional);
CheckExceptionCatch(TRUE); // Check for debug event on exception entry
if sync_errors then
SynchronizeErrors();
iesb_req = TRUE;
TakeUnmaskedPhysicalSErrorInterrupts(iesb_req);
end;
EndOfInstruction();
end;
// WaitForEventUntilDelay() // ======================== // Returns TRUE if WaitForEvent() returns before WFE trap delay expires, including potentially // some IMPLEMENTATION SPECIFIC additional delay, FALSE otherwise. impdef func WaitForEventUntilDelay(delay_enabled : boolean, delay : integer) => boolean begin return FALSE; end;
// AltDecodeBitMasks()
// ===================
// Alternative but logically equivalent implementation of DecodeBitMasks() that
// uses simpler primitives to compute tmask and wmask.
func AltDecodeBitMasks{M}(immN : bit, imms : bits(6), immr : bits(6),
immediate : boolean) => (bits(M), bits(M))
begin
var tmask, wmask : bits(64);
var tmask_and, wmask_and : bits(6);
var tmask_or, wmask_or : bits(6);
var levels : bits(6);
// Compute log2 of element size
// 2^len must be in range [2, M]
if immN::NOT(imms) == '000000x' then Undefined(); end;
let len : integer{} = HighestSetBitNZ(immN::NOT(imms));
assert 2 <= (2^len) && (2^len) <= M;
// Determine s, r and s - r parameters
levels = ZeroExtend{6}(Ones{len});
// For logical immediates an all-ones value of s is reserved
// since it would generate a useless all-ones result (many times)
if immediate && (imms AND levels) == levels then Undefined(); end;
let s : integer{} = UInt(imms AND levels);
let r : integer{} = UInt(immr AND levels);
let diff : integer{} = s - r; // 6-bit subtract with borrow
// Compute "top mask"
tmask_and = diff[5:0] OR NOT(levels);
tmask_or = diff[5:0] AND levels;
tmask = Ones{64};
tmask = ((tmask
AND Replicate{64, 2}(Replicate{1}(tmask_and[0]) :: Ones{1}))
OR Replicate{64, 2}(Zeros{1} :: Replicate{1}(tmask_or[0])));
// optimization of first step:
// tmask = Replicate{64}(tmask_and[0] :: '1');
tmask = ((tmask
AND Replicate{64, 4}(Replicate{2}(tmask_and[1]) :: Ones{2}))
OR Replicate{64, 4}(Zeros{2} :: Replicate{2}(tmask_or[1])));
tmask = ((tmask
AND Replicate{64, 8}(Replicate{4}(tmask_and[2]) :: Ones{4}))
OR Replicate{64, 8}(Zeros{4} :: Replicate{4}(tmask_or[2])));
tmask = ((tmask
AND Replicate{64, 16}(Replicate{8}(tmask_and[3]) :: Ones{8}))
OR Replicate{64, 16}(Zeros{8} :: Replicate{8}(tmask_or[3])));
tmask = ((tmask
AND Replicate{64, 32}(Replicate{16}(tmask_and[4]) :: Ones{16}))
OR Replicate{64, 32}(Zeros{16} :: Replicate{16}(tmask_or[4])));
tmask = ((tmask
AND Replicate{64, 64}(Replicate{32}(tmask_and[5]) :: Ones{32}))
OR Replicate{64, 64}(Zeros{32} :: Replicate{32}(tmask_or[5])));
// Compute "wraparound mask"
wmask_and = immr OR NOT(levels);
wmask_or = immr AND levels;
wmask = Zeros{64};
wmask = ((wmask
AND Replicate{64, 2}(Ones{1} :: Replicate{1}(wmask_and[0])))
OR Replicate{64, 2}(Replicate{1}(wmask_or[0]) :: Zeros{1}));
// wmask = Replicate{64}((wmask_or[0] ::: '0');', 32);
wmask = ((wmask
AND Replicate{64, 4}(Ones{2} :: Replicate{2}(wmask_and[1])))
OR Replicate{64, 4}(Replicate{2}(wmask_or[1]) :: Zeros{2}));
wmask = ((wmask
AND Replicate{64, 8}(Ones{4} :: Replicate{4}(wmask_and[2])))
OR Replicate{64, 8}(Replicate{4}(wmask_or[2]) :: Zeros{4}));
wmask = ((wmask
AND Replicate{64, 16}(Ones{8} :: Replicate{8}(wmask_and[3])))
OR Replicate{64, 16}(Replicate{8}(wmask_or[3]) :: Zeros{8}));
wmask = ((wmask
AND Replicate{64, 32}(Ones{16} :: Replicate{16}(wmask_and[4])))
OR Replicate{64, 32}(Replicate{16}(wmask_or[4]) :: Zeros{16}));
wmask = ((wmask
AND Replicate{64, 64}(Ones{32} :: Replicate{32}(wmask_and[5])))
OR Replicate{64, 64}(Replicate{32}(wmask_or[5]) :: Zeros{32}));
if diff[6] != '0' then // borrow from s - r
wmask = wmask AND tmask;
else
wmask = wmask OR tmask;
end;
return (wmask[M-1:0], tmask[M-1:0]);
end;
// AArch64_WriteTagMem()
// =====================
// Write to tag memory.
func AArch64_WriteTagMem(regval : bits(64), cachetypevaddress : bits(64),
accdesc_in : CacheType,
accdesc_in : AccessDescriptor, size : integer)
begin
assert accdesc_in.tagaccess && !accdesc_in.tagchecked;
var accdesc : AccessDescriptor = accdesc_in;
let vaddress : bits(64) = AlignDownSize{64}(regval, size as integer{16..2048});
let count : integer = size >> LOG2_TAG_GRANULE;
var tag : bits(4);
if cachetype == CacheType_TagZero then
;
let tag =: '0000';
else
tag bits(4) = AArch64_AllocationTagFromAddress(vaddress);
end;
let aligned : boolean = IsAlignedSize{64}(vaddress, TAG_GRANULE);
assert aligned;
accdesc.tagaccess = IsMTEEnabled(accdesc.el);
var (memtagtype, memaddrdesc) = AArch64_TranslateTagAddress(vaddress, accdesc, aligned, size);
// Check for aborts or debug exceptions
if IsFault(memaddrdesc) then
if IsDebugException(memaddrdesc.fault) then
AArch64_Abort(memaddrdesc.fault);
else
memaddrdesc.fault.vaddress = regval;
AArch64_Abort(memaddrdesc.fault);
end;
end;
if !accdesc.tagaccess || memtagtype != MemTag_AllocationTagged then
return;
end;
var memstatus : PhysMemRetStatus;
for i = 0 to count-1 do
memstatus = PhysMemTagWrite(memaddrdesc, accdesc, tag);
if IsFault(memstatus) then
HandleExternalWriteAbort(memstatus, memaddrdesc, 1, accdesc);
end;
memaddrdesc.paddress.address = memaddrdesc.paddress.address + TAG_GRANULE;
memaddrdesc.vaddress = memaddrdesc.vaddress + TAG_GRANULE;
end;
return;
end;
// AArch64_MemZero()
// =================
func AArch64_MemZero(regval : bits(64), cachetype : CacheType)
begin
let size : integer{} = (if cachetype IN {CacheType_TagWrite, CacheType_TagZero}
then 4*(2^(UInt(DCZID_EL0().TBS)))
else 4*(2^(UInt(DCZID_EL0().BS))));
assert size <= MAX_ZERO_BLOCK_SIZE;
if IsFeatureImplemented(FEAT_MTE2) then
assert size >= TAG_GRANULE;
end;
let vaddress : bits(64) = AlignDownSize{}(regval, size);
let accdesc : AccessDescriptor = CreateAccDescDCZero(cachetype);
if cachetype !=IN { } then
AArch64_WriteTagMem(Zeros{64}, vaddress, accdesc, size);
end;
if cachetype IN {CacheType_Tag, CacheType_TagWrite, CacheType_Data_TagCacheType_DataCacheType_TagZero } then
AArch64_WriteTagMem(regval, cachetypevaddress, accdesc, size);
end;
if cachetype IN {CacheType_Data, CacheType_Data_Tag} then
AArch64_DataMemZero(regval, vaddress, accdesc, size);
end;
return;
end;
// AArch64_EffectiveOpScopeAArch64_IC()
// ======================================
// Perform Instruction Cache Operation.
func AArch64_IC(opscope : AArch64_EffectiveOpScope(opscope_in : CacheOpScope)
begin
let =>regval : bits(64) = ARBITRARY : bits(64);
AArch64_IC(regval, opscope);
end;
// AArch64_IC()
// ============
// Perform Instruction Cache Operation.
func AArch64_IC(regval : bits(64), opscope : CacheOpScope
)
begin
var opscopecache : CacheOpScopeCacheRecord = opscope_in;
ifcache.acctype = PSTATEAccessType_IC.EL;
cache.cachetype !== EL1CacheType_Instruction then return opscope; end;
if IsFeatureImplemented(FEAT_TLBID) then
var fnb : bit;
if
cache.cacheop = IsHCRXEL2EnabledCacheOp_Invalidate();
cache.opscope = &&opscope;
if (!opscope IN {HaveEL(EL3) || SCR_EL3().VTLBIDEn == '1') then
fnb = HCRX_EL2().FNB;
else
fnb = '0';
end;
case fnb::HCR_EL2().FB of
when '00' =>
pass;
when '01' =>
if opscope == CacheOpScope_ALLU then
// The operation is broadcast within the Inner Shareable shareability domain.
opscope =, CacheOpScope_ALLUISCacheOpScope_ALLUIS_CnP;
end;
when '10' =>
if opscope ==, CacheOpScope_ALLUIS } then
//
let Thess operation only affects the PE on which the instruction is executed.
opscope =: SecurityState = SecurityStateAtEL(PSTATE.EL);
cache.cpas = CPASAtSecurityState(ss);
case opscope of
when CacheOpScope_ALLU;
end;
when '11' =>
ifcache.shareability opscope === Shareability_NSH;
when CacheOpScope_ALLUIS then
// The operation is broadcast to PEs which would share TLB entries with the
// current PE if CnP were 1.
opscope=>
cache.shareability = Shareability_ISH;
// When executed at EL1, if the Effective value of HCRX_EL2.VTLBIDEn is '1',
// then the operation is broadcast to the set of PEs selected by VTLBID0_EL2.TD0.
// Otherwise, the operation is broadcast to all PEs in the Shareability domain.
cache.domains = TLBIDomains(Broadcast_ISH, Zeros{16});
when CacheOpScope_ALLUIS_CnP;=>
end;
end;
else
ifcache.shareability opscope === CacheOpScope_ALLUShareability_ISH &&;
cache.domains = DEFAULT_TLBI_DOMAIN;
otherwise =>
unreachable;
end;
cache.regval = regval;
CACHE_OP(cache);
else
assert opscope == CacheOpScope_PoU;
if EL2Enabled() && HCR_EL2().FB == '1' then
opscope =! () then
if PSTATE.EL IN {EL0, EL1} then
cache.is_vmid_valid = TRUE;
cache.vmid = VMID();
else
cache.is_vmid_valid = FALSE;
end;
else
cache.is_vmid_valid = FALSE;
end;
if PSTATE.EL == EL0 then
cache.is_asid_valid = TRUE;
cache.asid = ASID();
else
cache.is_asid_valid = FALSE;
end;
let vaddress : bits(64) = regval;
cache.vaddress = regval;
let accdesc : AccessDescriptor = CreateAccDescIC(cache);
let aligned : boolean = TRUE;
let size : integer = 0;
var memaddrdesc : AddressDescriptor = AArch64_TranslateAddress(vaddress, accdesc,
aligned, size);
if IsFault(memaddrdesc) then
memaddrdesc.fault.vaddress = regval;
AArch64_Abort(memaddrdesc.fault);
end;
cache.cpas = CPASAtPAS(memaddrdesc.paddress.paspace);
cache.paddress = memaddrdesc.paddress;
cache.shareability = memaddrdesc.memattrs.shareability;
if memaddrdesc.memattrs.shareability == Shareability_OSH then
cache.shareability = Shareability_ISHCacheOpScope_ALLUISIsInHost;
end;
CACHE_OP(cache);
end;
return opscope;
end;
// AArch64_IC() // ============ // Perform Instruction Cache Operation. func AArch64_IC(opscope : CacheOpScope) begin let regval : bits(64) = ARBITRARY : bits(64); AArch64_IC(regval, opscope); end; // AArch64_IC() // ============ // Perform Instruction Cache Operation. func AArch64_IC(regval : bits(64), opscope_in : CacheOpScope) begin var cache : CacheRecord; var opscope : CacheOpScope = opscope_in; cache.acctype = AccessType_IC; cache.cachetype = CacheType_Instruction; cache.cacheop = CacheOp_Invalidate; cache.opscope = opscope; if opscope IN {CacheOpScope_ALLU, CacheOpScope_ALLUIS_CnP, CacheOpScope_ALLUIS} then let ss : SecurityState = SecurityStateAtEL(PSTATE.EL); cache.cpas = CPASAtSecurityState(ss); opscope = AArch64_EffectiveOpScope(opscope); case opscope of when CacheOpScope_ALLU => cache.shareability = Shareability_NSH; when CacheOpScope_ALLUIS => cache.shareability = Shareability_ISH; // When executed at EL1, if the Effective value of HCRX_EL2.VTLBIDEn is '1', // then the operation is broadcast to the set of PEs selected by VTLBID0_EL2.TD0. // Otherwise, the operation is broadcast to all PEs in the Shareability domain. cache.domains = TLBIDomains(Broadcast_ISH, Zeros{16}); when CacheOpScope_ALLUIS_CnP => cache.shareability = Shareability_ISH; cache.domains = DEFAULT_TLBI_DOMAIN; otherwise => unreachable; end; cache.regval = regval; CACHE_OP(cache); else assert opscope == CacheOpScope_PoU; if EL2Enabled() && !IsInHost() then if PSTATE.EL IN {EL0, EL1} then cache.is_vmid_valid = TRUE; cache.vmid = VMID(); else cache.is_vmid_valid = FALSE; end; else cache.is_vmid_valid = FALSE; end; if PSTATE.EL == EL0 then cache.is_asid_valid = TRUE; cache.asid = ASID(); else cache.is_asid_valid = FALSE; end; let vaddress : bits(64) = regval; cache.vaddress = regval; let accdesc : AccessDescriptor = CreateAccDescIC(cache); let aligned : boolean = TRUE; let size : integer = 0; var memaddrdesc : AddressDescriptor = AArch64_TranslateAddress(vaddress, accdesc, aligned, size); if IsFault(memaddrdesc) then memaddrdesc.fault.vaddress = regval; AArch64_Abort(memaddrdesc.fault); end; cache.cpas = CPASAtPAS(memaddrdesc.paddress.paspace); cache.paddress = memaddrdesc.paddress; cache.shareability = memaddrdesc.memattrs.shareability; if memaddrdesc.memattrs.shareability == Shareability_OSH then cache.shareability = Shareability_ISH; end; if memaddrdesc.memattrs.shareability != Shareability_NSH then // If the Effective value of HCRX_EL2().VTLBIDEn is '1', the invalidation is broadcast // to the set of PEs in the Inner shareable domain selected by VTLBID0_EL2().TD0 when // executed at EL1, or at EL0 when HCR_EL2().TGE is 0. cache.domains = TLBIDomains(Broadcast_ISH, Zeros{16}); end; CACHE_OP(cache); end; return; end;
// AArch64_MemSingleRead()
// =======================
// Perform an atomic, little-endian read of 'size' bits.
func AArch64_MemSingleRead{size : integer{8, 16, 32, 64, 128, 256}}(address : bits(64),
accdesc_in : AccessDescriptor,
aligned : boolean
) => (bits(size),
AddressDescriptor,
PhysMemRetStatus)
begin
var value : bits(size) = ARBITRARY : bits(size);
var memstatus : PhysMemRetStatus = ARBITRARY : PhysMemRetStatus;
let bytes : integer{} = size DIV 8;
memstatus.statuscode = Fault_None;
var accdesc : AccessDescriptor = accdesc_in;
if IsFeatureImplemented(FEAT_LSE2) then
let quantity : integer = MemSingleGranule();
assert ((IsFeatureImplemented(FEAT_LS64WB) &&
bytes == 32 && accdesc.acctype == AccessType_ASIMD) ||
AllInAlignedQuantity(address, bytes, quantity));
else
assert IsAlignedSize(address, bytes);
end;
// If the instruction encoding permits tag checking, confer with system register configuration
// which may override this.
if accdesc.tagchecked then
accdesc.tagchecked = AArch64_AccessIsTagChecked(address, accdesc);
end;
var memaddrdesc : AddressDescriptor;
memaddrdesc = AArch64_TranslateAddress(address, accdesc, aligned, bytes);
// Check for aborts or debug exceptions
if IsFault(memaddrdesc) then
return (value, memaddrdesc, memstatus);
end;
// Memory array access
if accdesc.tagchecked then
let ltag : bits(4) = AArch64_LogicalAddressTag(address);
let fault : FaultRecord = AArch64_CheckTag(memaddrdesc, accdesc, bytes, ltag);
if fault.statuscode != Fault_None then
memaddrdesc.fault = fault;
return (value, memaddrdesc, memstatus);
end;
end;
if accdesc.acctype != AccessType_IFETCH && SPESampleInFlight then
let is_load : boolean = TRUE;
SPESampleLoadStore(is_load, accdesc, memaddrdesc);
end;
var atomic : boolean;
if IsWBShareable(memaddrdesc.memattrs) then
atomic = TRUE;
elsif accdesc.exclusive then
atomic = TRUE;
elsif (accdesc.acctype == AccessType_SVE && accdesc.predicated &&
bytes == 8 && IsAlignedSize(address, 8)) then
// An SVE predicated load of a 128-bit element that is 64-bit aligned
// is treated as a pair of 64-bit single-copy atomic accesses.
// This is one of the 64-bit single-copy atomic access.
atomic = TRUE;
elsif aligned then
atomic = !accdesc.ispair;
else
// Misaligned accesses within MemSingleGranule() byte aligned memory but
// not Normal Cacheable Writeback are Atomic
atomic = ImpDefBool("FEAT_LSE2: access is atomic");
end;
if atomic then
(memstatus, value) = PhysMemRead{size}(memaddrdesc, accdesc);
elsif accdesc.acctype == AccessType_ASIMD && bytes == 32 && accdesc.ispair then
// A 32 byte LDP (SIMD&FP) that does not target Normal Inner Write-Back, Outer
// Write-Back cacheable, Shareable memory is treated as four 8 byte atomic accesses.
// As this access was not split in Mem(), it must be aligned to 32 bytes.
assert IsAlignedSize(address, 32);
accdesc.ispair = FALSE;
for i = 0 to 3 do
if !IsFault(memstatus) then // Do not continue past a fault
(memstatus, value[i*64+:64]) = PhysMemRead{64}(memaddrdesc, accdesc);
end;
if !IsFault(memstatus) then
memaddrdesc.paddress.address = memaddrdesc.paddress.address + 8;
memaddrdesc.vaddress = memaddrdesc.vaddress + 8;
end;
end;
elsif aligned && accdesc.ispair then
let half : integer{} = (size DIV 2) as integer{32, 64, 128};
(memstatus, value[0*:half]) = PhysMemRead{half}(memaddrdesc, accdesc);
if !IsFault(memstatus) then
memaddrdesc.paddress.address = memaddrdesc.paddress.address + (halfbytes DIV 82);
memaddrdesc.vaddress = memaddrdesc.vaddress + (halfbytes DIV 82);
(memstatus, value[1*:half]) = PhysMemRead{half}(memaddrdesc, accdesc);
end;
else
for i = 0 to bytes-1 do
if !IsFault(memstatus) then // Do not continue past a fault
(memstatus, value[i*:8]) = PhysMemRead{8}(memaddrdesc, accdesc);
end;
if !IsFault(memstatus) then
memaddrdesc.paddress.address = memaddrdesc.paddress.address + 1;
memaddrdesc.vaddress = memaddrdesc.vaddress + 1;
end;
end;
end;
if IsFault(memstatus) then
return (value, memaddrdesc, memstatus);
end;
if accdesc.acctype == AccessType_IFETCH then
memaddrdesc.fault = AArch64_CheckDebug(address, accdesc, bytes);
end;
return (value, memaddrdesc, memstatus);
end;
// AArch64_MemSingleWrite()
// ========================
// Perform an atomic, little-endian write of 'size' bits.
func AArch64_MemSingleWrite{size : integer{8, 16, 32, 64, 128, 256}}(address : bits(64),
accdesc_in : AccessDescriptor,
aligned : boolean,
value : bits(size)
) => (AddressDescriptor, PhysMemRetStatus)
begin
var accdesc : AccessDescriptor = accdesc_in;
let bytes : integer{} = size DIV 8;
if IsFeatureImplemented(FEAT_LSE2) then
let quantity : integer = MemSingleGranule();
assert ((IsFeatureImplemented(FEAT_LS64WB) &&
bytes == 32 && accdesc.acctype == AccessType_ASIMD) ||
AllInAlignedQuantity(address, bytes, quantity));
else
assert IsAlignedSize(address, bytes);
end;
// If the instruction encoding permits tag checking, confer with system register configuration
// which may override this.
if accdesc.tagchecked then
accdesc.tagchecked = AArch64_AccessIsTagChecked(address, accdesc);
end;
var memaddrdesc : AddressDescriptor;
var memstatus : PhysMemRetStatus = ARBITRARY : PhysMemRetStatus;
memaddrdesc = AArch64_TranslateAddress(address, accdesc, aligned, bytes);
// Check for aborts or debug exceptions
if IsFault(memaddrdesc) then
return (memaddrdesc, memstatus);
end;
// Effect on exclusives
if memaddrdesc.memattrs.shareability != Shareability_NSH then
ClearExclusiveByAddress(memaddrdesc.paddress, ProcessorID(), bytes);
end;
if accdesc.tagchecked then
let ltag : bits(4) = AArch64_LogicalAddressTag(address);
let fault : FaultRecord = AArch64_CheckTag(memaddrdesc, accdesc, bytes, ltag);
if fault.statuscode != Fault_None then
memaddrdesc.fault = fault;
return (memaddrdesc, memstatus);
end;
end;
if SPESampleInFlight then
let is_load : boolean = FALSE;
SPESampleLoadStore(is_load, accdesc, memaddrdesc);
end;
var atomic : boolean;
if IsWBShareable(memaddrdesc.memattrs) then
atomic = TRUE;
elsif accdesc.exclusive then
atomic = TRUE;
elsif (accdesc.acctype == AccessType_SVE && accdesc.predicated &&
bytes == 8 && IsAlignedSize(address, 8)) then
// An SVE predicated load of a 128-bit element that is 64-bit aligned
// is treated as a pair of 64-bit single-copy atomic accesses.
// This is one of the 64-bit single-copy atomic access.
atomic = TRUE;
elsif aligned then
atomic = !accdesc.ispair;
else
// Misaligned accesses within MemSingleGranule() byte aligned memory but
// not Normal Cacheable Writeback are Atomic
atomic = ImpDefBool("FEAT_LSE2: access is atomic");
end;
if atomic then
memstatus = PhysMemWrite{size}(memaddrdesc, accdesc, value);
if IsFault(memstatus) then
return (memaddrdesc, memstatus);
end;
elsif accdesc.acctype == AccessType_ASIMD && bytes == 32 && accdesc.ispair then
// A 32 byte STP (SIMD&FP) that does not target Normal Inner Write-Back, Outer
// Write-Back cacheable, Shareable memory is treated as four 8 byte atomic accesses.
// As this access was not split in Mem(), it must be aligned to 32 bytes.
assert IsAlignedSize(address, 32);
accdesc.ispair = FALSE;
for i = 0 to 3 do
memstatus = PhysMemWrite{64}(memaddrdesc, accdesc, value[64*i+:64]);
if IsFault(memstatus) then
return (memaddrdesc, memstatus);
end;
memaddrdesc.paddress.address = memaddrdesc.paddress.address + 8;
memaddrdesc.vaddress = memaddrdesc.vaddress + 8;
end;
elsif aligned && accdesc.ispair then
let half : integer{} = (size DIV 2) as integer{32, 64};
memstatus = PhysMemWrite{half}(memaddrdesc, accdesc, value[0*:half]);
if IsFault(memstatus) then
return (memaddrdesc, memstatus);
end;
memaddrdesc.paddress.address = memaddrdesc.paddress.address + (halfbytes DIV 82);
memaddrdesc.vaddress = memaddrdesc.vaddress + (halfbytes DIV 82);
memstatus = PhysMemWrite{half}(memaddrdesc, accdesc, value[1*:half]);
if IsFault(memstatus) then
return (memaddrdesc, memstatus);
end;
else
for i = 0 to bytes-1 do
memstatus = PhysMemWrite{8}(memaddrdesc, accdesc, value[i*:8]);
if IsFault(memstatus) then
return (memaddrdesc, memstatus);
end;
memaddrdesc.paddress.address = memaddrdesc.paddress.address + 1;
memaddrdesc.vaddress = memaddrdesc.vaddress + 1;
end;
end;
return (memaddrdesc, memstatus);
end;
// AArch64_MemTagWrite()
// =====================
// Store an Allocation Tag to memory.
func AArch64_MemTagWrite(address : bits(64),
accdesc_in : AccessDescriptor,
value : bits(4)) => (AddressDescriptor, PhysMemRetStatus)
begin
assert accdesc_in.tagaccess && !accdesc_in.tagchecked;
var accdesc : AccessDescriptor = accdesc_in;
var memaddrdesc : AddressDescriptor = ARBITRARY : AddressDescriptor;
var memtagtype : MemTagType = ARBITRARY : MemTagType;
var memstatus : PhysMemRetStatus = ARBITRARY : PhysMemRetStatus;
let aligned : boolean = IsAlignedSize(address, TAG_GRANULE);
// Stores of allocation tags must be aligned
if !aligned then
memaddrdesc.fault = AlignmentFault(accdesc, address);
return (memaddrdesc, memstatus);
end;
accdesc.tagaccess = IsMTEEnabled(accdesc.el);
(memtagtype, memaddrdesc) = AArch64_TranslateTagAddress(address, accdesc, aligned, TAG_GRANULE);
// Check for aborts or debug exceptions
if IsFault(memaddrdesc) then
memaddrdesc.fault.vaddress = memaddrdesc.vaddress;
return (memaddrdesc, memstatus);
end;
if accdesc.tagaccess && memtagtype == MemTag_AllocationTagged then
memstatus = PhysMemTagWrite(memaddrdesc, accdesc, value);
end;
return (memaddrdesc, memstatus);
end;
// Mem - accessor
// ==============
accessor Mem{size : integer{8, 16, 32, 64, 128, 256}}(address : bits(64),
accdesc_in : AccessDescriptor
) <=> value_in : bits(size)
begin
// Perform a read of 'size' bits. The access byte order is reversed for a big-endian access.
// Instruction fetches would call AArch64_MemSingle directly.
getter
var accdesc : AccessDescriptor = accdesc_in;
let bytes : integer{} = size DIV 8;
var value : bits(size);
// Check alignment on size of element accessed, not overall access size
varlet alignedalignment : boolean;
integer{} = (if accdesc.ispair && !accdesc.exclusive then
let halfbytes : integer{} = (size DIV 2)
else asbytes);
var integer{32, 64, 128};
aligned =: IsAlignedSize(address, half DIV 8);
else
aligned boolean = IsAlignedSize(address, bytesalignment);
end;
let quantity : integer = MemSingleGranule();
if !aligned && AArch64_UnalignedAccessFaults(accdesc, address, bytes) then
let fault : FaultRecord = AlignmentFault(accdesc, address);
AArch64_Abort(fault);
end;
if accdesc.acctype == AccessType_ASIMD && bytes == 16 && IsAlignedSize(address, 8) then
// If 128-bit SIMD&FP ordered access are treated as a pair of
// 64-bit single-copy atomic accesses, then these single copy atomic
// access can be observed in any order.
let half : integer{} = (size DIV 2) as integer{64};
let highaddress : bits(64) = AddressIncrement(address, halfbytes DIV 82, accdesc);
value[0*:half] = AArch64_MemSingle{half}(address, accdesc, aligned);
value[1*:half] = AArch64_MemSingle{half}(highaddress, accdesc, aligned);
elsif (accdesc.acctype == AccessType_ASIMD && bytes == 32 &&
accdesc.ispair && IsAlignedSize(address, 32)) then
value = AArch64_MemSingle{size}(address, accdesc, aligned);
elsif accdesc.acctype == AccessType_ASIMD && bytes == 32 && IsAlignedSize(address, 8) then
// If a 32 byte LDP (SIMD&FP) access is not aligned to 32 bytes but aligned to
// 8 bytes, it is treated as four 8 byte single-copy atomic accesses.
accdesc.ispair = FALSE;
aligned = TRUE;
for i = 0 to 3 do
let blockaddress : bits(64) = AddressIncrement(address, i*8, accdesc);
value[64*i+:64] = AArch64_MemSingle{64}(blockaddress, accdesc, aligned);
end;
elsif (IsFeatureImplemented(FEAT_LSE2) &&
AllInAlignedQuantity(address, bytes, quantity)) then
value = AArch64_MemSingle{size}(address, accdesc, aligned);
elsif ((aligned && accdesc.ispair) ||
(accdesc.acctype == AccessType_SVE && accdesc.predicated &&
bytes == 16 && IsAlignedSize(address, 8))) then
// Either: an aligned pair access, OR
// an SVE predicated load of a 128-bit element that is 64-bit aligned,
// which is treated as two 64-bit single-copy atomic accesses.
accdesc.ispair = FALSE;
let half : integer{} = (size DIV 2) as integer{32, 64, 128};
let highaddress : bits(64) = AddressIncrement(address, halfbytes DIV 82, accdesc);
if IsFeatureImplemented(FEAT_LRCPC3) && accdesc.highestaddressfirst then
value[1*:half] = AArch64_MemSingle{half}(highaddress, accdesc, aligned);
value[0*:half] = AArch64_MemSingle{half}(address, accdesc, aligned);
else
value[0*:half] = AArch64_MemSingle{half}(address, accdesc, aligned);
value[1*:half] = AArch64_MemSingle{half}(highaddress, accdesc, aligned);
end;
elsif aligned then
value = AArch64_MemSingle{size}(address, accdesc, aligned);
else
assert bytes > 1;
if (IsFeatureImplemented(FEAT_LRCPC3) && accdesc.ispair &&
accdesc.highestaddressfirst) then
let half : integer{} = (size DIV 2) as integer{32, 64, 128};
var lowhalf, highhalf : bits(half);
for i = 0 to (halfbytes DIV 82)-1 do
let byteaddress : bits(64) = AddressIncrement(address,
(halfbytes DIV 82) + i, accdesc);
// Individual byte access can be observed in any order
highhalf[i*:8] = AArch64_MemSingle{8}(byteaddress, accdesc, aligned);
end;
for i = 0 to (halfbytes DIV 82)-1 do
let byteaddress : bits(64) = AddressIncrement(address, i, accdesc);
// Individual byte access can be observed in any order
lowhalf[i*:8] = AArch64_MemSingle{8}(byteaddress, accdesc, aligned);
end;
value = highhalf::lowhalf;
else
value[7:0] = AArch64_MemSingle{8}(address, accdesc, aligned);
accdesc.lowestaddress = FALSE;
// For subsequent bytes, if they cross to a new translation page which assigns
// Device memory type, it is CONSTRAINED UNPREDICTABLE whether an unaligned access
// will generate an Alignment Fault.
let c : Constraint = ConstrainUnpredictable(Unpredictable_DEVPAGE2);
assert c IN {Constraint_FAULT, Constraint_NONE};
if c == Constraint_NONE then aligned = TRUE; end;
for i = 1 to bytes-1 do
let byteaddress : bits(64) = AddressIncrement(address, i, accdesc);
value[i*:8] = AArch64_MemSingle{8}(byteaddress, accdesc, aligned);
end;
end;
end;
if BigEndian(accdesc.acctype) then
value = BigEndianReverse{size}(value);
end;
return value;
end;
// Perform a write of 'size' bits. The byte order is reversed for a big-endian access.
setter
var value : bits(size) = value_in;
let bytes : integer{} = size DIV 8;
var accdesc : AccessDescriptor = accdesc_in;
// Check alignment on size of element accessed, not overall access size
varlet alignedalignment : boolean;
integer{} = (if accdesc.ispair && !accdesc.exclusive then
let halfbytes : integer{} = (size DIV 2)
else asbytes);
var integer{32, 64, 128};
aligned =: IsAlignedSize(address, half DIV 8);
else
aligned boolean = IsAlignedSize(address, bytesalignment);
end;
let quantity : integer = MemSingleGranule();
if !aligned && AArch64_UnalignedAccessFaults(accdesc, address, bytes) then
let fault : FaultRecord = AlignmentFault(accdesc, address);
AArch64_Abort(fault);
end;
if BigEndian(accdesc.acctype) then
value = BigEndianReverse{size}(value);
end;
if accdesc.acctype == AccessType_ASIMD && bytes == 16 && IsAlignedSize(address, 8) then
let half : integer{} = (size DIV 2) as integer{64};
// 128-bit SIMD&FP stores are treated as a pair of 64-bit single-copy atomic accesses
// 64-bit aligned.
let highaddress : bits(64) = AddressIncrement(address, half(bytes DIV 8,2), accdesc);
AArch64_MemSingle{half}(address, accdesc, aligned) = value[0+:half];
AArch64_MemSingle{half}(highaddress, accdesc, aligned) = value[half+:half];
elsif (accdesc.acctype == AccessType_ASIMD && bytes == 32 &&
accdesc.ispair && IsAlignedSize(address, 32)) then
AArch64_MemSingle{size}(address, accdesc, aligned) = value;
elsif accdesc.acctype == AccessType_ASIMD && bytes == 32 && IsAlignedSize(address, 8) then
// If a 32 byte STP (SIMD&FP) access is not aligned to 32 bytes but aligned to
// 8 bytes, it is treated as four 8 byte single-copy atomic accesses.
accdesc.ispair = FALSE;
aligned = TRUE;
for i = 0 to 3 do
let blockaddress : bits(64) = AddressIncrement(address, i*8, accdesc);
AArch64_MemSingle{64}(blockaddress, accdesc, aligned) = value[64*i+:64];
end;
elsif (IsFeatureImplemented(FEAT_LSE2) &&
AllInAlignedQuantity(address, bytes, quantity)) then
AArch64_MemSingle{size}(address, accdesc, aligned) = value;
elsif ((aligned && accdesc.ispair) ||
(accdesc.acctype == AccessType_SVE && accdesc.predicated &&
bytes == 16 && IsAlignedSize(address, 8))) then
// Either: an aligned pair access, OR
// an SVE predicated load of a 128-bit element that is 64-bit aligned,
// which is treated as two 64-bit single-copy atomic accesses.
let half : integer{} = (size DIV 2) as integer{32, 64, 128};
accdesc.ispair = FALSE;
let highaddress : bits(64) = AddressIncrement(address, half(bytes DIV 8,2), accdesc);
if IsFeatureImplemented(FEAT_LRCPC3) && accdesc.highestaddressfirst then
AArch64_MemSingle{half}(highaddress, accdesc, aligned) = value[half+:half];
AArch64_MemSingle{half}(address, accdesc, aligned) = value[0+:half];
else
AArch64_MemSingle{half}(address, accdesc, aligned) = value[0+:half];
AArch64_MemSingle{half}(highaddress, accdesc, aligned) = value[half+:half];
end;
elsif aligned then
AArch64_MemSingle{size}(address, accdesc, aligned) = value;
else
assert bytes > 1;
if (IsFeatureImplemented(FEAT_LRCPC3) && accdesc.ispair &&
accdesc.highestaddressfirst) then
let half : integer{} = (size DIV 2) as integer{32, 64};
var lowhalf, highhalf : bits(half);
(highhalf, lowhalf) = (value[half+:half], value[0+:half]);
for i = 0 to (halfbytes DIV 82)-1 do
let byteaddress : bits(64) = AddressIncrement(address,
(halfbytes DIV 82) + i, accdesc);
// Individual byte access can be observed in any order
AArch64_MemSingle{8}(byteaddress, accdesc, aligned) = highhalf[i*:8];
end;
for i = 0 to (halfbytes DIV 82)-1 do
let byteaddress : bits(64) = AddressIncrement(address,
(halfbytes DIV 82) + i, accdesc);
// Individual byte access can be observed in any order,
// but implies observability of highhalf
AArch64_MemSingle{8}(byteaddress, accdesc, aligned) = lowhalf[i*:8];
end;
else
AArch64_MemSingle{8}(address, accdesc, aligned) = value[7:0];
accdesc.lowestaddress = FALSE;
// For subsequent bytes, if they cross to a new translation page which assigns
// Device memory type, it is CONSTRAINED UNPREDICTABLE whether an unaligned access
// will generate an Alignment Fault.
let c : Constraint = ConstrainUnpredictable(Unpredictable_DEVPAGE2);
assert c IN {Constraint_FAULT, Constraint_NONE};
if c == Constraint_NONE then aligned = TRUE; end;
for i = 1 to bytes-1 do
let byteaddress : bits(64) = AddressIncrement(address, i, accdesc);
AArch64_MemSingle{8}(byteaddress, accdesc, aligned) = value[i*:8];
end;
end;
end;
end;
end;
// NVMem - accessor
// ================
accessor NVMem(offset : integer) <=> value : bits(64)
begin
// This function is the load memory access for the transformed System register read access
// when Enhanced Nested Virtualization is enabled with HCR_EL2.NV2 = 1.
// The address for the load memory access is calculated using
// the formula SignExtend{64}((VNCR_EL2.BADDR ::: Offset[11:0])], 64) where,
// * VNCR_EL2.BADDR holds the base address of the memory location, and
// * Offset is the unique offset value defined architecturally for each System register that
// supports transformation of register access to memory access.
getter
assert offset > 0 && offset MOD 8 == 0;
let directread : boolean = FALSE;
let baddr : bits(64) = EffectiveBADDR(VNCR_EL2().BADDR :: Zeros{12}, directread);
let address : bits(64) = baddr + offset;
let accdesc : AccessDescriptor = CreateAccDescNV2(MemOp_LOAD);
return Mem{64}(address, accdesc);
end;
// This function is the store memory access for the transformed System register write access
// when Enhanced Nested Virtualization is enabled with HCR_EL2.NV2 = 1.
// The address for the store memory access is calculated using
// the formula SignExtend{64}((VNCR_EL2.BADDR ::: Offset[11:0])], 64) where,
// * VNCR_EL2.BADDR holds the base address of the memory location, and
// * Offset is the unique offset value defined architecturally for each System register that
// supports transformation of register access to memory access.
setter
assert offset > 0 && offset MOD 8 == 0;
let directread : boolean = FALSE;
let baddr : bits(64) = EffectiveBADDR(VNCR_EL2().BADDR :: Zeros{12}, directread);
let address : bits(64) = baddr + offset;
let accdesc : AccessDescriptor = CreateAccDescNV2(MemOp_STORE);
Mem{64}(address, accdesc) = value;
return;
end;
end;
accessor NVMem128(offset : integer) <=> value : bits(128)
begin
getter
assert offset > 0 && offset MOD 16 == 0;
let directread : boolean = FALSE;
let baddr : bits(64) = EffectiveBADDR(VNCR_EL2().BADDR :: Zeros{12}, directread);
let address : bits(64) = baddr + offset;
let accdesc : AccessDescriptor = CreateAccDescNV2(MemOp_LOAD);
return Mem{128}(address, accdesc);
end;
setter
assert offset > 0 && offset MOD 16 == 0;
let directread : boolean = FALSE;
let baddr : bits(64) = EffectiveBADDR(VNCR_EL2().BADDR :: Zeros{12}, directread);
let address : bits(64) = baddr + offset;
let accdesc : AccessDescriptor = CreateAccDescNV2(MemOp_STORE);
Mem{128}(address, accdesc) = value;
end;
end;
// CheckSETConstrainedUnpredictable()
// ==================================
// Check for CONSTRAINED UNPREDICTABLE behaviour in the SET* and SETG* instructions.
func CheckSETConstrainedUnpredictable(memsetn : SETParamsinteger, d : integer, s : integer)
begin
if (memset.ss == memset.nn || memset.ss == memset.dd || memset.nn == memset.dd) then
let c : Constraint = ConstrainUnpredictable(Unpredictable_MOPSOVERLAP);
assert c IN {Constraint_UNDEF, Constraint_NOP};
case c of
when Constraint_UNDEF => Undefined();
when Constraint_NOP => ExecuteAsNOP();
end;
end;
if (memset.dd == 31 || memset.nn == 31) then
let c : Constraint = ConstrainUnpredictable(Unpredictable_MOPS_R31);
assert c IN {Constraint_UNDEF, Constraint_NOP};
case c of
when Constraint_UNDEF => Undefined();
when Constraint_NOP => ExecuteAsNOP();
end;
end;
end;
// InsertPAC()
// ===========
// Calculates the pointer authentication code for a 64-bit quantity and then
// inserts that into pointer authentication code field of that 64-bit quantity.
func InsertPAC(ptr : bits(64), modifier : bits(64), modifier2 : bits(64), use_modifier2 : boolean,
K : bits(128), data : boolean) => bits(64)
begin
var PAC : bits(64);
var result : bits(64);
var ext_ptr : bits(64);
var extfield : bits(64);
var selbit : bit;
var bit55 : bit;
let tbi : boolean = EffectiveTBI(ptr, !data, PSTATE.EL) == '1';
let mtx : boolean = (IsFeatureImplemented(FEAT_MTE_NO_ADDRESS_TAGS) &&
EffectiveMTX(ptr, !data, PSTATE.EL) == '1');
let top_bit : integer{} = if tbi then 55 else 63;
let EL3_using_lva3 : boolean = (IsFeatureImplemented(FEAT_LVA3) &&
TranslationRegime(PSTATE.EL) == Regime_EL3 &&
AArch64_IASize(TCR_EL3().T0SZ) > 52);
let is_VA_56bit : boolean = (TranslationRegime(PSTATE.EL) == Regime_EL3 &&
AArch64_IASize(TCR_EL3().T0SZ) == 56);
// If tagged pointers are in use for a regime with two TTBRs, use bit[55] of
// the pointer to select between upper and lower ranges, and preserve this.
// This handles the awkward case where there is apparently no correct choice between
// the upper and lower address range - ie an addr of 1xxxxxxx0... with TBI0=0 and TBI1=1
// and 0xxxxxxx1 with TBI1=0 and TBI0=1:
if PtrHasUpperAndLowerAddRanges() then
assert S1TranslationRegime() IN {EL1, EL2};
if S1TranslationRegime() == EL1 then
// EL1 translation regime registers
if data then
if TCR_EL1().TBI1 == '1' || TCR_EL1().TBI0 == '1' then
selbit = ptr[55];
else
selbit = ptr[63];
end;
else
if ((TCR_EL1().TBI1 == '1' && TCR_EL1().TBID1 == '0') ||
(TCR_EL1().TBI0 == '1' && TCR_EL1().TBID0 == '0')) then
selbit = ptr[55];
else
selbit = ptr[63];
end;
end;
else
// EL2 translation regime registers
if data then
if TCR_EL2().TBI1 == '1' || TCR_EL2().TBI0 == '1' then
selbit = ptr[55];
else
selbit = ptr[63];
end;
else
if ((TCR_EL2().TBI1 == '1' && TCR_EL2().TBID1 == '0') ||
(TCR_EL2().TBI0 == '1' && TCR_EL2().TBID0 == '0')) then
selbit = ptr[55];
else
selbit = ptr[63];
end;
end;
end;
else selbit = if tbi then ptr[55] else ptr[63];
end;
if IsFeatureImplemented(FEAT_PAuth2) && IsFeatureImplemented(FEAT_CONSTPACFIELD) then
selbit = ptr[55];
end;
let bottom_PAC_bit : AddressSize = CalculateBottomPACBit(selbit);
if EL3_using_lva3 then
extfield = Replicate{64}('0');
else
extfield = Replicate{64}(selbit);
end;
// Compute the pointer authentication code for a ptr with good extension bits
if tbi then
if bottom_PAC_bit <= 55 then
ext_ptr = (ptr[63:56] ::
extfield[55:bottom_PAC_bit] :: ptr[bottom_PAC_bit-1:0]);
else
ext_ptr = ptr[63:56] :: ptr[55:0];
end;
elsif mtx then
if bottom_PAC_bit <= 55 then
ext_ptr = (extfield[63:60] :: ptr[59:56] ::
extfield[55:bottom_PAC_bit] :: ptr[bottom_PAC_bit-1:0]);
else
ext_ptr = extfield[63:60] :: ptr[59:56] :: ptr[55:0];
end;
else
ext_ptr = extfield[63:bottom_PAC_bit] :: ptr[bottom_PAC_bit-1:0];
end;
if use_modifier2 then
assert IsFeatureImplemented(FEAT_PAuth_LR);
PAC = ComputePAC2(ext_ptr, modifier, modifier2, K[127:64], K[63:0]);
else
PAC = ComputePAC(ext_ptr, modifier, K[127:64], K[63:0]);
end;
if !IsFeatureImplemented(FEAT_PAuth2) then
// If FEAT_PAuth2 is not implemented, the PAC is corrupted if the pointer does not have
// a canonical VA.
assert bottom_PAC_bit <= 52;
if !IsZero(ptr[top_bit:bottom_PAC_bit]) && !IsOnes(ptr[top_bit:bottom_PAC_bit]) then
if IsFeatureImplemented(FEAT_EPAC) then
PAC = 0x0000000000000000[63:0];
else
PAC[top_bit-1] = NOT(PAC[top_bit-1]);
end;
end;
end;
// Preserve the determination between upper and lower address at bit[55] and insert PAC into
// bits that are not used for the address or the tag(s).
if !IsFeatureImplemented(FEAT_PAuth2) then
assert (bottom_PAC_bit <= 52);
if tbi then
result = ptr[63:56]::selbit::PAC[54:bottom_PAC_bit]::ptr[bottom_PAC_bit-1:0];
else
result = PAC[63:56]::selbit::PAC[54:bottom_PAC_bit]::ptr[bottom_PAC_bit-1:0];
end;
else
if EL3_using_lva3 then
// Bit 55 is an address bit (when VA size is 56-bits) or
// used to store PAC (when VA size is less than 56-bits)
if is_VA_56bit then
bit55 = ptr[55];
else
bit55 = ptr[55] XOR PAC[55];
end;
else
bit55 = selbit;
end;
if tbi then
if bottom_PAC_bit < 55 then
result = (ptr[63:56] :: bit55 ::
(ptr[54:bottom_PAC_bit] XOR PAC[54:bottom_PAC_bit]) ::
ptr[bottom_PAC_bit-1:0]);
else
result = (ptr[63:56] :: bit55 :: ptr[54:0]);
end;
elsif mtx then
if bottom_PAC_bit < 55 then
result = ((ptr[63:60] XOR PAC[63:60]) :: ptr[59:56] :: bit55 ::
(ptr[54:bottom_PAC_bit] XOR PAC[54:bottom_PAC_bit]) ::
ptr[bottom_PAC_bit-1:0]);
else
result = ((ptr[63:60] XOR PAC[63:60]) :: ptr[59:56] :: bit55 ::
ptr[54:0]);
end;
else
if bottom_PAC_bit < 55 then
result = ((ptr[63:56] XOR PAC[63:56]) :: bit55 ::
(ptr[54:bottom_PAC_bit] XOR PAC[54:bottom_PAC_bit]) ::
ptr[bottom_PAC_bit-1:0]);
else
result = ((ptr[63:56] XOR PAC[63:56]) :: bit55 ::
ptr[54:0]);
end;
end;
end;
return result;
end;
// IsAPDAKeyEnabled()
// ==================
// Returns TRUE if authentication using the APDAKey_EL1 key is enabled.
// Otherwise, depending on the state of the PE, generate a trap, or return FALSE.
func IsAPDAKeyEnabled() => boolean
begin
var TrapEL2 : boolean;
var TrapEL3 : boolean;
var Enable : bits(1);
case PSTATE.EL of
when PSTATE.EL of
when EL0 =>
let IsEL1Regime : boolean = S1TranslationRegime() == EL1;
Enable = if IsEL1Regime then SCTLR_EL1().EnDA else SCTLR_EL2().EnDA;
if IsFeatureImplemented(FEAT_PAuth_EnhCtl) then
var enda2 : bit;
if IsEL1Regime then
enda2 = if IsSCTLR2EL1Enabled() then SCTLR2_EL1().EnDA2 else '0';
else
enda2 = if IsSCTLR2EL2Enabled();
Enable = if IsEL1Regime then SCTLR2_EL2SCTLR_EL1().EnDA2EnDA else '0';
endSCTLR_EL2().EnDA;
if IsFeatureImplemented(FEAT_PAuth_EnhCtl) then
Enable = Enable XOR enda2;(if IsEL1Regime then SCTLR2_EL1().EnDA2
else SCTLR2_EL2().EnDA2);
end;
TrapEL2 = EL2Enabled() && HCR_EL2().API == '0' && !IsInHost();
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL1 =>
Enable = SCTLR_EL1().EnDA;
TrapEL2 = EL2Enabled() && HCR_EL2().API == '0';
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL2 =>
Enable = SCTLR_EL2().EnDA;
TrapEL2 = FALSE;
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL3 =>
Enable = SCTLR_EL3().EnDA;
TrapEL2 = FALSE;
TrapEL3 = FALSE;
end;
if Enable == '0' then
return FALSE;
elsif TrapEL3 && EL3SDDUndefPriority() then
Undefined();
elsif TrapEL2 then
TrapPACUse(EL2);
elsif TrapEL3 then
if EL3SDDUndef() then
Undefined();
else
TrapPACUse(EL3);
end;
else
return TRUE;
end;
end;
// IsAPDBKeyEnabled()
// ==================
// Returns TRUE if authentication using the APDBKey_EL1 key is enabled.
// Otherwise, depending on the state of the PE, generate a trap, or return FALSE.
func IsAPDBKeyEnabled() => boolean
begin
var TrapEL2 : boolean;
var TrapEL3 : boolean;
var Enable : bits(1);
case PSTATE.EL of
when PSTATE.EL of
when EL0 =>
let IsEL1Regime : boolean = S1TranslationRegime() == EL1;
Enable = if IsEL1Regime then SCTLR_EL1().EnDB else SCTLR_EL2().EnDB;
if IsFeatureImplemented(FEAT_PAuth_EnhCtl) then
var endb2 : bit;
if IsEL1Regime then
endb2 = if IsSCTLR2EL1Enabled() then SCTLR2_EL1().EnDB2 else '0';
else
endb2 = if IsSCTLR2EL2Enabled();
Enable = if IsEL1Regime then SCTLR2_EL2SCTLR_EL1().EnDB2EnDB else '0';
endSCTLR_EL2().EnDB;
if IsFeatureImplemented(FEAT_PAuth_EnhCtl) then
Enable = Enable XOR endb2;(if IsEL1Regime then SCTLR2_EL1().EnDB2
else SCTLR2_EL2().EnDB2);
end;
TrapEL2 = EL2Enabled() && HCR_EL2().API == '0' && !IsInHost();
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL1 =>
Enable = SCTLR_EL1().EnDB;
TrapEL2 = EL2Enabled() && HCR_EL2().API == '0';
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL2 =>
Enable = SCTLR_EL2().EnDB;
TrapEL2 = FALSE;
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL3 =>
Enable = SCTLR_EL3().EnDB;
TrapEL2 = FALSE;
TrapEL3 = FALSE;
end;
if Enable == '0' then
return FALSE;
elsif TrapEL3 && EL3SDDUndefPriority() then
Undefined();
elsif TrapEL2 then
TrapPACUse(EL2);
elsif TrapEL3 then
if EL3SDDUndef() then
Undefined();
else
TrapPACUse(EL3);
end;
else
return TRUE;
end;
end;
// IsAPIAKeyEnabled()
// ==================
// Returns TRUE if authentication using the APIAKey_EL1 key is enabled.
// Otherwise, depending on the state of the PE, generate a trap, or return FALSE.
func IsAPIAKeyEnabled() => boolean
begin
var TrapEL2 : boolean;
var TrapEL3 : boolean;
var Enable : bits(1);
case PSTATE.EL of
when PSTATE.EL of
when EL0 =>
let IsEL1Regime : boolean = S1TranslationRegime() == EL1;
Enable = if IsEL1Regime then SCTLR_EL1().EnIA else SCTLR_EL2().EnIA;
if IsFeatureImplemented(FEAT_PAuth_EnhCtl) then
var enia2 : bit;
if IsEL1Regime then
enia2 = if IsSCTLR2EL1Enabled() then SCTLR2_EL1().EnIA2 else '0';
else
enia2 = if IsSCTLR2EL2Enabled();
Enable = if IsEL1Regime then SCTLR2_EL2SCTLR_EL1().EnIA2EnIA else '0';
endSCTLR_EL2().EnIA;
if IsFeatureImplemented(FEAT_PAuth_EnhCtl) then
Enable = Enable XOR enia2;(if IsEL1Regime then SCTLR2_EL1().EnIA2
else SCTLR2_EL2().EnIA2);
end;
TrapEL2 = EL2Enabled() && HCR_EL2().API == '0' && !IsInHost();
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL1 =>
Enable = SCTLR_EL1().EnIA;
TrapEL2 = EL2Enabled() && HCR_EL2().API == '0';
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL2 =>
Enable = SCTLR_EL2().EnIA;
TrapEL2 = FALSE;
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL3 =>
Enable = SCTLR_EL3().EnIA;
TrapEL2 = FALSE;
TrapEL3 = FALSE;
end;
if Enable == '0' then
return FALSE;
elsif TrapEL3 && EL3SDDUndefPriority() then
Undefined();
elsif TrapEL2 then
TrapPACUse(EL2);
elsif TrapEL3 then
if EL3SDDUndef() then
Undefined();
else
TrapPACUse(EL3);
end;
else
return TRUE;
end;
end;
// IsAPIBKeyEnabled()
// ==================
// Returns TRUE if authentication using the APIBKey_EL1 key is enabled.
// Otherwise, depending on the state of the PE, generate a trap, or return FALSE.
func IsAPIBKeyEnabled() => boolean
begin
var TrapEL2 : boolean;
var TrapEL3 : boolean;
var Enable : bits(1);
case PSTATE.EL of
when PSTATE.EL of
when EL0 =>
let IsEL1Regime : boolean = S1TranslationRegime() == EL1;
Enable = if IsEL1Regime then SCTLR_EL1().EnIB else SCTLR_EL2().EnIB;
if IsFeatureImplemented(FEAT_PAuth_EnhCtl) then
var enib2 : bit;
if IsEL1Regime then
enib2 = if IsSCTLR2EL1Enabled() then SCTLR2_EL1().EnIB2 else '0';
else
enib2 = if IsSCTLR2EL2Enabled();
Enable = if IsEL1Regime then SCTLR2_EL2SCTLR_EL1().EnIB2EnIB else '0';
endSCTLR_EL2().EnIB;
if IsFeatureImplemented(FEAT_PAuth_EnhCtl) then
Enable = Enable XOR enib2;(if IsEL1Regime then SCTLR2_EL1().EnIB2
else SCTLR2_EL2().EnIB2);
end;
TrapEL2 = EL2Enabled() && HCR_EL2().API == '0' && !IsInHost();
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL1 =>
Enable = SCTLR_EL1().EnIB;
TrapEL2 = EL2Enabled() && HCR_EL2().API == '0';
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL2 =>
Enable = SCTLR_EL2().EnIB;
TrapEL2 = FALSE;
TrapEL3 = HaveEL(EL3) && SCR_EL3().API == '0';
when EL3 =>
Enable = SCTLR_EL3().EnIB;
TrapEL2 = FALSE;
TrapEL3 = FALSE;
end;
if Enable == '0' then
return FALSE;
elsif TrapEL3 && EL3SDDUndefPriority() then
Undefined();
elsif TrapEL2 then
TrapPACUse(EL2);
elsif TrapEL3 then
if EL3SDDUndef() then
Undefined();
else
TrapPACUse(EL3);
end;
else
return TRUE;
end;
end;
// AArch64_dESBOperation()
// =======================
// Perform the AArch64 ESB operation for a pending delegated SError exception.
func AArch64_dESBOperation()
begin
assert (IsFeatureImplemented(FEAT_E3DSE) && !ELUsingAArch32(EL3) && PSTATE.EL != PSTATE.EL != EL3);
// When FEAT_E3DSE is implemented, SCR_EL3.DSE might inject a delegated SError exception.
var dsei_pending, dsei_masked : boolean;
dsei_pending = EffectiveSCR_EL3_EnDSE());
// ==When '1'FEAT_E3DSE &&is implemented, SCR_EL3.DSE might inject a delegated SError exception.
var dsei_pending, dsei_masked : boolean;
dsei_pending = SCR_EL3().().[EnDSE,DSE] == '111';
(dsei_masked, -) = AArch64_DelegatedSErrorTarget();
if dsei_pending && dsei_masked then
var target : bits(64) = Zeros{};
target[31] = '1'; // A
target[24:0] = VSESR_EL3()[24:0];
VDISR_EL3() = target;
ClearPendingDelegatedSError();
end;
return;
end;
// EffectiveSCR_EL3_EnDSE() // ======================== // Return the Effective value of SCR_EL3().EnDSE. func EffectiveSCR_EL3_EnDSE() => bit begin if !IsFeatureImplemented(FEAT_E3DSE) then return '0'; end; if SCR_EL3().EA == '0' && EffectiveSCR_EL3_TMEA() == '0' then return '0'; end; return SCR_EL3().EnDSE; end;
// SysOp()
// =======
func SysOp(op1 : bits(3), CRn : bits(4), CRm : bits(4), op2 : bits(3)) => SystemOp
begin
case op1::CRn::CRm::op2 of
when '000 0111 1000 000' => return Sys_AT; // S1E1R
when '000 0111 1000 001' => return Sys_AT; // S1E1W
when '000 0111 1000 010' => return Sys_AT; // S1E0R
when '000 0111 1000 011' => return Sys_AT; // S1E0W
when '000 0111 1001 000' => return Sys_AT; // S1E1RP
when '000 0111 1001 001' => return Sys_AT; // S1E1WP
when '000 0111 1001 010' => return Sys_AT; // S1E1A
when '100 0111 1000 000' => return Sys_AT; // S1E2R
when '100 0111 1000 001' => return Sys_AT; // S1E2W
when '100 0111 1001 010' => return Sys_AT; // S1E2A
when '100 0111 1000 100' => return Sys_AT; // S12E1R
when '100 0111 1000 101' => return Sys_AT; // S12E1W
when '100 0111 1000 110' => return Sys_AT; // S12E0R
when '100 0111 1000 111' => return Sys_AT; // S12E0W
when '110 0111 1000 000' => return Sys_AT; // S1E3R
when '110 0111 1000 001' => return Sys_AT; // S1E3W
when '110 0111 1001 010' => return Sys_AT; // S1E3A
when '001 0111 0010 100' => return Sys_BRB; // IALL
when '001 0111 0010 101' => return Sys_BRB; // INJ
when '000 0111 0110 001' => return Sys_DC; // IVAC
when '000 0111 0110 010' => return Sys_DC; // ISW
when '000 0111 0110 011' => return Sys_DC; // IGVAC
when '000 0111 0110 100' => return Sys_DC; // IGSW
when '000 0111 0110 101' => return Sys_DC; // IGDVAC
when '000 0111 0110 110' => return Sys_DC; // IGDSW
when '000 0111 1010 010' => return Sys_DC; // CSW
when '000 0111 1010 100' => return Sys_DC; // CGSW
when '000 0111 1010 110' => return Sys_DC; // CGDSW
when '000 0111 1110 010' => return Sys_DC; // CISW
when '000 0111 1110 100' => return Sys_DC; // CIGSW
when '000 0111 1110 110' => return Sys_DC; // CIGDSW
when '011 0111 0100 001' => return Sys_DC; // ZVA
when '011 0111 0100 011' => return Sys_DC; // GVA
when '011 0111 0100 100' => return Sys_DC; // GZVA
when '011 0111 1010 001' => return Sys_DC; // CVAC
when '011 0111 1010 011' => return Sys_DC; // CGVAC
when '011 0111 1010 101' => return Sys_DC; // CGDVAC
when '011 0111 1011 001' => return Sys_DC; // CVAU
when '011 0111 1100 001' => return Sys_DC; // CVAP
when '011 0111 1100 011' => return Sys_DC; // CGVAP
when '011 0111 1100 101' => return Sys_DC; // CGDVAP
when '011 0111 1101 001' => return Sys_DC; // CVADP
when '011 0111 1101 011' => return Sys_DC; // CGVADP
when '011 0111 1101 101' => return Sys_DC; // CGDVADP
when '011 0111 1110 001' => return Sys_DC; // CIVAC
when '011 0111 1110 011' => return Sys_DC; // CIGVAC
when '011 0111 1110 101' => return Sys_DC; // CIGDVAC
when '100 0111 00001110 100000' => return Sys_MLBI; // ALLE1
when '100 0111 0000 101' => return Sys_MLBI; // VMALLE1
when '100 0111 0000 110' => return Sys_MLBI; // VPIDE1
when '100 0111 0000 111' => return Sys_MLBI; // VPMGE1
when '100 0111 1110 000' => return Sys_DC; // CIPAE
when '100 0111 1110 111' => return Sys_DC; // CIGDPAE
when '110 0111 1110 001' => return Sys_DC; // CIPAPA
when '110 0111 1110 101' => return Sys_DC; // CIGDPAPA
when '000 0111 1111 001' => return Sys_DC; // CIVAPS
when '000 0111 1111 101' => return Sys_DC; // CIGDVAPS
when '000 0111 0001 000' => return Sys_IC; // IALLUIS
when '000 0111 0101 000' => return Sys_IC; // IALLU
when '011 0111 0101 001' => return Sys_IC; // IVAU
when '000 1000 0001 000' => return Sys_TLBI; // VMALLE1OS
when '000 1000 0001 001' => return Sys_TLBI; // VAE1OS
when '000 1000 0001 010' => return Sys_TLBI; // ASIDE1OS
when '000 1000 0001 011' => return Sys_TLBI; // VAAE1OS
when '000 1000 0001 101' => return Sys_TLBI; // VALE1OS
when '000 1000 0001 111' => return Sys_TLBI; // VAALE1OS
when '000 1000 0010 001' => return Sys_TLBI; // RVAE1IS
when '000 1000 0010 011' => return Sys_TLBI; // RVAAE1IS
when '000 1000 0010 101' => return Sys_TLBI; // RVALE1IS
when '000 1000 0010 111' => return Sys_TLBI; // RVAALE1IS
when '000 1000 0011 000' => return Sys_TLBI; // VMALLE1IS
when '000 1000 0011 001' => return Sys_TLBI; // VAE1IS
when '000 1000 0011 010' => return Sys_TLBI; // ASIDE1IS
when '000 1000 0011 011' => return Sys_TLBI; // VAAE1IS
when '000 1000 0011 101' => return Sys_TLBI; // VALE1IS
when '000 1000 0011 111' => return Sys_TLBI; // VAALE1IS
when '000 1000 0101 001' => return Sys_TLBI; // RVAE1OS
when '000 1000 0101 011' => return Sys_TLBI; // RVAAE1OS
when '000 1000 0101 101' => return Sys_TLBI; // RVALE1OS
when '000 1000 0101 111' => return Sys_TLBI; // RVAALE1OS
when '000 1000 0110 001' => return Sys_TLBI; // RVAE1
when '000 1000 0110 011' => return Sys_TLBI; // RVAAE1
when '000 1000 0110 101' => return Sys_TLBI; // RVALE1
when '000 1000 0110 111' => return Sys_TLBI; // RVAALE1
when '000 1000 0111 000' => return Sys_TLBI; // VMALLE1
when '000 1000 0111 001' => return Sys_TLBI; // VAE1
when '000 1000 0111 010' => return Sys_TLBI; // ASIDE1
when '000 1000 0111 011' => return Sys_TLBI; // VAAE1
when '000 1000 0111 101' => return Sys_TLBI; // VALE1
when '000 1000 0111 111' => return Sys_TLBI; // VAALE1
when '000 1001 0001 000' => return Sys_TLBI; // VMALLE1OSNXS
when '000 1001 0001 001' => return Sys_TLBI; // VAE1OSNXS
when '000 1001 0001 010' => return Sys_TLBI; // ASIDE1OSNXS
when '000 1001 0001 011' => return Sys_TLBI; // VAAE1OSNXS
when '000 1001 0001 101' => return Sys_TLBI; // VALE1OSNXS
when '000 1001 0001 111' => return Sys_TLBI; // VAALE1OSNXS
when '000 1001 0010 001' => return Sys_TLBI; // RVAE1ISNXS
when '000 1001 0010 011' => return Sys_TLBI; // RVAAE1ISNXS
when '000 1001 0010 101' => return Sys_TLBI; // RVALE1ISNXS
when '000 1001 0010 111' => return Sys_TLBI; // RVAALE1ISNXS
when '000 1001 0011 000' => return Sys_TLBI; // VMALLE1ISNXS
when '000 1001 0011 001' => return Sys_TLBI; // VAE1ISNXS
when '000 1001 0011 010' => return Sys_TLBI; // ASIDE1ISNXS
when '000 1001 0011 011' => return Sys_TLBI; // VAAE1ISNXS
when '000 1001 0011 101' => return Sys_TLBI; // VALE1ISNXS
when '000 1001 0011 111' => return Sys_TLBI; // VAALE1ISNXS
when '000 1001 0101 001' => return Sys_TLBI; // RVAE1OSNXS
when '000 1001 0101 011' => return Sys_TLBI; // RVAAE1OSNXS
when '000 1001 0101 101' => return Sys_TLBI; // RVALE1OSNXS
when '000 1001 0101 111' => return Sys_TLBI; // RVAALE1OSNXS
when '000 1001 0110 001' => return Sys_TLBI; // RVAE1NXS
when '000 1001 0110 011' => return Sys_TLBI; // RVAAE1NXS
when '000 1001 0110 101' => return Sys_TLBI; // RVALE1NXS
when '000 1001 0110 111' => return Sys_TLBI; // RVAALE1NXS
when '000 1001 0111 000' => return Sys_TLBI; // VMALLE1NXS
when '000 1001 0111 001' => return Sys_TLBI; // VAE1NXS
when '000 1001 0111 010' => return Sys_TLBI; // ASIDE1NXS
when '000 1001 0111 011' => return Sys_TLBI; // VAAE1NXS
when '000 1001 0111 101' => return Sys_TLBI; // VALE1NXS
when '000 1001 0111 111' => return Sys_TLBI; // VAALE1NXS
when '100 1000 0000 001' => return Sys_TLBI; // IPAS2E1IS
when '100 1000 0000 010' => return Sys_TLBI; // RIPAS2E1IS
when '100 1000 0000 101' => return Sys_TLBI; // IPAS2LE1IS
when '100 1000 0000 110' => return Sys_TLBI; // RIPAS2LE1IS
when '100 1000 0001 000' => return Sys_TLBI; // ALLE2OS
when '100 1000 0001 001' => return Sys_TLBI; // VAE2OS
when '100 1000 0001 100' => return Sys_TLBI; // ALLE1OS
when '100 1000 0001 101' => return Sys_TLBI; // VALE2OS
when '100 1000 0001 110' => return Sys_TLBI; // VMALLS12E1OS
when '100 1000 0010 001' => return Sys_TLBI; // RVAE2IS
when '100 1000 0010 101' => return Sys_TLBI; // RVALE2IS
when '100 1000 0011 000' => return Sys_TLBI; // ALLE2IS
when '100 1000 0011 001' => return Sys_TLBI; // VAE2IS
when '100 1000 0011 100' => return Sys_TLBI; // ALLE1IS
when '100 1000 0011 101' => return Sys_TLBI; // VALE2IS
when '100 1000 0011 110' => return Sys_TLBI; // VMALLS12E1IS
when '100 1000 0100 000' => return Sys_TLBI; // IPAS2E1OS
when '100 1000 0100 001' => return Sys_TLBI; // IPAS2E1
when '100 1000 0100 010' => return Sys_TLBI; // RIPAS2E1
when '100 1000 0100 011' => return Sys_TLBI; // RIPAS2E1OS
when '100 1000 0100 100' => return Sys_TLBI; // IPAS2LE1OS
when '100 1000 0100 101' => return Sys_TLBI; // IPAS2LE1
when '100 1000 0100 110' => return Sys_TLBI; // RIPAS2LE1
when '100 1000 0100 111' => return Sys_TLBI; // RIPAS2LE1OS
when '100 1000 0101 001' => return Sys_TLBI; // RVAE2OS
when '100 1000 0101 101' => return Sys_TLBI; // RVALE2OS
when '100 1000 0110 001' => return Sys_TLBI; // RVAE2
when '100 1000 0110 101' => return Sys_TLBI; // RVALE2
when '100 1000 0111 000' => return Sys_TLBI; // ALLE2
when '100 1000 0111 001' => return Sys_TLBI; // VAE2
when '100 1000 0111 100' => return Sys_TLBI; // ALLE1
when '100 1000 0111 101' => return Sys_TLBI; // VALE2
when '100 1000 0111 110' => return Sys_TLBI; // VMALLS12E1
when '100 1001 0000 001' => return Sys_TLBI; // IPAS2E1ISNXS
when '100 1001 0000 010' => return Sys_TLBI; // RIPAS2E1ISNXS
when '100 1001 0000 101' => return Sys_TLBI; // IPAS2LE1ISNXS
when '100 1001 0000 110' => return Sys_TLBI; // RIPAS2LE1ISNXS
when '100 1001 0001 000' => return Sys_TLBI; // ALLE2OSNXS
when '100 1001 0001 001' => return Sys_TLBI; // VAE2OSNXS
when '100 1001 0001 100' => return Sys_TLBI; // ALLE1OSNXS
when '100 1001 0001 101' => return Sys_TLBI; // VALE2OSNXS
when '100 1001 0001 110' => return Sys_TLBI; // VMALLS12E1OSNXS
when '100 1001 0010 001' => return Sys_TLBI; // RVAE2ISNXS
when '100 1001 0010 101' => return Sys_TLBI; // RVALE2ISNXS
when '100 1001 0011 000' => return Sys_TLBI; // ALLE2ISNXS
when '100 1001 0011 001' => return Sys_TLBI; // VAE2ISNXS
when '100 1001 0011 100' => return Sys_TLBI; // ALLE1ISNXS
when '100 1001 0011 101' => return Sys_TLBI; // VALE2ISNXS
when '100 1001 0011 110' => return Sys_TLBI; // VMALLS12E1ISNXS
when '100 1001 0100 000' => return Sys_TLBI; // IPAS2E1OSNXS
when '100 1001 0100 001' => return Sys_TLBI; // IPAS2E1NXS
when '100 1001 0100 010' => return Sys_TLBI; // RIPAS2E1NXS
when '100 1001 0100 011' => return Sys_TLBI; // RIPAS2E1OSNXS
when '100 1001 0100 100' => return Sys_TLBI; // IPAS2LE1OSNXS
when '100 1001 0100 101' => return Sys_TLBI; // IPAS2LE1NXS
when '100 1001 0100 110' => return Sys_TLBI; // RIPAS2LE1NXS
when '100 1001 0100 111' => return Sys_TLBI; // RIPAS2LE1OSNXS
when '100 1001 0101 001' => return Sys_TLBI; // RVAE2OSNXS
when '100 1001 0101 101' => return Sys_TLBI; // RVALE2OSNXS
when '100 1001 0110 001' => return Sys_TLBI; // RVAE2NXS
when '100 1001 0110 101' => return Sys_TLBI; // RVALE2NXS
when '100 1001 0111 000' => return Sys_TLBI; // ALLE2NXS
when '100 1001 0111 001' => return Sys_TLBI; // VAE2NXS
when '100 1001 0111 100' => return Sys_TLBI; // ALLE1NXS
when '100 1001 0111 101' => return Sys_TLBI; // VALE2NXS
when '100 1001 0111 110' => return Sys_TLBI; // VMALLS12E1NXS
when '110 1000 0001 000' => return Sys_TLBI; // ALLE3OS
when '110 1000 0001 001' => return Sys_TLBI; // VAE3OS
when '110 1000 0001 100' => return Sys_TLBI; // PAALLOS
when '110 1000 0001 101' => return Sys_TLBI; // VALE3OS
when '110 1000 0010 001' => return Sys_TLBI; // RVAE3IS
when '110 1000 0010 101' => return Sys_TLBI; // RVALE3IS
when '110 1000 0011 000' => return Sys_TLBI; // ALLE3IS
when '110 1000 0011 001' => return Sys_TLBI; // VAE3IS
when '110 1000 0011 101' => return Sys_TLBI; // VALE3IS
when '110 1000 0100 011' => return Sys_TLBI; // RPAOS
when '110 1000 0100 111' => return Sys_TLBI; // RPALOS
when '110 1000 0101 001' => return Sys_TLBI; // RVAE3OS
when '110 1000 0101 101' => return Sys_TLBI; // RVALE3OS
when '110 1000 0110 001' => return Sys_TLBI; // RVAE3
when '110 1000 0110 101' => return Sys_TLBI; // RVALE3
when '110 1000 0111 000' => return Sys_TLBI; // ALLE3
when '110 1000 0111 001' => return Sys_TLBI; // VAE3
when '110 1000 0111 100' => return Sys_TLBI; // PAALL
when '110 1000 0111 101' => return Sys_TLBI; // VALE3
when '110 1001 0001 000' => return Sys_TLBI; // ALLE3OSNXS
when '110 1001 0001 001' => return Sys_TLBI; // VAE3OSNXS
when '110 1001 0001 101' => return Sys_TLBI; // VALE3OSNXS
when '110 1001 0010 001' => return Sys_TLBI; // RVAE3ISNXS
when '110 1001 0010 101' => return Sys_TLBI; // RVALE3ISNXS
when '110 1001 0011 000' => return Sys_TLBI; // ALLE3ISNXS
when '110 1001 0011 001' => return Sys_TLBI; // VAE3ISNXS
when '110 1001 0011 101' => return Sys_TLBI; // VALE3ISNXS
when '110 1001 0101 001' => return Sys_TLBI; // RVAE3OSNXS
when '110 1001 0101 101' => return Sys_TLBI; // RVALE3OSNXS
when '110 1001 0110 001' => return Sys_TLBI; // RVAE3NXS
when '110 1001 0110 101' => return Sys_TLBI; // RVALE3NXS
when '110 1001 0111 000' => return Sys_TLBI; // ALLE3NXS
when '110 1001 0111 001' => return Sys_TLBI; // VAE3NXS
when '110 1001 0111 101' => return Sys_TLBI; // VALE3NXS
when '000 1100 0000 000' => return Sys_GSB; // SYS
when '000 1100 0000 001' => return Sys_GSB; // ACK
when '000 1100 0001 000' => return Sys_GIC; // CDDIS
when '000 1100 0001 001' => return Sys_GIC; // CDEN
when '000 1100 0001 010' => return Sys_GIC; // CDPRI
when '000 1100 0001 011' => return Sys_GIC; // CDAFF
when '000 1100 0001 100' => return Sys_GIC; // CDPEND
when '000 1100 0001 101' => return Sys_GIC; // CDRCFG
when '000 1100 0001 111' => return Sys_GIC; // CDEOI
when '000 1100 0010 000' => return Sys_GIC; // CDDI
when '000 1100 0010 001' => return Sys_GIC; // CDHM
when '100 1100 0001 000' => return Sys_GIC; // VDDIS
when '100 1100 0001 001' => return Sys_GIC; // VDEN
when '100 1100 0001 010' => return Sys_GIC; // VDPRI
when '100 1100 0001 011' => return Sys_GIC; // VDAFF
when '100 1100 0001 100' => return Sys_GIC; // VDPEND
when '100 1100 0001 101' => return Sys_GIC; // VDRCFG
when '100 1100 0010 000' => return Sys_GIC; // VDDI
when '100 1100 0010 001' => return Sys_GIC; // VDHM
when '110 1100 0001 000' => return Sys_GIC; // LDDIS
when '110 1100 0001 001' => return Sys_GIC; // LDEN
when '110 1100 0001 010' => return Sys_GIC; // LDPRI
when '110 1100 0001 011' => return Sys_GIC; // LDAFF
when '110 1100 0001 100' => return Sys_GIC; // LDPEND
when '110 1100 0001 101' => return Sys_GIC; // LDRCFG
when '110 1100 0010 000' => return Sys_GIC; // LDDI
when '110 1100 0010 001' => return Sys_GIC; // LDHM
otherwise => return Sys_SYS;
end;
end;
// SystemOp
// ========
// System instruction types.
type SystemOp of enumeration {
Sys_AT,
Sys_BRB,
Sys_DC,
Sys_GIC,
Sys_GSB,
Sys_IC,
Sys_MLBISys_TLBI,
Sys_TLBI,Sys_SYS
};
Sys_SYS
};
// AArch64_InterruptPending()
// ==========================
// Returns TRUE if there are any pending physical, virtual, or delegated
// interrupts, and FALSE otherwise.
func AArch64_InterruptPending() => boolean
begin
let (irq_pending, -) = IRQPending();
let (fiq_pending, -) = FIQPending();
let pending_physical_interrupt : boolean = (irq_pending || fiq_pending ||
IsPhysicalSErrorPending());
var pending_virtual_interrupt : boolean = FALSE;
if EL2Enabled() && PSTATE.EL IN { PSTATE.EL IN {EL0, EL1} && HCR_EL2().TGE == '0' then
let virq_pending : boolean = (HCR_EL2().IMO == '1' && (VirtualIRQPending() ||
HCR_EL2().VI == '1'));
let vfiq_pending : boolean = (HCR_EL2().FMO == '1' && (VirtualFIQPending() ||
HCR_EL2().VF == '1'));
let vsei_pending : boolean = ((HCR_EL2().AMO == '1' ||
(IsFeatureImplemented(FEAT_DoubleFault2) &&
IsHCRXEL2Enabled() && HCRX_EL2().TMEA == '1')) &&
(IsVirtualSErrorPending() || HCR_EL2().VSE == '1'));
pending_virtual_interrupt = vsei_pending || virq_pending || vfiq_pending;
end;
let pending_delegated_interrupt : boolean = (IsFeatureImplemented(FEAT_E3DSE) &&
PSTATE.EL !=PSTATE.EL != EL3 &&
EffectiveSCR_EL3_EnDSE() == '1' &&
SCR_EL3().().[EnDSE,DSE] == '111');
return pending_physical_interrupt || pending_virtual_interrupt || pending_delegated_interrupt;
end;
// BTypeCompatible_PAC()
// =====================
// Returns TRUE if PACIxSP or PACIxSPPC instructions are implicitly compatible with PSTATE.BTYPE,
// FALSE otherwise.
func BTypeCompatible_PAC(pacinst : PACInstType) => boolean
begin
// For only PACIxSP instructions, check if BTI behavior should be disabled
if IsFeatureImplemented(FEAT_PAuth_EnhCtl) && pacinst == PACIxSP then
var btd : bit;
case PSTATE.EL of
when PSTATE.EL of
when EL0 =>
btd = if ELIsInHost(EL0) then
btd =SCTLR2_EL2().BTD0 ifelse SCTLR2_EL1().BTD0;
when IsSCTLR2EL2Enabled() then SCTLR2_EL2().BTD0 else '0';
else
btd = if IsSCTLR2EL1Enabled() then SCTLR2_EL1().BTD0 else '0';
end;
when EL1 => btd = ifSCTLR2_EL1().BTD;
when IsSCTLR2EL1Enabled() then SCTLR2_EL1().BTD else '0';
when EL2 => btd = ifSCTLR2_EL2().BTD;
when IsSCTLR2EL2Enabled() then SCTLR2_EL2().BTD else '0';
when EL3 => btd = SCTLR2_EL3().BTD;
end;
// When BTI compatibility is disabled,
// these instructions are not compatible when PSTATE.BTYPE is non-zero
if btd == '1' then return IsZero(PSTATE.BTYPE); end;
end;
if PSTATE.BTYPE != '11' then
return TRUE;
else
let index : integer = if PSTATE.EL=> btd = SCTLR2_EL3().BTD;
end;
// When BTI compatibility is disabled,
// these instructions are not compatible when PSTATE.BTYPE is non-zero
if btd == '1' then return IsZero(PSTATE.BTYPE); end;
end;
if PSTATE.BTYPE != '11' then
return TRUE;
else
let index : integer = if PSTATE.EL == EL0 then 35 else 36;
return SCTLR_ELx()[index] == '0';
end;
end;
// IsHCRXEL2Enabled() // ================== // Returns TRUE if access to HCRX_EL2 register is enabled, and FALSE otherwise. // Indirect read of HCRX_EL2 returns 0 when access is not enabled. readonly func IsHCRXEL2Enabled() => boolean begin if !IsFeatureImplemented(FEAT_HCX) then return FALSE; end; if ELUsingAArch32(EL2) then return FALSE; end; if HaveEL(EL3) && SCR_EL3().HXEn == '0' then return FALSE; end; return EL2Enabled(); end;
// IsSystemRegisterMaskingEnabled() // ================================ // Returns TRUE if access to the MASK registers introduced by FEAT_SRMASK is enabled and the // values in the register are not treated as 0. func IsSystemRegisterMaskingEnabled(el : bits(2)) => boolean begin assert IsFeatureImplemented(FEAT_SRMASK) && el IN {EL1, EL2}; if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return FALSE; end; return el == EL2 || !EL2Enabled() || (IsHCRXEL2Enabled() && HCRX_EL2().SRMASKEn == '1'); end;
// AArch64_EffectiveBroadcastAArch64_TLBIP_IPAS2()
// =================================================
// Invalidate by IPA all stage 2 only TLB entries in the indicated broadcast
// domain matching the indicated VMID in the indicated regime with the indicated security state.
// Note: stage 1 and stage 2 combined entries are not in the scope of this operation.
// IPA and related parameters of the are derived from Xt.
func AArch64_TLBIP_IPAS2(security : AArch64_EffectiveBroadcast(broadcast_in, regime : BroadcastRegime), =>vmid : bits(16),
broadcast_in : Broadcast
begin
var, broadcastlevel : TLBILevel, attr : TLBIMemAttr,
Xt : bits(128))
begin
assert PSTATE.EL IN {EL3, EL2};
var broadcast : Broadcast = broadcast_in;
ifvar r : PSTATETLBIRecord.EL !=;
r.op = EL1TLBIOp_IPAS2 then;
r.from_aarch64 return= broadcastTRUE;
r.security = endsecurity;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = TRUE;
r.level = level;
r.attr = attr;
r.ttl = Xt[47:44];
r.address = ZeroExtend{64}(Xt[107:64] :: Zeros{12});
if IsFeatureImplemented(FEAT_TLBID) && Xt[32] == '1' then
varr.d64 = fnbTRUE;
r.d128 = :r.ttl bit== '00xx';
else
r.d64 = r.ttl == '00xx';
r.d128 = TRUE;
end;
case security of
ifwhen IsHCRXEL2EnabledSS_NonSecure()=>
r.ipaspace && (!=HaveELPAS_NonSecure(;
whenEL3SS_Secure) || SCR_EL3().VTLBIDEn == '1') then=>
fnbr.ipaspace = HCRX_EL2().FNB;
else
fnbif =Xt[63] '0';
end;
case== fnb::HCR_EL2().FB of
when '001' =>
pass;
when '01' =>
if broadcast ==then Broadcast_NSHPAS_NonSecure then
// The operation is broadcast within the Inner Shareable shareability domain.
broadcast =else Broadcast_ForcedISHPAS_Secure;
end;
when '10' =>
if broadcast == Broadcast_ISHSS_Realm then
// The operation only affects the PE on which the instruction is executed.
broadcast=>
r.ipaspace = Broadcast_NSHPAS_Realm;
otherwise =>
// Root security state does not have stage 2 translation
unreachable;
end;
when
TLBI(r);
let '11'domains =>
if: broadcastbits(16) === Broadcast_ISHTLBIDomains then
// The operation is (broadcast, to PEs which would share TLB entries with the
// current PE Xt[15:0]);
if CnP were 1.
(broadcast === Broadcast_ISH_CnPBroadcast_OSH;
end;
end;
else
if broadcast ==&&
( Broadcast_NSHIsBroadcast_OSHnISH &&(regime) || EL2EnabledOSHDomainExceedsNIS()(domains))) && HCR_EL2().FB == '1' then
broadcast = ;
end;
if broadcast != Broadcast_NSHBroadcast_ForcedISHBroadcast_OSHnISH;
then BroadcastTLBI(broadcast, r, domains); end;
end;
return broadcast;
end;
// AArch64_TLBIP_IPAS2AArch64_TLBIP_RIPAS2()
// ===========================================
// InvalidateRange invalidate by IPA all stage 2 only TLB entries in the indicated broadcast
// broadcast domain matching the indicated VMID in the indicated regime with the indicated
// security state.
// Note: stage 1 and stage 2 combined entries are not in the scope of this operation.
// The range of IPA and related parameters of the are derived from Xt.
func AArch64_TLBIP_IPAS2AArch64_TLBIP_RIPAS2(security : SecurityState, regime : Regime, vmid : bits(16),
broadcast_in : Broadcast, level : TLBILevel, attr : TLBIMemAttr,
Xt : bits(128))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2};
var broadcast :, EL1};
var broadcast : Broadcast = broadcast_in;
var r : TLBIRecord;
r.op = TLBIOp_IPAS2TLBIOp_RIPAS2;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = TRUE;
r.level = level;
r.attr = attr;
r.ttl = Xt[471:44];
r.address 0] = ZeroExtend{64}(Xt[10738:64] :: Zeros{12});37];
if IsFeatureImplemented(FEAT_TLBID) && Xt[32] == '1' then
r.d64 = TRUE;
r.d128 = r.ttl[1:0] == '00xx00';
else
r.d64 = r.ttl[1:0] == '00xx00';
r.d128 = TRUE;
end;
var valid : boolean;
(valid, r.tg, r.address, r.end_address) = TLBIPRange(regime, Xt);
if !valid then return; end;
case security of
when SS_NonSecure =>
r.ipaspace = PAS_NonSecure;
when SS_Secure =>
r.ipaspace = if Xt[63] == '1' then PAS_NonSecure else PAS_Secure;
when SS_Realm =>
r.ipaspace = PAS_Realm;
otherwise =>
// Root security state does not have stage 2 translation
unreachable;
end;
TLBI(r);
let domains : bits(16) = TLBIDomains(broadcast, Xt[15:0]);
if (broadcast == Broadcast_OSH &&
(IsBroadcast_OSHnISH()(regime) || OSHDomainExceedsNIS(domains))) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r, domains); end;
return;
end;
// AArch64_TLBIP_RIPAS2AArch64_TLBIP_RVA()
// =========================================
// Range invalidate by IPAVA range all stage 21 only TLB entries in the indicated
// broadcast domain matching the indicated VMID and ASID (where regime
// supports VMID, ASID) in the indicated regime with the indicated
// security state.
// ASID, and range related parameters are derived from Xt.
// Note: stage 1 and stage 2 combined entries are not in the scope of this operation.
// The range of IPA and related parameters of the are derived from Xt.
func AArch64_TLBIP_RIPAS2AArch64_TLBIP_RVA(security : SecurityState, regime : Regime, vmid : bits(16),
broadcast_in : Broadcast, level : TLBILevel, attr : TLBIMemAttr,
Xt : bits(128))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2};
var broadcast :, EL1};
var broadcast : Broadcast = broadcast_in;
var r : TLBIRecord;
r.op = TLBIOp_RIPAS2TLBIOp_RVA;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = TRUE;
r.level = level;
r.attr = attr;
r.ttl[1:0] = Xt[38:37];
if IsFeatureImplemented(FEAT_TLBID) && Xt[32] == '1' then
r.d64 = TRUE;
r.d128 = r.ttl[1:0] == '00';
else
r.d64 = r.ttl[1:0] == '00';
r.d128 = TRUE;
end;
var valid : boolean;
(valid, r.tg, r.address, r.end_address) = TLBIPRange(regime, Xt);
if !valid then return; end;
case security of
when SS_NonSecureUseVMID =>
r.ipaspace = PAS_NonSecure;
when SS_Secure =>
r.ipaspace = if Xt[63] == '1' then PAS_NonSecure else PAS_Secure;
when SS_Realm =>
r.ipaspace = PAS_Realm(regime);
r.level = level;
r.attr = attr;
r.asid = Xt[63:48];
r.ttl[1:0] = Xt[38:37];
if IsFeatureImplemented(FEAT_TLBID) && Xt[32] == '1' then
otherwiser.d64 = =>
//TRUE;
r.d128 = Rootr.ttl[1:0] security== state'00';
else
r.d64 = doesr.ttl[1:0] not== have'00';
r.d128 = stageTRUE;
end;
var 2valid translation
unreachable: boolean;
(valid, r.tg, r.address, r.end_address) = TLBIPRange(regime, Xt);
if !valid then return; end;
TLBI(r);
let domains : bits(16) = TLBIDomains(broadcast, Xt[15:0]);
if (broadcast == Broadcast_OSH &&
(IsBroadcast_OSHnISH()(regime) || OSHDomainExceedsNIS(domains))) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r, domains); end;
return;
end;
// AArch64_TLBIP_RVAAArch64_TLBIP_RVAA()
// =======================================
// Range invalidate by VA range all stage 1 TLB entries in the indicated
// broadcast domain matching the indicated VMID and ASID (where regimeregimesupports VMID)
// supportsand VMID,all ASID) in the indicated regime with the indicated security state.
// ASID,VA and range related parameters are derived from Xt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch64_TLBIP_RVAAArch64_TLBIP_RVAA(security : SecurityState, regime_inregime : Regime, vmid_invmid : bits(16),
broadcast_in : Broadcast, level : TLBILevel, attr_inattr : TLBIMemAttr,
Xt : bits(128))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var broadcast : Broadcast = broadcast_in;
var r : AArch64_EffectiveBroadcast(broadcast_in);
var attr : TLBIMemAttr = attr_in;
if attr == TLBI_AllAttr && ExcludeXS() then
attr = TLBI_ExcludeXS;
end;
var regime : Regime = regime_in;
var vmid : bits(16) = vmid_in;
if ELIsInHost(EL0) then
regime = Regime_EL20;
vmid = VMID_NONE;
elsif regime == Regime_EL2 && ELIsInHost(EL2) then
regime = Regime_EL20;
end;
var r : TLBIRecord;
r.op = TLBIOp_RVATLBIOp_RVAA;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = level;
r.attr = attr;
r.asid = Xt[63:48];
r.ttl[1:0] = Xt[38:37];
if IsFeatureImplemented(FEAT_TLBID) && Xt[32] == '1' then
r.d64 = TRUE;
r.d128 = r.ttl[1:0] == '00';
else
r.d64 = r.ttl[1:0] == '00';
r.d128 = TRUE;
end;
var valid : boolean;
(valid, r.tg, r.address, r.end_address) = TLBIPRange(regime, Xt);
if !valid then return; end;
TLBI(r);
let domains : bits(16) = TLBIDomains(broadcast, Xt[15:0]);
if (broadcast == Broadcast_OSH &&
(IsBroadcast_OSHnISH()(regime) || OSHDomainExceedsNIS(domains))) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r, domains); end;
return;
end;
// AArch64_TLBIP_RVAAAArch64_TLBIP_VA()
// ======================================
// RangeInvalidate invalidate by VA range all stage 1 TLB entries in the indicated
// broadcast domain
// matching the indicated VMID and ASID (where regimesupportsregime supports VMID)
//, and all ASID) in the indicated regime
// with the indicated security state.
// ASID, VA rangeand related parameters are derived from Xt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch64_TLBIP_RVAAAArch64_TLBIP_VA(security : SecurityState, regime_inregime : Regime, vmid_invmid : bits(16),
broadcast_in : Broadcast, level : TLBILevel, attr_inattr : TLBIMemAttr,
Xt : bits(128))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var broadcast : Broadcast = broadcast_in;
var r : AArch64_EffectiveBroadcast(broadcast_in);
var attr : TLBIMemAttr = attr_in;
if attr == TLBI_AllAttr && ExcludeXS() then
attr = TLBI_ExcludeXS;
end;
var regime : Regime = regime_in;
var vmid : bits(16) = vmid_in;
if ELIsInHost(EL0) then
regime = Regime_EL20;
vmid = VMID_NONE;
end;
var r : TLBIRecord;
r.op = TLBIOp_RVAATLBIOp_VA;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = level;
r.attr = attr;
r.ttlr.asid = Xt[163:0] 48];
r.ttl = Xt[3847:3744];
r.address = ZeroExtend{64}(Xt[107:64] :: Zeros{12});
if IsFeatureImplemented(FEAT_TLBID) && Xt[32] == '1' then
r.d64 = TRUE;
r.d128 = r.ttl[1:0] == '0000xx';
else
r.d64 = r.ttl[1:0] == '0000xx';
r.d128 = TRUE;
end;
var valid : boolean;
(valid, r.tg, r.address, r.end_address) = TLBIPRange(regime, Xt);
if !valid then return; end;
TLBI(r);
let domains : bits(16) = TLBIDomains(broadcast, Xt[15:0]);
if (broadcast == Broadcast_OSH &&
(IsBroadcast_OSHnISH() || OSHDomainExceedsNIS(domains)))regime) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r, domains); end;
return;
end;
// AArch64_TLBIP_VAAArch64_TLBIP_VAA()
// =====================================
// Invalidate by VA all stage 1 TLB entries in the indicated broadcast domain
// matching the indicated VMID and ASID (where regime supports VMID,) and all ASID) in the indicated regime
// with the indicated security state.
// ASID, VA and related parameters are derived from Xt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch64_TLBIP_VAAArch64_TLBIP_VAA(security : SecurityState, regime_inregime : Regime, vmid_invmid : bits(16),
broadcast_in : Broadcast, level : TLBILevel, attr_inattr : TLBIMemAttr,
Xt : bits(128))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var broadcast : Broadcast = broadcast_in;
var r : AArch64_EffectiveBroadcast(broadcast_in);
var attr : TLBIMemAttr = attr_in;
if attr == TLBI_AllAttr && ExcludeXS() then
attr = TLBI_ExcludeXS;
end;
var regime : Regime = regime_in;
var vmid : bits(16) = vmid_in;
if regime == Regime_EL10 && ELIsInHost(EL0) then
regime = Regime_EL20;
vmid = VMID_NONE;
elsif regime == Regime_EL2 && ELIsInHost(EL2) then
regime = Regime_EL20;
end;
var r : TLBIRecord;
r.op = TLBIOp_VATLBIOp_VAA;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = level;
r.attr = attr;
r.asid = Xt[63:48];
r.ttl = Xt[47:44];
r.address = ZeroExtend{64}(Xt[107:64] :: Zeros{12});
if IsFeatureImplemented(FEAT_TLBID) && Xt[32] == '1' then
r.d64 = TRUE;
r.d128 = r.ttl == '00xx';
else
r.d64 = r.ttl == '00xx';
r.d128 = TRUE;
end;
TLBI(r);
let domains : bits(16) = TLBIDomains(broadcast, Xt[15:0]);
if (broadcast == Broadcast_OSH &&
(IsBroadcast_OSHnISH() || OSHDomainExceedsNIS(domains)))regime) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r, domains); end;
return;
end;
// AArch64_TLBIP_VAAAArch64_TLBI_ALL()
// =====================================
// Invalidate by VA all stage 1 TLB entries infor the indicated broadcasttranslation domainregime with the
// matching the indicated VMIDsecurity (wherestate regimefor supports VMID) and all ASIDTLBs inwithin the indicated regime
//broadcast with the indicated security state.domain.
// VAInvalidation andapplies relatedto parametersall areapplicable derived from Xt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.entries.
func AArch64_TLBIP_VAAAArch64_TLBI_ALL(security : SecurityState, regime_inregime : Regime, vmid_in : bits(16),
broadcast_in : Broadcast, levelattr : TLBILevel, attr_in : TLBIMemAttr,
Xt : bits(12864))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2,};
var broadcast : EL1};
var broadcast : Broadcast = broadcast_in;
var r : AArch64_EffectiveBroadcast(broadcast_in);
var attr : TLBIMemAttr = attr_in;
if attr == TLBI_AllAttr && ExcludeXS() then
attr = TLBI_ExcludeXS;
end;
var regime : Regime = regime_in;
var vmid : bits(16) = vmid_in;
if ELIsInHost(EL0) then
regime = Regime_EL20;
vmid = VMID_NONE;
end;
var r : TLBIRecord;
r.op = TLBIOp_VAATLBIOp_ALL;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid r.level = UseVMIDTLBILevel_Any(regime);
r.level = level;
r.attr = attr;
r.ttl = Xt[47:44];
r.address = ZeroExtend{64}(Xt[107:64] :: Zeros{12});
if IsFeatureImplemented(FEAT_TLBID) && Xt[32] == '1' then
r.d64 = TRUE;
r.d128 = r.ttl == '00xx';
else
r.d64 = r.ttl == '00xx';
r.d128 = TRUE;
end;
TLBI(r);
let domains : bits(16) = TLBIDomains(broadcast, Xt[15:0]);
if (broadcast == Broadcast_OSH &&
(IsBroadcast_OSHnISH()(regime) || OSHDomainExceedsNIS(domains))) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r, domains); end;
return;
end;
// AArch64_TLBI_ALLAArch64_TLBI_ASID()
// =====================================
// Invalidate all stage 1 entries formatching the indicated VMID (where regime supports)
// and ASID in the parameter Xt in the indicated translation regime with the
// the indicated security state for all TLBs within the indicated broadcast domain.
// InvalidationNote: applies to all applicable stage 1 and stage 2 entries.combined entries are in the scope of this operation.
func AArch64_TLBI_ALLAArch64_TLBI_ASID(security : SecurityState, regime : Regime,
vmid : bits(16),
broadcast_in : Broadcast, attr : TLBIMemAttr, Xt : bits(64))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2};
var broadcast :, EL1};
var broadcast : Broadcast = broadcast_in;
var r : TLBIRecord;
r.op = ;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMIDTLBIOp_ALLTLBIOp_ASID;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = (regime;);
r.level = TLBILevel_Any;
r.attr = attr;
r.asid = Xt[63:48];
TLBI(r);
let domains : bits(16) = TLBIDomains(broadcast, Xt[15:0]);
if (broadcast == Broadcast_OSH &&
(IsBroadcast_OSHnISH()(regime) || OSHDomainExceedsNIS(domains))) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r, domains); end;
return;
end;
// AArch64_TLBI_ASIDAArch64_TLBI_IPAS2()
// =======================================
// Invalidate by IPA all stage 12 only TLB entries matchingin the indicated VMID (where regime supports)broadcast
// anddomain ASIDmatching in the parameterindicated XtVMID in the indicated translation regime with the
// indicated security state for all TLBs within the indicated broadcast domain.state.
// Note: stage 1 and stage 2 combined entries are not in the scope of this operation.
// IPA and related parameters of the are derived from Xt.
func AArch64_TLBI_ASIDAArch64_TLBI_IPAS2(security : SecurityState, regime_inregime : Regime, vmid_invmid : bits(16),
broadcast_in : Broadcast, attr_inlevel : TLBILevel, attr : TLBIMemAttr,
Xt : bits(64))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2,};
var broadcast : EL1};
var broadcast : Broadcast = broadcast_in;
var r : AArch64_EffectiveBroadcastTLBIRecord(broadcast_in);;
var attr :r.op = TLBIMemAttrTLBIOp_IPAS2 ;
r.from_aarch64 = attr_inTRUE;
if
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = TRUE;
r.level = level;
r.attr = attr;
r.ttl = Xt[47:44];
r.address = ZeroExtend{64}(Xt[39:0] :: Zeros{12});
r.d64 = TRUE;
r.d128 = r.ttl == '00xx';
case security of
when TLBI_AllAttrSS_NonSecure &&=>
r.ipaspace = ExcludeXSPAS_NonSecure() then;
attr =when TLBI_ExcludeXSSS_Secure;
end;
var=>
r.ipaspace regime= :if Xt[63] == '1' then RegimePAS_NonSecure = regime_in;
var vmid : bits(16) = vmid_in;
ifelse ELIsInHostPAS_Secure(;
whenEL0SS_Realm) then
regime=>
r.ipaspace = Regime_EL20PAS_Realm;
vmid =otherwise =>
// Root security state does not have stage 2 translation
unreachable;
end;
TLBI(r);
if broadcast == VMID_NONE;
end;
var r : TLBIRecord;
r.op = TLBIOp_ASID;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = TLBILevel_Any;
r.attr = attr;
r.asid = Xt[63:48];
TLBI(r);
let domains : bits(16) = TLBIDomains(broadcast, Xt[15:0]);
if (broadcast == Broadcast_OSH &&
(IsBroadcast_OSHnISH() || OSHDomainExceedsNIS(domains)))regime) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r, domains); end;
return;
end;
// AArch64_TLBI_IPAS2() // ==================== // Invalidate by IPA all stage 2 only TLB entries in the indicated broadcast // domain matching the indicated VMID in the indicated regime with the indicated security state. // Note: stage 1 and stage 2 combined entries are not in the scope of this operation. // IPA and related parameters of the are derived from Xt. func AArch64_TLBI_IPAS2(security : SecurityState, regime : Regime, vmid : bits(16), broadcast_in : Broadcast, level : TLBILevel, attr : TLBIMemAttr, Xt : bits(64)) begin assert PSTATE.EL IN {EL3, EL2}; var broadcast : Broadcast = broadcast_in; var r : TLBIRecord; r.op = TLBIOp_IPAS2; r.from_aarch64 = TRUE; r.security = security; r.regime = regime; r.vmid = vmid; r.use_vmid = TRUE; r.level = level; r.attr = attr; r.ttl = Xt[47:44]; r.address = ZeroExtend{64}(Xt[39:0] :: Zeros{12}); r.d64 = TRUE; r.d128 = r.ttl == '00xx'; case security of when SS_NonSecure => r.ipaspace = PAS_NonSecure; when SS_Secure => r.ipaspace = if Xt[63] == '1' then PAS_NonSecure else PAS_Secure; when SS_Realm => r.ipaspace = PAS_Realm; otherwise => // Root security state does not have stage 2 translation unreachable; end; TLBI(r); if broadcast == Broadcast_OSH && IsBroadcast_OSHnISH() then broadcast = Broadcast_OSHnISH; end; if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end; return; end;
// AArch64_TLBI_RIPAS2()
// =====================
// Range invalidate by IPA all stage 2 only TLB entries in the indicated
// broadcast domain matching the indicated VMID in the indicated regime with the indicated
// security state.
// Note: stage 1 and stage 2 combined entries are not in the scope of this operation.
// The range of IPA and related parameters of the are derived from Xt.
func AArch64_TLBI_RIPAS2(security : SecurityState, regime : Regime, vmid : bits(16),
broadcast_in : Broadcast, level : TLBILevel, attr : TLBIMemAttr,
Xt : bits(64))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var broadcast : Broadcast = broadcast_in;
var r : TLBIRecord;
r.op = TLBIOp_RIPAS2;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = TRUE;
r.level = level;
r.attr = attr;
r.ttl[1:0] = Xt[38:37];
r.d64 = TRUE;
r.d128 = r.ttl[1:0] == '00';
var valid : boolean;
(valid, r.tg, r.address, r.end_address) = TLBIRange(regime, Xt);
if !valid then return; end;
case security of
when SS_NonSecure =>
r.ipaspace = PAS_NonSecure;
when SS_Secure =>
r.ipaspace = if Xt[63] == '1' then PAS_NonSecure else PAS_Secure;
when SS_Realm =>
r.ipaspace = PAS_Realm;
otherwise =>
// Root security state does not have stage 2 translation
unreachable;
end;
TLBI(r);
if broadcast == Broadcast_OSH && IsBroadcast_OSHnISH()(regime) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch64_TLBI_RPA()
// ==================
// TLB Range Invalidate GPT Information by PA.
// Invalidates cached copies of GPT entries from TLBs in the indicated
// Shareabilty domain.
// The invalidation applies to TLB entries containing GPT information relating
// to the indicated physical address range.
// When the indicated level is
// TLBILevel_Any : this applies to TLB entries containing GPT information
// from all levels of the GPT walk
// TLBILevel_Last : this applies to TLB entries containing GPT information
// from the last level of the GPT walk
func AArch64_TLBI_RPA(level : TLBILevel, Xt : bits(64), broadcast : Broadcast)
begin
assert IsFeatureImplemented(FEAT_RME) && PSTATE.EL == EL3;
var r : TLBIRecord;
var range_bits : AddressSize;
var p : AddressSize;
// r.security and r.regime do not apply for TLBI by PA operations
r.op = TLBIOp_RPA;
r.level = level;
r.attr = TLBI_AllAttr;
// SIZE field
case Xt[47:44] of
when '0000' => range_bits = 12; // 4KB
when '0001' => range_bits = 14; // 16KB
when '0010' => range_bits = 16; // 64KB
when '0011' => range_bits = 21; // 2MB
when '0100' => range_bits = 25; // 32MB
when '0101' => range_bits = 29; // 512MB
when '0110' => range_bits = 30; // 1GB
when '0111' => range_bits = 34; // 16GB
when '1000' => range_bits = 36; // 64GB
when '1001' => range_bits = 39; // 512GB
otherwise => return; // Reserved encoding, no TLB entries are required to be invalidated
end;
// If SIZE selects a range smaller than PGS, then PGS is used instead
case DecodePGS(GPCCR_EL3().PGS) of
when PGS_4KB => p = 12;
when PGS_16KB => p = 14;
when PGS_64KB => p = 16;
otherwise => return; // Reserved encoding, no TLB entries are required to be invalidated
end;
if range_bits < p then
range_bits = p;
end;
var BaseADDR : bits(5652) = Zeros{};
case GPCCR_EL3().PGS of
when '00' => BaseADDR[51:12] = Xt[39:0]; // 4KB
when '10' => BaseADDR[51:14] = Xt[39:2]; // 16KB
when '01' => BaseADDR[51:16] = Xt[39:4]; // 64KB
end;
if IsFeatureImplemented(FEAT_D128) && AArch64_PAMax() == 56 then
BaseADDR[55:52] = Xt[43:40]; // Extension to Address
end;
// The calculation here automatically aligns BaseADDR to the size of
// the region specififed in SIZE. However, the architecture does not
// require this alignment and if BaseADDR is not aligned to the region
// specified by SIZE then no entries are required to be invalidated.
let range_pbits : integer{} = range_bits;
let start_addr : bits(5652) = BaseADDR AND NOT ZeroExtend{5652}(Ones{range_pbits});
let end_addr : bits(5652) = start_addr + ZeroExtend{5652}(Ones{range_pbits});
// PASpace is not considered in TLBI by PA operations
r.address = ZeroExtend{64}(start_addr);
r.end_address = ZeroExtend{64}(end_addr);
TLBI(r);
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch64_TLBI_RVA()
// ==================
// Range invalidate by VA range all stage 1 TLB entries in the indicated
// broadcast domain matching the indicated VMID and ASID (where regime
// supports VMID, ASID) in the indicated regime with the indicated security state.
// ASID, and range related parameters are derived from Xt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch64_TLBI_RVA(security : SecurityState, regime_inregime : Regime, vmid_invmid : bits(16),
broadcast_in : Broadcast, level : TLBILevel, attr_inattr : TLBIMemAttr,
Xt : bits(64))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var broadcast : Broadcast = AArch64_EffectiveBroadcast(broadcast_in);
var attr : TLBIMemAttr = attr_in;
if attr == TLBI_AllAttr && ExcludeXS() then
attr = TLBI_ExcludeXS;
end;
var regime : Regime = regime_in;
var vmid : bits(16) = vmid_in;
if regime == Regime_EL10 && ELIsInHost(EL0) then
regime = Regime_EL20;
vmid = VMID_NONE;
elsif regime == Regime_EL2 && ELIsInHost(EL2) then
regime = Regime_EL20;
end= broadcast_in;
var r : TLBIRecord;
r.op = TLBIOp_RVA;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = level;
r.attr = attr;
r.asid = Xt[63:48];
r.ttl[1:0] = Xt[38:37];
r.d64 = TRUE;
r.d128 = r.ttl[1:0] == '00';
var valid : boolean;
(valid, r.tg, r.address, r.end_address) = TLBIRange(regime, Xt);
if !valid then return; end;
TLBI(r);
if broadcast == Broadcast_OSH && IsBroadcast_OSHnISH()(regime) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch64_TLBI_RVAA()
// ===================
// Range invalidate by VA range all stage 1 TLB entries in the indicated
// broadcast domain matching the indicated VMID (where regimesupports VMID)
// and all ASID in the indicated regime with the indicated security state.
// VA range related parameters are derived from Xt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch64_TLBI_RVAA(security : SecurityState, regime_inregime : Regime, vmid_invmid : bits(16),
broadcast_inbroadcast : Broadcast, level : TLBILevel, attr_inattr : TLBIMemAttr,
Xt : bits(64))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var broadcastr : Broadcast = AArch64_EffectiveBroadcast(broadcast_in);
var attr : TLBIMemAttr = attr_in;
if attr == TLBI_AllAttr && ExcludeXS() then
attr = TLBI_ExcludeXS;
end;
var regime : Regime = regime_in;
var vmid : bits(16) = vmid_in;
if ELIsInHost(EL0) then
regime = Regime_EL20;
vmid = VMID_NONE;
end;
var r : TLBIRecord;
r.op = TLBIOp_RVAA;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = level;
r.attr = attr;
r.ttl[1:0] = Xt[38:37];
r.d64 = TRUE;
r.d128 = r.ttl[1:0] == '00';
var valid : boolean;
(valid, r.tg, r.address, r.end_address) = TLBIRange(regime, Xt);
if !valid then return; end;
TLBI(r);
if broadcast == Broadcast_OSH && IsBroadcast_OSHnISH() then
broadcast = Broadcast_OSHnISH(regime, Xt);
if !valid then return;
end;
TLBI(r);
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch64_TLBI_VA()
// =================
// Invalidate by VA all stage 1 TLB entries in the indicated broadcast domain
// matching the indicated VMID and ASID (where regime supports VMID, ASID) in the indicated regime
// with the indicated security state.
// ASID, VA and related parameters are derived from Xt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch64_TLBI_VA(security : SecurityState, regime_inregime : Regime, vmid_invmid : bits(16),
broadcast_in : Broadcast, level : TLBILevel, attr_inattr : TLBIMemAttr,
Xt : bits(64))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var broadcast : Broadcast = AArch64_EffectiveBroadcast(broadcast_in);
var attr : TLBIMemAttr = attr_in;
if attr == TLBI_AllAttr && ExcludeXS() then
attr = TLBI_ExcludeXS;
end;
var regime : Regime = regime_in;
var vmid : bits(16) = vmid_in;
if regime == Regime_EL10 && ELIsInHost(EL0) then
regime = Regime_EL20;
vmid = VMID_NONE;
elsif regime == Regime_EL2 && ELIsInHost(EL2) then
regime = Regime_EL20;
end= broadcast_in;
var r : TLBIRecord;
r.op = TLBIOp_VA;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = level;
r.attr = attr;
r.asid = Xt[63:48];
r.ttl = Xt[47:44];
r.address = ZeroExtend{64}(Xt[43:0] :: Zeros{12});
r.d64 = TRUE;
r.d128 = r.ttl == '00xx';
TLBI(r);
if broadcast == Broadcast_OSH && IsBroadcast_OSHnISH()(regime) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch64_TLBI_VAA()
// ==================
// Invalidate by VA all stage 1 TLB entries in the indicated broadcast domain
// matching the indicated VMID (where regime supports VMID) and all ASID in the indicated regime
// with the indicated security state.
// VA and related parameters are derived from Xt.
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
func AArch64_TLBI_VAA(security : SecurityState, regime_inregime : Regime, vmid_invmid : bits(16),
broadcast_in : Broadcast, level : TLBILevel, attr_inattr : TLBIMemAttr,
Xt : bits(64))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var broadcast : Broadcast = AArch64_EffectiveBroadcast(broadcast_in);
var attr : TLBIMemAttr = attr_in;
if attr == TLBI_AllAttr && ExcludeXS() then
attr = TLBI_ExcludeXS;
end;
var regime : Regime = regime_in;
var vmid : bits(16) = vmid_in;
if ELIsInHost(EL0) then
regime = Regime_EL20;
vmid = VMID_NONE;
end= broadcast_in;
var r : TLBIRecord;
r.op = TLBIOp_VAA;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.level = level;
r.attr = attr;
r.ttl = Xt[47:44];
r.address = ZeroExtend{64}(Xt[43:0] :: Zeros{12});
r.d64 = TRUE;
r.d128 = r.ttl == '00xx';
TLBI(r);
if broadcast == Broadcast_OSH && IsBroadcast_OSHnISH()(regime) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r); end;
return;
end;
// AArch64_TLBI_VMALL()
// ====================
// Invalidate all stage 1 entries for the indicated translation regime with the
// the indicated security state for all TLBs within the indicated broadcast
// domain that match the indicated VMID (where applicable).
// Note: stage 1 and stage 2 combined entries are in the scope of this operation.
// Note: stage 2 only entries are not in the scope of this operation.
func AArch64_TLBI_VMALL(security : SecurityState, regime_inregime : Regime,
vmid_invmid : bits(16), broadcast_in : Broadcast,
attr_inattr : TLBIMemAttr, Xt : bits(64))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2, EL1};
var broadcast : Broadcast = AArch64_EffectiveBroadcast(broadcast_in);
var attr : TLBIMemAttr = attr_in;
if attr == TLBI_AllAttr && ExcludeXS() then
attr = TLBI_ExcludeXS;
end;
var regime : Regime = regime_in;
var vmid : bits(16) = vmid_in;
if ELIsInHost(EL0) then
regime = Regime_EL20;
vmid = VMID_NONE;
end= broadcast_in;
var r : TLBIRecord;
r.op = TLBIOp_VMALL;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.level = TLBILevel_Any;
r.vmid = vmid;
r.use_vmid = UseVMID(regime);
r.attr = attr;
TLBI(r);
let domains : bits(16) = TLBIDomains(broadcast, Xt[15:0]);
if (broadcast == Broadcast_OSH &&
(IsBroadcast_OSHnISH()(regime) || OSHDomainExceedsNIS(domains))) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r, domains); end;
return;
end;
// AArch64_TLBI_VMALLS12()
// =======================
// Invalidate all stage 1 and stage 2 entries for the indicated translation
// regime with the indicated security state for all TLBs within the indicated
// broadcast domain that match the indicated VMID.
func AArch64_TLBI_VMALLS12(security : SecurityState, regime : Regime,
vmid : bits(16), broadcast_in : Broadcast,
attr : TLBIMemAttr, Xt : bits(64))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2};
var broadcast : Broadcast = AArch64_EffectiveBroadcast(= broadcast_in);;
var r : TLBIRecord;
r.op = TLBIOp_VMALLS12;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.level = TLBILevel_Any;
r.vmid = vmid;
r.use_vmid = TRUE;
r.attr = attr;
TLBI(r);
let domains : bits(16) = TLBIDomains(broadcast, Xt[15:0]);
if (broadcast == Broadcast_OSH &&
(IsBroadcast_OSHnISH()(regime) || OSHDomainExceedsNIS(domains))) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r, domains); end;
return;
end;
// AArch64_TLBI_VMALLWS2()
// =======================
// Remove stage 2 dirty state from entries for the indicated translation regime
// with the indicated security state for all TLBs within the indicated broadcast
// domain that match the indicated VMID.
func AArch64_TLBI_VMALLWS2(security : SecurityState, regime : Regime, vmid : bits(16),
broadcast_in : Broadcast, attr : TLBIMemAttr,
Xt : bits(64))
begin
assert PSTATE.EL IN { PSTATE.EL IN {EL3, EL2};
assert regime == Regime_EL10;
if security == SS_Secure && HaveEL(EL3) && SCR_EL3().EEL2 == '0' then
return;
end;
var broadcast : Broadcast = broadcast_in;
var r : TLBIRecord;
r.op = TLBIOp_VMALLWS2;
r.from_aarch64 = TRUE;
r.security = security;
r.regime = regime;
r.level = TLBILevel_Any;
r.vmid = vmid;
r.use_vmid = TRUE;
r.attr = attr;
TLBI(r);
let domains : bits(16) = TLBIDomains(broadcast, Xt[15:0]);
if (broadcast == Broadcast_OSH &&
(IsBroadcast_OSHnISH()(regime) || OSHDomainExceedsNIS(domains))) then
broadcast = Broadcast_OSHnISH;
end;
if broadcast != Broadcast_NSH then BroadcastTLBI(broadcast, r, domains); end;
return;
end;
// GPTTLBIMatch()
// ==============
// Determine whether the GPT TLB entry lies within the scope of invalidation
func GPTTLBIMatch(tlbi : TLBIRecord, gpt_entry : GPTEntry) => boolean
begin
assert tlbi.op IN {TLBIOp_RPA, TLBIOp_PAALL};
var match : boolean;
let entry_size_mask : bits(64) = ZeroExtend{}(Ones{gpt_entry.size});
let entry_end_address : bits(64) = (ZeroExtend{64}(gpt_entry.pa[55:0] OR
entry_size_mask[55:0]));
let entry_start_address : bits(64) = (ZeroExtend{64}(gpt_entry.pa[55:0] AND NOT
entry_size_mask[55:0]));
case tlbi.op of
when TLBIOp_RPA =>
match = (UInt(tlbi.address[55:0]) <= UInt(entry_end_address[55:0]) &&
UInt(tlbi.end_address[55:0]) > UInt(entry_start_address[55:0]) &&
(tlbi.level == TLBILevel_Any || !gpt_entry.istablegpt_entry.level == 1));
when TLBIOp_PAALL =>
match = TRUE;
end;
return match;
end;
// IsBroadcast_OSHnISH()
// =====================
// Returns TRUE if a TLBI *OS* instruction affects TLBs in the Outer shareability domain,
// but not in the Inner shareability domain.
func IsBroadcast_OSHnISH()(regime => boolean
begin
case: PSTATERegime.EL) => boolean
begin
case regime of
when EL3Regime_EL3 => return FALSE;
when EL2Regime_EL20 => return IsSCTLR2EL2Enabled() && SCTLR2_EL2().TLBOSNIS == '1';
when EL1Regime_EL10 => return IsSCTLR2EL1Enabled() && SCTLR2_EL1().TLBOSNIS == '1';
otherwise => unreachable;
end;
end;
// TLBIDomains()
// =============
// Determine the domains the TLBI operation is broadcast to
func TLBIDomains(broadcast_in : Broadcast, tlbid_in : bits(16)) => bits(16)
begin
assert broadcast_in != Broadcast_OSHnISH;
var broadcast : Broadcast = broadcast_in;
var tlbid : bits(16) = tlbid_in;
if !IsFeatureImplemented(FEAT_TLBID) then return DEFAULT_TLBI_DOMAIN; end;
if broadcast == Broadcast_NSH then return DEFAULT_TLBI_DOMAIN; end;
if broadcast == Broadcast_ISH_CnP then return DEFAULT_TLBI_DOMAIN; end;
if PSTATE.EL == PSTATE.EL == EL3 then return DEFAULT_TLBI_DOMAIN; end;
let nos : integer{} = UInt(TLBIDIDR_EL1().NOS);
assert nos <= 16;
if broadcast == PSTATE.EL == EL0 && HCR_EL2().TGE == '1' then return DEFAULT_TLBI_DOMAIN; end;
let nos : integer{} = UInt(TLBIDIDR_EL1().NOS);
assert nos <= 16;
if broadcast == Broadcast_OSH && nos == 0 then
return DEFAULT_TLBI_DOMAIN;
end;
let nis : integer{} = UInt(TLBIDIDR_EL1().NIS);
assert nis <= 16;
if broadcast == Broadcast_ISH && nis == 0 then
return DEFAULT_TLBI_DOMAIN;
end;
if PSTATE.EL == PSTATE.EL == EL2 then
if broadcast == Broadcast_OSH then
return ZeroExtend{16}(tlbid[nos-1:0]);
else // Broadcast_ISH
return ZeroExtend{16}(tlbid[nis-1:0]);
end;
end;
assert PSTATE.EL == PSTATE.EL == EL1 || (PSTATE.EL == EL0 && HCR_EL2().TGE == '0');;
if broadcast == Broadcast_ForcedISH then
// For a TLBI instruction without an IS or OS qualifier executed at EL1, if HCR_EL2.FB
// is 1 then the process for a TLBI IS instruction is followed as though TLBID is zero.
broadcast = Broadcast_ISH;
tlbid = Zeros{16};
end;
assert broadcast IN {Broadcast_ISH, Broadcast_OSH};
// If the Effective value of VTLBID(OS)En is 0 the TLBID field is not transformed.
if ((HaveEL(EL3) && SCR_EL3().VTLBIDEn == '0') || !IsHCRXEL2Enabled() ||
(broadcast == Broadcast_OSH && HCRX_EL2().VTLBIDOSEn == '0') ||
(broadcast == Broadcast_ISH && HCRX_EL2().VTLBIDEn == '0')) then
if broadcast == Broadcast_OSH then
return ZeroExtend{16}(tlbid[nos-1:0]);
else // Broadcast_ISH
return ZeroExtend{16}(tlbid[nis-1:0]);
end;
end;
if broadcast == Broadcast_OSH then
let nvos : integer{} = UInt(TLBIDIDR_EL1().NVOS);
assert (nos <= 8 && nvos <= 5) || (nos <= 16 && nvos <= 4);
// If NVOS is 0, the TLBID field is ignored as only VTLBIDOS[VTLBIDOS_EL2(n]_EL2.TD0).TD0 is implemented.
let d : integer{} = if nvos == 0 then 0 else UInt(tlbid[nvos-1:0]);
let s : integer{} = if nos <= 8 then 8 else 4;
let n : integer = d DIVRM s;
let m : integer = d MOD s;
var vtlbid : bits(16);
if nos <= 8 then
vtlbid = ZeroExtend{16}(VTLBIDOS_EL2(n)[8*m+:8]);
else
vtlbid = VTLBIDOS_EL2(n)[16*m+:16];
end;
return ZeroExtend{16}(vtlbid[nos-1:0]);
else // Broadcast_ISH
let nvis : integer{} = UInt(TLBIDIDR_EL1().NVIS);
assert (nis <= 8 && nvis <= 5) || (nis <= 16 && nvis <= 4);
// If NVIS is 0, the TLBID field is ignored as only VTLBID[VTLBID_EL2(n]_EL2.TD0).TD0 is implemented.
let d : integer{} = if nvis == 0 then 0 else UInt(tlbid[nvis-1:0]);
let s : integer{} = if nis <= 8 then 8 else 4;
let n : integer = d DIVRM s;
let m : integer = d MOD s;
var vtlbid : bits(16);
if nis <= 8 then
vtlbid = ZeroExtend{16}(VTLBID_EL2(n)[8*m+:8]);
else
vtlbid = VTLBID_EL2(n)[16*m+:16];
end;
return ZeroExtend{16}(vtlbid[nis-1:0]);
end;
end;
// AArch64_S1DirectBasePermissions()
// =================================
// Computes the stage 1 direct base permissions
func AArch64_S1DirectBasePermissions(regime : Regime, walkstate : TTWState,
walkparams : S1TTWParams,
accdesc : AccessDescriptor) => S1AccessControls
begin
var r, w, x : bit;
var pr, pw, px : bit;
var ur, uw, ux : bit;
var permissions : Permissions = walkstate.permissions;
var s1perms : S1AccessControls;
// Descriptors marked with DBM set have the effective value of AP[2] cleared.
// This implies no Permission faults caused by lack of write permissions are
// reported, and the Dirty bit can be set.
if permissions.dbm == '1' && walkparams.hd == '1' then
permissions.ap[2] = '0';
end;
if HasUnprivileged(regime) then
// Apply leaf permissions
case permissions.ap[2:1] of
when '00' => (pr,pw,ur,uw) = ('1','1','0','0'); // Privileged access
when '01' => (pr,pw,ur,uw) = ('1','1','1','1'); // No effect
when '10' => (pr,pw,ur,uw) = ('1','0','0','0'); // Read-only, privileged access
when '11' => (pr,pw,ur,uw) = ('1','0','1','0'); // Read-only
end;
// Apply hierarchical permissions
case permissions.ap_table of
when '00' => (pr,pw,ur,uw) = ( pr, pw, ur, uw); // No effect
when '01' => (pr,pw,ur,uw) = ( pr, pw,'0','0'); // Privileged access
when '10' => (pr,pw,ur,uw) = ( pr,'0', ur,'0'); // Read-only
when '11' => (pr,pw,ur,uw) = ( pr,'0','0','0'); // Read-only, privileged access
end;
// Locations writable by unprivileged cannot be executed by privileged
px = NOT(permissions.pxn OR permissions.pxn_table OR uw);
ux = NOT(permissions.uxn OR permissions.uxn_table);
if (IsFeatureImplemented(FEAT_PAN) && accdesc.pan && !(regime == Regime_EL10 &&
walkparams.nv1 == '1')) then
var pan : bit;
if (ImpDefBool("SCR_EL3.SIF affects EPAN") && accdesc.ss == SS_Secure &&
walkstate.baseaddress.paspace == PAS_NonSecure && walkparams.sif == '1') then
ux = '0';
end;
if (ImpDefBool("Realm EL2&0 regime affects EPAN") && accdesc.ss == SS_Realm &&
regime == Regime_EL20 && walkstate.baseaddress.paspace != PAS_Realm) then
ux = '0';
end;
letpan = PSTATE.PAN AND (ur OR uw OR (walkparams.epan AND ux));
pr = pr AND NOT(pan);
pw := bitpw AND NOT(pan);
end;
else
// Apply leaf permissions
case permissions.ap[2] of
when '0' => (pr,pw) = ('1','1'); // No effect
when '1' => (pr,pw) = ('1','0'); // Read-only
end;
// Apply hierarchical permissions
case permissions.ap_table[1] of
when '0' => (pr,pw) = ( pr, pw); // No effect
when '1' => (pr,pw) = ( pr,'0'); // Read-only
end;
px = NOT(permissions.xn OR permissions.xn_table);
end;
(r,w,x) = if accdesc.el == PSTATE.PAN AND (ur OR uw OR (walkparams.epan AND ux));
pr = pr AND NOT(pan);
pw = pw AND NOT(pan);
end;
else
// Apply leaf permissions
case permissions.ap[2] of
when '0' => (pr,pw) = ('1','1'); // No effect
when '1' => (pr,pw) = ('1','0'); // Read-only
end;
// Apply hierarchical permissions
case permissions.ap_table[1] of
when '0' => (pr,pw) = ( pr, pw); // No effect
when '1' => (pr,pw) = ( pr,'0'); // Read-only
end;
px = NOT(permissions.xn OR permissions.xn_table);
end;
(r,w,x) = if accdesc.el == EL0 then (ur,uw,ux) else (pr,pw,px);
// Compute WXN value
let wxn : bit = walkparams.wxn AND w AND x;
// Prevent execution from Non-secure space by PE in secure state if SIF is set
if accdesc.ss == SS_Secure && walkstate.baseaddress.paspace == PAS_NonSecure then
x = x AND NOT(walkparams.sif);
end;
// Prevent execution from non-Root space by Root
if accdesc.ss == SS_Root && walkstate.baseaddress.paspace != PAS_Root then
x = '0';
end;
// Prevent execution from non-Realm space by Realm EL2 and Realm EL2&0
if (accdesc.ss == SS_Realm && regime IN {Regime_EL2, Regime_EL20} &&
walkstate.baseaddress.paspace != PAS_Realm) then
x = '0';
end;
s1perms.r = r;
s1perms.w = w;
s1perms.x = x;
s1perms.gcs = '0';
s1perms.wxn = wxn;
s1perms.overlay = TRUE;
return s1perms;
end;
// AArch64_S1HasAlignmentFaultDueToMemType()
// =========================================
// Returns whether stage 1 output fails alignment requirement on data accesses due to memory type
func AArch64_S1HasAlignmentFaultDueToMemType(regime : Regime, accdesc : AccessDescriptor,
aligned : boolean, ntlsmd : bit,
memattrs : MemoryAttributes) => boolean
begin
if accdesc.exclusive || accdesc.atomicop || accdesc.acqsc || accdesc.acqpc || accdesc.relsc then
if (!aligned && !(IsWBShareable(memattrs) && AArch64_S1DCacheEnabled(regime)) &&
ConstrainUnpredictableBool(Unpredictable_LSE2_ALIGNMENT_FAULT)) then
return TRUE;
end;
end;
iflet memattrs.memtypeisTagWrite !=: MemType_Deviceboolean then
return= FALSE;
elsifaccdesc.cachetype ((accdesc.acctypeIN =={ AccessType_DCZero &&
accdesc.cachetype IN {CacheType_Tag, CacheType_TagWrite, CacheType_TagZero };
if memattrs.memtype != MemType_Device then
return FALSE;
elsif ((accdesc.acctype == AccessType_DCZero})&& isTagWrite) ||
accdesc.stzgm) then
return ConstrainUnpredictable(Unpredictable_DEVICETAGSTORE) == Constraint_FAULT;
elsif accdesc.a32lsmd && ntlsmd == '0' then
return memattrs.device != DeviceType_GRE;
elsif accdesc.acctype == AccessType_DCZero then
return TRUE;
elsif !aligned then
return !(ImpDefBool("Device location supports unaligned access"));
else
return FALSE;
end;
end;
// AArch64_S1IndirectBasePermissions()
// ===================================
// Computes the stage 1 indirect base permissions
func AArch64_S1IndirectBasePermissions(regime : Regime, walkstate : TTWState,
walkparams : S1TTWParams,
accdesc : AccessDescriptor) => S1AccessControls
begin
var r, w, x, gcs, wxn, overlay : bit;
var pr, pw, px, pgcs, pwxn, p_overlay : bit;
var ur, uw, ux, ugcs, uwxn, u_overlay : bit;
let permissions : Permissions = walkstate.permissions;
var s1perms : S1AccessControls;
// Apply privileged indirect permissions
case permissions.ppi of
when '0000' => (pr,pw,px,pgcs) = ('0','0','0','0'); // No access
when '0001' => (pr,pw,px,pgcs) = ('1','0','0','0'); // Privileged read
when '0010' => (pr,pw,px,pgcs) = ('0','0','1','0'); // Privileged execute
when '0011' => (pr,pw,px,pgcs) = ('1','0','1','0'); // Privileged read and execute
when '0100' => (pr,pw,px,pgcs) = ('0','0','0','0'); // Reserved
when '0101' => (pr,pw,px,pgcs) = ('1','1','0','0'); // Privileged read and write
when '0110' => (pr,pw,px,pgcs) = ('1','1','1','0'); // Privileged read, write and execute
when '0111' => (pr,pw,px,pgcs) = ('1','1','1','0'); // Privileged read, write and execute
when '1000' => (pr,pw,px,pgcs) = ('1','0','0','0'); // Privileged read
when '1001' => (pr,pw,px,pgcs) = ('1','0','0','1'); // Privileged read and gcs
when '1010' => (pr,pw,px,pgcs) = ('1','0','1','0'); // Privileged read and execute
when '1011' => (pr,pw,px,pgcs) = ('0','0','0','0'); // Reserved
when '1100' => (pr,pw,px,pgcs) = ('1','1','0','0'); // Privileged read and write
when '1101' => (pr,pw,px,pgcs) = ('0','0','0','0'); // Reserved
when '1110' => (pr,pw,px,pgcs) = ('1','1','1','0'); // Privileged read, write and execute
when '1111' => (pr,pw,px,pgcs) = ('0','0','0','0'); // Reserved
end;
p_overlay = NOT(permissions.ppi[3]);
pwxn = if permissions.ppi == '0110' then '1' else '0';
if HasUnprivileged(regime) then
// Apply unprivileged indirect permissions
case permissions.upi of
when '0000' => (ur,uw,ux,ugcs) = ('0','0','0','0'); // No access
when '0001' => (ur,uw,ux,ugcs) = ('1','0','0','0'); // Unprivileged read
when '0010' => (ur,uw,ux,ugcs) = ('0','0','1','0'); // Unprivileged execute
when '0011' => (ur,uw,ux,ugcs) = ('1','0','1','0'); // Unprivileged read and execute
when '0100' => (ur,uw,ux,ugcs) = ('0','0','0','0'); // Reserved
when '0101' => (ur,uw,ux,ugcs)=('1','1','0','0');// Unprivileged read and write
when '0110' => (ur,uw,ux,ugcs)=('1','1','1','0');// Unprivileged read, write and execute
when '0111' => (ur,uw,ux,ugcs)=('1','1','1','0');// Unprivileged read, write and execute
when '1000' => (ur,uw,ux,ugcs)=('1','0','0','0');// Unprivileged read
when '1001' => (ur,uw,ux,ugcs)=('1','0','0','1');// Unprivileged read and gcs
when '1010' => (ur,uw,ux,ugcs)=('1','0','1','0');// Unprivileged read and execute
when '1011' => (ur,uw,ux,ugcs) = ('0','0','0','0');// Reserved
when '1100' => (ur,uw,ux,ugcs) =('1','1','0','0');// Unprivileged read and write
when '1101' => (ur,uw,ux,ugcs) =('0','0','0','0');// Reserved
when '1110' => (ur,uw,ux,ugcs) =('1','1','1','0');// Unprivileged read,write and execute
when '1111' => (ur,uw,ux,ugcs) =('0','0','0','0');// Reserved
end;
u_overlay = NOT(permissions.upi[3]);
uwxn = if permissions.upi == '0110' then '1' else '0';
// If the decoded permissions has either px or pgcs along with either uw or ugcs,
// then all effective Stage 1 Base Permissions are set to 0
if ((px == '1' || pgcs == '1') && (uw == '1' || ugcs == '1')) then
(pr,pw,px,pgcs) = ('0','0','0','0');
(ur,uw,ux,ugcs) = ('0','0','0','0');
elsifend;
if (IsFeatureImplemented(FEAT_PAN) && accdesc.pan && !(regime == Regime_EL10 &&
walkparams.nv1 == '1')) then
if PSTATE.PAN == '1' && (ImpDefBool("Realmpermissions.upi EL2&0!= regime'0000') affectsthen
(pr,pw) EPAN")= &&('0','0');
end;
end;
end;
if accdesc.ssaccdesc.el == SS_Realm &&
regime == Regime_EL20 && walkstate.baseaddress.paspace != PAS_Realm) then
ux = '0';
end;
if (ImpDefBool("SCR_EL3.SIF affects EPAN") && accdesc.ss == SS_Secure &&
walkstate.baseaddress.paspace == PAS_NonSecure && walkparams.sif == '1') then
ux = '0';
end;
if PSTATE.PAN == '1' && (!IsZero(ur::uw::ux::ugcs) || (!IsZero(permissions.upi) &&
ImpDefBool("PAN applies when S1UnprivBasePerm is reserved"))) then
(pr,pw) = ('0','0');
end;
end;
end;
if accdesc.el == EL0 then
(r,w,x,gcs,wxn,overlay) = (ur,uw,ux,ugcs,uwxn,u_overlay);
else
(r,w,x,gcs,wxn,overlay) = (pr,pw,px,pgcs,pwxn,p_overlay);
end;
// Prevent execution from Non-secure space by PE in secure state if SIF is set
if accdesc.ss == SS_Secure && walkstate.baseaddress.paspace == PAS_NonSecure then
x = x AND NOT(walkparams.sif);
gcs = '0';
end;
// Prevent execution from non-Root space by Root
if accdesc.ss == SS_Root && walkstate.baseaddress.paspace != PAS_Root then
x = '0';
gcs = '0';
end;
// Prevent execution from non-Realm space by Realm EL2 and Realm EL2&0
if (accdesc.ss == SS_Realm && regime IN {Regime_EL2, Regime_EL20} &&
walkstate.baseaddress.paspace != PAS_Realm) then
x = '0';
gcs = '0';
end;
s1perms.r = r;
s1perms.w = w;
s1perms.x = x;
s1perms.gcs = gcs;
s1perms.wxn = wxn;
s1perms.overlay = overlay == '1';
return s1perms;
end;
// AArch64_S2CheckPermissions()
// ============================
// Verifies memory access with available permissions.
func AArch64_S2CheckPermissions(fault_in : FaultRecord, walkstate : TTWState,
walkparams : S2TTWParams, ipa : AddressDescriptor,
accdesc : AccessDescriptor) => (FaultRecord, boolean)
begin
let memtype : MemType = walkstate.memattrs.memtype;
let permissions : Permissions = walkstate.permissions;
var fault : FaultRecord = fault_in;
let s2perms : S2AccessControls = AArch64_S2ComputePermissions(permissions, walkparams,
accdesc);
var r, w : bit;
var or, ow : bit;
if accdesc.acctype == AccessType_TTW then
r = s2perms.r_mmu;
w = s2perms.w_mmu;
or = s2perms.or_mmu;
ow = s2perms.ow_mmu;
elsif accdesc.rcw then
r = s2perms.r_rcw;
w = s2perms.w_rcw;
or = s2perms.or_rcw;
ow = s2perms.ow_rcw;
else
r = s2perms.r;
w = s2perms.w;
or = s2perms.or;
ow = s2perms.ow;
end;
if accdesc.acctype == AccessType_TTW then
if (accdesc.toplevel && accdesc.varange == VARange_LOWER &&
((walkparams.tl0 == '1' && s2perms.toplevel0 == '0') ||
(walkparams.tl1 == '1' && s2perms.[toplevel1,toplevel0] == '10'))) then
fault.statuscode = Fault_Permission;
fault.toplevel = TRUE;
elsif (accdesc.toplevel && accdesc.varange == VARange_UPPER &&
((walkparams.tl1 == '1' && s2perms.toplevel1 == '0') ||
(walkparams.tl0 == '1' && s2perms.[toplevel1,toplevel0] == '01'))) then
fault.statuscode = Fault_Permission;
fault.toplevel = TRUE;
// Stage 2 Permission fault due to AssuredOnly check
elsif (walkstate.s2assuredonly == '1' && !ipa.s1assured) then
fault.statuscode = Fault_Permission;
fault.assuredonly = TRUE;
elsif s2perms.overlay && or == '0' then
fault.statuscode = Fault_Permission;
fault.overlay = TRUE;
elsif accdesc.write && s2perms.overlay && ow == '0' then
fault.statuscode = Fault_Permission;
fault.overlay = TRUE;
elsif walkparams.ptw == '1' && memtype == MemType_Device then
fault.statuscode = Fault_Permission;
// Prevent translation table walks in Non-secure space by Realm state
elsif accdesc.ss == SS_Realm && walkstate.baseaddress.paspace != PAS_Realm then
fault.statuscode = Fault_Permission;
elsif r == '0' then
fault.statuscode = Fault_Permission;
elsif accdesc.write && w == '0' then
fault.statuscode = Fault_Permission;
fault.hdbssf = walkparams.hdbss == '1' && !CanAppendToHDBSS() && permissions.dbm == '1';
elsif (accdesc.write &&
(walkparams.hd walkparams.s2pie!= == '1' &&|| permissions.s2dirty(walkparams.hdbss == '01' &&
(walkparams.hd !=!CanAppendToHDBSS())) '1' ||
(accdesc.acctype != AccessType_AT &&
walkparams.hdbsswalkparams.s2pie == '1' && !CanAppendToHDBSS())))permissions.s2dirty == '0') then
fault.statuscode = Fault_Permission;
fault.dirtybit = TRUE;
fault.hdbssf = walkparams.hdbss == '1' && !CanAppendToHDBSS();
end;
// Stage 2 Permission fault due to AssuredOnly check
elsif ((walkstate.s2assuredonly == '1' && !ipa.s1assured) ||
(walkstate.s2assuredonly != '1' && IsFeatureImplemented(FEAT_GCS) &&
VTCR_EL2().GCSH == '1' && accdesc.acctype == AccessType_GCS && accdesc.el != EL0)) then
fault.statuscode = Fault_Permission;
fault.assuredonly = TRUE;
elsif accdesc.acctype == AccessType_IFETCH then
if s2perms.overlay && s2perms.ox == '0' then
fault.statuscode = Fault_Permission;
fault.overlay = TRUE;
elsif (memtype == MemType_Device &&
ConstrainUnpredictable(Unpredictable_INSTRDEVICE) == Constraint_FAULT) then
fault.statuscode = Fault_Permission;
// Prevent execution from Non-secure space by Realm state
elsif accdesc.ss == SS_Realm && walkstate.baseaddress.paspace != PAS_Realm then
fault.statuscode = Fault_Permission;
elsif s2perms.x == '0' then
fault.statuscode = Fault_Permission;
end;
elsif accdesc.acctype == AccessType_DC then
if accdesc.cacheop == CacheOp_Invalidate then
if !ELUsingAArch32(EL1) && s2perms.overlay && ow == '0' then
fault.statuscode = Fault_Permission;
fault.overlay = TRUE;
elsif !ELUsingAArch32(EL1) && w == '0' then
fault.statuscode = Fault_Permission;
elsif (walkparams.hd != '1' && walkparams.s2pie == '1' &&
permissions.s2dirty == '0') then
fault.statuscode = Fault_Permission;
fault.dirtybit = TRUE;
end;
elsif !ELUsingAArch32(EL1) && accdesc.el == EL0 && s2perms.overlay && or == '0' then
fault.statuscode = Fault_Permission;
fault.overlay = TRUE;
elsif (walkparams.cmow == '1' && accdesc.cacheop == CacheOp_CleanInvalidate &&
s2perms.overlay && ow == '0') then
fault.statuscode = Fault_Permission;
fault.overlay = TRUE;
elsif !ELUsingAArch32(EL1) && accdesc.el == EL0 && r == '0' then
fault.statuscode = Fault_Permission;
elsif (walkparams.cmow == '1' && accdesc.cacheop == CacheOp_CleanInvalidate &&
w == '0') then
fault.statuscode = Fault_Permission;
elsif (walkparams.cmow == '1' && accdesc.cacheop == CacheOp_CleanInvalidate &&
walkparams.hd != '1' && walkparams.s2pie == '1' && permissions.s2dirty == '0') then
fault.statuscode = Fault_Permission;
fault.dirtybit = TRUE;
end;
elsif accdesc.acctype == AccessType_IC then
if (!ELUsingAArch32(EL1) && accdesc.el == EL0 && s2perms.overlay && or == '0' &&
ImpDefBool("Permission fault on EL0 IC_IVAU execution")) then
fault.statuscode = Fault_Permission;
fault.overlay = TRUE;
elsif walkparams.cmow == '1' && s2perms.overlay && ow == '0' then
fault.statuscode = Fault_Permission;
fault.overlay = TRUE;
elsif (!ELUsingAArch32(EL1) && accdesc.el == EL0 && r == '0' &&
ImpDefBool("Permission fault on EL0 IC_IVAU execution")) then
fault.statuscode = Fault_Permission;
elsif walkparams.cmow == '1' && w == '0' then
fault.statuscode = Fault_Permission;
elsif (walkparams.cmow == '1' && walkparams.hd != '1' && walkparams.s2pie == '1' &&
permissions.s2dirty == '0') then
fault.statuscode = Fault_Permission;
fault.dirtybit = TRUE;
end;
elsif accdesc.read && s2perms.overlay && or == '0' then
fault.statuscode = Fault_Permission;
fault.overlay = TRUE;
fault.write = FALSE;
elsif accdesc.write && s2perms.overlay && ow == '0' then
fault.statuscode = Fault_Permission;
fault.overlay = TRUE;
fault.write = TRUE;
elsif accdesc.read && r == '0' then
fault.statuscode = Fault_Permission;
fault.write = FALSE;
elsif accdesc.write && w == '0' then
fault.statuscode = Fault_Permission;
fault.write = TRUE;
fault.hdbssf = walkparams.hdbss == '1' && !CanAppendToHDBSS() && permissions.dbm == '1';
elsif (IsFeatureImplemented(FEAT_MTE_PERM) &&
((accdesc.tagchecked &&
AArch64_EffectiveTCF(accdesc.el, accdesc.read) != TCFType_Ignore) ||
accdesc.tagaccess) &&
ipa.memattrs.tags == MemTag_AllocationTagged &&
permissions.s2tag_na == '1' && S2DCacheEnabled()) then
fault.statuscode = Fault_Permission;
fault.tagaccess = TRUE;
fault.write = accdesc.tagaccess && accdesc.write;
elsif (accdesc.write &&
(walkparams.hd != '1' || (walkparams.hdbss == '1' && !CanAppendToHDBSS())) &&
walkparams.s2pie == '1' && permissions.s2dirty == '0') then
fault.statuscode = Fault_Permission;
fault.dirtybit = TRUE;
fault.write = TRUE;
fault.hdbssf = walkparams.hdbss == '1' && !CanAppendToHDBSS();
end;
// MRO* allows only RCW and MMU writes
var mro : boolean;
if s2perms.overlay then
mro = (s2perms.[w,w_rcw,w_mmu] AND s2perms.[ow,ow_rcw,ow_mmu]) == '011';
else
mro = s2perms.[w,w_rcw,w_mmu] == '011';
end;
return (fault, mro);
end;
// AArch64_S2HasAlignmentFaultDueToMemType()
// =========================================
// Returns whether stage 2 output fails alignment requirement on data accesses due to memory type
func AArch64_S2HasAlignmentFaultDueToMemType(accdesc : AccessDescriptor, aligned : boolean,
memattrs : MemoryAttributes) => boolean
begin
if accdesc.exclusive || accdesc.atomicop || accdesc.acqsc || accdesc.acqpc || accdesc.relsc then
if (!aligned && !(IsWBShareable(memattrs) && S2DCacheEnabled()) &&
ConstrainUnpredictableBool(Unpredictable_LSE2_ALIGNMENT_FAULT)) then
return TRUE;
end;
end;
if memattrs.memtype != MemType_Device then
return FALSE;
elsif ((accdesc.acctype == AccessType_DCZero &&
accdesc.cachetype IN {==CacheType_Tag,) ||
accdesc.stzgm) then
return ConstrainUnpredictable( CacheType_TagWrite, CacheType_TagZero}) ||
accdesc.stzgm) then
return ConstrainUnpredictable(Unpredictable_DEVICETAGSTORE) == Constraint_FAULT;
elsif accdesc.acctype == AccessType_DCZero then
return TRUE;
elsif !aligned then
return !(ImpDefBool("Device location supports unaligned access"));
else
return FALSE;
end;
end;
// AArch64_S1Translate()
// =====================
// Translate VA to IPA/PA depending on the regime
func AArch64_S1Translate(fault_in : FaultRecord, regime : Regime,
va : bits(64), size : integer, aligned : boolean,
accdesc : AccessDescriptor) => (FaultRecord, AddressDescriptor)
recurselimit Unbounded_DescriptorUpdate
begin
var fault : FaultRecord = fault_in;
// Prepare fault fields in case a fault is detected
fault.secondstage = FALSE;
fault.s2fs1walk = FALSE;
if !AArch64_S1Enabled(regime, accdesc.acctype) then
return AArch64_S1DisabledOutput(fault, regime, va, accdesc, aligned);
end;
var walkparams : S1TTWParams = AArch64_GetS1TTWParams(regime, accdesc.el, accdesc.ss, va);
let s1mintxsz : integer = AArch64_S1MinTxSZ(regime, walkparams);
let s1maxtxsz : integer = AArch64_MaxTxSZ(walkparams.tgx);
if AArch64_S1TxSZFaults(regime, walkparams) then
fault.statuscode = Fault_Translation;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor);
elsif UInt(walkparams.txsz) < s1mintxsz then
walkparams.txsz = s1mintxsz[5:0];
elsif UInt(walkparams.txsz) > s1maxtxsz then
walkparams.txsz = s1maxtxsz[5:0];
end;
if AArch64_VAIsOutOfRange(va, accdesc.acctype, regime, walkparams) then
fault.statuscode = Fault_Translation;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor);
end;
if accdesc.el == EL0 && walkparams.e0pd == '1' then
fault.statuscode = Fault_Translation;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor);
end;
if (IsFeatureImplemented(FEAT_SVE) && accdesc.el == EL0 && walkparams.nfd == '1' &&
((accdesc.nonfault && accdesc.contiguous) ||
(accdesc.firstfault && !accdesc.first && !accdesc.contiguous))) then
fault.statuscode = Fault_Translation;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor);
end;
var descipaddr : AddressDescriptor;
var walkstate : TTWState;
var descriptor : bits(128);
if walkparams.d128 == '1' then
(fault, descipaddr, walkstate, descriptor) = AArch64_S1Walk{128}(fault, walkparams, va,
regime, accdesc);
else
(fault, descipaddr, walkstate, descriptor[63:0]) = AArch64_S1Walk{64}(fault, walkparams, va,
regime, accdesc);
descriptor[127:64] = Zeros{64};
end;
if fault.statuscode != Fault_None then
return (fault, ARBITRARY : AddressDescriptor);
end;
if AArch64_S1HasAlignmentFaultDueToMemType(regime, accdesc, aligned, walkparams.ntlsmd,
walkstate.memattrs) then
fault.statuscode = Fault_Alignment;
end;
let fault_perm : FaultRecord = AArch64_S1CheckPermissions(fault, va, size, regime,
walkstate, walkparams, accdesc);
var mem_desc : bits(128);
var new_desc : bits(128) = descriptor;
if AArch64_SetAccessFlag(walkparams.ha, accdesc, fault) then
// Set descriptor AF bit
new_desc[10] = '1';
end;
// If HW update of dirty bit is enabled, the walk state permissions
// will already reflect a configuration permitting writes.
// The update of the descriptor occurs only if the descriptor bits in
// memory do not reflect that and the access instigates a write.
if AArch64_SetDirtyState(walkparams.hd, (walkparams.pie OR descriptor[51]),
accdesc, fault, fault_perm) then
// Clear descriptor AP[2]/nDirty bit permitting stage 1 writes
new_desc[7] = '0';
end;
if fault.statuscode == Fault_None && fault_perm.statuscode != Fault_None then
fault = fault_perm;
end;
// Either the access flag was clear or AP[2]/nDirty wasis set
if new_desc != descriptor then
ifvar (!descpaddr :IsWBShareable(descipaddr.memattrs) &&
ConstrainUnpredictableBool(Unpredictable_Unsupported_Atomic_HW_Update)) then
fault.statuscode = Fault_HWUpdateAccessFlag;
return (fault, ARBITRARY : AddressDescriptor);
end;
var descpaddr : AddressDescriptor;
let descaccess : AccessDescriptor = CreateAccDescTTEUpdate(accdesc);
if regime == Regime_EL10 && EL2Enabled() then
var s2fault : FaultRecord;
let s1aarch64 : boolean = TRUE;
let s2aligned : boolean = TRUE;
(s2fault, descpaddr) = AArch64_S2Translate(fault, descipaddr, s1aarch64, s2aligned,
descaccess);
if s2fault.statuscode != Fault_None then
return (s2fault, ARBITRARY : AddressDescriptor);
end;
else
descpaddr = descipaddr;
end;
if walkparams.d128 == '1' then
(fault, mem_desc) = AArch64_MemSwapTableDesc{128}(fault, descriptor,
new_desc, walkparams.ee,
descaccess, descpaddr);
else
(fault, mem_desc[63:0]) = AArch64_MemSwapTableDesc{64}(fault, descriptor[63:0],
new_desc[63:0], walkparams.ee,
descaccess, descpaddr);
mem_desc[127:64] = Zeros{64};
end;
if fault.statuscode != Fault_None then
if (accdesc.acctype == AccessType_AT &&
!(ImpDefBool("AT reports the HW update fault"))) then
// Mask the fault
fault.statuscode = Fault_None;
else
return (fault, ARBITRARY : AddressDescriptor);
end;
elsif new_desc != descriptor && mem_desc != new_desc then
// HW update of Dirty state or AF was not successful due to the descriptor being updated
// not matching the descriptor used for translation. Due to this, the walk is restarted.
return AArch64_S1Translate(fault_in, regime, va, size, aligned, accdesc);
end;
end;
if fault.statuscode != Fault_None then
return (fault, ARBITRARY : AddressDescriptor);
end;
// Output Address
let oa : FullAddress = StageOA(va, walkparams.d128, walkparams.tgx, walkstate);
var memattrs : MemoryAttributes;
if AArch64_S1TreatAsNormalNC(walkstate, regime, accdesc) then
// Treat memory attributes as Normal Non-Cacheable
memattrs = NormalNCMemAttr();
memattrs.xs = walkstate.memattrs.xs;
// The effect of SCTLR_ELx.C when '0' is Constrained UNPREDICTABLE on the Tagged attribute
// when the memory region is Allocation Tagged.
if (IsFeatureImplemented(FEAT_MTE2) &&
walkstate.memattrs.tags == MemTag_AllocationTagged &&
ConstrainUnpredictableBool(Unpredictable_S1CTAGGED)) then
memattrs.tags = MemTag_AllocationTagged;
// SCTLR_ELx.C has no effect on whether the memory region is treated as Canonically Tagged.
elsif (IsFeatureImplemented(FEAT_MTE_CANONICAL_TAGS) &&
walkstate.memattrs.tags == MemTag_CanonicallyTagged) then
memattrs.tags = MemTag_CanonicallyTagged;
end;
else
memattrs = walkstate.memattrs;
end;
// Shareability value of stage 1 translation subject to stage 2 is IMPLEMENTATION DEFINED
// to be either effective value or descriptor value
if (regime == Regime_EL10 && EL2Enabled() && HCR_EL2().VM == '1' &&
!(ImpDefBool("Apply effective shareability at stage 1"))) then
memattrs.shareability = walkstate.memattrs.shareability;
else
memattrs.shareability = EffectiveShareability(memattrs);
end;
var ipa : AddressDescriptor = CreateAddressDescriptor(va, oa, memattrs, accdesc);
ipa.s1assured = walkstate.s1assured;
let varange : VARange = AArch64_GetVARange(va);
ipa.mecid = AArch64_S1OutputMECID{128}(walkparams, regime, varange, ipa.paddress.paspace,
descriptor);
if (accdesc.atomicop && !IsWBShareable(memattrs) &&
ConstrainUnpredictableBool(Unpredictable_Atomic_MMU_IMPDEF_FAULT)) then
fault.statuscode = Fault_Exclusive;
return (fault, ipa);
end;
if accdesc.ls64 && memattrs.memtype == MemType_Normal then
if IsFeatureImplemented(FEAT_LS64WB) && !accdesc.withstatus then
if (!IsWBShareable(memattrs) &&
!(memattrs.inner.attrs == MemAttr_NC &&
memattrs.outer.attrs == MemAttr_NC) &&
(ImpDefBool(
"LD64B or ST64B faults to cacheable non-iWBoWB memory"))) then
fault.statuscode = Fault_Exclusive;
return (fault, ipa);
end;
elsif !(memattrs.inner.attrs == MemAttr_NC && memattrs.outer.attrs == MemAttr_NC) then
fault.statuscode = Fault_Exclusive;
return (fault, ipa);
end;
end;
return (fault, ipa);
end;
// AArch64_S2Translate()
// =====================
// Translate stage 1 IPA to PA and combine memory attributes
func AArch64_S2Translate(fault_in : FaultRecord, ipa : AddressDescriptor,
s1aarch64 : boolean, aligned : boolean,
accdesc : AccessDescriptor) => (FaultRecord, AddressDescriptor)
recurselimit Unbounded_DescriptorUpdate
begin
var walkparams : S2TTWParams = AArch64_GetS2TTWParams(accdesc.ss, ipa.paddress.paspace,
s1aarch64);
var fault : FaultRecord = fault_in;
var s2fs1mro : boolean;
// Prepare fault fields in case a fault is detected
fault.statuscode = Fault_None; // Ignore any faults from stage 1
fault.dirtybit = FALSE;
fault.overlay = FALSE;
fault.tagaccess = FALSE;
fault.s1tagnotdata = FALSE;
fault.secondstage = TRUE;
fault.s2fs1walk = accdesc.acctype == AccessType_TTW;
fault.ipaddress = ipa.paddress;
if walkparams.vm != '1' then
// Stage 2 translation is disabled
return (fault, ipa);
end;
let s2mintxsz : integer = AArch64_S2MinTxSZ(walkparams, s1aarch64);
let s2maxtxsz : integer = AArch64_MaxTxSZ(walkparams.tgx);
if AArch64_S2TxSZFaults(walkparams, s1aarch64) then
fault.statuscode = Fault_Translation;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor);
elsif UInt(walkparams.txsz) < s2mintxsz then
walkparams.txsz = s2mintxsz[5:0];
elsif UInt(walkparams.txsz) > s2maxtxsz then
walkparams.txsz = s2maxtxsz[5:0];
end;
if (walkparams.d128 == '0' &&
(AArch64_S2InvalidSL(walkparams) || AArch64_S2InconsistentSL(walkparams))) then
fault.statuscode = Fault_Translation;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor);
end;
if AArch64_IPAIsOutOfRange(ipa.paddress.address, walkparams) then
fault.statuscode = Fault_Translation;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor);
end;
var descpaddr : AddressDescriptor;
var walkstate : TTWState;
var descriptor : bits(128);
if walkparams.d128 == '1' then
(fault, descpaddr, walkstate, descriptor) = AArch64_S2Walk{128}(fault, ipa, walkparams,
accdesc);
else
(fault, descpaddr, walkstate, descriptor[63:0]) = AArch64_S2Walk{64}(fault, ipa, walkparams,
accdesc);
descriptor[127:64] = Zeros{64};
end;
if fault.statuscode != Fault_None then
return (fault, ARBITRARY : AddressDescriptor);
end;
if AArch64_S2HasAlignmentFaultDueToMemType(accdesc, aligned, walkstate.memattrs) then
fault.statuscode = Fault_Alignment;
end;
var fault_perm : FaultRecord;
(fault_perm, s2fs1mro) = AArch64_S2CheckPermissions(fault, walkstate, walkparams, ipa, accdesc);
var mem_desc : bits(128);
var new_desc : bits(128) = descriptor;
if AArch64_SetAccessFlag(walkparams.ha, accdesc, fault) then
// Set descriptor AF bit
new_desc[10] = '1';
end;
// If HW update of dirty bit is enabled, the walk state permissions
// will already reflect a configuration permitting writes.
// The update of the descriptor occurs only if the descriptor bits in
// memory do not reflect that and the access instigates a write.
if AArch64_SetDirtyState(walkparams.hd, (walkparams.s2pie OR descriptor[51]),
accdesc, fault, fault_perm) then
// Set descriptor S2AP[1]/Dirty bit permitting stage 2 writes
new_desc[7] = '1';
end;
if fault.statuscode == Fault_None && fault_perm.statuscode != Fault_None then
fault = fault_perm;
end;
// Either the access flag was clear or S2AP[1]/Dirty wasis clear
if new_desc != descriptor then
if walkparams.hdbss == '1' && descriptor[7] == '0' && new_desc[7] == '1' then
fault = AppendToHDBSS(fault, ipa.paddress, accdesc, walkparams, walkstate.level);
end;
// If an error, other than a synchronous External abort, occurred on the HDBSS update,
// stage 2 hardware update of dirty state is not permitted.
if (HDBSSPROD_EL2().FSC != '101000' &&
(!fault.hdbssf ||IsWBShareable(descpaddr.memattrs) &&
ConstrainUnpredictableBool(Unpredictable_Unsupported_Atomic_HW_Update)) then
fault.statuscode = Fault_HWUpdateAccessFlag;
return (fault, ARBITRARY : AddressDescriptor);
end;
if walkparams.hdbss == '1' && descriptor[7] == '0' && new_desc[7] == '1' then
fault = AppendToHDBSS(fault, ipa.paddress, accdesc, walkparams, walkstate.level);
end;
// If an error, other than a synchronous External abort, occurred on the HDBSS update,
// stage 2 hardware update of dirty state is not permitted.
if (!(walkparams.hdbss == '1' && descriptor[7] != new_desc[7]) ||
(HDBSSPROD_EL2().FSC != '101000' &&
(!fault.hdbssf || IsExternalAbort(fault.statuscode))))))) then
let descaccess : AccessDescriptor = CreateAccDescTTEUpdate(accdesc);
if walkparams.d128 == '1' then
(fault, mem_desc) = AArch64_MemSwapTableDesc{128}(fault, descriptor, new_desc,
walkparams.ee, descaccess,
descpaddr);
else
(fault, mem_desc[63:0]) = AArch64_MemSwapTableDesc{64}(fault, descriptor[63:0],
new_desc[63:0], walkparams.ee,
descaccess, descpaddr);
mem_desc[127:64] = Zeros{64};
end;
end;
if fault.statuscode != Fault_None then
if (accdesc.acctype == AccessType_AT &&
!(ImpDefBool("AT reports the HW update fault"))) then
// Mask the fault
fault.statuscode = Fault_None;
else
return (fault, ARBITRARY : AddressDescriptor);
end;
elsif new_desc != descriptor && mem_desc != new_desc then
// HW update of Dirty state or AF was not successful due to the descriptor being updated
// not matching the descriptor used for translation. Due to this, the walk is restarted.
return AArch64_S2Translate(fault_in, ipa, s1aarch64, aligned, accdesc);
end;
end;
if fault.statuscode != Fault_None then
return (fault, ARBITRARY : AddressDescriptor);
end;
let ipa_64 : bits(64) = ZeroExtend{}(ipa.paddress.address);
// Output Address
let oa : FullAddress = StageOA(ipa_64, walkparams.d128, walkparams.tgx, walkstate);
var s2_memattrs : MemoryAttributes;
if AArch64_S2TreatAsNormalNC(walkstate, walkparams, accdesc) then
// Treat memory attributes as Normal Non-Cacheable
s2_memattrs = NormalNCMemAttr();
s2_memattrs.xs = walkstate.memattrs.xs;
if walkstate.memattrs.tags == MemTag_CanonicallyTagged then
s2_memattrs.tags = MemTag_CanonicallyTagged;
end;
else
s2_memattrs = walkstate.memattrs;
end;
let s2aarch64 : boolean = TRUE;
var memattrs : MemoryAttributes;
if walkparams.fwb == '0' then
memattrs = S2CombineS1MemAttrs(ipa.memattrs, s2_memattrs, s2aarch64);
else
memattrs = s2_memattrs;
end;
var pa : AddressDescriptor = CreateAddressDescriptor(ipa.vaddress, oa, memattrs, accdesc);
pa.s2fs1mro = s2fs1mro;
pa.mecid = AArch64_S2OutputMECID{128}(walkparams, pa.paddress.paspace, descriptor);
if (accdesc.acctype == AccessType_TTW && accdesc.atomicop && !IsWBShareable(pa.memattrs) &&
ConstrainUnpredictableBool(Unpredictable_Unsupported_Atomic_HW_Update)) then
fault.statuscode = Fault_HWUpdateAccessFlag;
return (fault, pa);
end;
if (accdesc.acctype != AccessType_TTW &&{128}(walkparams, pa.paddress.paspace, descriptor);
if (accdesc.atomicop && !IsWBShareable(pa.memattrss2_memattrs) &&
ConstrainUnpredictableBool(Unpredictable_Atomic_MMU_IMPDEF_FAULT)) then
fault.statuscode = Fault_Exclusive;
return (fault, pa);
end;
if accdesc.ls64 && s2_memattrs.memtype == MemType_Normal then
if IsFeatureImplemented(FEAT_LS64WB) && !accdesc.withstatus then
if (!IsWBShareable(s2_memattrs) &&
!(s2_memattrs.inner.attrs == MemAttr_NC &&
s2_memattrs.outer.attrs == MemAttr_NC) &&
(ImpDefBool(
"LD64B or ST64B faults to cacheable non-iWBoWB memory"))) then
fault.statuscode = Fault_Exclusive;
return (fault, ipa);
end;
elsif !(s2_memattrs.inner.attrs == MemAttr_NC && s2_memattrs.outer.attrs == MemAttr_NC) then
fault.statuscode = Fault_Exclusive;
return (fault, ipa);
end;
end;
return (fault, pa);
end;
// AArch64_S1Walk()
// ================
// Traverse stage 1 translation tables obtaining the final descriptor
// as well as the address leading to that descriptor
func AArch64_S1Walk{N : integer{64, 128}}(fault_in : FaultRecord,
walkparams : S1TTWParams,
va : bits(64), regime : Regime,
accdesc : AccessDescriptor
) => (FaultRecord, AddressDescriptor, TTWState, bits(N))
begin
var fault : FaultRecord = fault_in;
var aligned : boolean;
if HasUnprivileged(regime) && AArch64_S1EPD(regime, va) == '1' then
fault.statuscode = Fault_Translation;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState, ARBITRARY : bits(N));
end;
var walkstate : TTWState = AArch64_S1InitialTTWState(walkparams, va, regime, accdesc.ss);
let startlevel : integer = walkstate.level;
if startlevel > 3 then
fault.statuscode = Fault_Translation;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState, ARBITRARY : bits(N));
end;
var descriptor : bits(N);
var walkaddress : AddressDescriptor;
var skl : bits(2) = '00';
walkaddress.vaddress = va;
walkaddress.mecid = AArch64_S1TTWalkMECID(walkparams.emec, regime, accdesc.ss);
if !AArch64_S1DCacheEnabled(regime) then
walkaddress.memattrs = NormalNCMemAttr();
walkaddress.memattrs.xs = walkstate.memattrs.xs;
else
walkaddress.memattrs = walkstate.memattrs;
end;
// Shareability value of stage 1 translation subject to stage 2 is IMPLEMENTATION DEFINED
// to be either effective value or descriptor value
if (regime == Regime_EL10 && EL2Enabled() && HCR_EL2().VM == '1' &&
!(ImpDefBool("Apply effective shareability at stage 1"))) then
walkaddress.memattrs.shareability = walkstate.memattrs.shareability;
else
walkaddress.memattrs.shareability = EffectiveShareability(walkaddress.memattrs);
end;
var s2fs1mro : boolean = FALSE;
var desctype : DescriptorType;
var descaddress : FullAddress = AArch64_S1SLTTEntryAddress(walkstate.level, walkparams, va,
walkstate.baseaddress);
// Detect Address Size Fault by Descriptor Address
if AArch64_S1OAOutOfRange(descaddress.address, walkparams) then
fault.statuscode = Fault_AddressSize;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState, ARBITRARY : bits(N));
end;
repeat
fault.level = walkstate.level;
walkaddress.paddress = descaddress;
walkaddress.s1assured = walkstate.s1assured;
let toplevel : boolean = walkstate.level == startlevel;
let varange : VARange = AArch64_GetVARange(va);
let walkaccess : AccessDescriptor = CreateAccDescS1TTW(toplevel, varange, accdesc);
var s2fault : FaultRecord;
var s2walkaddress : AddressDescriptor;
if regime == Regime_EL10 && EL2Enabled() then
let s1aarch64 : boolean = TRUE;
aligned = TRUE;
(s2fault, s2walkaddress) = AArch64_S2Translate(fault, walkaddress, s1aarch64, aligned,
walkaccess);
if s2fault.statuscode != Fault_None then
return (s2fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState,
ARBITRARY : bits(N));
end;
s2fs1mro = s2walkaddress.s2fs1mro;
(fault, descriptor) = FetchDescriptor{N}(walkparams.ee, s2walkaddress, walkaccess,
fault);
else
(fault, descriptor) = FetchDescriptor{N}(walkparams.ee, walkaddress, walkaccess,
fault);
end;
if fault.statuscode != Fault_None then
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState,
ARBITRARY : bits(N));
end;
var new_descriptor : bits(N);
repeat
new_descriptor = descriptor;
desctype = AArch64_DecodeDescriptorType{N}(descriptor, walkparams.d128, walkparams.ds,
walkparams.tgx, walkstate.level);
case desctype of
when DescriptorType_Table =>
walkstate = AArch64_S1NextWalkStateTable{N}(walkstate, s2fs1mro,
regime, walkparams, descriptor);
skl = if walkparams.d128 == '1' then descriptor[110:109] else '00';
descaddress = AArch64_S1TTEntryAddress{N}(walkstate.level, walkparams, skl, va,
walkstate.baseaddress, descriptor);
// Detect Address Size Fault by Descriptor Address
if AArch64_S1OAOutOfRange(descaddress.address, walkparams) then
fault.statuscode = Fault_AddressSize;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState,
ARBITRARY : bits(N));
end;
if walkparams.haft == '1' then
new_descriptor[10] = '1';
end;
if (walkparams.d128 == '1' && skl != '00' &&
AArch64_nTFaults{N}(walkparams.d128, descriptor)) then
fault.statuscode = Fault_Translation;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState,
ARBITRARY : bits(N));
end;
when DescriptorType_Leaf =>
walkstate = AArch64_S1NextWalkStateLeaf{N}(walkstate, s2fs1mro, regime, accdesc,
walkparams, descriptor);
when DescriptorType_Invalid =>
fault.statuscode = Fault_Translation;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState,
ARBITRARY : bits(N));
otherwise =>
unreachable;
end;
if new_descriptor != descriptor then
if
var (!descpaddr :IsWBShareable(walkaddress.memattrs) &&
ConstrainUnpredictableBool(Unpredictable_Unsupported_Atomic_HW_Update)) then
fault.statuscode = Fault_HWUpdateAccessFlag;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState,
ARBITRARY : bits(N));
end;
var descpaddr : AddressDescriptor;
let descaccess : AccessDescriptor = CreateAccDescTTEUpdate(accdesc);
if regime == Regime_EL10 && EL2Enabled() then
let s1aarch64 : boolean = TRUE;
aligned = TRUE;
(s2fault, descpaddr) = AArch64_S2Translate(fault, walkaddress,
s1aarch64, aligned,
descaccess);
if s2fault.statuscode != Fault_None then
return (s2fault, ARBITRARY : AddressDescriptor,
ARBITRARY : TTWState, ARBITRARY : bits(N));
end;
else
descpaddr = walkaddress;
end;
(fault, descriptor) = AArch64_MemSwapTableDesc{N}(fault, descriptor, new_descriptor,
walkparams.ee, descaccess,
descpaddr);
if fault.statuscode != Fault_None then
return (fault, ARBITRARY : AddressDescriptor,
ARBITRARY : TTWState, ARBITRARY : bits(N));
end;
end;
until new_descriptor == descriptor looplimit Unbounded_DescriptorUpdate;
until desctype == DescriptorType_Leaf looplimit MAX_WALK_LEVELS;
let oa : FullAddress = StageOA(va, walkparams.d128, walkparams.tgx, walkstate);
if (walkstate.contiguous == '1' &&
AArch64_ContiguousBitFaults(walkparams.d128, walkparams.txsz, walkparams.tgx,
walkstate.level)) then
fault.statuscode = Fault_Translation;
elsif walkstate.level < FINAL_LEVEL && AArch64_nTFaults{N}(walkparams.d128, descriptor) then
fault.statuscode = Fault_Translation;
elsif AArch64_S1AMECFault{N}(walkparams, walkstate.baseaddress.paspace, regime, descriptor) then
fault.statuscode = Fault_Translation;
// Detect Address Size Fault by final output
elsif AArch64_S1OAOutOfRange(oa.address, walkparams) then
fault.statuscode = Fault_AddressSize;
// Check descriptor AF bit
elsif (descriptor[10] == '0' && walkparams.ha == '0' &&
(!accdesc.acctype IN {AccessType_DC, AccessType_IC} ||
ImpDefBool("Generate access flag fault on IC/DC operations"))) then
fault.statuscode = Fault_AccessFlag;
end;
if fault.statuscode != Fault_None then
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState, ARBITRARY : bits(N));
end;
return (fault, walkaddress, walkstate, descriptor);
end;
// AArch64_S2Walk()
// ================
// Traverse stage 2 translation tables obtaining the final descriptor
// as well as the address leading to that descriptor
func AArch64_S2Walk{N : integer{64, 128}}(fault_in : FaultRecord,
ipa : AddressDescriptor,
walkparams : S2TTWParams,
accdesc : AccessDescriptor) => (FaultRecord,
AddressDescriptor,
TTWState,
bits(N))
begin
var fault : FaultRecord = fault_in;
let ipa_64 : bits(64) = ZeroExtend{}(ipa.paddress.address);
var walkstate : TTWState;
if accdesc.ss == SS_Secure then
walkstate = AArch64_SS2InitialTTWState(walkparams, ipa.paddress.paspace);
else
walkstate = AArch64_S2InitialTTWState(accdesc.ss, walkparams);
end;
let startlevel : integer = walkstate.level;
if startlevel > 3 then
fault.statuscode = Fault_Translation;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState, ARBITRARY : bits(N));
end;
var descriptor : bits(N);
let walkaccess : AccessDescriptor = CreateAccDescS2TTW(accdesc);
var walkaddress : AddressDescriptor;
var skl : bits(2) = '00';
walkaddress.vaddress = ipa.vaddress;
walkaddress.mecid = AArch64_S2TTWalkMECID(walkparams.emec, accdesc.ss);
if !S2DCacheEnabled() then
walkaddress.memattrs = NormalNCMemAttr();
walkaddress.memattrs.xs = walkstate.memattrs.xs;
else
walkaddress.memattrs = walkstate.memattrs;
end;
walkaddress.memattrs.shareability = EffectiveShareability(walkaddress.memattrs);
var desctype : DescriptorType;
// Initial lookup might index into concatenated tables
var descaddress : FullAddress = AArch64_S2SLTTEntryAddress(walkparams, ipa.paddress.address,
walkstate.baseaddress);
// Detect Address Size Fault by Descriptor Address
if AArch64_S2OAOutOfRange(descaddress.address, walkparams) then
fault.statuscode = Fault_AddressSize;
fault.level = 0;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState, ARBITRARY : bits(N));
end;
repeat
fault.level = walkstate.level;
walkaddress.paddress = descaddress;
(fault, descriptor) = FetchDescriptor{N}(walkparams.ee, walkaddress, walkaccess, fault);
if fault.statuscode != Fault_None then
return (fault, ARBITRARY : AddressDescriptor,
ARBITRARY : TTWState, ARBITRARY : bits(N));
end;
var new_descriptor : bits(N);
repeat
new_descriptor = descriptor;
desctype = AArch64_DecodeDescriptorType{N}(descriptor, walkparams.d128, walkparams.ds,
walkparams.tgx, walkstate.level);
case desctype of
when DescriptorType_Table =>
walkstate = AArch64_S2NextWalkStateTable{N}(walkstate, walkparams, descriptor);
skl = if walkparams.d128 == '1' then descriptor[110:109] else '00';
descaddress = AArch64_S2TTEntryAddress(walkstate.level, walkparams, skl,
ipa.paddress.address,
walkstate.baseaddress);
// Detect Address Size Fault by table descriptor
if AArch64_S2OAOutOfRange(descaddress.address, walkparams) then
fault.statuscode = Fault_AddressSize;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState,
ARBITRARY : bits(N));
end;
if walkparams.haft == '1' then
new_descriptor[10] = '1';
end;
if (walkparams.d128 == '1' && skl != '00' &&
AArch64_nTFaults{N}(walkparams.d128, descriptor)) then
fault.statuscode = Fault_Translation;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState,
ARBITRARY : bits(N));
end;
when DescriptorType_Leaf =>
walkstate = AArch64_S2NextWalkStateLeaf{N}(walkstate, accdesc.ss, walkparams,
ipa, descriptor);
when DescriptorType_Invalid =>
fault.statuscode = Fault_Translation;
return (fault, ARBITRARY : AddressDescriptor,
ARBITRARY : TTWState, ARBITRARY : bits(N));
otherwise =>
unreachable;
end;
if new_descriptor != descriptor then
if
let (!descaccess :IsWBShareable(walkaddress.memattrs) &&
ConstrainUnpredictableBool(Unpredictable_Unsupported_Atomic_HW_Update)) then
fault.statuscode = Fault_HWUpdateAccessFlag;
return (fault, ARBITRARY : AddressDescriptor, ARBITRARY : TTWState,
ARBITRARY : bits(N));
end;
let descaccess : AccessDescriptor = CreateAccDescTTEUpdate(accdesc);
(fault, descriptor) = AArch64_MemSwapTableDesc{N}(fault, descriptor, new_descriptor,
walkparams.ee, descaccess,
walkaddress);
if fault.statuscode != Fault_None then
return (fault, ARBITRARY : AddressDescriptor,
ARBITRARY : TTWState, ARBITRARY : bits(N));
end;
end;
until new_descriptor == descriptor looplimit Unbounded_DescriptorUpdate;
until desctype == DescriptorType_Leaf looplimit MAX_WALK_LEVELS;
let oa : FullAddress = StageOA(ipa_64, walkparams.d128, walkparams.tgx, walkstate);
if (walkstate.contiguous == '1' &&
AArch64_ContiguousBitFaults(walkparams.d128, walkparams.txsz, walkparams.tgx,
walkstate.level)) then
fault.statuscode = Fault_Translation;
elsif walkstate.level < FINAL_LEVEL && AArch64_nTFaults{N}(walkparams.d128, descriptor) then
fault.statuscode = Fault_Translation;
// Detect Address Size Fault by final output
elsif AArch64_S2OAOutOfRange(oa.address, walkparams) then
fault.statuscode = Fault_AddressSize;
// Check descriptor AF bit
elsif (descriptor[10] == '0' && walkparams.ha == '0' &&
(!accdesc.acctype IN {AccessType_DC, AccessType_IC} ||
ImpDefBool("Generate access flag fault on IC/DC operations"))) then
fault.statuscode = Fault_AccessFlag;
end;
return (fault, walkaddress, walkstate, descriptor);
end;
// Component
// =========
// Component Types.
type Component of enumeration {
Component_AMUComponent_ETE,
Component_ETEComponent_TRBE,
Component_TRBEComponent_RAS,
Component_RASComponent_GIC,
Component_GICComponent_PMU,
Component_PMUComponent_Debug,
Component_Debug,Component_CTI
};
Component_CTI
};
// GetAccessComponent()
// ====================
// DeterminesReturns the componentaccessed by decoding the physical address in the address descriptor.component.
impdef func GetAccessComponent(addrdesc() :=> AddressDescriptor) => Component
begin
return Component_Debug;
end;
// SoftwareLockStatus()
// ====================
// Returns the state of the Software Lock.
func SoftwareLockStatus(addrdesc() => boolean
begin
let component : AddressDescriptor) => boolean
begin
let component : Component = GetAccessComponent(addrdesc);();
if !HaveSoftwareLock(component) then
return FALSE;
end;
case component of
when Component_ETE => return TRCLSR().SLK == '1';
when Component_Debug => return EDLSR().SLK == '1';
when Component_PMU => return PMLSR().SLK == '1';
when Component_CTI => return CTILSR().SLK == '1';
otherwise => return FALSE;
end;
end;
// AllowExternalDebugAccess()
// ==========================
// Returns TRUE if an external debug interface access to the External DBGBVR<DBGBVR_EL1(n>_EL1,),
// DBGBCR<DBGBCR_EL1(n>_EL1,), DBGWVR<DBGWVR_EL1(n>_EL1,), DBGWCR<DBGWCR_EL1(n>_EL1) registers, and, from Armv8.2, the
// OSLAR_EL1 register is allowed for the access. Returns FALSE otherwise.
func AllowExternalDebugAccess(addrdesc : AddressDescriptor) => boolean
begin
// The access may also be subject to OS Lock, power-down, etc.
if IsFeatureImplemented(FEAT_RME) then
case MDCR_EL3().[EDADE,EDAD] of
when '00' => return TRUE;
when '01' => return addrdesc.paddress.paspace IN {PAS_Root, PAS_Secure};
when '10' => return addrdesc.paddress.paspace IN {PAS_Root, PAS_Realm};
when '11' => return addrdesc.paddress.paspace == PAS_Root;
end;
end;
if IsFeatureImplemented(FEAT_Debugv8p4) then
if addrdesc.paddress.paspace == PAS_Secure then return TRUE; end;
else
if !ExternalInvasiveDebugEnabled() then return FALSE; end;
if ExternalSecureInvasiveDebugEnabled() then return TRUE; end;
end;
if HaveEL(EL3) then
let EDAD_bit : bit = if ELUsingAArch32(EL3) then SDCR().EDAD else MDCR_EL3().EDAD;
return EDAD_bit == '0';
else
return NonSecureOnlyImplementation();
end;
end;
// ExternalInvasiveDebugEnabled() // ============================== // The definition of this function is IMPLEMENTATION DEFINED. // In the recommended interface, this function returns the state of the DBGEN signal. readonly func ExternalInvasiveDebugEnabled() => boolean begin return DBGEN == HIGH; end;
// ExternalNoninvasiveDebugEnabled() // ================================= // This function returns TRUE if the FEAT_Debugv8p4 is implemented. // Otherwise, this function is IMPLEMENTATION DEFINED, and, in the // recommended interface, ExternalNoninvasiveDebugEnabled returns // the state of the (DBGEN OR NIDEN) signal. readonly func ExternalNoninvasiveDebugEnabled() => boolean begin return (IsFeatureImplemented(FEAT_Debugv8p4) || ExternalInvasiveDebugEnabled() || NIDEN == HIGH); end;
// ExternalRealmInvasiveDebugEnabled() // =================================== // The definition of this function is IMPLEMENTATION DEFINED. // In the recommended interface, this function returns the state of the // (DBGEN AND RLPIDEN) signal. readonly func ExternalRealmInvasiveDebugEnabled() => boolean begin if !IsFeatureImplemented(FEAT_RME) then return FALSE; end; return ExternalInvasiveDebugEnabled() && RLPIDEN == HIGH; end;
// ExternalRealmNoninvasiveDebugEnabled() // ====================================== // The definition of this function is IMPLEMENTATION DEFINED. // In the recommended interface, this function returns the state of the // (DBGEN AND RLPIDEN) signal. readonly func ExternalRealmNoninvasiveDebugEnabled() => boolean begin if !IsFeatureImplemented(FEAT_RME) then return FALSE; end; return ExternalRealmInvasiveDebugEnabled(); end;
// ExternalSecureInvasiveDebugEnabled()
// ====================================
// The definition of this function is IMPLEMENTATION DEFINED.
// In the recommended interface, this function returns the state of the (DBGEN AND SPIDEN) signal.
// CoreSight allows asserting SPIDEN without also asserting DBGEN, but this is not recommended.
readonly func ExternalSecureInvasiveDebugEnabled() => boolean
begin
if !HaveSecureState() then
return (!IsFeatureImplemented(FEAT_RME)FALSE; || RTPIDEN == HIGH);
end;
return ExternalInvasiveDebugEnabled() && SPIDEN == HIGH;
end;
// ExternalSecureNoninvasiveDebugEnabled() // ======================================= // This function returns the value of ExternalSecureInvasiveDebugEnabled() when FEAT_Debugv8p4 // is implemented. Otherwise, the definition of this function is IMPLEMENTATION DEFINED. // In the recommended interface, this function returns the state of the (DBGEN OR NIDEN) AND // (SPIDEN OR SPNIDEN) signal. readonly func ExternalSecureNoninvasiveDebugEnabled() => boolean begin if !HaveSecureState() then return FALSE; end; if !IsFeatureImplemented(FEAT_Debugv8p4) then return (ExternalNoninvasiveDebugEnabled() && (SPIDEN == HIGH || SPNIDEN == HIGH)); else return ExternalSecureInvasiveDebugEnabled(); end; end;
// ExitDebugState()
// ================
func ExitDebugState()
begin
assert Halted();
SynchronizeContext();
// Although EDSCR.STATUS signals that the PE is restarting, debuggers must use EDPRSR.SDR to
// detect that the PE has restarted.
EDSCR().STATUS = '000001'; // Signal restarting
// Clear any pending Halting debug events
if IsFeatureImplemented(FEAT_Debugv8p8) then
EDESR()[3:0] = '0000';
else
EDESR()[2:0] = '000';
end;
var new_pc : bits(64);
var spsr : bits(64);
if UsingAArch32() then
new_pc = ZeroExtend{64}(DLR());
if IsFeatureImplemented(FEAT_Debugv8p9) then
spsr = DSPSR2() :: DSPSR();
else
spsr = ZeroExtend{64}(DSPSR());
end;
else
new_pc = DLR_EL0();
spsr = DSPSR_EL0();
end;
let illegal_psr_state : boolean = IllegalExceptionReturn{64}(spsr);
// If this is an illegal return, SetPSTATEFromPSR() will set PSTATE.IL.
SetPSTATEFromPSR{64}(spsr); // Can update privileged bits, even at EL0
let branch_conditional : boolean = FALSE;
if UsingAArch32() then
if ConstrainUnpredictableBool(Unpredictable_RESTARTALIGNPC) then new_pc[0] = '0'; end;
// AArch32 branch
BranchTo{32}(new_pc[31:0], BranchType_DBGEXIT, branch_conditional);
else
// If targeting AArch32 then PC[63:32,1:0] might be set to UNKNOWN.
if illegal_psr_state && spsr[4] == '1' then
new_pc[63:32] = ARBITRARY : bits(32);
new_pc[1:0] = ARBITRARY : bits(2);
end;
if IsFeatureImplemented(FEAT_BRBE) then
BRBEDebugStateExit(new_pc);
end;
// A type of branch that is never predicted
BranchTo{64}(new_pc,AArch64_BranchAddr(new_pc,PSTATE.EL));
end;
// A type of branch that is never predicted
BranchTo{64}(new_pc, BranchType_DBGEXIT, branch_conditional);
end;
// Atomically signal restarted
EDSCR().STATUS = '000010';
EDPRSR().SDR = '1';
// End of atomically signal
EDPRSR().HALTED = '0';
UpdateEDSCRFields(); // Stop signalling PE state
DisableITRAndResumeInstructionPrefetch();
return;
end;
// Halt()
// ======
func Halt(reason : bits(6))
begin
let is_async : boolean = FALSE;
let fault : FaultRecord = NoFault();
Halt(reason, is_async, fault);
end;
// Halt()
// ======
func Halt(reason : bits(6), is_async : boolean, fault : FaultRecord)
begin
CTI_SignalEvent(CrossTriggerIn_CrossHalt); // Trigger other cores to halt
let preferred_restart_address : bits(64) = ThisInstrAddr{}();
var spsr : bits(64) = GetPSRFromPSTATE{}( GetPSRFromPSTATE{64}(DebugState);
if (IsFeatureImplemented(FEAT_BTI) && !is_async &&
! reason IN {DebugHalt_Step_Normal, DebugHalt_Step_Exclusive,
DebugHalt_Step_NoSyndrome, DebugHalt_Breakpoint,
DebugHalt_HaltInstruction} &&
ConstrainUnpredictableBool(Unpredictable_ZEROBTYPE)) then
spsr[11:10] = '00';
end;
if UsingAArch32() then
DLR() = preferred_restart_address[31:0];
DSPSR() = spsr[31:0];
if IsFeatureImplemented(FEAT_Debugv8p9) then
DSPSR2() = spsr[63:32];
end;
else
DLR_EL0() = preferred_restart_address;
DSPSR_EL0() = spsr;
end;
EDSCR().ITE = '1';
EDSCR().ITO = '0';
if IsFeatureImplemented(FEAT_RME) then
if PSTATE.EL == PSTATE.EL == EL3 then
EDSCR().SDD = '0';
else
EDSCR().SDD = if ExternalRootInvasiveDebugEnabled() then '0' else '1';
end;
elsif CurrentSecurityState() == SS_Secure then
EDSCR().SDD = '0'; // If entered in Secure state, allow debug
elsif HaveEL(EL3) then
EDSCR().SDD = if ExternalSecureInvasiveDebugEnabled() then '0' else '1';
else
EDSCR().SDD = '1'; // Otherwise EDSCR.SDD is RES1
end;
EDSCR().MA = '0';
// In Debug state:
// * PSTATE.[SS,SSBS,D,A,I,F] are not observable and ignored so behave-as-if UNKNOWN.
// * PSTATE.[N,Z,C,V,Q,GE,E,M,nRW,EL,SP,DIT] are also not observable, but since these
// are not changed on exception entry, this function also leaves them unchanged.
// * PSTATE.[IT,T] are ignored.
// * PSTATE.IL is ignored and behave-as-if 0.
// * PSTATE.BTYPE is ignored and behave-as-if 0.
// * PSTATE.TCO is set 1.
// * PSTATE.PACM is ignored and behave-as-if 0.
// * PSTATE.[UAO,PAN] are observable and not changed on entry into Debug state.
// * PSTATE.UINJ is set to 0.
if UsingAArch32() then
PSTATE.[IT,SS,SSBS,A,I,F,T] = ARBITRARY : bits(14);
else
PSTATE.[SS,SSBS,D,A,I,F] = ARBITRARY : bits(6);
end;
if IsFeatureImplemented(FEAT_MTE) then PSTATE.TCO = '1'; end;
if IsFeatureImplemented(FEAT_BTI) then PSTATE.BTYPE = '00'; end;
if IsFeatureImplemented(FEAT_PAuth_LR) then PSTATE.PACM = '0'; end;
PSTATE.IL = '0';
if IsFeatureImplemented(FEAT_UINJ) then PSTATE.UINJ() then
PSTATE.[IT,SS,SSBS,A,I,F,T] = ARBITRARY : bits(14);
else
PSTATE.[SS,SSBS,D,A,I,F] = ARBITRARY : bits(6);
end;
if IsFeatureImplemented(FEAT_MTE) then PSTATE.TCO = '1'; end;
if IsFeatureImplemented(FEAT_BTI) then PSTATE.BTYPE = '00'; end;
if IsFeatureImplemented(FEAT_PAuth_LR) then PSTATE.PACM = '0'; end;
PSTATE.IL = '0';
if IsFeatureImplemented(FEAT_UINJ) then PSTATE.UINJ = '0'; end;
if IsFeatureImplemented(FEAT_BRBE) then
BRBEDebugStateEntry(preferred_restart_address);
end;
StopInstructionPrefetchAndEnableITR();
// atomic write
EDSCR().STATUS = reason;
EDPRSR().HALTED = '1';
// end of atomic write
UpdateEDSCRFields(); // Update EDSCR PE state flags.
if IsFeatureImplemented(FEAT_EDHSR) then
UpdateEDHSR(reason, fault); // Update EDHSR fields.
end;
if !is_async then EndOfInstruction(); end;
return;
end;
// UpdateEDSCRFields()
// ===================
// Update EDSCR PE state fields
func UpdateEDSCRFields()
begin
if !Halted() then
EDSCR().EL = '00';
if IsFeatureImplemented(FEAT_RME) then
// SDD bit.
EDSCR().SDD = if ExternalRootInvasiveDebugEnabled() then '0' else '1';
EDSCR().[NSE,NS] = ARBITRARY : bits(2);
else
// SDD bit.
EDSCR().SDD = if ExternalSecureInvasiveDebugEnabled() then '0' else '1';
EDSCR().NS = ARBITRARY : bit;
end;
EDSCR().RW = '1111';
else
EDSCR().EL = PSTATE.EL;
// SError Pending.
if PSTATE.EL;
// SError Pending.
if EL2Enabled() && HCR_EL2().[AMO,TGE] == '10' && PSTATE.EL IN { PSTATE.EL IN {EL0,EL1} then
EDSCR().A = if IsVirtualSErrorPending() then '1' else '0';
elsif (IsFeatureImplemented(FEAT_E3DSE) && SCR_EL3().EnDSE == '1' &&
PSTATE.EL IN {EffectiveSCR_EL3_EnDSE() == '1' && PSTATE.EL IN {EL0,EL1,EL2}) then
EDSCR().A = if IsDelegatedSErrorPending() then '1' else '0';
else
EDSCR().A = if IsPhysicalSErrorPending() then '1' else '0';
end;
let ss : SecurityState = CurrentSecurityState();
if IsFeatureImplemented(FEAT_RME) then
case ss of
when SS_Secure => EDSCR().[NSE,NS] = '00';
when SS_NonSecure => EDSCR().[NSE,NS] = '01';
when SS_Root => EDSCR().[NSE,NS] = '10';
when SS_Realm => EDSCR().[NSE,NS] = '11';
end;
else
EDSCR().NS = if ss == SS_Secure then '0' else '1';
end;
var RW : bits(4);
RW[1] = if ELUsingAArch32(EL1) then '0' else '1';
if PSTATE.EL) then '0' else '1';
if PSTATE.EL != EL0 then
RW[0] = RW[1];
else
RW[0] = if UsingAArch32() then '0' else '1';
end;
if !EL2Enabled() then
RW[2] = RW[1];
else
RW[2] = if ELUsingAArch32(EL2) then '0' else '1';
end;
if !HaveEL(EL3) then
RW[3] = RW[2];
else
RW[3] = if ELUsingAArch32(EL3) then '0' else '1';
end;
// The least-significant bits of EDSCR.RW are UNKNOWN if any higher EL is using AArch32.AArch32_
if RW[3] == '0' then RW[2:0] = ARBITRARY : bits(3);
elsif RW[2] == '0' then RW[1:0] = ARBITRARY : bits(2);
elsif RW[1] == '0' then RW[0] = ARBITRARY : bit; end;
EDSCR().RW = RW;
end;
return;
end;
var PMUEventAccumulator : array [[31]] of integer; // Accumulates PMU events for a cycle
var PMULastThresholdValue : array [[31]] of boolean; //;// A record of the threshold result for each
// Constant used in PMU functions to represent actions on the cycle counter.
constant CYCLE_COUNTER_ID : integer = 31;
// Constant used in PMU functions to represent actions on the instruction counter.
constant INSTRUCTION_COUNTER_ID : integer = 32;
// EncodeLDFSC()
// =============
// Function that gives the Long-descriptor FSC code for types of Fault
func EncodeLDFSC(statuscode : Fault, level : integer) => bits(6)
begin
var result : bits(6);
// 128-bit descriptors will start from level -2 for 4KB to resolve bits IA[55:51]
if level == -2 then
assert IsFeatureImplemented(FEAT_D128);
case statuscode of
when Fault_AddressSize => result = '101100';
when Fault_Translation => result = '101010';
when Fault_SyncExternalOnWalk => result = '010010';
when Fault_SyncParityOnWalk =>
result = '011010';
assert !IsFeatureImplemented(FEAT_RAS);
when Fault_GPCFOnWalk => result = '100010';
otherwise => unreachable;
end;
return result;
end;
if level == -1 then
assert IsFeatureImplemented(FEAT_LPA2);
case statuscode of
when Fault_AddressSize => result = '101001';
when Fault_Translation => result = '101011';
when Fault_SyncExternalOnWalk => result = '010011';
when Fault_SyncParityOnWalk =>
result = '011011';
assert !IsFeatureImplemented(FEAT_RAS);
when Fault_GPCFOnWalk => result = '100011';
otherwise => unreachable;
end;
return result;
end;
case statuscode of
when Fault_AddressSize => result = '0000'::level[1:0]; assert level IN {0,1,2,3};
when Fault_AccessFlag => result = '0010'::level[1:0]; assert level IN {0,1,2,3};
when Fault_Permission => result = '0011'::level[1:0]; assert level IN {0,1,2,3};
when Fault_Translation => result = '0001'::level[1:0]; assert level IN {0,1,2,3};
when Fault_AsyncExternal => result = '010001'; assert UsingAArch32();
when Fault_SyncExternal => result = '010000';
when Fault_SyncExternalOnWalk => result = '0101'::level[1:0]; assert level IN {0,1,2,3};
when Fault_SyncParity => result = '011000';
when Fault_SyncParityOnWalk => result = '0111'::level[1:0]; assert level IN {0,1,2,3};
when Fault_AsyncParity => result = '011001';
when Fault_AsyncExternal => result = '010001'; assert UsingAArch32 => result = '011001';();
when Fault_TagCheck => result = '010001'; assert IsFeatureImplemented(FEAT_MTE2);
when Fault_Alignment => result = '100001';
when Fault_Debug => result = '100010';
when Fault_GPCFOnWalk => result = '1001'::level[1:0]; assert level IN {0,1,2,3};
when Fault_GPCFOnOutput => result = '101000';
when Fault_TLBConflict => result = '110000';
when Fault_HWUpdateAccessFlag => result = '110001';
when Fault_Lockdown => result = '110100'; // IMPLEMENTATION DEFINED
when Fault_Exclusive => result = '110101'; // IMPLEMENTATION DEFINED
otherwise => unreachable;
end;
return result;
end;
// HaveTraceExt() // ============== // Returns TRUE if Trace functionality as described by the Trace Architecture // is implemented. readonly func HaveTraceExt() => boolean begin return IsFeatureImplemented(FEAT_ETE) || IsFeatureImplemented(FEAT_ETMv4); end;
// CreateAccDescDCZero() // ===================== // Access descriptor for data cache zero operations func CreateAccDescDCZero(cachetype : CacheType) => AccessDescriptor begin var accdesc : AccessDescriptor = NewAccDesc(AccessType_DCZero); accdesc.write = TRUE; accdesc.pan = TRUE; accdesc.tagchecked = cachetype == CacheType_Data; accdesc.tagaccess = cachetype IN {CacheType_Tag, CacheType_TagWrite, CacheType_TagZero, CacheType_Data_Tag}; accdesc.cachetype = cachetype; return accdesc; end;
// IsContiguousSVEAccess()
// =======================
// Return TRUE if memory access is contiguous load/stores in an SVE mode.
func IsContiguousSVEAccess(accdesc : AccessDescriptor) => boolean
begin
return (IsFeatureImplemented(FEAT_SVE) &&
accdesc.acctype == AccessType_SVE && accdesc.contiguous;);
end;
// IsSMEAccess()
// =============
// Return TRUE if access is of SME load/stores.
func IsSMEAccess(accdesc : AccessDescriptor) => boolean
begin
return IsFeatureImplemented(FEAT_SME) && accdesc.acctype == AccessType_SME;
end;
// ReportVIDFault()
// ================
// Report a GPCF or External abort on an MVMS or MITT access.
func ReportVIDFault(mpamdata : MPAMdata, el : bits(2),
fault_address : bits(56), fsc : bits(2))
begin
assert el == '0x';
MPAMVIDSR_EL2().FADDR = fault_address;
MPAMVIDSR_EL2().FSC = fsc;
MPAMVIDSR_EL2().FIR = if mpamdata.sm then '10' else el;
end;
// SPSR_ELx - accessor
// ===================
accessor SPSR_ELx() <=> value : bits(64)
begin
getter
var result : bits(64);
case PSTATE.EL of
when PSTATE.EL of
when EL1 => result = SPSR_EL1()[63:0];
when EL2 => result = SPSR_EL2()[63:0];
when EL3 => result = SPSR_EL3()[63:0];
otherwise => unreachable;
end;
return result;
end;
setter
case PSTATE.EL=> result = SPSR_EL3()[63:0];
otherwise => unreachable;
end;
return result;
end;
setter
case PSTATE.EL of
when EL1 => SPSR_EL1()[63:0] = value[63:0];
when EL2 => SPSR_EL2()[63:0] = value[63:0];
when EL3 => SPSR_EL3()[63:0] = value[63:0];
otherwise => unreachable;
end;
return;
end;
end;
// ELStateUsingAArch32K()
// ======================
// Returns (known, aarch32):
// 'known' is FALSE for EL0 if the current Exception level is not EL0 and EL1 is
// using AArch64, since it cannot determine the state of EL0; TRUE otherwise.
// 'aarch32' is TRUE if the specified Exception level is using AArch32; FALSE otherwise.
readonly func ELStateUsingAArch32K(el : bits(2), secure : boolean) => (boolean, boolean)
begin
assert HaveEL(el);
if !HaveAArch32EL(el) then
return (TRUE, FALSE); // Exception level is using AArch64
elsif secure && el == EL2 then
return (TRUE, FALSE); // Secure EL2 is using AArch64
elsif !HaveAArch64() then
return (TRUE, TRUE); // Highest Exception level, therefore all levels are using AArch32
end;
// Remainder of function deals with the interprocessing cases when highest
// Exception level is using AArch64.AArch64_
if el == EL3 then
return (TRUE, FALSE);
end;
if (HaveEL(EL3) && SCR_EL3().RW == '0' &&
(!secure || !IsFeatureImplemented(FEAT_SEL2) || SCR_EL3().EEL2 == '0')) then
// AArch32 below EL3.
return (TRUE, TRUE);
end;
if el == EffectiveSCR_EL3_RW() == '0' &&
(!secure || !IsFeatureImplemented(FEAT_SEL2) || SCR_EL3().EEL2 == '0')) then
// AArch32 below EL3.
return (TRUE, TRUE);
end;
if el == EL2 then
return (TRUE, FALSE);
end;
if (HaveEL(EL2) && !ELIsInHost(EL0) && HCR_EL2().RW == '0' &&
(!secure || (IsFeatureImplemented(FEAT_SEL2) && SCR_EL3().EEL2 == '1'))) then
// AArch32 below EL2.
return (TRUE, TRUE);
end;
if el == EL1 then
return (TRUE, FALSE);
end;
// The execution state of EL0 is only known from PSTATE.nRW when executing at EL0.
if PSTATE.EL == PSTATE.EL == EL0 then
return (TRUE, PSTATE.nRWthen
return (TRUE, PSTATE.nRW == '1');
else
return (FALSE, ARBITRARY : boolean);
end;
end;
// EffectiveEA() // ============= // Returns effective SCR_EL3.EA value readonly func EffectiveEA() => bit begin if !HaveEL(EL3) || Halted() then return '0'; else return if HaveAArch64() then SCR_EL3().EA else SCR().EA; end; end;
// EffectiveHCR_EL2_NVx()
// ======================
// Return the Effective value of HCR_EL2.[HCR_EL2().[NV2,NV1,NV].
func EffectiveHCR_EL2_NVx() => bits(3)
begin
if !EL2Enabled() || !IsFeatureImplemented(FEAT_NV) then
return '000';
end;
var nv1 : bit = HCR_EL2().NV1;
if (!IsFeatureImplemented(FEAT_E2H0) &&
ImpDefBool("HCR_EL2.NV1 is implemented as RAZ")) then
nv1 = '0';
end;
if HCR_EL2().NV == '0' then
if nv1 == '1' then
case ConstrainUnpredictable(Unpredictable_NVNV1) of
when Constraint_NVNV1_00 => return '000';
when Constraint_NVNV1_01 => return '010';
when Constraint_NVNV1_11 => return '011';
end;
else
return '000';
end;
end;
if !IsFeatureImplemented(FEAT_NV2) then
return '0' :: nv1 :: '1';
end;
var nv2 : bit = HCR_EL2().NV2;
if (nv2 == '0' && ImpDefBool(
"Programming HCR_EL2.<NV,NV2> to '10' behaves as '11'")) then
nv2 = '1';
end;
return nv2 :: nv1 :: '1';
end;
// EffectiveSCR_EL3_FIQ() // ====================== // Returns effective SCR_EL3().FIQ value readonly func EffectiveSCR_EL3_FIQ() => bit begin if !HaveEL(EL3) || ELUsingAArch32(EL3) then return '0'; end; if IsFeatureImplemented(FEAT_GCIE) && IsFeatureImplemented(FEAT_EL3) then return '1'; end; return SCR_EL3().FIQ; end;
// EffectiveSCR_EL3_IRQ() // ====================== // Returns effective SCR_EL3().IRQ value readonly func EffectiveSCR_EL3_IRQ() => bit begin if !HaveEL(EL3) || ELUsingAArch32(EL3) then return '0'; end; if IsFeatureImplemented(FEAT_GCIE) then return '0'; end; return SCR_EL3().IRQ; end;
// EffectiveSCR_EL3_RW() // ===================== // Returns effective SCR_EL3.RW value readonly func EffectiveSCR_EL3_RW() => bit begin if !HaveAArch64() then return '0'; end; if !HaveAArch32EL(EL2) && !HaveAArch32EL(EL1) then return '1'; end; if HaveAArch32EL(EL1) then if !HaveAArch32EL(EL2) && EffectiveSCR_EL3_NS() == '1' then return '1'; end; if (IsFeatureImplemented(FEAT_SEL2) && SCR_EL3().EEL2 == '1' && EffectiveSCR_EL3_NS() == '0') then return '1'; end; end; return SCR_EL3().RW; end;
// IllegalExceptionReturn()
// ========================
func IllegalExceptionReturn{N}(spsr : bits(N)) => boolean
begin
// Check for illegal return:
// * To an unimplemented Exception level.
// * To EL2 in Secure state, when SecureEL2 is not enabled.
// * To EL0 using AArch64 state, with SPSR.M[0]==1.
// * To AArch64 state with SPSR.M[1]==1.
// * To AArch32 state with an illegal value of SPSR.M.
let (valid, target) : (boolean, bits(2)) = ELFromSPSR{N}(spsr);
if !valid then return TRUE; end;
// Check for return to higher Exception level.
if UInt(target) > UInt(PSTATE.EL) then return TRUE; end;
let spsr_mode_is_aarch32 : boolean = (spsr[4] == '1');
// Check for illegal return:
// * To EL1, EL2 or EL3 with register width specified in the SPSR different from the
// Execution state used in the Exception level being returned to, as determined by
// the SCR_EL3.RW or HCR_EL2.RW bits, or as configured from reset.
// * To EL0 using AArch64 state when EL1 is using AArch32 state as determined by the
// SCR_EL3.RW or HCR_EL2.RW bits or as configured from reset.
// * To AArch64 state from AArch32 state (should be caught by above).
let (known, target_el_is_aarch32) : (boolean, boolean) =PSTATE.EL) then return TRUE; end;
let spsr_mode_is_aarch32 : boolean = (spsr[4] == '1');
// Check for illegal return:
// * To EL1, EL2 or EL3 with register width specified in the SPSR different from the
// Execution state used in the Exception level being returned to, as determined by
// the SCR_EL3.RW or HCR_EL2.RW bits, or as configured from reset.
// * To EL0 using AArch64 state when EL1 is using AArch32 state as determined by the
// SCR_EL3.RW or HCR_EL2.RW bits or as configured from reset.
// * To AArch64 state from AArch32 state (should be caught by above).
let (known, target_el_is_aarch32) : (boolean, boolean) = ELUsingAArch32K(target);
assert known || (target == EL0 && !ELUsingAArch32(EL1));
if known && spsr_mode_is_aarch32 != target_el_is_aarch32 then return TRUE; end;
// Check for illegal return from AArch32 to AArch64.AArch64_
if UsingAArch32() && !spsr_mode_is_aarch32 then return TRUE; end;
// Check for illegal return to EL1 when HCR_EL2.TGE is set and when either of
// * SecureEL2 is enabled.
// * SecureEL2 is not enabled and EL1 is in Non-secure state.
if EL2Enabled() && target == EL1 && HCR_EL2().TGE == '1' then
if (!IsSecureBelowEL3() || IsSecureEL2Enabled()) then return TRUE; end;
end;
// Check for an illegal return to EL1 by a Guest Hypervisor at EL1 when HCRX_EL2.NVTGE is set.
if (IsFeatureImplemented(FEAT_NV3) && PSTATE.EL == PSTATE.EL == EL1 && spsr[3:2] == '01' &&
EffectiveHCR_EL2_NVx() == '101' && IsHCRXEL2Enabled() && HCRX_EL2().NVTGE == '1' &&
NVHCR_EL2().TGE == '1') then
return TRUE;
end;
if (IsFeatureImplemented(FEAT_GCS) && PSTATE.EXLOCK == '0' &&
PSTATE.EL() && HCRX_EL2().NVTGE == '1' &&
NVHCR_EL2().TGE == '1') then
return TRUE;
end;
if (IsFeatureImplemented(FEAT_GCS) && PSTATE.EXLOCK == '0' &&
PSTATE.EL == target && GetCurrentEXLOCKEN()) then
return TRUE;
end;
return FALSE;
end;
// PSTATE
// ======
// PE state bits.
// There is no significance to the field order.
var PSTATE : collection {
N : bits (1), // Negative condition flag
Z : bits (1), // Zero condition flag
C : bits (1), // Carry condition flag
V : bits (1), // Overflow condition flag
D : bits (1), // Debug mask bit [AArch64 only]
A : bits (1), // SError interrupt mask bit
I : bits (1), // IRQ mask bit
F : bits (1), // FIQ mask bit
EXLOCK : bits (1), // Lock exception return state
PAN : bits (1), // Privileged Access Never Bit [v8.1]
UAO : bits (1), // User Access Override [v8.2]
DIT : bits (1), // Data Independent Timing [v8.4]
TCO : bits (1), // Tag Check Override [v8.5, AArch64 only]
PM : bits (1), // PMU exception Mask
PPEND : bits (1), // synchronous PMU exception to be observed
BTYPE : bits (2), // Branch Type [v8.5]
PACM : bits (1), // PAC instruction modifier
ZA : bits (1), // Accumulation array enabled [SME]
SM : bits (1), // Streaming SVE mode enabled [SME]
ALLINT : bits (1), // Interrupt mask bit
UINJ : bits (1), // Undefined Exception Injection
SS : bits (1), // Software step bit
IL : bits (1), // Illegal Execution state bit
EL : bits (2), // Exception level
nRW : bits (1), // Execution state: 0=AArch64, 1=AArch32
SP : bits (1), // Stack pointer select: 0=SP0, 1=SPx [AArch64 only]
Q : bits (1), // Cumulative saturation flag [AArch32 only]
GE : bits (4), // Greater than or Equal flags [AArch32 only]
SSBS : bits (1), // Speculative Store Bypass Safe
IT : bits (8), // If-then bits, RES0 in CPSR [AArch32 only]
J : bits (1), // J bit, RES0 [AArch32 only, RES0 in SPSR and CPSR]
T : bits (1), // T32 bit, RES0 in CPSR [AArch32 only]
E : bits (1), // Endianness bit [AArch32 only]
M : bits (5); // Mode field [AArch32 only]
}; PSTATE : collection {
N : bits (1), // Negative condition flag
Z : bits (1), // Zero condition flag
C : bits (1), // Carry condition flag
V : bits (1), // Overflow condition flag
D : bits (1), // Debug mask bit [AArch64 only]
A : bits (1), // SError interrupt mask bit
I : bits (1), // IRQ mask bit
F : bits (1), // FIQ mask bit
EXLOCK : bits (1), // Lock exception return state
PAN : bits (1), // Privileged Access Never Bit [v8.1]
UAO : bits (1), // User Access Override [v8.2]
DIT : bits (1), // Data Independent Timing [v8.4]
TCO : bits (1), // Tag Check Override [v8.5, AArch64 only]
PM : bits (1), // PMU exception Mask
PPEND : bits (1), // synchronous PMU exception to be observed
BTYPE : bits (2), // Branch Type [v8.5]
PACM : bits (1), // PAC instruction modifier
ZA : bits (1), // Accumulation array enabled [SME]
SM : bits (1), // Streaming SVE mode enabled [SME]
ALLINT : bits (1), // Interrupt mask bit
UINJ : bits (1), // Undefined Exception Injection
SS : bits (1), // Software step bit
IL : bits (1), // Illegal Execution state bit
EL : bits (2), // Exception level
nRW : bits (1), // Execution state: 0=AArch64, 1=AArch32
SP : bits (1), // Stack pointer select: 0=SP0, 1=SPx [AArch64 only]
Q : bits (1), // Cumulative saturation flag [AArch32 only]
GE : bits (4), // Greater than or Equal flags [AArch32 only]
SSBS : bits (1), // Speculative Store Bypass Safe
IT : bits (8), // If-then bits, RES0 in CPSR [AArch32 only]
J : bits (1), // J bit, RES0 [AArch32 only, RES0 in SPSR and CPSR]
T : bits (1), // T32 bit, RES0 in CPSR [AArch32 only]
E : bits (1), // Endianness bit [AArch32 only]
M : bits (5) // Mode field [AArch32 only]
};
// ExcludeXS() // =========== // Returns TRUE if a TLBI maintenance instruction without the nXS qualifier executed at EL1 // behaves in the same way as the corresponding TLBI maintenance instruction with the nXS qualifier. func ExcludeXS() => boolean begin return (IsFeatureImplemented(FEAT_XS) && PSTATE.EL == EL1 && IsHCRXEL2Enabled() && HCRX_EL2().FnXS == '1'); end;
// ConstrainUnpredictable() // ======================== // Return the appropriate Constraint result to control the caller's behavior. // The return value is IMPLEMENTATION DEFINED within a permitted list for each // UNPREDICTABLE case. // (The permitted list is determined by an assert or case statement at the call site.) readonly impdef func ConstrainUnpredictable(which : Unpredictable) => Constraint begin case which of when Unpredictable_VMSR => return Constraint_UNDEF; when Unpredictable_WBOVERLAPLD => return Constraint_WBSUPPRESS; // return loaded value when Unpredictable_WBOVERLAPST => return Constraint_NONE; // store pre-writeback value when Unpredictable_LDPOVERLAP => return Constraint_UNDEF; // instruction is UNDEFINED when Unpredictable_BASEOVERLAP => return Constraint_UNKNOWN; // use UNKNOWN address when Unpredictable_DATAOVERLAP => return Constraint_UNKNOWN; // store UNKNOWN value when Unpredictable_DEVPAGE2 => return Constraint_FAULT; // take an alignment fault when Unpredictable_RESTCF => return Constraint_UNKNOWN; // Do not take a fault when Unpredictable_DEVICETAGSTORE => return Constraint_NONE; // Do not take a fault when Unpredictable_INSTRDEVICE => return Constraint_NONE; // Do not take a fault when Unpredictable_RESCPACR => return Constraint_TRUE; // Map to UNKNOWN value when Unpredictable_RESMAIR => return Constraint_UNKNOWN; // Map to UNKNOWN value when Unpredictable_S1CTAGGED => return Constraint_FALSE; // SCTLR_ELx.C == '0' marks address as untagged when Unpredictable_S2RESMEMATTR => return Constraint_NC; // Map to Noncacheable value when Unpredictable_RESTEXCB => return Constraint_UNKNOWN; // Map to UNKNOWN value when Unpredictable_RESDACR => return Constraint_UNKNOWN; // Map to UNKNOWN value when Unpredictable_RESPRRR => return Constraint_UNKNOWN; // Map to UNKNOWN value when Unpredictable_RESVTCRS => return Constraint_UNKNOWN; // Map to UNKNOWN value when Unpredictable_RESTnSZ => return Constraint_FORCE; // Map to the limit value when Unpredictable_OORTnSZ => return Constraint_FORCE; // Map to the limit value when Unpredictable_LARGEIPA => return Constraint_FORCE; // Restrict the IA size to the PAMax value when Unpredictable_ESRCONDPASS => return Constraint_FALSE; // Report as "AL" when Unpredictable_ILZEROIT => return Constraint_FALSE; // Do not zero PSTATE.IT when Unpredictable_ILZEROT => return Constraint_FALSE; // Do not zero PSTATE.T when Unpredictable_BPVECTORCATCHPRI => return Constraint_TRUE; // Debug Vector Catch: match on 2nd halfword when Unpredictable_VCMATCHHALF => return Constraint_FALSE; // No match when Unpredictable_VCMATCHDAPA => return Constraint_FALSE; // No match on Data Abort or Prefetch abort when Unpredictable_WPMASKANDBAS => return Constraint_FALSE; // Watchpoint disabled when Unpredictable_WPBASCONTIGUOUS => return Constraint_FALSE; // Watchpoint disabled when Unpredictable_RESWPMASK => return Constraint_DISABLED; // Watchpoint disabled when Unpredictable_WPMASKEDBITS => return Constraint_FALSE; // Watchpoint disabled when Unpredictable_RESBPWPCTRL => return Constraint_DISABLED; // Breakpoint/watchpoint disabled when Unpredictable_BPNOTIMPL => return Constraint_DISABLED; // Breakpoint disabled when Unpredictable_RESBPTYPE => return Constraint_DISABLED; // Breakpoint disabled when Unpredictable_BPNOTCTXCMP => return Constraint_DISABLED; // Breakpoint disabled when Unpredictable_RESMDSELR => return Constraint_UNKNOWN; // Map to UNKNOWN value when Unpredictable_BPMATCHHALF => return Constraint_FALSE; // No match when Unpredictable_BPMISMATCHHALF => return Constraint_FALSE; // No match when Unpredictable_BPLINKINGDISABLED => return Constraint_FALSE; // Breakpoint does not match when Unpredictable_RESTARTALIGNPC => return Constraint_FALSE; // Do not force alignment when Unpredictable_RESTARTZEROUPPERPC => return Constraint_TRUE; // Force zero extension when Unpredictable_ZEROUPPER => return Constraint_TRUE; // zero top halves of X registers when Unpredictable_ERETZEROUPPERPC => return Constraint_TRUE; // zero top half of PC when Unpredictable_A32FORCEALIGNPC => return Constraint_FALSE; // Do not force alignment when Unpredictable_SMD => return Constraint_UNDEF; // disabled SMC is Unallocated when Unpredictable_NONFAULT => return Constraint_FALSE; // Speculation enabled when Unpredictable_SVEZEROUPPER => return Constraint_TRUE; // zero top bits of Z registers when Unpredictable_SVELDNFDATA => return Constraint_TRUE; // Load mem data in NF loads when Unpredictable_SVELDNFZERO => return Constraint_TRUE; // Write zeros in NF loads when Unpredictable_CHECKSPNONEACTIVE => return Constraint_TRUE; // Check SP alignment when Unpredictable_SMEZEROUPPER => return Constraint_TRUE; // zero top bits of ZA registers when Unpredictable_NVNV1 => return Constraint_NVNV1_00; // Map unpredictable configuration of HCR_EL2[NV,NV1] // to NV = 0 and NV1 = 0 when Unpredictable_BADDR_RESS => return Constraint_RESS; // Values behave as RESS when Unpredictable_Shareability => return Constraint_OSH; // Map reserved encoding of shareability to Outer Shareable when Unpredictable_AFUPDATE => // AF update for alignment or Permission fault return Constraint_TRUE; when Unpredictable_DBUPDATE => // DB State update for alignment fault return Constraint_TRUE; when Unpredictable_Unsupported_Atomic_HW_Update => return Constraint_FALSE; // Do not raise Unsupported Atomic HW Update fault // when encountering unsupported memory attributes when Unpredictable_IESBinDebug => // Use SCTLR_ELx[].IESB in Debug state return Constraint_TRUE; when Unpredictable_BADPMSFCR => // Bad settings for PMSFCR_EL1/PMSEVFR_EL1/PMSLATFR_EL1 return Constraint_TRUE; when Unpredictable_RES_PMU_VS => // Bad setting for SVE Streaming mode filter return Constraint_FALSE; when Unpredictable_COUNT_CHAIN => // Chained PMU counters idx, idx+1 are not in same range return Constraint_FALSE; when Unpredictable_EL1TIMESTAMP => // Bad settings for TRFCR_EL1 return Constraint_EL1TIMESTAMP; when Unpredictable_EL2TIMESTAMP => // Bad settings for TRFCR_EL2 return Constraint_EL2TIMESTAMP; when Unpredictable_ZEROBTYPE => return Constraint_TRUE; // Save BTYPE in SPSR_ELx/DPSR_EL0 as '00' when Unpredictable_CLEARERRITEZERO => // Clearing sticky errors when instruction in flight return Constraint_FALSE; when Unpredictable_ALUEXCEPTIONRETURN => return Constraint_UNDEF; when Unpredictable_DBGxVR_RESS => return Constraint_FALSE; when Unpredictable_PMSCR_PCT => return Constraint_PMSCR_PCT_VIRT; when Unpredictable_WFxTDEBUG => return Constraint_FALSE; // WFxT in Debug state does not execute as a NOP // Accesses are not single-copy atomic above the byte level when Unpredictable_LS64UNSUPPORTED => return Constraint_LIMITED_ATOMICITY; // Unaligned exclusives, atomics, acquire/release // to a region that is not to Normal inner write-back // outer write-back shareable generate an Alignment fault. when Unpredictable_LSE2_ALIGNMENT_FAULT => return Constraint_FALSE; when Unpredictable_LSE128OVERLAP => return Constraint_UNDEF; // instruction is UNDEFINED when Unpredictable_IGNORETRAPINDEBUG => return Constraint_FALSE; // Trap to register access in debug state is enabled when Unpredictable_PMUEVENTCOUNTER => return Constraint_UNDEF; // Accesses to the register are UNDEFINED when Unpredictable_RES_HPMN => return Constraint_UNKNOWN; // The counter is reserved for EL2 use when Unpredictable_RES_EPMN => return Constraint_UNKNOWN; // The counter is reserved for external use when Unpredictable_BRBFILTRATE => return Constraint_FALSE; // BRB_FILTRATE event not generated on BRB injection when Unpredictable_PMUSNAPSHOTEVENT => // PMU_SNAPSHOT event not generated in Debug state return Constraint_FALSE; when Unpredictable_RESEPMSSAD => // External access to PMUv3 Snapshot extension allowed in Secure state // when FEAT_RME is not implemented or Root state otherwise return Constraint_UNKNOWN; when Unpredictable_RESPMSSE => return Constraint_DISABLED; // PMU capture events disabled when Unpredictable_RESPMEE => return Constraint_DISABLED; // PMU Profiling exception disabled, PMUIRQ enabled when Unpredictable_RESPMSEE => return Constraint_DISABLED; // SPE Profiling exception disabled when Unpredictable_RESTRFEE => return Constraint_DISABLED; // TRBE Profiling exception disabled when Unpredictable_RESTC => return Constraint_DISABLED; // Threshold features disabled when Unpredictable_MOPSOVERLAP => // Instruction is UNDEFINED return Constraint_UNDEF; when Unpredictable_MOPS_R31 => // Instruction is UNDEFINED return Constraint_UNDEF; when Unpredictable_CASRETURNOLDVALUE => return Constraint_TRUE; when Unpredictable_WRITEFAILEDCAS => return Constraint_FALSE; when Unpredictable_STRONLYTAGCHECKEDCAS => return Constraint_TRUE; // CAS with compare fail does a Tag Check when Unpredictable_STRONLYTAGCHECKEDRCWSCAS => return Constraint_TRUE; // RCW(S)CAS with RCW(S) fail/compare fail does a Tag Check when Unpredictable_RESERVEDNSxB => return Constraint_MAPTOALLOCATED; when Unpredictable_RESERVEDNSxB_Trap => return Constraint_TRUE; when Unpredictable_RES_ETBAD => // ExternalTracebufferaccess disabled for res values return Constraint_DISABLED; when Unpredictable_RESBPMASK => return Constraint_DISABLED; // Mask set to 0 when Unpredictable_BPMASK => return Constraint_FALSE; // Breakpoint match will fail when Unpredictable_BPMASKEDBITS => return Constraint_FALSE; // Breakpoint match will fail when Unpredictable_BPLINKEDADDRMATCH => return Constraint_FALSE; // Breakpoint match will fail when Unpredictable_16BYTEROUNDEDUPACCESS => // Watchpoint match of 16 byte rounded range in case of SVE access return Constraint_TRUE; when Unpredictable_16BYTEROUNDEDDOWNACCESS => // Watchpoint match of 16 byte rounded range in case of SVE access return Constraint_TRUE; when Unpredictable_NODTRTAGCHK => // The load or store operation does not perform the Tag check in Debug state return Constraint_TRUE; when Unpredictable_CPACHECK => // Do not perform Checked Pointer Arithmetic return Constraint_FALSE; when Unpredictable_Atomic_SYNC_ABORT => return Constraint_FALSE; when Unpredictable_Atomic_SERROR => return Constraint_FALSE; when Unpredictable_Atomic_NOP => return Constraint_FALSE; when Unpredictable_Atomic_MMU_IMPDEF_FAULT => return Constraint_FALSE; when Unpredictable_MPAM_TRUNCATE_VID => return Constraint_TRUE; when Unpredictable_USE_DEFAULT_PMG => return Constraint_TRUE; when Unpredictable_BankedRegister => return Constraint_NOP; when Unpredictable_UnimplementedRegister => return Constraint_NOP; otherwise => unreachable; end; end;
// Unpredictable
// =============
// List of Constrained Unpredictable situations.
type Unpredictable of enumeration {
// VMSR on MVFR
Unpredictable_VMSR,
// Writeback/transfer register overlap (load)
Unpredictable_WBOVERLAPLD,
// Writeback/transfer register overlap (store)
Unpredictable_WBOVERLAPST,
// Load Pair transfer register overlap
Unpredictable_LDPOVERLAP,
// Store-exclusive base/status register overlap
Unpredictable_BASEOVERLAP,
// Store-exclusive data/status register overlap
Unpredictable_DATAOVERLAP,
// Load-store alignment checks
Unpredictable_DEVPAGE2,
// Instruction fetch from Device memory
Unpredictable_INSTRDEVICE,
// Reserved CPACR value
Unpredictable_RESCPACR,
// Reserved MAIR value
Unpredictable_RESMAIR,
// Effect of SCTLR_ELx.C on Tagged attribute
Unpredictable_S1CTAGGED,
// Reserved Stage 2 MemAttr value
Unpredictable_S2RESMEMATTR,
// Reserved TEX:::C:::B value
Unpredictable_RESTEXCB,
// Reserved PRRR value
Unpredictable_RESPRRR,
// Reserved DACR field
Unpredictable_RESDACR,
// Reserved VTCR.S value
Unpredictable_RESVTCRS,
// Reserved TCR.TnSZ value
Unpredictable_RESTnSZ,
// Reserved SCTLR_ELx.TCF value
Unpredictable_RESTCF,
// Tag stored to Device memory
Unpredictable_DEVICETAGSTORE,
// Out-of-range TCR.TnSZ value
Unpredictable_OORTnSZ,
// IPA size exceeds PA size
Unpredictable_LARGEIPA,
// Syndrome for a known-passing conditional A32 instruction
Unpredictable_ESRCONDPASS,
// Illegal State exception: zero PSTATE.IT
Unpredictable_ILZEROIT,
// Illegal State exception: zero PSTATE.T
Unpredictable_ILZEROT,
// Debug: prioritization of Vector Catch
Unpredictable_BPVECTORCATCHPRI,
// Debug Vector Catch: match on 2nd halfword
Unpredictable_VCMATCHHALF,
// Debug Vector Catch: match on Data Abort
// or Prefetch abort
Unpredictable_VCMATCHDAPA,
// Debug watchpoints: nonzero MASK and non-ones BAS
Unpredictable_WPMASKANDBAS,
// Debug watchpoints: non-contiguous BAS
Unpredictable_WPBASCONTIGUOUS,
// Debug watchpoints: reserved MASK
Unpredictable_RESWPMASK,
// Debug watchpoints: nonzero MASKed bits of address
Unpredictable_WPMASKEDBITS,
// Debug breakpoints and watchpoints: reserved control bits
Unpredictable_RESBPWPCTRL,
// Debug breakpoints: not implemented
Unpredictable_BPNOTIMPL,
// Debug breakpoints: reserved type
Unpredictable_RESBPTYPE,
// Debug breakpoints and watchpoints: reserved MDSELR_EL1.BANK
Unpredictable_RESMDSELR,
// Debug breakpoints: not-context-aware breakpoint
Unpredictable_BPNOTCTXCMP,
// Debug breakpoints: match on 2nd halfword of instruction
Unpredictable_BPMATCHHALF,
// Debug breakpoints: mismatch on 2nd halfword of instruction
Unpredictable_BPMISMATCHHALF,
// Debug breakpoints: a breakpoint is linked to that is not
// programmed with linking enabled
Unpredictable_BPLINKINGDISABLED,
// Debug breakpoints: reserved MASK
Unpredictable_RESBPMASK,
// Debug breakpoints: MASK is set for a Context matching
// breakpoint or when DBGBCR_EL1([n).].BAS != '1111'
Unpredictable_BPMASK,
// Debug breakpoints: nonzero MASKed bits of address
Unpredictable_BPMASKEDBITS,
// Debug breakpoints: A linked breakpoint is
// linked to an address matching breakpoint
Unpredictable_BPLINKEDADDRMATCH,
// Debug: restart to a misaligned AArch32 PC value
Unpredictable_RESTARTALIGNPC,
// Debug: restart to a not-zero-extended AArch32 PC value
Unpredictable_RESTARTZEROUPPERPC,
// Zero top 32 bits of X registers in AArch32 state
Unpredictable_ZEROUPPER,
// Zero top 32 bits of PC on illegal return to
// AArch32 state
Unpredictable_ERETZEROUPPERPC,
// Force address to be aligned when interworking
// branch to A32 state
Unpredictable_A32FORCEALIGNPC,
// SMC disabled
Unpredictable_SMD,
// FF speculation
Unpredictable_NONFAULT,
// Zero top bits of Z registers in EL change
Unpredictable_SVEZEROUPPER,
// Load mem data in NF loads
Unpredictable_SVELDNFDATA,
// Write zeros in NF loads
Unpredictable_SVELDNFZERO,
// SP alignment fault when predicate is all zero
Unpredictable_CHECKSPNONEACTIVE,
// Zero top bits of ZA registers in EL change
Unpredictable_SMEZEROUPPER,
// Watchpoint match of last rounded up memory access in case of
// 16 byte rounding
Unpredictable_16BYTEROUNDEDUPACCESS,
// Watchpoint match of first rounded down memory access in case of
// 16 byte rounding
Unpredictable_16BYTEROUNDEDDOWNACCESS,
// HCR_EL2.[HCR_EL2().[NV,NV1] == '01'
Unpredictable_NVNV1,
// Upper bits of a BADDR are not RESS
Unpredictable_BADDR_RESS,
// Reserved shareability encoding
Unpredictable_Shareability,
// Access Flag Update by HW
Unpredictable_AFUPDATE,
// Dirty Bit State Update by HW
Unpredictable_DBUPDATE,
// UnsupportedConsider memorySCTLR_ELx[].IESB attributesin forDebug HW updatestate
Unpredictable_Unsupported_Atomic_HW_UpdateUnpredictable_IESBinDebug,
// ConsiderBad SCTLR_ELx().IESBsettings infor Debug statePMSFCR_EL1/PMSEVFR_EL1/PMSLATFR_EL1
Unpredictable_IESBinDebugUnpredictable_BADPMSFCR,
// TheZero HCR_EL2.TERRsaved /BType HCR2.TERRvalue andin SCR_EL3.TERR SPSR_ELx/ SCR.TERR
// trap control can be treated as RES0.DPSR_EL0
Unpredictable_MINIMALRASv2Unpredictable_ZEROBTYPE,
// BadTimestamp settingsconstrained forto PMSFCR_EL1/PMSEVFR_EL1/PMSLATFR_EL1virtual or physical
Unpredictable_BADPMSFCRUnpredictable_EL2TIMESTAMP,
// Zero saved BType value in SPSR_ELx/DPSR_EL0
Unpredictable_ZEROBTYPEUnpredictable_EL1TIMESTAMP,
// TimestampReserved constrainedMDCR_EL3().[NSTBE,NSTB] toor virtualMDCR_EL3().[NSPBE,NSPB] or physicalvalue
Unpredictable_EL2TIMESTAMPUnpredictable_RESERVEDNSxB,
Unpredictable_EL1TIMESTAMPUnpredictable_RESERVEDNSxB_Trap,
// ReservedWFET MDCR_EL3.[NSTBE,NSTB] or MDCR_EL3.[NSPBE,NSPB]WFIT valueinstruction in Debug state
Unpredictable_RESERVEDNSxBUnpredictable_WFxTDEBUG,
// Address does not support LS64 instructions
Unpredictable_RESERVEDNSxB_TrapUnpredictable_LS64UNSUPPORTED,
// WFETUnaligned orexclusives, WFITatomics, instructionacquire/release
// into Debuga stateregion that is not to Normal inner write-back
// outer write-back shareable generate an Alignment fault.
Unpredictable_WFxTDEBUGUnpredictable_LSE2_ALIGNMENT_FAULT,
// Address128-bit doesAtomic notor support128-bit LS64RCW{S} instructionstransfer register overlap
Unpredictable_LS64UNSUPPORTEDUnpredictable_LSE128OVERLAP,
// UnalignedClearing exclusives, atomics, acquireDCC/release
//ITR tosticky aflags regionwhen thatinstruction is notin to Normal inner write-back
// outer write-back shareable generate an Alignment fault.flight
Unpredictable_LSE2_ALIGNMENT_FAULTUnpredictable_CLEARERRITEZERO,
// 128-bitALUEXCEPTIONRETURN Atomicwhen orin 128-bituser/system RCW{S}mode transferin
// registerA32 overlapinstructions
Unpredictable_LSE128OVERLAPUnpredictable_ALUEXCEPTIONRETURN,
// ClearingTrap DCC/ITRto stickyregister flagsin whendebug instructionstate isare in flightignored
Unpredictable_CLEARERRITEZEROUnpredictable_IGNORETRAPINDEBUG,
// ALUEXCEPTIONRETURNCompare whenDBGBVR.RESS infor userBP/system mode in
// A32 instructionsWP
Unpredictable_ALUEXCEPTIONRETURNUnpredictable_DBGxVR_RESS,
// TrapInaccessible toevent register in debug state are ignoredcounter
Unpredictable_IGNORETRAPINDEBUGUnpredictable_PMUEVENTCOUNTER,
// CompareReserved DBGBVR.RESSPMSCR.PCT for BP/WPbehavior
Unpredictable_DBGxVR_RESSUnpredictable_PMSCR_PCT,
// InaccessibleMDCR_EL2.HPMN eventor counterHDCR.HPMN is larger than PMCR.N or
// FEAT_HPMN0 is not implemented and HPMN is 0.
Unpredictable_PMUEVENTCOUNTERUnpredictable_RES_HPMN,
// ReservedChained PMSCR.PCTPMU behaviorcounters idx and idx+1 are not in same range
Unpredictable_PMSCR_PCTUnpredictable_COUNT_CHAIN,
// MDCR_EL2.HPMNPMCCR.EPMN or HDCR.HPMN is larger than PMCR.N or
// FEAT_HPMN0 is not implemented and HPMN is 0.
Unpredictable_RES_HPMNUnpredictable_RES_EPMN,
// ChainedGenerate PMUBRB_FILTRATE countersevent idxon andBRB idx+1 are not in same rangeinjection
Unpredictable_COUNT_CHAINUnpredictable_BRBFILTRATE,
// PMCCR.EPMNGenerate isPMU_SNAPSHOT largerevent thanin PMCR.NDebug state
Unpredictable_RES_EPMNUnpredictable_PMUSNAPSHOTEVENT,
// GenerateReserved BRB_FILTRATEMDCR_EL3.EPMSSAD event on BRB injectionvalue
Unpredictable_BRBFILTRATEUnpredictable_RESEPMSSAD,
// GenerateReserved PMU_SNAPSHOTPMECR_EL1.SSE event in Debug statevalue
Unpredictable_PMUSNAPSHOTEVENTUnpredictable_RESPMSSE,
// ReservedEnable MDCR_EL3.EPMSSADfor valuePMU Profiling exception and PMUIRQ
Unpredictable_RESEPMSSADUnpredictable_RESPMEE,
// ReservedEnables PMECR_EL1.SSEfor valueSPE Profiling exceptions and PMSIRQ
Unpredictable_RESPMSSEUnpredictable_RESPMSEE,
// EnableEnables for PMUTRBE Profiling exceptionexceptions and PMUIRQPMSIRQ
Unpredictable_RESPMEEUnpredictable_RESTRFEE,
// EnablesOperands for SPECPY*/SET* Profilinginstructions exceptions and PMSIRQoverlap
Unpredictable_RESPMSEEUnpredictable_MOPSOVERLAP,
// EnablesOperands for TRBECPY*/SET* Profilinginstructions exceptionsuse and0b11111
// PMSIRQas a register specifier
Unpredictable_RESTRFEEUnpredictable_MOPS_R31,
// OperandsChooses forwhich CPY*/SET*value instructionsto overlapreturn in a non failed Atomic Compare and Swap
Unpredictable_MOPSOVERLAPUnpredictable_CASRETURNOLDVALUE,
// OperandsEnables forwrite CPY*/SET*of instructionsthe usenewvalue 0b11111
//in as a registerfailed specifierAtomic Compare and Swap
Unpredictable_MOPS_R31Unpredictable_WRITEFAILEDCAS,
// ChoosesStore-only whichTag valuechecking toon return in a non failed Atomic Compare and Swap
Unpredictable_CASRETURNOLDVALUEUnpredictable_STRONLYTAGCHECKEDCAS,
// EnablesStore-only writeTag ofchecking theon newvaluea infailed aRCW(S) failedchecks
// or RCW(S) Atomic Compare and Swap
Unpredictable_WRITEFAILEDCASUnpredictable_STRONLYTAGCHECKEDRCWSCAS,
// Store-onlyReserved TagMDCR_EL3.ETBAD checking on a failed Atomic Compare and Swapvalue
Unpredictable_STRONLYTAGCHECKEDCASUnpredictable_RES_ETBAD,
// Store-onlyInvalid TagStreaming checkingMode onfilter a failed RCW(S) checks
// or RCW(S) Atomic Compare and Swapbits
Unpredictable_STRONLYTAGCHECKEDRCWSCASUnpredictable_RES_PMU_VS,
// ReservedApply MDCR_EL3.ETBADChecked valuePointer Arithmetic on a sequential access to bytes
// that cross the 0xXXFF_FFFF_FFFF_FFFF boundary.
Unpredictable_RES_ETBADUnpredictable_CPACHECK,
// InvalidReserved StreamingPMEVTYPER_EL0(n).[TC,TE,TC2] Mode filter bitsvalues
Unpredictable_RES_PMU_VSUnpredictable_RESTC,
// ApplyWhen CheckedFEAT_MTE Pointeris Arithmeticimplemented, onif aMemory sequential access tomode bytesis enabled
// thatand crossPSTATE.TCO is 0, Reads and writes to the 0xXXFF_FFFF_FFFF_FFFFexternal boundary.debug
// interface DTR registers are CONSTRAINED UNPREDICTABLE for tagcheck
Unpredictable_CPACHECKUnpredictable_NODTRTAGCHK,
// ReservedUse PMEVTYPER[n]_EL0.[TC,TE,TC2]the valuesdefault PMG when the default PARTID is generated
// due to MPAM error
Unpredictable_RESTCUnpredictable_USE_DEFAULT_PMG,
// WhenIf FEAT_MTEthe isatomic implemented,instructions ifare Memorynot accessatomic modein isregard enabledto other
// andagents PSTATE.TCOthat isaccess 0memory, Reads andthen writesthe toinstruction thecan externalhave debugone or
// interfacemore DTRof registersthe arefollowing CONSTRAINED UNPREDICTABLE for tagcheckeffects
Unpredictable_NODTRTAGCHKUnpredictable_Atomic_SYNC_ABORT,
// Use the default PMG when the default PARTID is generated
// due to MPAM error
Unpredictable_USE_DEFAULT_PMGUnpredictable_Atomic_SERROR,
// If the atomic instructions are not atomic in regard to other
// agents that access memory, then the instruction can have one or
// more of the following effects
Unpredictable_Atomic_SYNC_ABORTUnpredictable_Atomic_NOP,
Unpredictable_Atomic_SERRORUnpredictable_Atomic_MMU_IMPDEF_FAULT,
// Truncate virtual identifier to bottom 12 bits if it exceeds 2^12
Unpredictable_Atomic_NOPUnpredictable_MPAM_TRUNCATE_VID,
// Accessing DBGDSCRint via MRC in debug state
Unpredictable_Atomic_MMU_IMPDEF_FAULTUnpredictable_MRC_APSR_TARGET,
// TruncateAccessing virtualBanked identifierregister tonot bottomaccessible 12from bitsthe ifPE it exceeds 2^12mode
Unpredictable_MPAM_TRUNCATE_VIDUnpredictable_BankedRegister,
// Accessing DBGDSCRintunimplemented viaBanked MRC in debug stateregister
Unpredictable_MRC_APSR_TARGETUnpredictable_UnimplementedRegister,
// Accessing Banked register not accessible from the PE mode
};
Unpredictable_BankedRegister,
// Accessing unimplemented Banked register
Unpredictable_UnimplementedRegister,
};
// CheckMDCR_EL3_NSTBTrap()
// ========================
// Check if the register access is trappable by MDCR_EL3.[NSTBE, NSTB]
func CheckMDCR_EL3_NSTBTrap() => boolean
begin
var state_bits : bits(3);
var reserved : boolean;
(state_bits, reserved) = EffectiveMDCR_EL3_NSTB();
return ((reserved && ConstrainUnpredictableBool(Unpredictable_RESERVEDNSxB_Trap)) ||
state_bits[0] == '0' || state_bits[1] != SCR_EL3().NS ||
(IsFeatureImplemented(FEAT_RME) && state_bits[2] != SCR_EL3().NSE));
end; EffectiveSCR_EL3_NS() ||
(IsFeatureImplemented(FEAT_RME) && state_bits[2] != EffectiveSCR_EL3_NSE()));
end;
// SelfHostedTraceEnabled() // ======================== // Returns TRUE if Self-hosted Trace is enabled. readonly func SelfHostedTraceEnabled() => boolean begin var secure_trace_enable : bit = '0'; if !(HaveTraceExt() && IsFeatureImplemented(FEAT_TRF)) then return FALSE; end; if EDSCR().TFO == '0' then return TRUE; end; if IsFeatureImplemented(FEAT_RME) then secure_trace_enable = if IsFeatureImplemented(FEAT_SEL2) then MDCR_EL3().STE else '0'; return ((secure_trace_enable == '1' && !ExternalSecureNoninvasiveDebugEnabled()) || (MDCR_EL3().RLTE == '1' && !ExternalRealmNoninvasiveDebugEnabled())); end; if HaveEL(EL3) then secure_trace_enable = if ELUsingAArch32(EL3) then SDCR().STE else MDCR_EL3().STE; else secure_trace_enable = if SecureOnlyImplementation() then '1' else '0'; end; if secure_trace_enable == '1' && !ExternalSecureNoninvasiveDebugEnabled() then return TRUE; end; return FALSE; end;
// DecodeGPTBlock() // ================ // Decode a GPT Block descriptor. func DecodeGPTBlock(pgs : PGSe, gpt_entry : bits(64)) => GPTEntry begin assert gpt_entry[3:0] == GPT_Block; var result : GPTEntry; result.gpi = gpt_entry[7:4]; result.level = 0; result.istable = FALSE; // GPT information from a level 0 GPT Block descriptor is permitted // to be cached in a TLB as though the Block is a contiguous region // of granules each of the size configured in GPCCR_EL3.PGS. case pgs of when PGS_4KB => result.size = GPTRange_4KB; when PGS_16KB => result.size = GPTRange_16KB; when PGS_64KB => result.size = GPTRange_64KB; otherwise => unreachable; end; result.contig_size = GPTL0Size(); return result; end;
// DecodeGPTContiguous() // ===================== // Decode a GPT Contiguous descriptor. func DecodeGPTContiguous(pgs : PGSe, gpt_entry : bits(64)) => GPTEntry begin assert gpt_entry[3:0] == GPT_Contig; var result : GPTEntry; result.gpi = gpt_entry[7:4]; case pgs of when PGS_4KB => result.size = GPTRange_4KB; when PGS_16KB => result.size = GPTRange_16KB; when PGS_64KB => result.size = GPTRange_64KB; otherwise => unreachable; end; case gpt_entry[9:8] of when '01' => result.contig_size = GPTRange_2MB; when '10' => result.contig_size = GPTRange_32MB; when '11' => result.contig_size = GPTRange_512MB; otherwise => unreachable; end; result.level = 1; result.istable = FALSE; return result; end;
// DecodeGPTGranules() // =================== // Decode a GPT Granules descriptor. func DecodeGPTGranules(pgs : PGSe, index : integer, gpt_entry : bits(64)) => GPTEntry begin var result : GPTEntry; result.gpi = gpt_entry[index*4 +:4]; case pgs of when PGS_4KB => result.size = GPTRange_4KB; when PGS_16KB => result.size = GPTRange_16KB; when PGS_64KB => result.size = GPTRange_64KB; otherwise => unreachable; end; result.contig_size = result.size; // No contiguity result.level = 1; result.istable = FALSE; return result; end;
// DecodeGPTTable()
// ================
// Decode a GPT Table descriptor.
func DecodeGPTTable(pgs : PGSe, gpt_entry : bits(64)) => GPTTable
begin
assert gpt_entry[3:0] == GPT_Table;
var result : GPTTable;
// Descriptor bits [L0GPTSZ-PGS-2:12] are RES0
var s : integer{30, 34, 36, 39};
case GPTL0Size() of
when GPTRange_1GB => s = 30;
when GPTRange_16GB => s = 34;
when GPTRange_64GB => s = 36;
when GPTRange_512GB => s = 39;
otherwise => unreachable;
end;
var p : integer{12, 14, 16};
case pgs of
when PGS_4KB => presult.address = 12;gpt_entry[55:17]::Zeros{17};
when PGS_16KB => presult.address = 14;gpt_entry[55:15]::Zeros{15};
when PGS_64KB => presult.address = 16;gpt_entry[55:13]::Zeros{13};
otherwise => unreachable;
end;
let align_bits : integer{} = (s - p) - 1;
result.address = AlignDownP2(gpt_entry[55:0],align_bits);
return result;
end;
// GPTEntry
// ========
type GPTEntry of record {
gpi : bits(4), // GPI value for this region
size : AddressSize, // Region size
contig_size : AddressSize, // Contiguous region size
istable :level boolean, // Flag a table entry
level : integer, // Level of GPT lookup
pa : bits(56) // PA uniquely identifying the GPT entry
};
// GPTTableDescriptorValid()
// =========================
// Returns TRUE if the given GPT Table descriptor is valid, and FALSE otherwise.
func GPTTableDescriptorValid(level_0_entry : bits(64)) => boolean
begin
assert level_0_entry[3:0] == GPT_Table;
let l0sz : integer{} = GPTL0Size();
let pgs : PGSe = DecodePGS(GPCCR_EL3().PGS);
let p : integer{} = DecodePGSRange(pgs);
let top : integer{} = if DecodePPS() == 56 then 56 else 52;
return IsZero(level_0_entry[63:top52,11:4]) && IsZero(level_0_entry[(l0sz-p)-2:12]);
end;
// EffectiveACTLRMASK_EL1()
// ========================
// Return the effective value of ACTLRMASK_EL1.
func EffectiveACTLRMASK_EL1() => ACTLR_EL1_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
if EL2Enabled() && (!IsHCRXEL2Enabled() || HCRX_EL2().SRMASKEn == '0') then
return Zeros{64};
end;
let mask : ACTLR_EL1_Type = ImpDefBits{64}("ACTLR_EL1 layout");
return mask;
end;
// EffectiveACTLRMASK_EL2()
// ========================
// Return the effective value of ACTLRMASK_EL2.
func EffectiveACTLRMASK_EL2() => ACTLR_EL2_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
let mask : ACTLR_EL2_Type = ImpDefBits{64}("ACTLR_EL2 layout");
return mask;
end;
// EffectiveCPACRMASK_EL1()
// ========================
// Return the effective value of CPACRMASK_EL1.
func EffectiveCPACRMASK_EL1() => CPACR_EL1_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
if EL2Enabled() && (!IsHCRXEL2Enabled() || HCRX_EL2().SRMASKEn == '0') then
return Zeros{64};
end;
var mask : CPACR_EL1_Type = Ones{64};
let mask_reg : CPACRMASK_EL1_Type = CPACRMASK_EL1();
mask.TCPAC = mask_reg.TCPAC;
mask.TAM = mask_reg.TAM;
mask.E0POE = mask_reg.E0POE;
mask.TTA = mask_reg.TTA;
mask.SMEN = SignExtend{2}(mask_reg.SMEN);
mask.FPEN = SignExtend{2}(mask_reg.FPEN);
mask.ZEN = SignExtend{2}(mask_reg.ZEN);
mask[32+: 32] = Zeros{32};
mask[26+: 2] = Zeros{2};
mask[22+: 2] = Zeros{2};
mask[18+: 2] = Zeros{2};
mask[0+: 16] = Zeros{16};
return mask;
end;
// EffectiveCPTRMASK_EL2()
// =======================
// Return the effective value of CPTRMASK_EL2.
func EffectiveCPTRMASK_EL2() => CPTR_EL2_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
var mask : CPTR_EL2_Type = Ones{64};
let mask_reg : CPTRMASK_EL2_Type = CPTRMASK_EL2();
if ELIsInHost(EL2) then
mask.TCPAC = mask_reg.TCPAC;
mask.TAM = mask_reg.TAM;
mask.E0POE = mask_reg.E0POE;
mask.TTA = mask_reg.TTA;
mask.SMEN = SignExtend{2}(mask_reg.SMEN);
mask.FPEN = SignExtend{2}(mask_reg.FPEN);
mask.ZEN = SignExtend{2}(mask_reg.ZEN);
mask[32+: 32] = Zeros{32};
mask[26+: 2] = Zeros{2};
mask[22+: 2] = Zeros{2};
mask[18+: 2] = Zeros{2};
mask[0+: 16] = Zeros{16};
else
mask.TCPAC = mask_reg.TCPAC;
mask.TAM = mask_reg.TAM;
mask.TTA = mask_reg.TTA;
mask.TSM = mask_reg.TSM;
mask.TFP = mask_reg.TFP;
mask.TZ = mask_reg.TZ;
mask[32+: 32] = Zeros{32};
mask[21+: 9] = Zeros{9};
mask[14+: 6] = Zeros{6};
mask[13+: 1] = '0';
mask[11+: 1] = '0';
mask[9+: 1] = '0';
mask[0+: 8] = Zeros{8};
end;
return mask;
end;
// EffectiveHCRMASK_EL2()
// ======================
// Return the effective value of HCRMASK_EL2.
func EffectiveHCRMASK_EL2() => HCR_EL2_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK2) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
var mask : HCR_EL2_Type = Ones{64};
let mask_reg : HCRMASK_EL2_Type = HCRMASK_EL2();
mask.TWEDEL = SignExtend{4}(mask_reg.TWEDEL);
mask.TWEDEn = mask_reg.TWEDEn;
mask.TID5 = mask_reg.TID5;
mask.DCT = mask_reg.DCT;
mask.ATA = mask_reg.ATA;
mask.TTLBOS = mask_reg.TTLBOS;
mask.TTLBIS = mask_reg.TTLBIS;
mask.EnSCXT = mask_reg.EnSCXT;
mask.TOCU = mask_reg.TOCU;
mask.AMVOFFEN = mask_reg.AMVOFFEN;
mask.TICAB = mask_reg.TICAB;
mask.TID4 = mask_reg.TID4;
mask.GPF = mask_reg.GPF;
mask.FIEN = mask_reg.FIEN;
mask.FWB = mask_reg.FWB;
mask.NV2 = mask_reg.NV2;
mask.AT = mask_reg.AT;
mask.NV1 = mask_reg.NV1;
mask.NV = mask_reg.NV;
mask.API = mask_reg.API;
mask.APK = mask_reg.APK;
mask.TEA = mask_reg.TEA;
mask.TERR = mask_reg.TERR;
mask.TLOR = mask_reg.TLOR;
mask.E2H = mask_reg.E2H;
mask.ID = mask_reg.ID;
mask.CD = mask_reg.CD;
mask.RW = mask_reg.RW;
mask.TRVM = mask_reg.TRVM;
mask.HCD = mask_reg.HCD;
mask.TDZ = mask_reg.TDZ;
mask.TGE = mask_reg.TGE;
mask.TVM = mask_reg.TVM;
mask.TTLB = mask_reg.TTLB;
mask.TPU = mask_reg.TPU;
mask.TPCP = mask_reg.TPCP;
mask.TSW = mask_reg.TSW;
mask.TACR = mask_reg.TACR;
mask.TIDCP = mask_reg.TIDCP;
mask.TSC = mask_reg.TSC;
mask.TID3 = mask_reg.TID3;
mask.TID2 = mask_reg.TID2;
mask.TID1 = mask_reg.TID1;
mask.TID0 = mask_reg.TID0;
mask.TWE = mask_reg.TWE;
mask.TWI = mask_reg.TWI;
mask.DC = mask_reg.DC;
mask.BSU = SignExtend{2}(mask_reg.BSU);
mask.FB = mask_reg.FB;
mask.VSE = mask_reg.VSE;
mask.VI = mask_reg.VI;
mask.VF = mask_reg.VF;
mask.AMO = mask_reg.AMO;
mask.IMO = mask_reg.IMO;
mask.FMO = mask_reg.FMO;
mask.PTW = mask_reg.PTW;
mask.SWIO = mask_reg.SWIO;
mask.VM = mask_reg.VM;
mask[38+: 2] = Zeros{2};
return mask;
end;
// EffectiveHCRXMASK_EL2()
// =======================
// Return the effective value of HCRXMASK_EL2.
func EffectiveHCRXMASK_EL2() => HCRX_EL2_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK2) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
var mask : HCRX_EL2_Type = Ones{64};
let mask_reg : HCRXMASK_EL2_Type = HCRXMASK_EL2();
mask.FNB = mask_reg.FNB;
mask.VTLBIDOSEn = mask_reg.VTLBIDOSEn;
mask.NVnTTLBOS = mask_reg.NVnTTLBOS;
mask.NVnTTLBIS = mask_reg.NVnTTLBIS;
mask.NVnTTLB = mask_reg.NVnTTLB;
mask.FDIT = mask_reg.FDIT;
mask.NVTGE = mask_reg.NVTGE;
mask.SRMASKEn = mask_reg.SRMASKEn;
mask.VTLBIDEn = mask_reg.VTLBIDEn;
mask.PACMEn = mask_reg.PACMEn;
mask.EnFPM = mask_reg.EnFPM;
mask.GCSEn = mask_reg.GCSEn;
mask.EnIDCP128 = mask_reg.EnIDCP128;
mask.EnSDERR = mask_reg.EnSDERR;
mask.TMEA = mask_reg.TMEA;
mask.EnSNERR = mask_reg.EnSNERR;
mask.D128En = mask_reg.D128En;
mask.PTTWI = mask_reg.PTTWI;
mask.SCTLR2En = mask_reg.SCTLR2En;
mask.TCR2En = mask_reg.TCR2En;
mask.MSCEn = mask_reg.MSCEn;
mask.MCE2 = mask_reg.MCE2;
mask.CMOW = mask_reg.CMOW;
mask.VFNMI = mask_reg.VFNMI;
mask.VINMI = mask_reg.VINMI;
mask.TALLINT = mask_reg.TALLINT;
mask.SMPME = mask_reg.SMPME;
mask.FGTnXS = mask_reg.FGTnXS;
mask.FnXS = mask_reg.FnXS;
mask.EnASR = mask_reg.EnASR;
mask.EnALS = mask_reg.EnALS;
mask.EnAS0 = mask_reg.EnAS0;
mask[37+: 27] = Zeros{27};
mask[28+: 3] = Zeros{3};
mask[12+: 2] = Zeros{2};
return mask;
end;
// EffectiveNVHCRMASK_EL2()
// ========================
// Return the effective value of NVHCRMASK_EL2.
func EffectiveNVHCRMASK_EL2() => NVHCR_EL2_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK2) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
var mask : NVHCR_EL2_Type = Ones{64};
let mask_reg : NVHCRMASK_EL2_Type = NVHCRMASK_EL2();
mask.TWEDEL = mask_reg.TWEDEL;
mask.TWEDEn = mask_reg.TWEDEn;
mask.TID5 = mask_reg.TID5;
mask.DCT = mask_reg.DCT;
mask.ATA = mask_reg.ATA;
mask.EnSCXT = mask_reg.EnSCXT;
mask.TOCU = mask_reg.TOCU;
mask.AMVOFFEN = mask_reg.AMVOFFEN;
mask.TICAB = mask_reg.TICAB;
mask.TID4 = mask_reg.TID4;
mask.GPF = mask_reg.GPF;
mask.FIEN = mask_reg.FIEN;
mask.FWB = mask_reg.FWB;
mask.NV2 = mask_reg.NV2;
mask.AT = mask_reg.AT;
mask.NV1 = mask_reg.NV1;
mask.NV = mask_reg.NV;
mask.API = mask_reg.API;
mask.APK = mask_reg.APK;
mask.TEA = mask_reg.TEA;
mask.TERR = mask_reg.TERR;
mask.TLOR = mask_reg.TLOR;
mask.E2H = mask_reg.E2H;
mask.ID = mask_reg.ID;
mask.CD = mask_reg.CD;
mask.RW = mask_reg.RW;
mask.HCD = mask_reg.HCD;
mask.TDZ = mask_reg.TDZ;
mask.TGE = mask_reg.TGE;
mask.TVM = mask_reg.TVM;
mask.TTLB = mask_reg.TTLB;
mask.TPU = mask_reg.TPU;
mask.TPCP = mask_reg.TPCP;
mask.TSW = mask_reg.TSW;
mask.TACR = mask_reg.TACR;
mask.TIDCP = mask_reg.TIDCP;
mask.TSC = mask_reg.TSC;
mask.TID3 = mask_reg.TID3;
mask.TID2 = mask_reg.TID2;
mask.TID1 = mask_reg.TID1;
mask.TID0 = mask_reg.TID0;
mask.TWE = mask_reg.TWE;
mask.TWI = mask_reg.TWI;
mask.DC = mask_reg.DC;
mask.BSU = mask_reg.BSU;
mask.FB = mask_reg.FB;
mask.VSE = mask_reg.VSE;
mask.VI = mask_reg.VI;
mask.VF = mask_reg.VF;
mask.AMO = mask_reg.AMO;
mask.IMO = mask_reg.IMO;
mask.FMO = mask_reg.FMO;
mask.PTW = mask_reg.PTW;
mask.SWIO = mask_reg.SWIO;
mask.VM = mask_reg.VM;
mask[61+: 3] = Zeros{3};
mask[38+: 2] = Zeros{2};
mask[11+: 1] = '0';
return mask;
end;
// EffectiveNVHCRXMASK_EL2()
// =========================
// Return the effective value of NVHCRXMASK_EL2.
func EffectiveNVHCRXMASK_EL2() => NVHCRX_EL2_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK2) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
var mask : NVHCRX_EL2_Type = Ones{64};
let mask_reg : NVHCRXMASK_EL2_Type = NVHCRXMASK_EL2();
mask.FNB = mask_reg.FNB;
mask.VTLBIDOSEn = mask_reg.VTLBIDOSEn;
mask.NVnTTLBOS = mask_reg.NVnTTLBOS;
mask.NVnTTLBIS = mask_reg.NVnTTLBIS;
mask.NVnTTLB = mask_reg.NVnTTLB;
mask.FDIT = mask_reg.FDIT;
mask.NVTGE = mask_reg.NVTGE;
mask.SRMASKEn = mask_reg.SRMASKEn;
mask.VTLBIDEn = mask_reg.VTLBIDEn;
mask.PACMEn = mask_reg.PACMEn;
mask.EnFPM = mask_reg.EnFPM;
mask.GCSEn = mask_reg.GCSEn;
mask.EnIDCP128 = mask_reg.EnIDCP128;
mask.EnSDERR = mask_reg.EnSDERR;
mask.TMEA = mask_reg.TMEA;
mask.EnSNERR = mask_reg.EnSNERR;
mask.D128En = mask_reg.D128En;
mask.PTTWI = mask_reg.PTTWI;
mask.SCTLR2En = mask_reg.SCTLR2En;
mask.TCR2En = mask_reg.TCR2En;
mask.MSCEn = mask_reg.MSCEn;
mask.MCE2 = mask_reg.MCE2;
mask.CMOW = mask_reg.CMOW;
mask.VFNMI = mask_reg.VFNMI;
mask.VINMI = mask_reg.VINMI;
mask.TALLINT = mask_reg.TALLINT;
mask.SMPME = mask_reg.SMPME;
mask.FGTnXS = mask_reg.FGTnXS;
mask.FnXS = mask_reg.FnXS;
mask.EnASR = mask_reg.EnASR;
mask.EnALS = mask_reg.EnALS;
mask.EnAS0 = mask_reg.EnAS0;
mask[37+: 27] = Zeros{27};
mask[28+: 3] = Zeros{3};
mask[12+: 2] = Zeros{2};
return mask;
end;
// EffectiveSCTLR2MASK_EL1()
// =========================
// Return the effective value of SCTLR2MASK_EL1.
func EffectiveSCTLR2MASK_EL1() => SCTLR2_EL1_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
if EL2Enabled() && (!IsHCRXEL2Enabled() || HCRX_EL2().SRMASKEn == '0') then
return Zeros{64};
end;
var mask : SCTLR2_EL1_Type = Ones{64};
let mask_reg : SCTLR2MASK_EL1_Type = SCTLR2MASK_EL1();
mask.TLBOSNIS = mask_reg.TLBOSNIS;
mask.FDIT = mask_reg.FDIT;
mask.BTD = mask_reg.BTD;
mask.BTD0 = mask_reg.BTD0;
mask.EnIA2 = mask_reg.EnIA2;
mask.EnIB2 = mask_reg.EnIB2;
mask.EnDA2 = mask_reg.EnDA2;
mask.EnDB2 = mask_reg.EnDB2;
mask.CPTM0 = mask_reg.CPTM0;
mask.CPTM = mask_reg.CPTM;
mask.CPTA0 = mask_reg.CPTA0;
mask.CPTA = mask_reg.CPTA;
mask.EnPACM0 = mask_reg.EnPACM0;
mask.EnPACM = mask_reg.EnPACM;
mask.EnIDCP128 = mask_reg.EnIDCP128;
mask.EASE = mask_reg.EASE;
mask.EnANERR = mask_reg.EnANERR;
mask.EnADERR = mask_reg.EnADERR;
mask.NMEA = mask_reg.NMEA;
mask[27+: 37] = Zeros{37};
mask[13+: 6] = Zeros{6};
mask[0+: 2] = Zeros{2};
return mask;
end;
// EffectiveSCTLR2MASK_EL2()
// =========================
// Return the effective value of SCTLR2MASK_EL2.
func EffectiveSCTLR2MASK_EL2() => SCTLR2_EL2_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
var mask : SCTLR2_EL2_Type = Ones{64};
let mask_reg : SCTLR2MASK_EL2_Type = SCTLR2MASK_EL2();
mask.TLBOSNIS = mask_reg.TLBOSNIS;
mask.FDIT = mask_reg.FDIT;
mask.BTD = mask_reg.BTD;
mask.BTD0 = mask_reg.BTD0;
mask.EnIA2 = mask_reg.EnIA2;
mask.EnIB2 = mask_reg.EnIB2;
mask.EnDA2 = mask_reg.EnDA2;
mask.EnDB2 = mask_reg.EnDB2;
mask.CPTM0 = mask_reg.CPTM0;
mask.CPTM = mask_reg.CPTM;
mask.CPTA0 = mask_reg.CPTA0;
mask.CPTA = mask_reg.CPTA;
mask.EnPACM0 = mask_reg.EnPACM0;
mask.EnPACM = mask_reg.EnPACM;
mask.EnIDCP128 = mask_reg.EnIDCP128;
mask.EASE = mask_reg.EASE;
mask.EnANERR = mask_reg.EnANERR;
mask.EnADERR = mask_reg.EnADERR;
mask.NMEA = mask_reg.NMEA;
mask.EMEC = mask_reg.EMEC;
mask[27+: 37] = Zeros{37};
mask[13+: 6] = Zeros{6};
mask[0+: 1] = '0';
return mask;
end;
// EffectiveSCTLRMASK_EL1()
// ========================
// Return the effective value of SCTLRMASK_EL1.
func EffectiveSCTLRMASK_EL1() => SCTLR_EL1_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
if EL2Enabled() && (!IsHCRXEL2Enabled() || HCRX_EL2().SRMASKEn == '0') then
return Zeros{64};
end;
var mask : SCTLR_EL1_Type = Ones{64};
let mask_reg : SCTLRMASK_EL1_Type = SCTLRMASK_EL1();
mask.TIDCP = mask_reg.TIDCP;
mask.SPINTMASK = mask_reg.SPINTMASK;
mask.NMI = mask_reg.NMI;
mask.EnTP2 = mask_reg.EnTP2;
mask.TCSO = mask_reg.TCSO;
mask.TCSO0 = mask_reg.TCSO0;
mask.EPAN = mask_reg.EPAN;
mask.EnALS = mask_reg.EnALS;
mask.EnAS0 = mask_reg.EnAS0;
mask.EnASR = mask_reg.EnASR;
mask.TWEDEL = SignExtend{4}(mask_reg.TWEDEL);
mask.TWEDEn = mask_reg.TWEDEn;
mask.DSSBS = mask_reg.DSSBS;
mask.ATA = mask_reg.ATA;
mask.ATA0 = mask_reg.ATA0;
mask.TCF = SignExtend{2}(mask_reg.TCF);
mask.TCF0 = SignExtend{2}(mask_reg.TCF0);
mask.ITFSB = mask_reg.ITFSB;
mask.BT1 = mask_reg.BT1;
mask.BT0 = mask_reg.BT0;
mask.EnFPM = mask_reg.EnFPM;
mask.MSCEn = mask_reg.MSCEn;
mask.CMOW = mask_reg.CMOW;
mask.EnIA = mask_reg.EnIA;
mask.EnIB = mask_reg.EnIB;
mask.LSMAOE = mask_reg.LSMAOE;
mask.nTLSMD = mask_reg.nTLSMD;
mask.EnDA = mask_reg.EnDA;
mask.UCI = mask_reg.UCI;
mask.EE = mask_reg.EE;
mask.E0E = mask_reg.E0E;
mask.SPAN = mask_reg.SPAN;
mask.EIS = mask_reg.EIS;
mask.IESB = mask_reg.IESB;
mask.TSCXT = mask_reg.TSCXT;
mask.WXN = mask_reg.WXN;
mask.nTWE = mask_reg.nTWE;
mask.nTWI = mask_reg.nTWI;
mask.UCT = mask_reg.UCT;
mask.DZE = mask_reg.DZE;
mask.EnDB = mask_reg.EnDB;
mask.I = mask_reg.I;
mask.EOS = mask_reg.EOS;
mask.EnRCTX = mask_reg.EnRCTX;
mask.UMA = mask_reg.UMA;
mask.SED = mask_reg.SED;
mask.ITD = mask_reg.ITD;
mask.nAA = mask_reg.nAA;
mask.CP15BEN = mask_reg.CP15BEN;
mask.SA0 = mask_reg.SA0;
mask.SA = mask_reg.SA;
mask.C = mask_reg.C;
mask.A = mask_reg.A;
mask.M = mask_reg.M;
mask[50+: 4] = Zeros{4};
mask[17+: 1] = '0';
return mask;
end;
// EffectiveSCTLRMASK_EL2()
// ========================
// Return the effective value of SCTLRMASK_EL2.
func EffectiveSCTLRMASK_EL2() => SCTLR_EL2_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
var mask : SCTLR_EL2_Type = Ones{64};
let mask_reg : SCTLRMASK_EL2_Type = SCTLRMASK_EL2();
mask.TIDCP = mask_reg.TIDCP;
mask.SPINTMASK = mask_reg.SPINTMASK;
mask.NMI = mask_reg.NMI;
mask.EnTP2 = mask_reg.EnTP2;
mask.TCSO = mask_reg.TCSO;
mask.TCSO0 = mask_reg.TCSO0;
mask.EPAN = mask_reg.EPAN;
mask.EnALS = mask_reg.EnALS;
mask.EnAS0 = mask_reg.EnAS0;
mask.EnASR = mask_reg.EnASR;
mask.TWEDEL = SignExtend{4}(mask_reg.TWEDEL);
mask.TWEDEn = mask_reg.TWEDEn;
mask.DSSBS = mask_reg.DSSBS;
mask.ATA = mask_reg.ATA;
mask.ATA0 = mask_reg.ATA0;
mask.TCF = SignExtend{2}(mask_reg.TCF);
mask.TCF0 = SignExtend{2}(mask_reg.TCF0);
mask.ITFSB = mask_reg.ITFSB;
mask.BT = mask_reg.BT;
mask.BT0 = mask_reg.BT0;
mask.EnFPM = mask_reg.EnFPM;
mask.MSCEn = mask_reg.MSCEn;
mask.CMOW = mask_reg.CMOW;
mask.EnIA = mask_reg.EnIA;
mask.EnIB = mask_reg.EnIB;
mask.LSMAOE = mask_reg.LSMAOE;
mask.nTLSMD = mask_reg.nTLSMD;
mask.EnDA = mask_reg.EnDA;
mask.UCI = mask_reg.UCI;
mask.EE = mask_reg.EE;
mask.E0E = mask_reg.E0E;
mask.SPAN = mask_reg.SPAN;
mask.EIS = mask_reg.EIS;
mask.IESB = mask_reg.IESB;
mask.TSCXT = mask_reg.TSCXT;
mask.WXN = mask_reg.WXN;
mask.nTWE = mask_reg.nTWE;
mask.nTWI = mask_reg.nTWI;
mask.UCT = mask_reg.UCT;
mask.DZE = mask_reg.DZE;
mask.EnDB = mask_reg.EnDB;
mask.I = mask_reg.I;
mask.EOS = mask_reg.EOS;
mask.EnRCTX = mask_reg.EnRCTX;
mask.SED = mask_reg.SED;
mask.ITD = mask_reg.ITD;
mask.nAA = mask_reg.nAA;
mask.CP15BEN = mask_reg.CP15BEN;
mask.SA0 = mask_reg.SA0;
mask.SA = mask_reg.SA;
mask.C = mask_reg.C;
mask.A = mask_reg.A;
mask.M = mask_reg.M;
mask[50+: 4] = Zeros{4};
mask[17+: 1] = '0';
mask[9+: 1] = '0';
return mask;
end;
// EffectiveTCR2MASK_EL1()
// =======================
// Return the effective value of TCR2MASK_EL1.
func EffectiveTCR2MASK_EL1() => TCR2_EL1_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
if EL2Enabled() && (!IsHCRXEL2Enabled() || HCRX_EL2().SRMASKEn == '0') then
return Zeros{64};
end;
var mask : TCR2_EL1_Type = Ones{64};
let mask_reg : TCR2MASK_EL1_Type = TCR2MASK_EL1();
mask.FNGNA1 = mask_reg.FNGNA1;
mask.FNGNA0 = mask_reg.FNGNA0;
mask.FNG1 = mask_reg.FNG1;
mask.FNG0 = mask_reg.FNG0;
mask.A2 = mask_reg.A2;
mask.DisCH1 = mask_reg.DisCH1;
mask.DisCH0 = mask_reg.DisCH0;
mask.HAFT = mask_reg.HAFT;
mask.PTTWI = mask_reg.PTTWI;
mask.D128 = mask_reg.D128;
mask.AIE = mask_reg.AIE;
mask.POE = mask_reg.POE;
mask.E0POE = mask_reg.E0POE;
mask.PIE = mask_reg.PIE;
mask.PnCH = mask_reg.PnCH;
mask[22+: 42] = Zeros{42};
mask[19+: 1] = '0';
mask[12+: 2] = Zeros{2};
mask[6+: 4] = Zeros{4};
return mask;
end;
// EffectiveTCR2MASK_EL2()
// =======================
// Return the effective value of TCR2MASK_EL2.
func EffectiveTCR2MASK_EL2() => TCR2_EL2_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
var mask : TCR2_EL2_Type = Ones{64};
let mask_reg : TCR2MASK_EL2_Type = TCR2MASK_EL2();
if !ELIsInHost(EL2) then
mask.AMEC0 = mask_reg.AMEC0;
mask.HAFT = mask_reg.HAFT;
mask.PTTWI = mask_reg.PTTWI;
mask.AIE = mask_reg.AIE;
mask.POE = mask_reg.POE;
mask.PIE = mask_reg.PIE;
mask.PnCH = mask_reg.PnCH;
mask[13+: 51] = Zeros{51};
mask[5+: 5] = Zeros{5};
mask[2+: 1] = '0';
else
mask.FNG1 = mask_reg.FNG1;
mask.FNG0 = mask_reg.FNG0;
mask.A2 = mask_reg.A2;
mask.DisCH1 = mask_reg.DisCH1;
mask.DisCH0 = mask_reg.DisCH0;
mask.AMEC1 = mask_reg.AMEC1;
mask.AMEC0 = mask_reg.AMEC0;
mask.HAFT = mask_reg.HAFT;
mask.PTTWI = mask_reg.PTTWI;
mask.D128 = mask_reg.D128;
mask.AIE = mask_reg.AIE;
mask.POE = mask_reg.POE;
mask.E0POE = mask_reg.E0POE;
mask.PIE = mask_reg.PIE;
mask.PnCH = mask_reg.PnCH;
mask[19+: 45] = Zeros{45};
mask[6+: 4] = Zeros{4};
end;
return mask;
end;
// EffectiveTCRMASK_EL1()
// ======================
// Return the effective value of TCRMASK_EL1.
func EffectiveTCRMASK_EL1() => TCR_EL1_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
if EL2Enabled() && (!IsHCRXEL2Enabled() || HCRX_EL2().SRMASKEn == '0') then
return Zeros{64};
end;
var mask : TCR_EL1_Type = Ones{64};
let mask_reg : TCRMASK_EL1_Type = TCRMASK_EL1();
mask.MTX1 = mask_reg.MTX1;
mask.MTX0 = mask_reg.MTX0;
mask.DS = mask_reg.DS;
mask.TCMA1 = mask_reg.TCMA1;
mask.TCMA0 = mask_reg.TCMA0;
mask.E0PD1 = mask_reg.E0PD1;
mask.E0PD0 = mask_reg.E0PD0;
mask.NFD1 = mask_reg.NFD1;
mask.NFD0 = mask_reg.NFD0;
mask.TBID1 = mask_reg.TBID1;
mask.TBID0 = mask_reg.TBID0;
mask.HWU162 = mask_reg.HWU162;
mask.HWU161 = mask_reg.HWU161;
mask.HWU160 = mask_reg.HWU160;
mask.HWU159 = mask_reg.HWU159;
mask.HWU062 = mask_reg.HWU062;
mask.HWU061 = mask_reg.HWU061;
mask.HWU060 = mask_reg.HWU060;
mask.HWU059 = mask_reg.HWU059;
mask.HPD1 = mask_reg.HPD1;
mask.HPD0 = mask_reg.HPD0;
mask.HD = mask_reg.HD;
mask.HA = mask_reg.HA;
mask.TBI1 = mask_reg.TBI1;
mask.TBI0 = mask_reg.TBI0;
mask.AS = mask_reg.AS;
mask.IPS = SignExtend{3}(mask_reg.IPS);
mask.TG1 = SignExtend{2}(mask_reg.TG1);
mask.SH1 = SignExtend{2}(mask_reg.SH1);
mask.ORGN1 = SignExtend{2}(mask_reg.ORGN1);
mask.IRGN1 = SignExtend{2}(mask_reg.IRGN1);
mask.EPD1 = mask_reg.EPD1;
mask.A1 = mask_reg.A1;
mask.T1SZ = SignExtend{6}(mask_reg.T1SZ);
mask.TG0 = SignExtend{2}(mask_reg.TG0);
mask.SH0 = SignExtend{2}(mask_reg.SH0);
mask.ORGN0 = SignExtend{2}(mask_reg.ORGN0);
mask.IRGN0 = SignExtend{2}(mask_reg.IRGN0);
mask.EPD0 = mask_reg.EPD0;
mask.T0SZ = SignExtend{6}(mask_reg.T0SZ);
mask[62+: 2] = Zeros{2};
mask[35+: 1] = '0';
mask[6+: 1] = '0';
return mask;
end;
// EffectiveTCRMASK_EL2()
// ======================
// Return the effective value of TCRMASK_EL2.
func EffectiveTCRMASK_EL2() => TCR_EL2_Type
begin
if !IsFeatureImplemented(FEAT_SRMASK) then return Zeros{64}; end;
if HaveEL(EL3) && SCR_EL3().SRMASKEn == '0' then return Zeros{64}; end;
var mask : TCR_EL2_Type = Ones{64};
let mask_reg : TCRMASK_EL2_Type = TCRMASK_EL2();
if !ELIsInHost(EL2) then
mask.MTX = mask_reg.MTX;
mask.DS = mask_reg.DS;
mask.TCMA = mask_reg.TCMA;
mask.TBID = mask_reg.TBID;
mask.HWU62 = mask_reg.HWU62;
mask.HWU61 = mask_reg.HWU61;
mask.HWU60 = mask_reg.HWU60;
mask.HWU59 = mask_reg.HWU59;
mask.HPD = mask_reg.HPD;
mask.HD = mask_reg.HD;
mask.HA = mask_reg.HA;
mask.TBI = mask_reg.TBI;
mask.PS = SignExtend{3}(mask_reg.PS);
mask.TG0 = SignExtend{2}(mask_reg.TG0);
mask.SH0 = SignExtend{2}(mask_reg.SH0);
mask.ORGN0 = SignExtend{2}(mask_reg.ORGN0);
mask.IRGN0 = SignExtend{2}(mask_reg.IRGN0);
mask.T0SZ = SignExtend{6}(mask_reg.T0SZ);
mask[34+: 30] = Zeros{30};
mask[31+: 1] = '0';
mask[23+: 1] = '0';
mask[19+: 1] = '0';
mask[6+: 2] = Zeros{2};
else
mask.MTX1 = mask_reg.MTX1;
mask.MTX0 = mask_reg.MTX0;
mask.DS = mask_reg.DS;
mask.TCMA1 = mask_reg.TCMA1;
mask.TCMA0 = mask_reg.TCMA0;
mask.E0PD1 = mask_reg.E0PD1;
mask.E0PD0 = mask_reg.E0PD0;
mask.NFD1 = mask_reg.NFD1;
mask.NFD0 = mask_reg.NFD0;
mask.TBID1 = mask_reg.TBID1;
mask.TBID0 = mask_reg.TBID0;
mask.HWU162 = mask_reg.HWU162;
mask.HWU161 = mask_reg.HWU161;
mask.HWU160 = mask_reg.HWU160;
mask.HWU159 = mask_reg.HWU159;
mask.HWU062 = mask_reg.HWU062;
mask.HWU061 = mask_reg.HWU061;
mask.HWU060 = mask_reg.HWU060;
mask.HWU059 = mask_reg.HWU059;
mask.HPD1 = mask_reg.HPD1;
mask.HPD0 = mask_reg.HPD0;
mask.HD = mask_reg.HD;
mask.HA = mask_reg.HA;
mask.TBI1 = mask_reg.TBI1;
mask.TBI0 = mask_reg.TBI0;
mask.AS = mask_reg.AS;
mask.IPS = SignExtend{3}(mask_reg.IPS);
mask.TG1 = SignExtend{2}(mask_reg.TG1);
mask.SH1 = SignExtend{2}(mask_reg.SH1);
mask.ORGN1 = SignExtend{2}(mask_reg.ORGN1);
mask.IRGN1 = SignExtend{2}(mask_reg.IRGN1);
mask.EPD1 = mask_reg.EPD1;
mask.A1 = mask_reg.A1;
mask.T1SZ = SignExtend{6}(mask_reg.T1SZ);
mask.TG0 = SignExtend{2}(mask_reg.TG0);
mask.SH0 = SignExtend{2}(mask_reg.SH0);
mask.ORGN0 = SignExtend{2}(mask_reg.ORGN0);
mask.IRGN0 = SignExtend{2}(mask_reg.IRGN0);
mask.EPD0 = mask_reg.EPD0;
mask.T0SZ = SignExtend{6}(mask_reg.T0SZ);
mask[62+: 2] = Zeros{2};
mask[35+: 1] = '0';
mask[6+: 1] = '0';
end;
return mask;
end;
2025-12_rel2025-09_diff_tag
2025-12-102025-11-28 16:4129:4505
Copyright © 2010-2025 Arm Limited or its affiliates. All rights reserved. This document is Non-Confidential.
| (old) | htmldiff from- | (new) |