/*  *********************************************************************
    *  ASTRIS - Remote JTAG probe
    *
    *  ARM Architecture support			File: astris_arm.h
    *
    *  Support for the ARM ISA is defined here
    *
    *********************************************************************
    *
    *  Copyright (C) 2009-2011 Apple, Inc. All rights reserved.
    *
    *  This document is the property of Apple Inc.
    *  It is considered confidential and proprietary.
    *
    *  This document may not be reproduced or transmitted in any form,
    *  in whole or in part, without the express written permission of
    *  Apple Inc.
    ********************************************************************* */

#ifndef _ASTRIS_ARM_H
#define _ASTRIS_ARM_H

#include "bitfields.h"

typedef enum {
    ARMDAPDUMMY,
    ARMDBGV4,
    ARMDBGV6,
    ARMDBGV6_1,
    ARMDBGV7,
    ARMDBGV7M,
    ARMDBGV8,
    XTENSA,
    ARC,
    LACC
} dbgarch_t;

//
// Canonical mode names
//
#define K_ARM_MODE_THUMB   "T32"
#define K_ARM_MODE_THUMBEE "T32EE"
#define K_ARM_MODE_ARM     "A32"
#define K_ARM_MODE_ARM64   "A64"

//
// Instruction lengths
//

#define ARM32_INST_LEN 4
#define THUMB_INST_LEN 2

//
// Breakpoint instructions
//

#define ARM32_INST_BRPT 0xE1200070
#define ARM64_INST_HALT 0xD4400000
#define THUMB_INST_BRPT 0xBE00

/******************************************************************************
 ******************************************************************************
 **                          ARM7 (ARMv4/EICE)                               **
 ******************************************************************************
 *****************************************************************************/

//
//  ARM instructions
//
#define ARM_MRS_R0_CPSR  0xe10f0000
#define ARM_MRS_R0_SPSR  0xe14f0000
#define ARM_STM_R0(mask) (0xe8000000 | (mask))
#define ARM_NOP          0xe1a08008
#define ARM_LDM_R0(mask) (0xe8100000 | (mask))
#define ARM_MSR_CPSR_R0  0xe129f000

/*
 *  ARM Scan List structure.  We hold the sequence of
 *  scans to do common operations (like halt/resume) in
 *  an array so we can play them back easily.
 */
#define M_SCAN_OUT      0x80000000
#define M_SCAN_IN       0x40000000
#define M_SCAN_EXEC     0x20000000
#define M_SCAN_OUTIDX   0x10000000
#define M_SCAN_SYSSPEED 0x08000000
#define M_SCAN_RESTART  0x04000000
#define M_SCAN_WAITHALT 0x02000000

#define V_SCAN_REGIDX(x) (x)
#define G_SCAN_REGIDX(x) ((x) & 0xFF)

/*
 * Macros that expand to scanlist entries.
 */
#define SCAN_STUFF(instr)         {(M_SCAN_EXEC), (instr)}
#define SCAN_STUFF_SYS(instr)     {(M_SCAN_SYSSPEED | M_SCAN_EXEC), (instr)}
#define SCAN_STUFF_RESTART(instr) {(M_SCAN_RESTART | M_SCAN_EXEC), (instr)}
#define SCAN_RECV(idx)            {(M_SCAN_IN | V_SCAN_REGIDX(idx)), (0)}
#define SCAN_SEND(val)            {(M_SCAN_OUT), (val)}
#define SCAN_SENDIDX(idx)         {(M_SCAN_OUTIDX | V_SCAN_REGIDX(idx)), (0)}
#define SCAN_RESTART()            {M_SCAN_RESTART, 0}
#define SCAN_WAITHALT()           {M_SCAN_WAITHALT, 0}

/*
 * Register indicies
 */
#define REGIDX_R0   0
#define REGIDX_R1   1
#define REGIDX_R2   2
#define REGIDX_R3   3
#define REGIDX_R4   4
#define REGIDX_R5   5
#define REGIDX_R6   6
#define REGIDX_R7   7
#define REGIDX_R8   8
#define REGIDX_R9   9
#define REGIDX_R10  10
#define REGIDX_R11  11
#define REGIDX_R12  12
#define REGIDX_R13  13
#define REGIDX_R14  14
#define REGIDX_R15  15
#define REGIDX_PC   REGIDX_R15
#define REGIDX_CPSR 16

/*
 * User mode
 */
#define REGIDX_R13_USR 17
#define REGIDX_R14_USR 18

/*
 * FIQ mode
 */
#define REGIDX_R8_FIQ   19
#define REGIDX_R9_FIQ   20
#define REGIDX_R10_FIQ  21
#define REGIDX_R11_FIQ  22
#define REGIDX_R12_FIQ  23
#define REGIDX_R13_FIQ  24
#define REGIDX_R14_FIQ  25
#define REGIDX_SPSR_FIQ 26

/*
 * Abort mode
 */
#define REGIDX_R13_ABORT  27
#define REGIDX_R14_ABORT  28
#define REGIDX_SPSR_ABORT 29

/*
 * IRQ mode
 */
#define REGIDX_R13_IRQ  30
#define REGIDX_R14_IRQ  31
#define REGIDX_SPSR_IRQ 32

/*
 * Undefined mode
 */
#define REGIDX_R13_UNDEF  33
#define REGIDX_R14_UNDEF  34
#define REGIDX_SPSR_UNDEF 35

/*
 * Supervisor mode
 */
#define REGIDX_R13_SUPER  36
#define REGIDX_R14_SUPER  37
#define REGIDX_SPSR_SUPER 38

#define REGIDX_LAST_REALREG REGIDX_SPSR_SUPER

/*
 * These aren't really registers, but we use them to do scans for
 * data transfer.
 */
#define REGIDX_DATA_ADDR 39 /* Transfer address */
#define REGIDX_DATA_DATA 40 /* Transfer data */
#define REGIDX_DATA_CPSR 41 /* CPSR after transfer */

#define A7_REGIDX_MAX 42

/******************************************************************************
 ******************************************************************************
 **                                    ARM32                                 **
 ******************************************************************************
 *****************************************************************************/

/***********************
 * Register definitions
 **********************/

// Predefined ARM32 coprocessor registers
// Index values for astris_arm32cpu.cpp:: static AXregid_t cpregs[]
typedef enum {
// ARM architected registers
    K_COP_DBGDTRTX,
    K_COP_DBGDSCR,

    K_COP_DFSR,
    K_COP_ADFSR,
    K_COP_DACR,
    K_COP_DFAR,

    K_COP_CSSELR,
    K_COP_CCSIDR,
    K_COP_ICIALLUI,
    K_COP_ICIMVAU,
    K_COP_DCCMVAC,
    K_COP_DCCSW,
    K_COP_DCCIMVAU,
    K_COP_DCCIMVAC,
    K_COP_DCCISW,
    K_COP_DSB,

    K_COP_SCTLR,
    K_COP_ACTLR,
    K_COP_TTBR0,
    K_COP_TTBR1,
    K_COP_TTBCR,
// Cortex A8
    K_COP_RD_DTAG,
    K_COP_RD_DDATA,
    K_COP_RD_DHVAB,
    K_COP_WR_DTAG,
    K_COP_WR_DDATA,
    K_COP_DDATA0,
    K_COP_DDATA1,
    K_COP_RD_ITAG,
    K_COP_RD_IDATA,
    K_COP_RD_IHVAB,
    K_COP_WR_ITAG,
    K_COP_WR_IDATA,
    K_COP_IDATA0,
    K_COP_IDATA1,
    K_COP_RD_DCAM,
    K_COP_RD_DATTR,
    K_COP_RD_DPA,
    K_COP_RD_ICAM,
    K_COP_RD_IATTR,
    K_COP_RD_IPA,
// Swift
    K_COP_L2DATA0,
    K_COP_L2DATA1,
    K_COP_L2DATA2,
    K_COP_WR_L2TAG,
    K_COP_WR_L2DATA,
    K_COP_WR_L2PARITY,
    K_COP_RD_L2TAG,
    K_COP_RD_L2DATA,
    K_COP_RD_L2PARITY,
    K_COP_WR_HID0,
    K_COP_WR_HID9,
    K_COP_BIUERRSTS,
    K_COP_BIUERRINF,
    K_COP_BIUERRADR,
    K_COP_LSUERRSTS,
    K_COP_LSUERRADR,
    K_COP_FEDERRSTS,
    K_COP_FEDERRADR,
    K_COP_L2CERRSTS,
    K_COP_L2CERRINF,
    K_COP_L2CERRADR,
// V7A Translation Support
    K_COP_PAR,
    K_COP_PAR64,
    K_COP_ATS1CPR,
    K_COP_ATS1CPW,
    K_COP_ATS1CUR,
    K_COP_ATS1CUW,
    K_COP_ATS12NSOPR,
    K_COP_ATS12NSOPW,
    K_COP_ATS12NSOUR,
    K_COP_ATS12NSOUW,

    K_LAST_COP_REG
} coproc_t;

// AXregid_t for ARM32 register access, forced to line up with GDB numbering
// for simplicity
#define REG_GPR_0 0
#define REG_SP    13
#define REG_LR    14
#define REG_PC    15
#define REG_FPR_0 16 // these are legacy soft-fp registers,
#define REG_FPS   24 // not used in armv7 and later
#define REG_CPSR  25
#define REG_S0    26
#define REG_FPSCR 58
#define REG_D16   59
#define REG_D0    75
#define REG_Q0    91
#define REG_SPSR  107     // only used when accessing explicit regsets

// Masks to deal with coprocessor registers, either enumerated coproc_t
// or arbitrary full A32 MRC/MCR field encodings and VFP/NEON 64-bit register numbers
#define REG_COPROC_T 0x80000000
#define REG_COP_ARB  0x40000000
#define REG_COP_64   0x20000000
#define REG_COP_VFP  0x10000000
#define REG_COP_MASK 0xF0000000

// Masks to deal with banked registers in specific PL1/EL1 modes
#define REG_REGSETFLG  0x08000000
#define REG_REGSETMASK 0x0F000000

// [API] Construct arbitrary coprocessor registers
// ARMv7 32-bit coprocessor register encoding
#define ARM_CPREG(coproc, op1, CRn, CRm, op2) \
    (REG_COP_ARB | ((coproc) << 8) | ((op1) << 21) | ((CRn) << 16) | ((CRm) << 0) | ((op2) << 5))
// ARMv7 64-bit coprocessor register encoding
#define ARM_CP64REG(coproc, op1, CRm) \
    (REG_COP_ARB | REG_COP_64 | ((coproc) << 8) | ((op1) << 4) | ((CRm) << 0))

// [API] Convert a coproc_t into the register number space
#define COP_TO_REG(r) (AXregid_t)((r) | REG_COPROC_T)

// Definitions for PL1/EL1 modes
#define REGSET_USERSYS    0
#define REGSET_SUPER      1
#define REGSET_ABORT      2
#define REGSET_UNDEF      3
#define REGSET_INTR       4
#define REGSET_FIQ        5
#define REGSET_HYPERVISOR 6
#define REGSET_MONITOR    7
#define REGSET_MAX        8

// Count of indexed register slots for any given register set
#define REGSET_INDEX_COUNT 16

// [API] Construct a banked register ID
#define REG_REGSET(_m, _r) (AXregid_t)(REG_REGSETFLG | ((_m) << 24) | (_r))

// [INTERNAL] Tests on AXregid_t to determine what kind (if any) of corprocessor register is it
#define IS_COPROC(_r)   ((_r) & REG_COP_MASK)
#define IS_COP_ARB(_r)  ((_r) & REG_COP_ARB)
#define IS_COPROC_T(_r) ((_r) & REG_COPROC_T)
#define IS_COP_64(_r)   ((_r) & REG_COP_64)
#define IS_VFP_64(_r)   (((_r) & REG_COP_MASK) == REG_COP_VFP)

// [INTERNAL] Strip marker out of coprocessor number, both coproc_t and arbitrary formats
#define REG_TO_COP(r) (coproc_t)((r) & ~REG_COP_MASK)

// [INTERNAL] Test on AXregid_t to find a banked register
#define IS_REGSET(_r) ((_r) & REG_REGSETFLG)

// [INTERNAL] Determine the PL1/EL1 mode the register belongs to
#define REG_GETREGSET(_r)     (((_r) >> 24) & 7)
#define REG_GETREGSET_REG(_r) ((_r) & ~REG_REGSETMASK)

/**************************
 *  CPSR field definitions
 *************************/

#define M_CPSR_N _MM_MAKEMASK1(31)
#define M_CPSR_Z _MM_MAKEMASK1(30)
#define M_CPSR_C _MM_MAKEMASK1(29)
#define M_CPSR_V _MM_MAKEMASK1(28)
#define M_CPSR_Q _MM_MAKEMASK1(27)
#define M_CPSR_J _MM_MAKEMASK1(26)

#define S_CPSR_IT    10
#define M_CPSR_IT    _MM_MAKEMASK(6, S_CPSR_IT)
#define V_CPSR_IT(v) _MM_MAKEVALUE((v), S_CPSR_IT)
#define G_CPSR_IT(v) _MM_GETVALUE((v), S_CPSR_IT, M_CPSR_IT)

#define M_CPSR_E _MM_MAKEMASK1(9)
#define M_CPSR_A _MM_MAKEMASK1(8)
#define M_CPSR_I _MM_MAKEMASK1(7)
#define M_CPSR_F _MM_MAKEMASK1(6)
#define M_CPSR_T _MM_MAKEMASK1(5)

#define S_CPSR_M    0
#define M_CPSR_M    _MM_MAKEMASK(5, S_CPSR_M)
#define V_CPSR_M(v) _MM_MAKEVALUE((v), S_CPSR_M)
#define G_CPSR_M(v) _MM_GETVALUE((v), S_CPSR_M, M_CPSR_M)

#define M_CPSR_M_64 _MM_MAKEMASK1(4) // ARM64

#define K_CPSR_M_USER   0x10
#define K_CPSR_M_FIQ    0x11
#define K_CPSR_M_IRQ    0x12
#define K_CPSR_M_SUP    0x13
#define K_CPSR_M_ABORT  0x17
#define K_CPSR_M_UNDEF  0x1B
#define K_CPSR_M_SYSTEM 0x1F
#define K_CPSR_M_SECMON 0x16

/* DPSR Values */

static const uint32_t
/* Just SPSel */
    S_ARM64_DSPSR_SPSEL = 0,
/* Together Mode: EL + SPSel */
    S_ARM64_DSPSR_MODE = 0,
/* Just EL */
    S_ARM64_DSPSR_EL   = 2,
    S_ARM64_DSPSR_RW   = 4,
    S_ARM64_DSPSR_DAIF = 6,
    S_ARM64_DSPSR_NZVC = 28;

static const uint32_t
    M_ARM64_DSPSR_SPSEL = _MM_MAKEMASK(1, S_ARM64_DSPSR_SPSEL),
    M_ARM64_DSPSR_MODE  = _MM_MAKEMASK(4, S_ARM64_DSPSR_MODE),
    M_ARM64_DSPSR_EL    = _MM_MAKEMASK(2, S_ARM64_DSPSR_EL),
    M_ARM64_DSPSR_RW    = _MM_MAKEMASK(1, S_ARM64_DSPSR_RW),
    M_ARM64_DSPSR_DAIF  = _MM_MAKEMASK(4, S_ARM64_DSPSR_DAIF),
    M_ARM64_DSPSR_NZVC  = _MM_MAKEMASK(4, S_ARM64_DSPSR_NZVC);

/*
 * SCTLR shift values
 */
static const uint32_t
    S_SCTLR_MMU     = 0,  // MMU enable for EL1 and EL0 stage 1 address translation
    S_SCTLR_A       = 1,  // Alignment check enable
    S_SCTLR_C       = 2,  // Cache enable
    S_SCTLR_CP15BEN = 5,  // CP15 barrier enable
    S_SCTLR_B       = 7,  // in ARMv7 this bit is RAZ/SBZP, indicating use of the endianness model
    S_SCTLR_SW      = 10, // SWP and SWPB enable
    S_SCTLR_Z       = 11, // Branch prediction enable
    S_SCTLR_I       = 12, // Instruction cache enable - global enable bit for instruction caches
    S_SCTLR_V       = 13, // Vectors bit - selects the base address of the exception vectors
    S_SCTLR_RR      = 14, // Round Robin select
    S_SCTLR_HA      = 17, // Hardware Access flag enable
    S_SCTLR_WXN     = 19, // Write permission implies XN (Execute Never) (if Virtualization Extensions)
    S_SCTLR_UWXN    = 20, // Unprivileged write permission implies PL1 XN (if Virtualization Extensions)
    S_SCTLR_FI      = 21, // Fast interrupts configuration enable
    S_SCTLR_U       = 22, // In ARMv7 this bit is RAO/SBOP, indicating use of the alignment model
    S_SCTLR_VE      = 24, // Interrupt Vectors Enable
    S_SCTLR_EE      = 25, // Exception Endianness of translation table lookups
    S_SCTLR_NMFI    = 27, // Non-maskable FIQ (NMFI) support
    S_SCTLR_TRE     = 28, // TEX remap enable
    S_SCTLR_AFE     = 29, // Access flag enable
    S_SCTLR_TE      = 30; // Thumb Exception enable

/*
 * SCTLR mask values
 */
static const uint32_t
    M_SCTLR_MMU     = _MM_MAKEMASK1(S_SCTLR_MMU),
    M_SCTLR_A       = _MM_MAKEMASK1(S_SCTLR_A),
    M_SCTLR_C       = _MM_MAKEMASK1(S_SCTLR_C),
    M_SCTLR_CP15BEN = _MM_MAKEMASK1(S_SCTLR_CP15BEN),
    M_SCTLR_B       = _MM_MAKEMASK1(S_SCTLR_B),
    M_SCTLR_SW      = _MM_MAKEMASK1(S_SCTLR_SW),
    M_SCTLR_Z       = _MM_MAKEMASK1(S_SCTLR_Z),
    M_SCTLR_I       = _MM_MAKEMASK1(S_SCTLR_I),
    M_SCTLR_V       = _MM_MAKEMASK1(S_SCTLR_V),
    M_SCTLR_RR      = _MM_MAKEMASK1(S_SCTLR_RR),
    M_SCTLR_HA      = _MM_MAKEMASK1(S_SCTLR_HA),
    M_SCTLR_WXN     = _MM_MAKEMASK1(S_SCTLR_WXN),
    M_SCTLR_UWXN    = _MM_MAKEMASK1(S_SCTLR_UWXN),
    M_SCTLR_FI      = _MM_MAKEMASK1(S_SCTLR_FI),
    M_SCTLR_U       = _MM_MAKEMASK1(S_SCTLR_U),
    M_SCTLR_VE      = _MM_MAKEMASK1(S_SCTLR_VE),
    M_SCTLR_EE      = _MM_MAKEMASK1(S_SCTLR_EE),
    M_SCTLR_NMFI    = _MM_MAKEMASK1(S_SCTLR_NMFI),
    M_SCTLR_TRE     = _MM_MAKEMASK1(S_SCTLR_TRE),
    M_SCTLR_AFE     = _MM_MAKEMASK1(S_SCTLR_AFE),
    M_SCTLR_TE      = _MM_MAKEMASK1(S_SCTLR_TE);

/*
 * PRRR shift values
 */
static const uint32_t
    S_PRRR_TR0  = 0,  // Primary TEX mapping for memory attributes 0
    S_PRRR_TR1  = 2,  // Primary TEX mapping for memory attributes 1
    S_PRRR_TR2  = 4,  // Primary TEX mapping for memory attributes 2
    S_PRRR_TR3  = 6,  // Primary TEX mapping for memory attributes 3
    S_PRRR_TR4  = 8,  // Primary TEX mapping for memory attributes 4
    S_PRRR_TR5  = 10, // Primary TEX mapping for memory attributes 5
    S_PRRR_TR6  = 12, // Primary TEX mapping for memory attributes 6
    S_PRRR_TR7  = 14, // Primary TEX mapping for memory attributes 7
    S_PRRR_DS0  = 16, // Mapping of S = 0 attribute for device memory
    S_PRRR_DS1  = 17, // Mapping of S = 1 attribute for device memory
    S_PRRR_NS0  = 18, // Mapping of S = 0 attribute for normal memory
    S_PRRR_NS1  = 19, // Mapping of S = 1 attribute for normal memory
    S_PRRR_NOS0 = 24, // Outer Shareable property mapping for memory attributes 0
    S_PRRR_NOS1 = 25, // Outer Shareable property mapping for memory attributes 1
    S_PRRR_NOS2 = 26, // Outer Shareable property mapping for memory attributes 2
    S_PRRR_NOS3 = 27, // Outer Shareable property mapping for memory attributes 3
    S_PRRR_NOS4 = 28, // Outer Shareable property mapping for memory attributes 4
    S_PRRR_NOS5 = 29, // Outer Shareable property mapping for memory attributes 5
    S_PRRR_NOS6 = 30, // Outer Shareable property mapping for memory attributes 6
    S_PRRR_NOS7 = 31; // Outer Shareable property mapping for memory attributes 7

/*
 * PRRR mask values
 */
static const uint32_t
    M_PRRR_TR0  = _MM_MAKEMASK(2, S_PRRR_TR0),
    M_PRRR_TR1  = _MM_MAKEMASK(2, S_PRRR_TR1),
    M_PRRR_TR2  = _MM_MAKEMASK(2, S_PRRR_TR2),
    M_PRRR_TR3  = _MM_MAKEMASK(2, S_PRRR_TR3),
    M_PRRR_TR4  = _MM_MAKEMASK(2, S_PRRR_TR4),
    M_PRRR_TR5  = _MM_MAKEMASK(2, S_PRRR_TR5),
    M_PRRR_TR6  = _MM_MAKEMASK(2, S_PRRR_TR6),
    M_PRRR_TR7  = _MM_MAKEMASK(2, S_PRRR_TR7),
    M_PRRR_DS0  = _MM_MAKEMASK1(S_PRRR_DS0),
    M_PRRR_DS1  = _MM_MAKEMASK1(S_PRRR_DS1),
    M_PRRR_NS0  = _MM_MAKEMASK1(S_PRRR_NS0),
    M_PRRR_NS1  = _MM_MAKEMASK1(S_PRRR_NS1),
    M_PRRR_NOS0 = _MM_MAKEMASK1(S_PRRR_NOS0),
    M_PRRR_NOS1 = _MM_MAKEMASK1(S_PRRR_NOS1),
    M_PRRR_NOS2 = _MM_MAKEMASK1(S_PRRR_NOS2),
    M_PRRR_NOS3 = _MM_MAKEMASK1(S_PRRR_NOS3),
    M_PRRR_NOS4 = _MM_MAKEMASK1(S_PRRR_NOS4),
    M_PRRR_NOS5 = _MM_MAKEMASK1(S_PRRR_NOS5),
    M_PRRR_NOS6 = _MM_MAKEMASK1(S_PRRR_NOS6),
    M_PRRR_NOS7 = _MM_MAKEMASK1(S_PRRR_NOS7);

/*
 * PRRR bitfield values
 */
static const uint32_t
    K_PRRR_TR_STRONGLY_ORDERED = 0,
    K_PRRR_TR_DEVICE           = 1,
    K_PRRR_TR_NORMAL_MEMORY    = 2,
    K_PRRR_TR_RESERVED         = 3;

/******************************************************************************
 ******************************************************************************
 **                                    ARM64                                 **
 ******************************************************************************
 *****************************************************************************/

/*
 * Normal registers: x0...x30 (lr) - can be directly MSR'ed to transfer registers
 */
#define ARM64_REG_GPR_0 0
#define ARM64_REG_FP    29
#define ARM64_REG_LR    30
#define ARM64_REG_SP    31  /* Special: must bounce through a GPR */
#define ARM64_GPR_COUNT 32
#define T32_GPR_COUNT   15

/*
 * Registers that need a special access pattern, including pc and sp
 */
#define ARM64_REG_PC   32 /* Use DLR_EL0 */
#define ARM64_REG_CPSR 33 /* Use DSPSR_EL0 */

/*
 * Registers that are accessed through MRS/MSR
 */

#define ARM64_REG_FPSR 0x401b4420 /* 3,3,4,4,1 */
#define ARM64_REG_FPCR 0x401b4400 /* 3,3,4,4,0 */

/*
 * VFP/SIMD Registers that are accessed through VMOV are treated as an array of 64-bit values,
 * numbered consecutively from 0 to 63, and marked with the same flag as we use for ARM32.
 * That is, they are top/bottom halves of the Vn registers - not the Dn registers on ARMv8.
 */

#define ARM64_REG_VFP_FLAG 0x10000000 /* = REG_COP_VFP */
#define ARM64_REG_VFP_MASK 0xF0000000 /* Must not set other bits! */

/*
 * System registers: enumerated, encoded like ARM32 registers, but
 * logic for constructing instructions lives in ARM64cpu_t.
 */
#define ARM64_REG_SYSREG_ID_FLAG   0x80000000  /* Indicates that this is an ID for a register that we should have in our table */
#define ARM64_REG_SYSREG_ENC_FLAG  0x40000000  /* Indicates that this is an encoding for an "msr" or "mrs" */
#define ARM64_REG_SYSREG_TYPE_MASK (ARM64_REG_SYSREG_ENC_FLAG | ARM64_REG_SYSREG_ID_FLAG)

/*
 * ARMv8 privilege/exception levels
 */
#define ARM64_PL_EL_0 0x0
#define ARM64_PL_EL_1 0x1
#define ARM64_PL_EL_2 0x2
#define ARM64_PL_EL_3 0x3

#define ARM64_REG_SYSREG_MIN_EL_SHIFT   28
#define ARM64_REG_SYSREG_MIN_EL_MASK    _MM_MAKEMASK(2, ARM64_REG_SYSREG_MIN_EL_SHIFT)
#define G_ARM64_SYSREG_MIN_EL(sysregid) _MM_GETVALUE((sysregid), ARM64_REG_SYSREG_MIN_EL_SHIFT, ARM64_REG_SYSREG_MIN_EL_MASK)

#define ARM64_REG_SYSREG_REGID_MASK (~(ARM64_REG_SYSREG_MIN_EL_MASK | ARM64_REG_SYSREG_TYPE_MASK))

// Index values for astris_arm64cpu.cpp:: const uint32_t ARM64cpu_t::m_aarch64_msr_mrs_sysreg_encodings[]
typedef enum {
// EL0 Registers (6)
    ARM64_SYSREG_MDDTRRX_EL0, /* Debugger to CPU */
    ARM64_SYSREG_MDDTRTX_EL0, /* CPU to debugger */
    ARM64_SYSREG_MDDTR_EL0,   /* Half-duplex 64-bit union of the above */
    ARM64_SYSREG_DLR_EL0,     /* PC on entry to Debug state (invalidated after any exception) */
    ARM64_SYSREG_DSPSR_EL0,   /* CPSR on entry to Debug state (invalidated after any exception) */
    ARM64_SYSREG_SP_EL0,
// EL1 Registers (5)
    ARM64_SYSREG_ESR_EL1,  /* Exception syndrome */
    ARM64_SYSREG_FAR_EL1,  /* Data fault address */
    ARM64_SYSREG_ELR_EL1,  /* Exception link register */
    ARM64_SYSREG_SPSR_EL1, /* PSTATE (invalidated after any exception)  */
    ARM64_SYSREG_SP_EL1,
// EL2 Registers (5)
    ARM64_SYSREG_ESR_EL2,  /* Exception syndrome */
    ARM64_SYSREG_FAR_EL2,  /* Data fault address */
    ARM64_SYSREG_ELR_EL2,  /* Exception link register */
    ARM64_SYSREG_SPSR_EL2, /* PSTATE (invalidated after any exception)  */
    ARM64_SYSREG_HCR_EL2,
// EL3 Registers (5)
    ARM64_SYSREG_ESR_EL3,  /* Exception syndrome */
    ARM64_SYSREG_FAR_EL3,  /* Data fault address */
    ARM64_SYSREG_ELR_EL3,  /* Exception link register */
    ARM64_SYSREG_SPSR_EL3, /* PSTATE (invalidated after any exception)  */
    ARM64_SYSREG_SP_EL3,
// Cache and Physical Address Registers (4)
    ARM64_SYSREG_CLIDR,  /* Cache level ID */
    ARM64_SYSREG_CSSELR, /* Cache size select */
    ARM64_SYSREG_CCSIDR, /* Cache size register */

    ARM64_SYSREG_PAR_EL1, /* Physical Address Register, Output of a Address Translation */
// Sys Ctl Registers (3)
    ARM64_SYSREG_SCTLR_EL1, /* System Control Register */
    ARM64_SYSREG_SCTLR_EL2, /* System Control Register */
    ARM64_SYSREG_SCTLR_EL3, /* System Control Register */
// SYS encodings for address translation (12)
    ARM64_SYSOP_ATS1E1R,
    ARM64_SYSOP_ATS1E2R,
    ARM64_SYSOP_ATS1E3R,
    ARM64_SYSOP_ATS1E1W,
    ARM64_SYSOP_ATS1E2W,
    ARM64_SYSOP_ATS1E3W,
    ARM64_SYSOP_ATS1E0R,
    ARM64_SYSOP_ATS1E0W,
    ARM64_SYSOP_ATS12E1R,
    ARM64_SYSOP_ATS12E1W,
    ARM64_SYSOP_ATS12E0R,
    ARM64_SYSOP_ATS12E0W,

} arm64_sysreg_t;

static const uint32_t PAGESIZE = 4096;

static const uint32_t
    M_FLG_DATA_ABORT = 0x00000001,
    M_FLG_ADDR_TRANS = 0x00000002,
    M_FLG_GOT_PARAMS = 0x00000004;

static const uint32_t
    M_PSTATE_AIF  = 0x000001C0,
    M_PSTATE_MODE = 0x0000000F;

/*
 * External debug register offsets
 */
static const uint32_t
    R_ARM64DBG_EDESR          = 0x020,
    R_ARM64DBG_EDECR          = 0x024,
    R_ARM64DBG_EDWARLO        = 0x030,
    R_ARM64DBG_EDWARHI        = 0x034,
    R_ARM64DBG_EDDTRRX        = 0x080,
    R_ARM64DBG_EDITR          = 0x084,
    R_ARM64DBG_EDSCR          = 0x088,
    R_ARM64DBG_EDDTRTX        = 0x08c,
    R_ARM64DBG_EDRCR          = 0x090,
    R_ARM64DBG_EDACR          = 0x094,
    R_ARM64DBG_EDECCR         = 0x098,
    R_ARM64DBG_EDPCSRlo       = 0x0a0,
    R_ARM64DBG_EDPCSRhi       = 0x0ac,
    R_ARM64DBG_OSLAR_EL1      = 0x300,
    R_ARM64DBG_EDPRCR         = 0x310,
    R_ARM64DBG_EDPRSR_AON     = 0x314,
    R_ARM64DBG_EDBVR0         = 0x400,
    R_ARM64DBG_EDBXVR0        = 0x404,
    R_ARM64DBG_DBGBCR0_EL1    = 0x408,
    R_ARM64DBG_EDBVR1         = 0x410,
    R_ARM64DBG_EDBXVR1        = 0x414,
    R_ARM64DBG_DBGBCR1_EL1    = 0x418,
    R_ARM64DBG_EDBVR2         = 0x420,
    R_ARM64DBG_EDBXVR2        = 0x424,
    R_ARM64DBG_DBGBCR2_EL1    = 0x428,
    R_ARM64DBG_EDBVR3         = 0x430,
    R_ARM64DBG_EDBXVR3        = 0x434,
    R_ARM64DBG_DBGBCR3_EL1    = 0x438,
    R_ARM64DBG_EDBVR4         = 0x440,
    R_ARM64DBG_EDBXVR4        = 0x444,
    R_ARM64DBG_DBGBCR4_EL1    = 0x448,
    R_ARM64DBG_EDBVR5         = 0x450,
    R_ARM64DBG_EDBXVR5        = 0x454,
    R_ARM64DBG_DBGBCR5_EL1    = 0x458,
    R_ARM64DBG_EDWVR0         = 0x800,
    R_ARM64DBG_EDWXVR0        = 0x804,
    R_ARM64DBG_DBGWCR0_EL1    = 0x808,
    R_ARM64DBG_EDWVR1         = 0x810,
    R_ARM64DBG_EDWXVR1        = 0x814,
    R_ARM64DBG_DBGWCR1_EL1    = 0x818,
    R_ARM64DBG_EDWVR2         = 0x820,
    R_ARM64DBG_EDWXVR2        = 0x824,
    R_ARM64DBG_DBGWCR2_EL1    = 0x828,
    R_ARM64DBG_EDWVR3         = 0x830,
    R_ARM64DBG_EDWXVR3        = 0x834,
    R_ARM64DBG_DBGWCR3_EL1    = 0x838,
    R_ARM64DBG_AA64_PFR0_LO   = 0xd20,
    R_ARM64DBG_AA64_PFR0_HI   = 0xd24,
    R_ARM64DBG_AA64_DFR0_LO   = 0xd28,
    R_ARM64DBG_AA64_DFR0_HI   = 0xd2c,
    R_ARM64DBG_AA64_ISAR0_LO  = 0xd30,
    R_ARM64DBG_AA64_ISAR0_HI  = 0xd34,
    R_ARM64DBG_AA64_MMFR0_LO  = 0xd38,
    R_ARM64DBG_AA64_MMFR0_HI  = 0xd3c,
    R_ARM64DBG_AA64_PFR1_LO   = 0xd40,
    R_ARM64DBG_AA64_PFR1_HI   = 0xd44,
    R_ARM64DBG_AA64_DFR1_LO   = 0xd48,
    R_ARM64DBG_AA64_DFR1_HI   = 0xd4c,
    R_ARM64DBG_AA64_ISAR1_LO  = 0xd50,
    R_ARM64DBG_AA64_ISAR1_HI  = 0xd54,
    R_ARM64DBG_AA64_MMFR1_LO  = 0xd58,
    R_ARM64DBG_AA64_MMFR1_HI  = 0xd5c,
    R_ARM64DBG_EDITCTRL       = 0xf00,
    R_ARM64DBG_CLAIMSETRV_EL1 = 0xfa0,
    R_ARM64DBG_CLAIMSET_EL1   = 0xfa0,
    R_ARM64DBG_CLAIMCLR_EL1   = 0xfa4,
    R_ARM64DBG_EDLAR          = 0xfb0,
    R_ARM64DBG_EDLSR          = 0xfb4,
    R_ARM64DBG_AUTHSTAT_EL1   = 0xfb8,
    R_ARM64DBG_EDDEVARCH      = 0xfbc,
    R_ARM64DBG_EDDEVID        = 0xfc0,
    R_ARM64DBG_EDDEVID1       = 0xfc4,
    R_ARM64DBG_EDDEVID2       = 0xfc8,
    R_ARM64DBG_EDDEVTYPE      = 0xfcc,
    R_ARM64DBG_EDPIDR4        = 0xfd0,
    R_ARM64DBG_EDPIDR5        = 0xfd4,
    R_ARM64DBG_EDPIDR6        = 0xfd8,
    R_ARM64DBG_EDPIDR7        = 0xfdc,
    R_ARM64DBG_EDPIDR0        = 0xfe0,
    R_ARM64DBG_EDPIDR1        = 0xfe4,
    R_ARM64DBG_EDPIDR2        = 0xfe8,
    R_ARM64DBG_EDPIDR3        = 0xfec,
    R_ARM64DBG_EDCIDR0        = 0xff0,
    R_ARM64DBG_EDCIDR1        = 0xff4,
    R_ARM64DBG_EDCIDR2        = 0xff8,
    R_ARM64DBG_EDCIDR3        = 0xffc;

/*
 * CTI block offset
 */
static const uint32_t ARM64_CTI_BLOCK_OFFSET = 0x10000; // 16KB

/*
 * CTI register offsets
 */
static const uint32_t
    R_ARM64CTI_CTL          = 0x000, // Control (enable/disable))
    R_ARM64CTI_INT_ACK      = 0x010,
    R_ARM64CTI_INT_ACK_RV   = 0x010,
    R_ARM64CTI_APP          = 0x014, // Alias for R_ARM64CTI_APP_SET
    R_ARM64CTI_APP_SET      = 0x014,
    R_ARM64CTI_APP_CLR      = 0x018,
    R_ARM64CTI_CH_PULSE     = 0x01c,
    R_ARM64CTI_IN_EN0       = 0x020,
    R_ARM64CTI_IN_EN1       = 0x024,
    R_ARM64CTI_IN_EN2       = 0x028,
    R_ARM64CTI_IN_EN3       = 0x02c,
    R_ARM64CTI_IN_EN4       = 0x030,
    R_ARM64CTI_IN_EN5       = 0x034,
    R_ARM64CTI_IN_EN6       = 0x038,
    R_ARM64CTI_IN_EN7       = 0x03c,
    R_ARM64CTI_OUT_EN0      = 0x0a0,
    R_ARM64CTI_OUT_EN1      = 0x0a4,
    R_ARM64CTI_OUT_EN2      = 0x0a8,
    R_ARM64CTI_OUT_EN3      = 0x0ac,
    R_ARM64CTI_OUT_EN4      = 0x0b0,
    R_ARM64CTI_OUT_EN5      = 0x0b4,
    R_ARM64CTI_OUT_EN6      = 0x0b8,
    R_ARM64CTI_OUT_EN7      = 0x0bc,
    R_ARM64CTI_TRIG_IN_STS  = 0x130,
    R_ARM64CTI_TRIG_OUT_STS = 0x134,
    R_ARM64CTI_CH_IN_STS    = 0x138,
    R_ARM64CTI_CH_OUT_STS   = 0x13c,
    R_ARM64CTI_GATE         = 0x140,
    R_ARM64CTI_ASIC_CTL     = 0x144,
    R_ARM64CTI_AUTH_STS     = 0xfb8,
    R_ARM64CTI_DEV_ID       = 0xfc8,
    R_ARM64CTI_DEV_TYPE     = 0xfcc,
    R_ARM64CTI_PID4         = 0xfd0,
    R_ARM64CTI_PID5         = 0xfd4,
    R_ARM64CTI_PID6         = 0xfd8,
    R_ARM64CTI_PID7         = 0xfdc,
    R_ARM64CTI_PID0         = 0xfe0,
    R_ARM64CTI_PID1         = 0xfe4,
    R_ARM64CTI_PID2         = 0xfe8,
    R_ARM64CTI_PID3         = 0xfec,
    R_ARM64CTI_CID0         = 0xff0,
    R_ARM64CTI_CID1         = 0xff4,
    R_ARM64CTI_CID2         = 0xff8,
    R_ARM64CTI_CID3         = 0xffc;

/*
 * CTI Register bits
 */
static const uint32_t
    R_ARM64CTI_CTL_GLBEN = 0x1;

static const uint32_t
    R_ARM64CTI_CTL_OUTEN_DBG     = 0x1,
    R_ARM64CTI_CTL_OUTEN_RESTART = 0x2,
    R_ARM64CTI_CTL_OUTEN_IRQ     = 0x4;

/*
 * XXX EDPRSR bits come from armdbgarch.h
 */

/*
 * EDSCR shift values
 */
static const uint32_t
    S_EDSCR_STATUS  = 0,  // Status bits.  RO.
    S_EDSCR_ERR     = 6,  // Cumulative error. RO.
    S_EDSCR_A       = 7,  // Async abort pending.  RO.
    S_EDSCR_EL      = 8,  // Exception Level.  RO.
    S_EDSCR_RW      = 10, // Register width.  RO.
    S_EDSCR_HDE     = 14, // Halting debug enable.  RW.
    S_EDSCR_SDD     = 16, // Secure debug disabled.  RO.
    S_EDSCR_NS      = 18, // Non-secure status.  RO.
    S_EDSCR_MA      = 20, // Memory access mode (0 = Normal, 1 = Mem). RW.
    S_EDSCR_TDA     = 21, // Trap debug reg accesses.  RW.
    S_EDSCR_INTDIS  = 22, // Interrupt disable for Non-Debug state.  RW.
    S_EDSCR_ITE     = 24, // ITR empty bit.  1 = ready for instruction.  RO.
    S_EDSCR_PIPEADV = 25, // Pipline advance (ref ARMv7).  Set to 1 when instruction retires.
    S_EDSCR_TXU     = 26, // DTRTX underrun. RO, cleared by EDRCR.CSE.
    S_EDSCR_RXO     = 27, // DTRRX overrun.  RO, cleared by EDRCR.CSE.
    S_EDSCR_ITO     = 28, // EDITR overrun.  RO, cleared by EDRCR.CSE.
    S_EDSCR_TXFULL  = 29, // Channel to host full.
    S_EDSCR_RXFULL  = 30; // Channel to ARM processor full.

/*
 * EDSCR mask values
 */
static const uint32_t
    M_EDSCR_STATUS  = _MM_MAKEMASK(6, S_EDSCR_STATUS),
    M_EDSCR_ERR     = _MM_MAKEMASK1(S_EDSCR_ERR),
    M_EDSCR_A       = _MM_MAKEMASK1(S_EDSCR_A),
    M_EDSCR_EL      = _MM_MAKEMASK(2, S_EDSCR_EL),
    M_EDSCR_RW      = _MM_MAKEMASK(4, S_EDSCR_RW),
    M_EDSCR_HDE     = _MM_MAKEMASK1(S_EDSCR_HDE),
    M_EDSCR_SDD     = _MM_MAKEMASK1(S_EDSCR_SDD),
    M_EDSCR_NS      = _MM_MAKEMASK1(S_EDSCR_NS),
    M_EDSCR_MA      = _MM_MAKEMASK1(S_EDSCR_MA),
    M_EDSCR_TDA     = _MM_MAKEMASK1(S_EDSCR_TDA),
    M_EDSCR_INTDIS  = _MM_MAKEMASK(2, S_EDSCR_INTDIS),
    M_EDSCR_ITE     = _MM_MAKEMASK1(S_EDSCR_ITE),
    M_EDSCR_PIPEADV = _MM_MAKEMASK1(S_EDSCR_PIPEADV),
    M_EDSCR_TXU     = _MM_MAKEMASK1(S_EDSCR_TXU),
    M_EDSCR_RXO     = _MM_MAKEMASK1(S_EDSCR_RXO),
    M_EDSCR_ITO     = _MM_MAKEMASK1(S_EDSCR_ITO),
    M_EDSCR_TXFULL  = _MM_MAKEMASK1(S_EDSCR_TXFULL),
    M_EDSCR_RXFULL  = _MM_MAKEMASK1(S_EDSCR_RXFULL),
    M_EDSCR_CONTROL = (M_EDSCR_INTDIS | M_EDSCR_TDA | M_EDSCR_MA | M_EDSCR_HDE);

static const uint32_t
    K_EDSCR_STATUS_RESTARTING          = 0x001,
    K_EDSCR_STATUS_NON_DEBUG           = 0x002,
    K_EDSCR_STATUS_BREAKPOINT          = 0x007,
    K_EDSCR_STATUS_EXT_DEBUG           = 0x013,
    K_EDSCR_STATUS_HALT_STEP_NORMAL    = 0x01b,
    K_EDSCR_STATUS_HALT_STEP_EXCLUSIVE = 0x01f,
    K_EDSCR_STATUS_OS_UNLOCK           = 0x023,
    K_EDSCR_STATUS_RESET_CATCH         = 0x027,
    K_EDSCR_STATUS_WATCHPOINT          = 0x02b,
    K_EDSCR_STATUS_HALT_INSTR          = 0x02f,
    K_EDSCR_STATUS_DEBUG_REG_ACCESS    = 0x033,
    K_EDSCR_STATUS_EXCEPTION_CATCH     = 0x037,
    K_EDSCR_STATUS_HALT_STEP_NOSYN     = 0x03b;

/*
 * Debug feature register 0 (a.k.a. ID_AA64DFR0_EL1) shift values
 */
static const uint32_t
    S_AA64DFR0_DBGARCH         = 0,
    S_AA64DFR0_TRACE_EXTENSION = 4,
    S_AA64DFR0_PERF_EXTENSION  = 8,
    S_AA64DFR0_BRP_COUNT       = 12,
    S_AA64DFR0_WRP_COUNT       = 20,
    S_AA64DFR0_CTXBRP_COUNT    = 28;

/*
 * Debug feature register 0 (a.k.a. ID_AA64DFR0_EL1) mask values
 */
static const uint32_t
    M_AA64DFR0_DBGARCH         = _MM_MAKEMASK(4, S_AA64DFR0_DBGARCH),
    M_AA64DFR0_TRACE_EXTENSION = _MM_MAKEMASK(4, S_AA64DFR0_TRACE_EXTENSION),
    M_AA64DFR0_PERF_EXTENSION  = _MM_MAKEMASK(4, S_AA64DFR0_PERF_EXTENSION),
    M_AA64DFR0_BRP_COUNT       = _MM_MAKEMASK(4, S_AA64DFR0_BRP_COUNT),
    M_AA64DFR0_WRP_COUNT       = _MM_MAKEMASK(4, S_AA64DFR0_WRP_COUNT),
    M_AA64DFR0_CTXBRP_COUNT    = _MM_MAKEMASK(4, S_AA64DFR0_CTXBRP_COUNT);

/*
 * Process feature register 0 (a.k.a. ID_AA64_PFR0_EL1) shift values
 */
static const uint32_t
    S_AA64PFR0_EL0 = 0,
    S_AA64PFR0_EL1 = 4,
    S_AA64PFR0_EL2 = 8,
    S_AA64PFR0_EL3 = 12;

/*
 * Process feature register 0 (a.k.a. ID_AA64_PFR0_EL1) mask values
 */
static const uint32_t
    M_AA64PFR0_EL0 = _MM_MAKEMASK(4, S_AA64PFR0_EL0),
    M_AA64PFR0_EL1 = _MM_MAKEMASK(4, S_AA64PFR0_EL1),
    M_AA64PFR0_EL2 = _MM_MAKEMASK(4, S_AA64PFR0_EL2),
    M_AA64PFR0_EL3 = _MM_MAKEMASK(4, S_AA64PFR0_EL3);

/*
 * EDECR bits shift values
 */
static const uint32_t
    S_EDECR_OSUC = 0, // OS Unlock
    S_EDECR_RC   = 1, // Reset catch
    S_EDECR_SS   = 2; // Single-step

/*
 * EDECR bits mask values
 */
static const uint32_t
    M_EDECR_OSUC = _MM_MAKEMASK1(S_EDECR_OSUC),
    M_EDECR_RC   = _MM_MAKEMASK1(S_EDECR_RC),
    M_EDECR_SS   = _MM_MAKEMASK1(S_EDECR_SS);

/*
 * EDESR shift values
 */
static const uint32_t
    S_EDESR_OSUC = 1, // OS Unlock
    S_EDESR_RC   = 2, // Reset catch
    S_EDESR_SS   = 3; // Single-step

/*
 * EDESR mask values
 */
static const uint32_t
    M_EDESR_OSUC = _MM_MAKEMASK1(S_EDESR_OSUC),
    M_EDESR_RC   = _MM_MAKEMASK1(S_EDESR_RC),
    M_EDESR_SS   = _MM_MAKEMASK1(S_EDESR_SS);

/*
 * EDRCR shift values
 */
static const uint32_t
    S_EDRCR_CSE   = 2,
    S_EDRCR_CSPA  = 3,
    S_EDRCR_CBRRQ = 4;

/*
 * EDRCR mask values
 */
static const uint32_t
    M_EDRCR_CSE   = _MM_MAKEMASK1(S_EDRCR_CSE),
    M_EDRCR_CSPA  = _MM_MAKEMASK1(S_EDRCR_CSPA),
    M_EDRCR_CBRRQ = _MM_MAKEMASK1(S_EDRCR_CBRRQ);

/*
 * CSSELR shift values
 * Keep in mind that Ln is encoded as (n-1) << S_CSSELR_LEVEL
 */
static const uint32_t
    S_CSSELR_IND   = 0,
    S_CSSELR_LEVEL = 1;

/*
 * CSSELR values
 */
static const uint32_t
    V_CSSELR_IND_INST = _MM_MAKEVALUE(1, S_CSSELR_IND),
    V_CSSELR_IND_DATA = _MM_MAKEVALUE(0, S_CSSELR_IND);

/*
 * CCSIDR shift values
 */
static const uint32_t
    S_CCSIDR_LINESIZE = 0,
    S_CCSIDR_ASSOC    = 3,
    S_CCSIDR_NUMSETS  = 13;

/*
 * CCSIDR mask values
 */
static const uint32_t
    M_CCSIDR_LINESIZE = _MM_MAKEMASK(3, S_CCSIDR_LINESIZE),
    M_CCSIDR_ASSOC    = _MM_MAKEMASK(10, S_CCSIDR_ASSOC),
    M_CCSIDR_NUMSETS  = _MM_MAKEMASK(15, S_CCSIDR_NUMSETS);

/*
 * ESR shift values
 */
static const uint32_t
    ARM64_ESR_EC_SHIFT = 26;

/*
 * ESR mask values
 */
static const uint32_t
    ARM64_ESR_EC_MASK = (0x3F << ARM64_ESR_EC_SHIFT);

static const uint32_t
    ARM64_ESR_EC_UNCATEGORIZED     = 0x00,
    ARM64_ESR_EC_TRAP_SIMD_FP      = 0x07,
    ARM64_ESR_EC_ILLEGAL_INSTR_SET = 0x0c,
    ARM64_ESR_EC_SVC_32            = 0x11,
    ARM64_ESR_EC_SVC_64            = 0x15,
    ARM64_ESR_EC_MSR_TRAP          = 0x18,
    ARM64_ESR_EC_IABORT_EL0        = 0x20,
    ARM64_ESR_EC_IABORT_EL1        = 0x21,
    ARM64_ESR_EC_PC_ALIGN          = 0x22,
    ARM64_ESR_EC_DABORT_LOWER_EL   = 0x24,
    ARM64_ESR_EC_DABORT_SAME_EL    = 0x25,
    ARM64_ESR_EC_SP_ALIGN          = 0x26;

/*
 * SCTLR_EL1 shift values
 */
static const uint64_t
    S_SCTLR_EL1_MMU     = 0,  // MMU enable for EL1 and EL0 stage 1 address translation
    S_SCTLR_EL1_A       = 1,  // Alignment check enable
    S_SCTLR_EL1_C       = 2,  // Cache enable
    S_SCTLR_EL1_SA      = 3,  // Stack Alignment Check Enable
    S_SCTLR_EL1_SA0     = 4,  // Stack Alignment Check Enable for EL0
    S_SCTLR_EL1_CP15BEN = 5,  // CP15 barrier enable
    S_SCTLR_EL1_THEE    = 6,  // T32EE enable
    S_SCTLR_EL1_ITD     = 7,  // IT instruction Disable
    S_SCTLR_EL1_SED     = 8,  // SETEND instruction Disable
    S_SCTLR_EL1_UMA     = 9,  // User Mask Access. Controls access to interrupt masks from EL0
    S_SCTLR_EL1_I       = 12, // Instruction cache enable for instruction caches at EL0 and EL1
    S_SCTLR_EL1_DZE     = 14, // Access to DC ZVA instruction at EL0
    S_SCTLR_EL1_UCT     = 15, // EL0 access enabled to the CTR_EL0 register
    S_SCTLR_EL1_NTWI    = 16, // Not trap WFI
    S_SCTLR_EL1_NTWE    = 18, // Not trap WFE
    S_SCTLR_EL1_WXN     = 19, // Write permission implies XN (Execute Never)
    S_SCTLR_EL1_E0E     = 24, // Endianness of explicit data accesses at EL0
    S_SCTLR_EL1_EE      = 25, // Exception Endianness controlling explicit EL1 data accesses and stage 1 walks at EL1 & EL0
    S_SCTLR_EL1_UCI     = 26; // EL0 access enabled for DC CVAU, DC CIVAC, DC CVAC, and IC IVAU instructions

/*
 * SCTLR_EL1 mask values
 */
static const uint64_t
    M_SCTLR_EL1_MMU     = _MM64_MAKEMASK1(S_SCTLR_EL1_MMU),
    M_SCTLR_EL1_A       = _MM64_MAKEMASK1(S_SCTLR_EL1_A),
    M_SCTLR_EL1_C       = _MM64_MAKEMASK1(S_SCTLR_EL1_C),
    M_SCTLR_EL1_SA      = _MM64_MAKEMASK1(S_SCTLR_EL1_SA),
    M_SCTLR_EL1_SA0     = _MM64_MAKEMASK1(S_SCTLR_EL1_SA0),
    M_SCTLR_EL1_CP15BEN = _MM64_MAKEMASK1(S_SCTLR_EL1_CP15BEN),
    M_SCTLR_EL1_THEE    = _MM64_MAKEMASK1(S_SCTLR_EL1_THEE),
    M_SCTLR_EL1_ITD     = _MM64_MAKEMASK1(S_SCTLR_EL1_ITD),
    M_SCTLR_EL1_SED     = _MM64_MAKEMASK1(S_SCTLR_EL1_SED),
    M_SCTLR_EL1_UMA     = _MM64_MAKEMASK1(S_SCTLR_EL1_UMA),
    M_SCTLR_EL1_I       = _MM64_MAKEMASK1(S_SCTLR_EL1_I),
    M_SCTLR_EL1_DZE     = _MM64_MAKEMASK1(S_SCTLR_EL1_DZE),
    M_SCTLR_EL1_UCT     = _MM64_MAKEMASK1(S_SCTLR_EL1_UCT),
    M_SCTLR_EL1_NTWI    = _MM64_MAKEMASK1(S_SCTLR_EL1_NTWI),
    M_SCTLR_EL1_NTWE    = _MM64_MAKEMASK1(S_SCTLR_EL1_NTWE),
    M_SCTLR_EL1_WXN     = _MM64_MAKEMASK1(S_SCTLR_EL1_WXN),
    M_SCTLR_EL1_E0E     = _MM64_MAKEMASK1(S_SCTLR_EL1_E0E),
    M_SCTLR_EL1_EE      = _MM64_MAKEMASK1(S_SCTLR_EL1_EE),
    M_SCTLR_EL1_UCI     = _MM64_MAKEMASK1(S_SCTLR_EL1_UCI);

/*
 * SCTLR__ELX mask values (common to ARM64 SCTRL EL1,EL2,EL3)
 */
#define M_ARM64_SCTLR__ELX_MMU _MM64_MAKEMASK1(S_SCTLR_EL1_MMU)

/*
 * TTBR_EL1 shift values common to TTBR0_EL1 and TTBR1_EL1
 */
static const uint64_t
    S_TTBR_EL1_ADDR = 0,  // Translation table base address (low order bits that are not significant are 0)
    S_TTBR_EL1_ASID = 48; // Address Space Identifier for the translation table base address

/*
 * TTBR_EL1 mask values common to TTBR0_EL1 and TTBR1_EL1
 */
static const uint64_t
    M_TTBR_EL1_ADDR = _MM64_MAKEMASK(48, S_TTBR_EL1_ADDR),
    M_TTBR_EL1_ASID = _MM64_MAKEMASK(16, S_TTBR_EL1_ASID);

/*
 * MAIR_EL1 shift values
 */
static const uint64_t
    S_MAIR_EL1_ATTR0 = 0,
    S_MAIR_EL1_ATTR1 = 8,
    S_MAIR_EL1_ATTR2 = 16,
    S_MAIR_EL1_ATTR3 = 24,
    S_MAIR_EL1_ATTR4 = 32,
    S_MAIR_EL1_ATTR5 = 40,
    S_MAIR_EL1_ATTR6 = 48,
    S_MAIR_EL1_ATTR7 = 56;

/*
 * MAIR_EL1 mask values
 */
static const uint64_t
    M_MAIR_EL1_ATTR0 = _MM64_MAKEMASK(8, S_MAIR_EL1_ATTR0),
    M_MAIR_EL1_ATTR1 = _MM64_MAKEMASK(8, S_MAIR_EL1_ATTR1),
    M_MAIR_EL1_ATTR2 = _MM64_MAKEMASK(8, S_MAIR_EL1_ATTR2),
    M_MAIR_EL1_ATTR3 = _MM64_MAKEMASK(8, S_MAIR_EL1_ATTR3),
    M_MAIR_EL1_ATTR4 = _MM64_MAKEMASK(8, S_MAIR_EL1_ATTR4),
    M_MAIR_EL1_ATTR5 = _MM64_MAKEMASK(8, S_MAIR_EL1_ATTR5),
    M_MAIR_EL1_ATTR6 = _MM64_MAKEMASK(8, S_MAIR_EL1_ATTR6),
    M_MAIR_EL1_ATTR7 = _MM64_MAKEMASK(8, S_MAIR_EL1_ATTR7);

/*
 * MAIR_EL1_ATTR shift values
 */
static const uint64_t
    S_MAIR_EL1_ATTR_UPPER = 4,
    S_MAIR_EL1_ATTR_LOWER = 0;

/*
 * MAIR_EL1_ATTR mask values
 */
static const uint64_t
    M_MAIR_EL1_ATTR_UPPER = _MM64_MAKEMASK(4, S_MAIR_EL1_ATTR_UPPER),
    M_MAIR_EL1_ATTR_LOWER = _MM64_MAKEMASK(4, S_MAIR_EL1_ATTR_LOWER);

/*
 * MAIRn Attr (UPPER[U] [7:4] or LOWER[L] [3:0]) values
 *   where: SD   = Strongly-ordered or Device memory
 *          OUT  = Outer
 *          IN   = Inner
 *          WTHR = Write-Through
 *          WBAK = Write-Back
 *          T    = Transient
 *          NT   = Non-Transient
 *          C    = Cacheable
 *          NC   = Non-Cacheable
 *          R    = Read-allocate policy
 *          W    = Write-allocate policy
 */

static const uint8_t
    K_MAIR_U_SD               = 0,  // Strongly-ordered or Device memory, see encoding of Attrm[3:0]
    K_MAIR_U_OUT_WTHR_T_W     = 1,  // Normal memory, Outer Write-Through Transient R:no alloc W:alloc
    K_MAIR_U_OUT_WTHR_T_R     = 2,  // Normal memory, Outer Write-Through Transient R:alloc W: no alloc
    K_MAIR_U_OUT_WTHR_T_RW    = 3,  // Normal memory, Outer Write-Through Transient R:alloc W:alloc
    K_MAIR_U_OUT_NC           = 4,  // Normal memory, Outer Non-cacheable
    K_MAIR_U_OUT_WBAK_T_W     = 5,  // Normal memory, Outer Write-Back Transient R:no alloc W:alloc
    K_MAIR_U_OUT_WBAK_T_R     = 6,  // Normal memory, Outer Write-Back Transient R:alloc W: no alloc
    K_MAIR_U_OUT_WBAK_T_RW    = 7,  // Normal memory, Outer Write-Back Transient R:alloc W:alloc
    K_MAIR_U_OUT_WTHR_C_NT    = 8,  // Normal memory, Outer Write-Through Cacheable, Non-transient R:no alloc W:no alloc
    K_MAIR_U_OUT_WTHR_C_NT_W  = 9,  // Normal memory, Outer Write-Through Cacheable, Non-transient R:no alloc W:alloc
    K_MAIR_U_OUT_WTHR_C_NT_R  = 10, // Normal memory, Outer Write-Through Cacheable, Non-transient R:alloc W:no alloc
    K_MAIR_U_OUT_WTHR_C_NT_RW = 11, // Normal memory, Outer Write-Through Cacheable, Non-transient R:alloc W:alloc
    K_MAIR_U_OUT_WBAK_C_NT    = 12, // Normal memory, Outer Write-Back Cacheableb, Non-transient R:no alloc W:no alloc
    K_MAIR_U_OUT_WBAK_C_NT_W  = 13, // Normal memory, Outer Write-Back Cacheableb, Non-transient R:no alloc W:alloc
    K_MAIR_U_OUT_WBAK_C_NT_R  = 14, // Normal memory, Outer Write-Back Cacheableb, Non-transient R:alloc W:no alloc
    K_MAIR_U_OUT_WBAK_C_NT_RW = 15; // Normal memory, Outer Write-Back Cacheableb, Non-transient R:alloc W:alloc

static const uint8_t
    K_MAIR_L_USD_STRONG = 0, // [MAIR_U == SD] Strongly-ordered memory
    K_MAIR_L_USD_DEVICE = 4, // [MAIR_U == SD] Device memory

    K_MAIR_L_IN_WTHR_T_W     = 1,  // Normal memory, Inner Write-Through Transient R:no alloc W:alloc
    K_MAIR_L_IN_WTHR_T_R     = 2,  // Normal memory, Inner Write-Through Transient R:alloc W: no alloc
    K_MAIR_L_IN_WTHR_T_RW    = 3,  // Normal memory, Inner Write-Through Transient R:alloc W:alloc
    K_MAIR_L_IN_NC           = 4,  // Normal memory, Inner Non-cacheable
    K_MAIR_L_IN_WBAK_T_W     = 5,  // Normal memory, Inner Write-Back Transient R:no alloc W:alloc
    K_MAIR_L_IN_WBAK_T_R     = 6,  // Normal memory, Inner Write-Back Transient R:alloc W: no alloc
    K_MAIR_L_IN_WBAK_T_RW    = 7,  // Normal memory, Inner Write-Back Transient R:alloc W:alloc
    K_MAIR_L_IN_WTHR_C_NT    = 8,  // Normal memory, Inner Write-Through Cacheable, Non-transient R:no alloc W:no alloc
    K_MAIR_L_IN_WTHR_C_NT_W  = 9,  // Normal memory, Inner Write-Through Cacheable, Non-transient R:no alloc W:alloc
    K_MAIR_L_IN_WTHR_C_NT_R  = 10, // Normal memory, Inner Write-Through Cacheable, Non-transient R:alloc W:no alloc
    K_MAIR_L_IN_WTHR_C_NT_RW = 11, // Normal memory, Inner Write-Through Cacheable, Non-transient R:alloc W:alloc
    K_MAIR_L_IN_WBAK_C_NT    = 12, // Normal memory, Inner Write-Back Cacheableb, Non-transient R:no alloc W:no alloc
    K_MAIR_L_IN_WBAK_C_NT_W  = 13, // Normal memory, Inner Write-Back Cacheableb, Non-transient R:no alloc W:alloc
    K_MAIR_L_IN_WBAK_C_NT_R  = 14, // Normal memory, Inner Write-Back Cacheableb, Non-transient R:alloc W:no alloc
    K_MAIR_L_IN_WBAK_C_NT_RW = 15; // Normal memory, Inner Write-Back Cacheableb, Non-transient R:alloc W:alloc

/*
 * TCR_EL1 shift values
 */
static const uint64_t
    S_TCR_EL1_T0SZ  = 0,  // Size of virtual address memory range for TTBR0: size = 2^(64 - T0SZ) bytes
    S_TCR_EL1_EPD0  = 7,  // Translation Table walk disable for TTBR0 as described in LPAE
    S_TCR_EL1_IRGN0 = 8,  // Inner Cacheability attributes for TTBR0 as described in LPAE
    S_TCR_EL1_ORGN0 = 10, // Outer Cacheability attributes for TTBR0 as described in LPAE
    S_TCR_EL1_SH0   = 12, // Shareability attributes for TTBR0 as described in LPAE
    S_TCR_EL1_TG0   = 14, // TTBR0_EL1 Granule size
    S_TCR_EL1_T1SZ  = 16, // Size of virtual address memory range for TTBR1: size = 2^(64 - T1SZ) bytes
    S_TCR_EL1_A1    = 22, // ASID selection from TTBR1 as described in LPAE
    S_TCR_EL1_EPD1  = 23, // Translation Table walk disable for TTBR1 as described in LPAE
    S_TCR_EL1_IRGN1 = 24, // Inner Cacheability attributes for TTBR1 as described in LPAE
    S_TCR_EL1_ORGN1 = 26, // Outer Cacheability attributes for TTBR1 as described in LPAE
    S_TCR_EL1_SH1   = 28, // Shareability attributes for TTBR1 as described in LPAE
    S_TCR_EL1_TG1   = 30, // TTBR1_EL1 Granule size
    S_TCR_EL1_IPS   = 32, // IPASize – see section 3.7 of AArch_v8A_MemoryModel
    S_TCR_EL1_AS    = 36, // ASID Size
    S_TCR_EL1_TBI0  = 37, // Top Byte ignored – whether top byte of input addr used for TTBR0 region addr match
    S_TCR_EL1_TBI1  = 38; // Top Byte ignored – whether top byte of input addr used for TTBR1 region addr match

/*
 * TCR_EL1 mask values
 */
static const uint64_t
    M_TCR_EL1_T0SZ  = _MM64_MAKEMASK(6, S_TCR_EL1_T0SZ),
    M_TCR_EL1_EPD0  = _MM64_MAKEMASK1(S_TCR_EL1_EPD0),
    M_TCR_EL1_IRGN0 = _MM64_MAKEMASK(2, S_TCR_EL1_IRGN0),
    M_TCR_EL1_ORGN0 = _MM64_MAKEMASK(2, S_TCR_EL1_ORGN0),
    M_TCR_EL1_SH0   = _MM64_MAKEMASK(2, S_TCR_EL1_SH0),
    M_TCR_EL1_TG0   = _MM64_MAKEMASK(2, S_TCR_EL1_TG0),
    M_TCR_EL1_T1SZ  = _MM64_MAKEMASK(6, S_TCR_EL1_T1SZ),
    M_TCR_EL1_A1    = _MM64_MAKEMASK1(S_TCR_EL1_A1),
    M_TCR_EL1_EPD1  = _MM64_MAKEMASK1(S_TCR_EL1_EPD1),
    M_TCR_EL1_IRGN1 = _MM64_MAKEMASK(2, S_TCR_EL1_IRGN1),
    M_TCR_EL1_ORGN1 = _MM64_MAKEMASK(2, S_TCR_EL1_ORGN1),
    M_TCR_EL1_SH1   = _MM64_MAKEMASK(2, S_TCR_EL1_SH1),
    M_TCR_EL1_TG1   = _MM64_MAKEMASK(2, S_TCR_EL1_TG1),
    M_TCR_EL1_IPS   = _MM64_MAKEMASK(3, S_TCR_EL1_IPS),
    M_TCR_EL1_AS    = _MM64_MAKEMASK1(S_TCR_EL1_AS),
    M_TCR_EL1_TBI0  = _MM64_MAKEMASK1(S_TCR_EL1_TBI0),
    M_TCR_EL1_TBI1  = _MM64_MAKEMASK1(S_TCR_EL1_TBI1);

static const uint64_t
    K_TCR_EL1_EPD_WALK               = 0, // Perform translation table walks
    K_TCR_EL1_EPD_NO_WALK            = 1, // No translation table walk is performed
    K_TCR_EL1_EPD_RESERVED           = 2, // all other values are reserved
    K_TCR_EL1_IRGN_NOCA              = 0, // Normal memory, Inner Non-cacheable
    K_TCR_EL1_IRGN_WBACK_WALLOC_CA   = 1, // Normal memory, Inner Write-Back Write-Allocate Cacheable
    K_TCR_EL1_IRGN_WTHROUGH_CA       = 2, // Normal memory, Inner Write-Through Cacheable
    K_TCR_EL1_IRGN_WBACK_NOWALLOC_CA = 3, // Normal memory, Inner Write-Back no Write-Allocate Cacheable
    K_TCR_EL1_IRGN_RESERVED          = 4, // all other values are reserved
    K_TCR_EL1_ORGN_NOCA              = 0, // Normal memory, Outer Non-cacheable
    K_TCR_EL1_ORGN_WBACK_WALLOC_CA   = 1, // Normal memory, Outer Write-Back Write-Allocate Cacheable
    K_TCR_EL1_ORGN_WTHROUGH_CA       = 2, // Normal memory, Outer Write-Through Cacheable
    K_TCR_EL1_ORGN_WBACK_NOWALLOC_CA = 3, // Normal memory, Outer Write-Back no Write-Allocate Cacheable
    K_TCR_EL1_ORGN_RESERVED          = 4, // all other values are reserved
    K_TRC_EL1_A1_ASID_SELECT_CLEAR   = 0, // ASID selection from TTBR1 clear (as described in LPAE)
    K_TRC_EL1_A1_ASID_SELECT_SET     = 1, // ASID selection from TTBR1 set (as described in LPAE)
    K_TCR_EL1_A1_RESERVED            = 2, // all other values are reserved
    K_TCR_EL1_SH_NON_SHARABLE        = 0, // Non-shareable
    K_TCR_EL1_SH_RESERVED_1          = 1,
    K_TCR_EL1_SH_OUTER_SHARABLE      = 2, // Outer Shareable
    K_TCR_EL1_SH_INNER_SHARABLE      = 3, // Inner Shareable
    K_TCR_EL1_SH_RESERVED            = 4, // all other values are reserved
    K_TCR_EL1_TG0_4K_BYTE            = 0, // 4KB granule size
    K_TCR_EL1_TG0_64K_BYTE           = 1, // 64KB granule size
    K_TCR_EL1_TG0_16K_BYTE           = 2, // 16KB granule size
    K_TCR_EL1_TG0_RESERVED           = 3, // all other values are reserved
    K_TCR_EL1_TG1_RESERVED_0         = 0,
    K_TCR_EL1_TG1_16K_BYTE           = 1, // 16KB granule size
    K_TCR_EL1_TG1_4K_BYTE            = 2, // 4KB granule size
    K_TCR_EL1_TG1_64K_BYTE           = 3, // 64KB granule size
    K_TCR_EL1_TG1_RESERVED           = 4, // all other values are reserved
    K_TCR_EL1_IPS_32BIT_4GB          = 0, // 32 bits, 4 GB
    K_TCR_EL1_IPS_36BIT_64GB         = 1, // 36 bits, 64 GB
    K_TCR_EL1_IPS_40BIT_1TB          = 2, // 40 bits, 1 TB
    K_TCR_EL1_IPS_42BIT_4TB          = 3, // 42 bits, 4 TB
    K_TCR_EL1_IPS_44BIT_16TB         = 4, // 44 bits, 16 TB
    K_TCR_EL1_IPS_48BIT_256TB        = 5, // 48 bits, 256 TB
    K_TCR_EL1_IPS_RESERVED           = 6, // all other values are reserved
    K_TCR_EL1_AS_8_BIT               = 0, // upper 8 bits of TTBR ignored by HW
    K_TCR_EL1_AS_16_BIT              = 1, // upper 16 bits of TTBR used for alloc & match
    K_TCR_EL1_AS_RESERVED            = 2, // all other values are reserved
    K_TCR_EL1_TBI_USED               = 0, // Top Byte used
    K_TCR_EL1_TBI_IGNORED            = 1, // Top Byte ignored
    K_TCR_EL1_TBI_RESERVED           = 2; // all other values are reserved

/**/
static const uint64_t
    S_HCR_EL2_TIDCP = 20, // Trap Implementation Defined
    S_HCR_EL2_TGE   = 27, // Trap General Exceptions
    S_HCR_EL2_E2H   = 34, // EL2 Host
    S_HCR_EL2_VM    = 0;  // Virtualization enable

static const uint64_t
    M_HCR_EL2_TIDCP = _MM64_MAKEMASK1(S_HCR_EL2_TIDCP),
    M_HCR_EL2_TGE   = _MM64_MAKEMASK1(S_HCR_EL2_TGE),
    M_HCR_EL2_E2H   = _MM64_MAKEMASK1(S_HCR_EL2_E2H),
    M_HCR_EL2_VM    = _MM64_MAKEMASK1(S_HCR_EL2_VM);

/*
 * TT_IA2OA (Translation Table Input Address (IA) to Output Address (OA)
 *
 * The IA is broken into a set of fields providing the indexes for translation.
 * The size of each index depends on the granulation size: 4K, 16K or 64K.
 */

/*
 * TT_IA2OA_4K (Translation Table IA to OA [4KB granule])
 */
static const uint64_t
    S_TT_IA2OA_4K_BASE = 0,  // Base portion of address (directly maps IA -> OA)
    S_TT_IA2OA_4K_L3   = 12, // Index the third level translation table
    S_TT_IA2OA_4K_L2   = 21, // Index the second level translation table
    S_TT_IA2OA_4K_L1   = 30, // Index the first level translation table
    S_TT_IA2OA_4K_L0   = 39; // Index the zero level translation table

static const uint64_t
    M_TT_IA2OA_4K_BASE = _MM64_MAKEMASK(12, S_TT_IA2OA_4K_BASE),
    M_TT_IA2OA_4K_L3   = _MM64_MAKEMASK(9, S_TT_IA2OA_4K_L3),
    M_TT_IA2OA_4K_L2   = _MM64_MAKEMASK(9, S_TT_IA2OA_4K_L2),
    M_TT_IA2OA_4K_L1   = _MM64_MAKEMASK(9, S_TT_IA2OA_4K_L1),
    M_TT_IA2OA_4K_L0   = _MM64_MAKEMASK1(S_TT_IA2OA_4K_L0);

static const uint64_t
    K_TT_IA2OA_4K_L0_CONCAT = 0x1000; // TTBRn offset when TT_IA2OA_4K_L0 set

/*
 * TT_IA2OA_16K (Translation Table IA to OA [16KB granule])
 */
static const uint64_t
    S_TT_IA2OA_16K_BASE = 0,  // Base portion of address (directly maps IA -> OA)
    S_TT_IA2OA_16K_L3   = 14, // Index the third level translation table
    S_TT_IA2OA_16K_L2   = 25, // Index the second level translation table
    S_TT_IA2OA_16K_L1   = 36, // Index the first level translation table
    S_TT_IA2OA_16K_L0   = 47; // Index the zero level translation table

static const uint64_t
    M_TT_IA2OA_16K_BASE = _MM64_MAKEMASK(14, S_TT_IA2OA_16K_BASE),
    M_TT_IA2OA_16K_L3   = _MM64_MAKEMASK(11, S_TT_IA2OA_16K_L3),
    M_TT_IA2OA_16K_L2   = _MM64_MAKEMASK(11, S_TT_IA2OA_16K_L2),
    M_TT_IA2OA_16K_L1   = _MM64_MAKEMASK(11, S_TT_IA2OA_16K_L1),
    M_TT_IA2OA_16K_L0   = _MM64_MAKEMASK1(S_TT_IA2OA_16K_L0);

/*
 * TT_IA2OA_64K (Translation Table IA to OA [64KB granule])
 */
static const uint64_t
    S_TT_IA2OA_64K_BASE = 0,  // Base portion of address (directly maps IA -> OA)
    S_TT_IA2OA_64K_L3   = 16, // Index the third level translation table
    S_TT_IA2OA_64K_L2   = 29, // Index the second level translation table
    S_TT_IA2OA_64K_L1   = 42; // Index the first level translation table

static const uint64_t
    M_TT_IA2OA_64K_BASE = _MM64_MAKEMASK(16, S_TT_IA2OA_64K_BASE),
    M_TT_IA2OA_64K_L3   = _MM64_MAKEMASK(13, S_TT_IA2OA_64K_L3),
    M_TT_IA2OA_64K_L2   = _MM64_MAKEMASK(13, S_TT_IA2OA_64K_L2),
    M_TT_IA2OA_64K_L1   = _MM64_MAKEMASK(6, S_TT_IA2OA_64K_L1);

/******************************************************************************
 * Translation Table Descriptor [Short Descriptor]
 *
 * S|M|K_TTD_SD[_<subset>]_<name>
 *
 * where <subset>:
 *   PG   - specific to Page table entry
 *   SECT - specific to Section entry
 *   SUP  - specific to Supersection entry
 *   LG   - specific to Large page entry
 *   SM   - specific to Small page entry
 *
 * shorthand for combinations of applicable entry types:
 *   SS   - applicable to Section and Supersection entries
 *   LGSM - applicable to Large page and Small page entries
 *   SSLG - applicable to Section, Supersection and Large page entries
 ******************************************************************************/

/*
 * TTD_SD (Translation Table Descriptor [Short-Descriptor]) shift values
 */
static const uint32_t
    S_TTD_SD_TYPE          = 0,  // Identification of descriptor type
    S_TTD_SD_SS_PXN        = 0,  // {[Super]Section} Privileged eXecute-Never
    S_TTD_SD_SM_XN         = 0,  // {Small Page} eXecute Never
    S_TTD_SD_B             = 2,  // Bufferable
    S_TTD_SD_C             = 3,  // Cacheable
    S_TTD_SD_SS_XN         = 4,  // {[Super]Section} eXecute Never
    S_TTD_SD_LGSM_AP_LOWER = 4,  // {Large|Small Page} Access Permissions (lower portion)
    S_TTD_SD_SECT_DOMAIN   = 5,  // {Section} which of the 16 Domains the entry is in
    S_TTD_SD_SUP_EXT_UPPER = 5,  // {Supersection} Extended Base Address (upper portion)
    S_TTD_SD_SM_TEX        = 6,  // {Small Page} Type Extension (when SCTLR.TRE = 0)
    S_TTD_SD_LGSM_AP_UPPER = 9,  // {Large|Small Page} Access Permissions (upper portion)
    S_TTD_SD_PG_BASEADDR   = 10, // {Page Table} Base Address
    S_TTD_SD_SS_AP_LOWER   = 10, // {[Super]Section} Access Permissions (lower portion)
    S_TTD_SD_LGSM_S        = 10, // {Large|Small Page} Shareable - whether Shareable memory
    S_TTD_SD_LGSM_NG       = 11, // Not Global - how translation is marked in the TLB
    S_TTD_SD_SM_BASEADDR   = 12, // {Small Page} Base Address
    S_TTD_SD_SSLG_TEX      = 12, // {[Super]Section|Large Page} Type Extension (when SCTLR.TRE = 0)
    S_TTD_SD_SS_AP_UPPER   = 15, // {[Super]Section} Access Permissions (upper portion)
    S_TTD_SD_LG_XN         = 15, // {Large Page} eXecute Never
    S_TTD_SD_SS_S          = 16, // {[Super]Section} Shareable - whether Shareable memory
    S_TTD_SD_LG_BASEADDR   = 16, // {Large Page} Base Address
    S_TTD_SD_SS_TYPE       = 18, // {[Super]Section} set = Supersection; clear = Section
    S_TTD_SD_SS_NS         = 19, // {[Super]Section} Non-Secure
    S_TTD_SD_SECT_BASEADDR = 20, // {Section} Base Address
    S_TTD_SD_SUP_EXT_LOWER = 20, // {Supersection} Extended Base Address (lower portion)
    S_TTD_SD_SUP_BASEADDR  = 24; // {Supersection} Base Address
/*
 * TTD_SD (Translation Table Descriptor [Short-Descriptor]) mask values
 */
static const uint32_t
    M_TTD_SD_TYPE          = _MM_MAKEMASK(2, S_TTD_SD_TYPE),
    M_TTD_SD_SS_PXN        = _MM_MAKEMASK1(S_TTD_SD_SS_PXN),
    M_TTD_SD_SM_XN         = _MM_MAKEMASK1(S_TTD_SD_SM_XN),
    M_TTD_SD_B             = _MM_MAKEMASK1(S_TTD_SD_B),
    M_TTD_SD_C             = _MM_MAKEMASK1(S_TTD_SD_C),
    M_TTD_SD_SS_XN         = _MM_MAKEMASK1(S_TTD_SD_SS_XN),
    M_TTD_SD_LGSM_AP_LOWER = _MM_MAKEMASK(2, S_TTD_SD_LGSM_AP_LOWER),
    M_TTD_SD_SECT_DOMAIN   = _MM_MAKEMASK(4, S_TTD_SD_SECT_DOMAIN),
    M_TTD_SD_SUP_EXT_UPPER = _MM_MAKEMASK(4, S_TTD_SD_SUP_EXT_UPPER),
    M_TTD_SD_SM_TEX        = _MM_MAKEMASK(3, S_TTD_SD_SM_TEX),
    M_TTD_SD_LGSM_AP_UPPER = _MM_MAKEMASK1(S_TTD_SD_LGSM_AP_UPPER),
    M_TTD_SD_PG_BASEADDR   = _MM_MAKEMASK(22, S_TTD_SD_PG_BASEADDR),
    M_TTD_SD_SS_AP_LOWER   = _MM_MAKEMASK(2, S_TTD_SD_SS_AP_LOWER),
    M_TTD_SD_LGSM_S        = _MM_MAKEMASK1(S_TTD_SD_LGSM_S),
    M_TTD_SD_LGSM_NG       = _MM_MAKEMASK1(S_TTD_SD_LGSM_NG),
    M_TTD_SD_SM_BASEADDR   = _MM_MAKEMASK(20, S_TTD_SD_SM_BASEADDR),
    M_TTD_SD_SSLG_TEX      = _MM_MAKEMASK(3, S_TTD_SD_SSLG_TEX),
    M_TTD_SD_SS_AP_UPPER   = _MM_MAKEMASK1(S_TTD_SD_SS_AP_UPPER),
    M_TTD_SD_LG_XN         = _MM_MAKEMASK1(S_TTD_SD_LG_XN),
    M_TTD_SD_SS_S          = _MM_MAKEMASK1(S_TTD_SD_SS_S),
    M_TTD_SD_LG_BASEADDR   = _MM_MAKEMASK(16, S_TTD_SD_LG_BASEADDR),
    M_TTD_SD_SS_TYPE       = _MM_MAKEMASK1(S_TTD_SD_SS_TYPE),
    M_TTD_SD_SS_NS         = _MM_MAKEMASK1(S_TTD_SD_SS_NS),
    M_TTD_SD_SECT_BASEADDR = _MM_MAKEMASK(12, S_TTD_SD_SECT_BASEADDR),
    M_TTD_SD_SUP_EXT_LOWER = _MM_MAKEMASK(4, S_TTD_SD_SUP_EXT_LOWER),
    M_TTD_SD_SUP_BASEADDR  = _MM_MAKEMASK(8, S_TTD_SD_SUP_BASEADDR);

/*
 * TTD_SD (Translation Table Descriptor [Short-Descriptor]) bitfield values
 */
static const uint32_t
    K_TTD_SD_L1_TYPE_IGNORE     = 0,
    K_TTD_SD_L1_TYPE_PAGE_TABLE = 1, // level-1 entry points to level-2 page
    K_TTD_SD_L1_TYPE_SS         = 2, // Section or Supersection (PXN = 0)
    K_TTD_SD_L1_TYPE_RESERVED   = 3, // Reserved (Large Physical Address Extension no implemented)

    K_TTD_SD_L2_TYPE_FAULT         = 0,
    K_TTD_SD_L2_TYPE_LARGE_PAGE    = 1,
    K_TTD_SD_L2_TYPE_SMALL_PAGE    = 2, // Small Page (XN = 0)
    K_TTD_SD_L2_TYPE_SMALL_PAGE_XN = 3, // Small Page (XN = 1)

//                                                      Memory Type         Page Shareable
//                                                      =================== ===================
    K_TTD_SD_TEXCB_R_DIS_STRONGLY_ORDERED    = 0x00, // Strongly-ordered    Shareable
    K_TTD_SD_TEXCB_R_DIS_SHAREABLE_DEVICE    = 0x01, // Device              Shareable
    K_TTD_SD_TEXCB_R_DIS_WRITE_THROUGH       = 0x02, // Normal              S-bit
    K_TTD_SD_TEXCB_R_DIS_WRITE_BACK_NO_ALLOC = 0x03, // Normal              S-bit
    K_TTD_SD_TEXCB_R_DIS_NON_CACHEABLE       = 0x04, // Normal              S-bit
    K_TTD_SD_TEXCB_R_DIS_WRITE_BACK_ALLOC    = 0x07, // Normal              S-bit
    K_TTD_SD_TEXCB_R_DIS_NON_SHAREABLE_DEV   = 0x08, // Device              Non-Shareable
    K_TTD_SD_TEXCB_R_DIS_CACHEABLE_MIN       = 0x10, // Normal              S-bit
    K_TTD_SD_TEXCB_R_DIS_CACHEABLE_MAX       = 0x1F, // Normal              S-bit

    K_TDD_SD_TEXCB_R_ENA_TR0 = 0x0, // Memory type from PRRR.TR0
    K_TDD_SD_TEXCB_R_ENA_TR1 = 0x1, // Memory type from PRRR.TR1
    K_TDD_SD_TEXCB_R_ENA_TR2 = 0x2, // Memory type from PRRR.TR2
    K_TDD_SD_TEXCB_R_ENA_TR3 = 0x3, // Memory type from PRRR.TR3
    K_TDD_SD_TEXCB_R_ENA_TR4 = 0x4, // Memory type from PRRR.TR4
    K_TDD_SD_TEXCB_R_ENA_TR5 = 0x5, // Memory type from PRRR.TR5
    K_TDD_SD_TEXCB_R_ENA_TR7 = 0x7; // Memory type from PRRR.TR7

/*
 * TTD_SD (Translation Table Descriptor [Short-Descriptor]) AP portion compilation
 */
static const uint32_t
    S_TTD_SD_AP_UPPER_COMP = 2; // Access Permissions (upper portion compilation)

/*
 * TTD_S1 (Translation Table Descriptor [Stage-1 Long format]) shift values
 */
static const uint64_t
    S_TTD_S1_VALID    = 0,  // whether the descriptor is valid
    S_TTD_S1_TYPE     = 1,  // descriptor type
    S_TTD_S1_NEXTADDR = 12, // Next-level address

    S_TTD_S1_BLK_PG_LOWER = 2,  // Lower block attributes
    S_TTD_S1_BLK_PG_UPPER = 52, // Upper block attributes

    S_TTD_S1_BLK_PG_A_INDX  = 2,  // AttrIndx[2:0] (IDs Memory Attribute Indirection Register)
    S_TTD_S1_BLK_PG_NS      = 5,  // Non-secure
    S_TTD_S1_BLK_PG_AP      = 6,  // Access Permissions
    S_TTD_S1_BLK_PG_SH      = 8,  // Shareability field
    S_TTD_S1_BLK_PG_AF      = 10, // Access flag
    S_TTD_S1_BLK_PG_NG      = 11, // not global
    S_TTD_S1_BLK_PG_CONTIG  = 52, // Contiguous hint
    S_TTD_S1_BLK_PG_PXN     = 53, // Privileged execute-never
    S_TTD_S1_BLK_PG_UXN     = 54, // Execute-never
    S_TTD_S1_BLK_PG_SW_USE  = 55, // Reserved for software use
    S_TTD_S1_BLK_PG_TN      = 55, // TN[2:0] Table number for SPRR
    S_TTD_S1_BLK_PG_IGNORED = 59, // ignored

    S_TTD_S1_TABLE_PXN = 59, // PXN Table
    S_TTD_S1_TABLE_UXN = 60, // UXN Table (or XN Table when not EL1|EL0)
    S_TTD_S1_TABLE_AP  = 61, // Ap Table
    S_TTD_S1_TABLE_NS  = 63, // NS Table

    S_TTD_S1_PG_4K_OUTADDR      = 12, // Output address - 4K granularity
    S_TTD_S1_PG_16K_OUTADDR     = 14, // Output address - 16K granularity
    S_TTD_S1_PG_64K_OUTADDR     = 16, // Output address - 64K granularity
    S_TTD_S1_BLK_4K_L1_OUTADDR  = 30, // Output address of 4K granularity level-1 block (1GB)
    S_TTD_S1_BLK_4K_L2_OUTADDR  = 21, // Output address of 4K granularity level-2 block (2 MB)
    S_TTD_S1_BLK_16K_L2_OUTADDR = 25, // Output address of 16K granularity level-2 block (32 MB)
    S_TTD_S1_BLK_64K_L2_OUTADDR = 29; // Output address of 64K granularity level-2 block (512 MB)

/*
 * TTD_S1 (Translation Table Descriptor [Stage-1 Long format]) mask values
 */
static const uint64_t
    M_TTD_S1_VALID    = _MM64_MAKEMASK1(S_TTD_S1_VALID),
    M_TTD_S1_TYPE     = _MM64_MAKEMASK1(S_TTD_S1_TYPE),
    M_TTD_S1_NEXTADDR = _MM64_MAKEMASK(36, S_TTD_S1_NEXTADDR), // This is a mask [47:12]

    M_TTD_S1_BLK_PG_LOWER = _MM64_MAKEMASK(10, S_TTD_S1_BLK_PG_LOWER),
    M_TTD_S1_BLK_PG_UPPER = _MM64_MAKEMASK(12, S_TTD_S1_BLK_PG_UPPER),

    M_TTD_S1_BLK_PG_A_INDX  = _MM64_MAKEMASK(3, S_TTD_S1_BLK_PG_A_INDX),
    M_TTD_S1_BLK_PG_NS      = _MM64_MAKEMASK1(S_TTD_S1_BLK_PG_NS),
    M_TTD_S1_BLK_PG_AP      = _MM64_MAKEMASK(2, S_TTD_S1_BLK_PG_AP),
    M_TTD_S1_BLK_PG_SH      = _MM64_MAKEMASK(2, S_TTD_S1_BLK_PG_SH),
    M_TTD_S1_BLK_PG_AF      = _MM64_MAKEMASK1(S_TTD_S1_BLK_PG_AF),
    M_TTD_S1_BLK_PG_NG      = _MM64_MAKEMASK1(S_TTD_S1_BLK_PG_NG),
    M_TTD_S1_BLK_PG_CONTIG  = _MM64_MAKEMASK1(S_TTD_S1_BLK_PG_CONTIG),
    M_TTD_S1_BLK_PG_PXN     = _MM64_MAKEMASK1(S_TTD_S1_BLK_PG_PXN),
    M_TTD_S1_BLK_PG_UXN     = _MM64_MAKEMASK1(S_TTD_S1_BLK_PG_UXN),
    M_TTD_S1_BLK_PG_SW_USE  = _MM64_MAKEMASK(4, S_TTD_S1_BLK_PG_SW_USE),
    M_TTD_S1_BLK_PG_TN      = _MM64_MAKEMASK(3, S_TTD_S1_BLK_PG_TN),
    M_TTD_S1_BLK_PG_IGNORED = _MM64_MAKEMASK(5, S_TTD_S1_BLK_PG_IGNORED),

    M_TTD_S1_TABLE_PXN = _MM64_MAKEMASK1(S_TTD_S1_TABLE_PXN),
    M_TTD_S1_TABLE_UXN = _MM64_MAKEMASK1(S_TTD_S1_TABLE_UXN),
    M_TTD_S1_TABLE_AP  = _MM64_MAKEMASK(2, S_TTD_S1_TABLE_AP),
    M_TTD_S1_TABLE_NS  = _MM64_MAKEMASK1(S_TTD_S1_TABLE_NS),

    M_TTD_S1_PG_4K_OUTADDR      = _MM64_MAKEMASK(36, S_TTD_S1_PG_4K_OUTADDR),
    M_TTD_S1_PG_16K_OUTADDR     = _MM64_MAKEMASK(34, S_TTD_S1_PG_16K_OUTADDR),
    M_TTD_S1_PG_64K_OUTADDR     = _MM64_MAKEMASK(32, S_TTD_S1_PG_64K_OUTADDR),
    M_TTD_S1_BLK_4K_L1_OUTADDR  = _MM64_MAKEMASK(18, S_TTD_S1_BLK_4K_L1_OUTADDR),
    M_TTD_S1_BLK_4K_L2_OUTADDR  = _MM64_MAKEMASK(27, S_TTD_S1_BLK_4K_L2_OUTADDR),
    M_TTD_S1_BLK_16K_L2_OUTADDR = _MM64_MAKEMASK(23, S_TTD_S1_BLK_16K_L2_OUTADDR),
    M_TTD_S1_BLK_64K_L2_OUTADDR = _MM64_MAKEMASK(19, S_TTD_S1_BLK_64K_L2_OUTADDR);

static const uint64_t
    K_TTD_S1_TYPE_BLOCK = 0, // [L1|L2] addr & attribs of a memory block
    K_TTD_S1_TYPE_TABLE = 1, // [L1|L2] next level addr ([L1] + some attribs)
    K_TTD_S1_TYPE_PAGE  = 1, // [L3] addr & attribs of a 4KB page of memory

    K_TTD_S1_BLK_PG_PXN_EXECUTE_OK = 0, // no privilege level restriction applies to allowing execution from region
    K_TTD_S1_BLK_PG_PXN_NO_EXECUTE = 1, // processor access at PL1 never allowed to execute instructions
    K_TTD_S1_BLK_PG_XN_EXECUTE_OK  = 0, // processor can execute instructions from a memory region
    K_TTD_S1_BLK_PG_XN_NO_EXECUTE  = 1, // processor never allowed to execute instructions from memory region

    K_TTD_S1_BLK_OUTADDR_N = 30,
    K_TTD_S1_BLK_PG_SZ     = (1024 * 1024 * 1024), // Level-1 memory block = 1GB

    K_TTD_S1_TABLE_SEC_NS_IS_SECURE     = 0,
    K_TTD_S1_TABLE_SEC_NS_NON_SECURE    = 1,
    K_TTD_S1_TABLE_AP_NO_PERMISSIONS    = 0, // No effect on permissions in subsequent levels of lookup
    K_TTD_S1_TABLE_AP_NO_PL0            = 1, // Access at PL0 not permitted, regardless of permissions in subsequent levels of lookup
    K_TTD_S1_TABLE_AP_NO_WRITE          = 2, // No write access (any PL), regardless of permissions in subsequent levels of lookup
    K_TTD_S1_TABLE_AP_NO_WRITE_PL0_READ = 3; // Write access not permitted in subsequent lookups, read access at PL0 not permitted

/*
 * TTD_S1_AP - Data access permissions for stage 1 of the EL1&0 translation regime
 */
static const uint64_t
    TTD_S1_AP_EL1_RW_EL0_NONE = 0, // Access from - EL1: Read/Write EL0: None
    TTD_S1_AP_EL1_RW_EL0_RW   = 1, // Access from - EL1: Read/Write EL0: Read/Write
    TTD_S1_AP_EL1_RO_EL0_NONE = 2, // Access from - EL1: Read-Only  EL0: None
    TTD_S1_AP_EL1_RO_EL0_RO   = 3; // Access from - EL1: Read-Only  EL0: Read-Only

/*
 * TTD_S1_SPRR_AP - SPRR Data access permissions for stage 1 of the Guarded&Normal translation regime
 */
static const uint8_t
    TTD_S1_AP_GTR_NONE_NTR_NONE = 0,  // Guarded Translation Regime: None Normal Translation Regime: None
    TTD_S1_AP_GTR_NONE_NTR_RX   = 1,  // Guarded Translation Regime: None Normal Translation Regime: Read/Execute
    TTD_S1_AP_GTR_NONE_NTR_RO   = 2,  // Guarded Translation Regime: None Normal Translation Regime: Read-Only
    TTD_S1_AP_GTR_NONE_NTR_RW   = 3,  // Guarded Translation Regime: None Normal Translation Regime: Read/Write
    TTD_S1_AP_GTR_RX_NTR_NONE4  = 4,  // Guarded Translation Regime: Read/Execute Normal Translation Regime: None
    TTD_S1_AP_GTR_RX_NTR_RX     = 5,  // Guarded Translation Regime: Read/Execute Normal Translation Regime: Read/Execute
    TTD_S1_AP_GTR_RX_NTR_RO     = 6,  // Guarded Translation Regime: Read/Execute Normal Translation Regime: Read-Only
    TTD_S1_AP_GTR_RX_NTR_NONE7  = 7,  // Guarded Translation Regime: Read/Execute Normal Translation Regime: None
    TTD_S1_AP_GTR_RO_NTR_NONE   = 8,  // Guarded Translation Regime: Read-Only Normal Translation Regime: None
    TTD_S1_AP_GTR_RO_NTR_XO     = 9,  // Guarded Translation Regime: Read-Only Normal Translation Regime: Execute-Only
    TTD_S1_AP_GTR_RO_NTR_RO     = 10, // Guarded Translation Regime: Read-Only  Normal Translation Regime: Read-Only
    TTD_S1_AP_GTR_RO_NTR_RW     = 11, // Guarded Translation Regime: Read-Only  Normal Translation Regime: Read/Write
    TTD_S1_AP_GTR_RW_NTR_NONE   = 12, // Guarded Translation Regime: Read/Write Normal Translation Regime: None
    TTD_S1_AP_GTR_RW_NTR_RX     = 13, // Guarded Translation Regime: Read/Write Normal Translation Regime: Read/Execute
    TTD_S1_AP_GTR_RW_NTR_RO     = 14, // Guarded Translation Regime: Read-Write  Normal Translation Regime: Read-Only
    TTD_S1_AP_GTR_RW_NTR_RW     = 15; // Guarded Translation Regime: Read-Write  Normal Translation Regime: Read/Write

/*
 * TTD_S1_APTABLE - Data access permissions applied to subsequent levels of lookup
 */
static const uint64_t
    TTD_S1_APTABLE_NO_EFFECT     = 0, // No effect on permissions in subsequent levels of lookup
    TTD_S1_APTABLE_EL0_NONE      = 1, // Access at EL0 not permitted
    TTD_S1_APTABLE_NO_W          = 2, // Write access not permitted, at any Exception level
    TTD_S1_APTABLE_NO_W_EL0_NONE = 3; // Write access not permitted, at any Exception level, Read access not permitted at EL0

/********************************
 * AArch64 instruction encodings
 *******************************/

/*
 * Encodings for ARM64 "mrs" and "msr" instructions
 */
static const uint32_t
    ARM64_MSR_MRS_BASE_SHIFT = 22,
    ARM64_MSR_MRS_BASE_MASK  = _MM_MAKEMASK(10, ARM64_MSR_MRS_BASE_SHIFT),
    ARM64_MSR_MRS_BASE_ENC   = (0x354 << ARM64_MSR_MRS_BASE_SHIFT),
    ARM64_MSR_MRS_RT_SHIFT   = 0,                   // Source or destination register
    ARM64_MSR_MRS_RT_MASK    = 0x1f << ARM64_MSR_MRS_RT_SHIFT,
    ARM64_MSR_MRS_OP2_SHIFT  = 5,                   // Op2
    ARM64_MSR_MRS_OP2_MASK   = 0x7 << ARM64_MSR_MRS_OP2_SHIFT,
    ARM64_MSR_MRS_CRM_SHIFT  = 8,                   // CRm
    ARM64_MSR_MRS_CRM_MASK   = 0x7 << ARM64_MSR_MRS_CRM_SHIFT,
    ARM64_MSR_MRS_CRN_SHIFT  = 12,                  // CRn
    ARM64_MSR_MRS_CRN_MASK   = 0xf << ARM64_MSR_MRS_CRN_SHIFT,
    ARM64_MSR_MRS_OP1_SHIFT  = 16,                  // Op1
    ARM64_MSR_MRS_OP1_MASK   = 0x7 << ARM64_MSR_MRS_OP1_SHIFT,
    ARM64_MSR_MRS_OP0_SHIFT  = 19,                  // Op0
    ARM64_MSR_MRS_OP0_MASK   = 0x3 << ARM64_MSR_MRS_OP0_SHIFT,
    ARM64_MSR_MRS_L_SHIFT    = 21,                  // "L" (L = 1 -> instruction is "mrs")
    ARM64_MSR_MRS_L_MSR      = 0x0 << ARM64_MSR_MRS_L_SHIFT,
    ARM64_MSR_MRS_L_MRS      = 0x1 << ARM64_MSR_MRS_L_SHIFT;

// [API] Construct ARMv8 system registers
#define AARCH64_SYSREG_ENCODING(Op0, Op1, CRn, CRm, Op2) \
    (((CRn) << ARM64_MSR_MRS_CRN_SHIFT) |                \
     ((CRm) << ARM64_MSR_MRS_CRM_SHIFT) |                \
     ((Op0) << ARM64_MSR_MRS_OP0_SHIFT) |                \
     ((Op1) << ARM64_MSR_MRS_OP1_SHIFT) |                \
     ((Op2) << ARM64_MSR_MRS_OP2_SHIFT))

/*
 * [API]
 * This macro is used for encoding ARMv8 system registers for MSR/MRS
 * instructions.  We are being pessimistic in assuming that the min EL to
 * access any register is EL3, but it guarantees that we will be able to do so.
 */
#define ARM64_SYSREG_MRS_MSR(op0, op1, crn, crm, op2)     \
    ((ARM64_REG_SYSREG_ENC_FLAG) |                        \
     (AARCH64_SYSREG_ENCODING(op0, op1, crn, crm, op2)) | \
     ((ARM64_PL_EL_3 << ARM64_REG_SYSREG_MIN_EL_SHIFT) & ARM64_REG_SYSREG_MIN_EL_MASK))

#define ARM64_SYSREG_MRS_MSR_WITH_EL(op0, op1, crn, crm, op2, el) \
    ((ARM64_REG_SYSREG_ENC_FLAG) |                                \
     (AARCH64_SYSREG_ENCODING(op0, op1, crn, crm, op2)) |         \
     ((el << ARM64_REG_SYSREG_MIN_EL_SHIFT) & ARM64_REG_SYSREG_MIN_EL_MASK))

/*
 * Encodings for:
 *     FMOV Dd, Xn
 *     FMOV Vd.D[1], Xn
 *     FMOV Xd, Dn
 *     FMOV Xd, Vn.D[1]
 * d in bits [9,5]
 * n in bits [4,0]
 *
 * NOTE: 64-bit transfer size only
 */
static const uint32_t
    ARM64_MOV_GPR_TO_VFP_BASE_ENC     = 0x9e670000,
    ARM64_MOV_GPR_TO_VFP_TOP_BASE_ENC = 0x9eaf0000,
    ARM64_MOV_VFP_TO_GPR_BASE_ENC     = 0x9e660000,
    ARM64_MOV_VFP_TOP_TO_GPR_BASE_ENC = 0x9eae0000,
    ARM64_MOV_VFP_SRC_SHIFT           = 5,
    ARM64_MOV_VFP_DEST_SHIFT          = 0;

/*
 * Encoding for:
 *  add Xd, Xn, #imm {, <shift>}
 * Xn in bits [9,5]
 * We include an implicit shift of 0 in [23:22]
 */
static const uint32_t
    ARM64_ADD_BASE_ENC   = 0x91000000,
    ARM64_ADD_DEST_SHIFT = 0,
    ARM64_ADD_SRC_SHIFT  = 5,
    ARM64_ADD_IMM_SHIFT  = 10;

/*
 * Encodings for:
 *  ldr Xd, [Xn], #imm
 *  str Xd, [Xn], #imm
 * and byte, half-word, and word variants
 */
static const uint32_t
    ARM64_LDRSTR_POSTINC_BASE_ENC   = 0x38000400,
    ARM64_LDRSTR_OP_SHIFT           = 22,
    ARM64_LDRSTR_OP_LDR             = 1 << ARM64_LDRSTR_OP_SHIFT,
    ARM64_LDRSTR_OP_STR             = 0 << ARM64_LDRSTR_OP_SHIFT,
    ARM64_LDRSTR_SIZE_SHIFT         = 30,
    ARM64_LDRSTR_SIZE_1B            = 0 << ARM64_LDRSTR_SIZE_SHIFT,
    ARM64_LDRSTR_SIZE_2B            = 1 << ARM64_LDRSTR_SIZE_SHIFT,
    ARM64_LDRSTR_SIZE_4B            = 2 << ARM64_LDRSTR_SIZE_SHIFT,
    ARM64_LDRSTR_SIZE_8B            = 3 << ARM64_LDRSTR_SIZE_SHIFT,
    ARM64_LDRSTR_POSTINC_DEST_SHIFT = 0,
    ARM64_LDRSTR_POSTINC_BASE_SHIFT = 5,
    ARM64_LDRSTR_POSTINC_IMM_SHIFT  = 12,
    ARM64_LDRSTR_POSTINC_MAX_IMM    = ((1 << 9) - 1); // 9 bits

/*
 * Encodings for:
 *  drps
 *  dcps1 #0
 *  dcps2 #0
 *  dcps3 #0
 */
static const uint32_t
    ARM64_DRPS_ENC       = 0xd6bf03e0,
    ARM64_DCPSX_BASE_ENC = 0xd4a00000,
    ARM64_DCPSX_EL_SHIFT = 0;

/*
 * Encoding for:
 *  isb sy (for breakpoint serialization)
 */
static const uint32_t
    ARM64_ISB_SY_ENCODING = 0xd5033fdf;

/*
 * Encodings for:
 *  dc csw, x1
 *  dc cisw, x1
 *  dc cvac, x1
 *  dc civac, x1
 */
static const uint32_t
    ARM64_DC_CSW_X1_ENC   = 0xd5087a41, // 0, c7, c10, 2 {Xt}
    ARM64_DC_CISW_X1_ENC  = 0xd5087e41, // 0, C7, C14, 2 {Xt}
    ARM64_DC_CVAC_X1_ENC  = 0xd50b7a21, // 3, c7, c10, 1 {Xt}
    ARM64_DC_CIVAC_X1_ENC = 0xd50b7e21; // 3, c7, c14, 1 {Xt}

/*
 * Encodings for:
 *  ic iallu
 *  ic ivau, 11
 */
static const uint32_t
    ARM64_IC_IALLU_ENC   = 0xd508751f, // 0, c7, c5, 0
    ARM64_IC_IVAU_X1_ENC = 0xd50b7521; // 3, c7, c5, 1 {Xt}

/*
 * Base encoding for:
 *  hint #imm
 */
static const uint32_t
    ARM64_HINT_BASE_ENC = 0xD503201F;

/*
 * Shift values for hint encoding.
 */
static const uint32_t
    ARM64_HINT_OP2_SHIFT = 5,
    ARM64_HINT_CRM_SHIFT = 8;

/*
 * Mask values for hint encoding.
 */
static const uint32_t
    ARM64_HINT_OP2_MASK = 0x000000E00,
    ARM64_HINT_CRM_MASK = 0x00000F000;

/*
 * Max values that will fit in the CRm and OP2 bitfields of hint instruction.
 */
static const uint32_t
    ARM64_HINT_OP2_MAX = 0xF,
    ARM64_HINT_CRM_MAX = 0x7;

/*
 * CRm and OP2 values for system hint op types.
 */
static const uint32_t
    ARM64_HINT_NOP_OP2_VAL = 0,
    ARM64_HINT_NOP_CRM_VAL = 0;

/******************************************************
 * T32 instruction encodings - little endian halfwords
 *****************************************************/

/*
 * mcr [Rt]
 * mrc [Rt]
 */
static const uint32_t
    T32_MCR_BASE_ENC     = 0x0010ee00,
    T32_MRC_BASE_ENC     = 0x0010ee10,
    T32_MRC_MCR_RT_SHIFT = 28;

/*
 * Encodings for:
 *  ldr Rt, [Rn], #imm
 *  str Rt, [Rn], #imm
 * and byte and half-word variants.
 */
static const uint32_t
    T32_LDRSTR_POSTINC_BASE_ENC   = 0x0b00f800,
    T32_LDRSTR_OP_SHIFT           = 4,
    T32_LDRSTR_OP_LDR             = 1 << T32_LDRSTR_OP_SHIFT,
    T32_LDRSTR_OP_STR             = 0 << T32_LDRSTR_OP_SHIFT,
    T32_LDRSTR_SIZE_SHIFT         = 5,
    T32_LDRSTR_SIZE_1B            = 0 << T32_LDRSTR_SIZE_SHIFT,
    T32_LDRSTR_SIZE_2B            = 1 << T32_LDRSTR_SIZE_SHIFT,
    T32_LDRSTR_SIZE_4B            = 2 << T32_LDRSTR_SIZE_SHIFT,
    T32_LDRSTR_POSTINC_DEST_SHIFT = 28,
    T32_LDRSTR_POSTINC_BASE_SHIFT = 0,
    T32_LDRSTR_POSTINC_IMM_SHIFT  = 16,
    T32_LDRSTR_POSTINC_MAX_IMM    = ((1 << 8) - 1); // 8 bits

/*
 * ISB
 */
static const uint32_t
    T32_ISB_SY_ENC = 0x8f6ff3bf;

/*
 * DCPS
 */
static const uint32_t
    T32_DCPSX_BASE_ENC = 0x8000f78f,
    T32_DCPSX_EL_SHIFT = 16;

#define ARM64_SYSREG_TO_REGID(x) (ARM64_REG_SYSREG_ID_FLAG | (x))

//------------------------------------------------------------------------------
// ARM PL310 Cache Controller
//------------------------------------------------------------------------------

static const uint64_t
    ARM_PL310_CACHE_ID          = 0x000, // Cache ID Register
    ARM_PL310_CACHE_TYPE        = 0x004, // Cache Type Register
    ARM_PL310_CONTROL           = 0x100, // Control Register
    ARM_PL310_AUXILIARY_CONTROL = 0x104, // Auxiliary Control
    ARM_PL310_CLEAN_BY_WAY      = 0x7BC; // Clean by Way

//
// PL310 Cache ID
//

static const uint64_t
    S_PL310_CACHE_ID_RTL_RELEASE = 0,
    S_PL310_CACHE_ID_PART_NUMBER = 6,
    S_PL310_CACHE_ID_CACHE_ID    = 10,
    S_PL310_CACHE_ID_IMPLEMENTER = 24;

static const uint64_t
    M_PL310_CACHE_ID_RTL_RELEASE = _MM64_MAKEMASK(6, S_PL310_CACHE_ID_RTL_RELEASE),
    M_PL310_CACHE_ID_PART_NUMBER = _MM64_MAKEMASK(4, S_PL310_CACHE_ID_PART_NUMBER),
    M_PL310_CACHE_ID_CACHE_ID    = _MM64_MAKEMASK(6, S_PL310_CACHE_ID_CACHE_ID),
    M_PL310_CACHE_ID_IMPLEMENTER = _MM64_MAKEMASK(8, S_PL310_CACHE_ID_IMPLEMENTER);

static const uint64_t
    K_PL310_CACHE_ID_PART_NUMBER = 0x3,  // ARM PL310 Level 2 Cache Controller
    K_PL310_CACHE_ID_IMPLEMENTER = 0x41; // ARM

//
// PL310 Cache Control
//

static const uint64_t
    S_PL310_CACHE_CONTROL_L2_ENABLE = 0;

static const uint64_t
    M_PL310_CACHE_CONTROL_L2_ENABLE = _MM64_MAKEMASK1(S_PL310_CACHE_CONTROL_L2_ENABLE);

//
// PL310 Auxiliary Control
//

static const uint64_t
    S_PL310_AUX_CTL_CYCLES_LATENCY_READ  = 0,
    S_PL310_AUX_CTL_CYCLES_LATENCY_WRITE = 3,
    S_PL310_AUX_CTL_CYCLES_LATENTCY_TAG  = 6,
    S_PL310_AUX_CTL_EXCLUSIVE            = 12,
    S_PL310_AUX_CTL_ASSOCIATIVITY        = 16,
    S_PL310_AUX_CTL_WAY_SIZE             = 17,
    S_PL310_AUX_CTL_EVENT_MON_BUS_EN     = 20,
    S_PL310_AUX_CTL_PARITY_EN            = 21,
    S_PL310_AUX_CTL_SHARED_ATTR_OVR_EN   = 22,
    S_PL310_AUX_CTL_FORCE_WRITE_ALLOC    = 23,
    S_PL310_AUX_CTL_NON_SEC_LOCKDOWN_EN  = 26,
    S_PL310_AUX_CTL_NON_SEC_INTR_ACC_CTL = 27,
    S_PL310_AUX_CTL_DATA_PREFETCH_EN     = 28,
    S_PL310_AUX_CTL_INSTRUCT_PREFETCH_EN = 29;

static const uint64_t
    M_PL310_AUX_CTL_CYCLES_LATENCY_READ  = _MM64_MAKEMASK(3, S_PL310_AUX_CTL_CYCLES_LATENCY_READ),
    M_PL310_AUX_CTL_CYCLES_LATENCY_WRITE = _MM64_MAKEMASK(3, S_PL310_AUX_CTL_CYCLES_LATENCY_WRITE),
    M_PL310_AUX_CTL_CYCLES_LATENTCY_TAG  = _MM64_MAKEMASK(3, S_PL310_AUX_CTL_CYCLES_LATENTCY_TAG),
    M_PL310_AUX_CTL_EXCLUSIVE            = _MM64_MAKEMASK1(S_PL310_AUX_CTL_EXCLUSIVE),
    M_PL310_AUX_CTL_ASSOCIATIVITY        = _MM64_MAKEMASK1(S_PL310_AUX_CTL_ASSOCIATIVITY),
    M_PL310_AUX_CTL_WAY_SIZE             = _MM64_MAKEMASK(3, S_PL310_AUX_CTL_WAY_SIZE),
    M_PL310_AUX_CTL_EVENT_MON_BUS_EN     = _MM64_MAKEMASK1(S_PL310_AUX_CTL_EVENT_MON_BUS_EN),
    M_PL310_AUX_CTL_PARITY_EN            = _MM64_MAKEMASK1(S_PL310_AUX_CTL_PARITY_EN),
    M_PL310_AUX_CTL_SHARED_ATTR_OVR_EN   = _MM64_MAKEMASK1(S_PL310_AUX_CTL_SHARED_ATTR_OVR_EN),
    M_PL310_AUX_CTL_FORCE_WRITE_ALLOC    = _MM64_MAKEMASK(2, S_PL310_AUX_CTL_FORCE_WRITE_ALLOC),
    M_PL310_AUX_CTL_NON_SEC_LOCKDOWN_EN  = _MM64_MAKEMASK1(S_PL310_AUX_CTL_NON_SEC_LOCKDOWN_EN),
    M_PL310_AUX_CTL_NON_SEC_INTR_ACC_CTL = _MM64_MAKEMASK1(S_PL310_AUX_CTL_NON_SEC_INTR_ACC_CTL),
    M_PL310_AUX_CTL_DATA_PREFETCH_EN     = _MM64_MAKEMASK1(S_PL310_AUX_CTL_DATA_PREFETCH_EN),
    M_PL310_AUX_CTL_INSTRUCT_PREFETCH_EN = _MM64_MAKEMASK1(S_PL310_AUX_CTL_INSTRUCT_PREFETCH_EN);

//
// PL310 Clean by Way
//

static const uint64_t
    S_PL310_CLEAN_WAY_WAY_BITS = 0;

static const uint64_t
    M_PL310_CLEAN_WAY_WAY_BITS = _MM64_MAKEMASK(16, S_PL310_CLEAN_WAY_WAY_BITS);

#endif /* _ASTRIS_ARM_H */
