Add support of MSR/MRS, system registers

This commit is contained in:
rkx1209 2018-03-23 12:36:23 +09:00
parent 99a9efa369
commit e966853ac4
6 changed files with 275 additions and 8 deletions

View file

@ -8,8 +8,11 @@ ARMv8State arm_state;
void Init() {
Interpreter::create ();
cpu_engine = Interpreter::get_instance ();
cpu_engine->Init ();
PC = 0x0;
//PC = 0x30f0;
SP = 0x3100000;
SYSR.tpidrro_el[0] = (1 << 24) + 0x1000 * 1;
}
void RunLoop() {

View file

@ -401,6 +401,125 @@ static void DisasException(uint32_t insn, DisasCallback *cb) {
}
}
std::map<uint32_t, const A64SysRegInfo*> sysreg_table;
static const A64SysRegInfo cp_reginfo[] = {
// name, state, opc0, opc1, opc2, crn, crm, offset
A64SysRegInfo("TPIDRRO_EL0", ARM_CP_STATE_AA64,
3, 3, 3, 13, 0, offsetof(ARMv8::ARMv8State::SysReg, tpidrro_el[0])),
A64SysRegInfo(ARM_CP_SENTINEL)
};
static void AddSysReg(const A64SysRegInfo *r, int state, int secstate, int crm, int opc1, int opc2) {
uint32_t key;
uint8_t cp = r->cp;
if (state == ARM_CP_STATE_AA64) {
if (r->cp == 0 || r->state == ARM_CP_STATE_BOTH) {
cp = CP_REG_ARM64_SYSREG_CP;
}
key = ENCODE_SYSTEM_REG (cp, r->crn, crm, r->opc0, opc1, opc2);
sysreg_table[key] = r;
}
}
static void DefineSysReg(const A64SysRegInfo *r) {
int crm, opc1, opc2, state;
int crmmin = (r->crm == CP_ANY) ? 0 : r->crm;
int crmmax = (r->crm == CP_ANY) ? 15 : r->crm;
int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1;
int opc1max = (r->opc1 == CP_ANY) ? 7 : r->opc1;
int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2;
int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2;
for (crm = crmmin; crm <= crmmax; crm++) {
for (opc1 = opc1min; opc1 <= opc1max; opc1++) {
for (opc2 = opc2min; opc2 <= opc2max; opc2++) {
for (state = ARM_CP_STATE_AA32;
state <= ARM_CP_STATE_AA64; state++) {
if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
continue;
}
if (state == ARM_CP_STATE_AA32) {
/* TODO: */
} else {
AddSysReg (r, state, ARM_CP_SECSTATE_NS, crm, opc1, opc2);
}
}
}
}
}
}
static void DefineSysRegs(const A64SysRegInfo *regs) {
const A64SysRegInfo *r;
for (r = regs; r->type != ARM_CP_SENTINEL; r++) {
DefineSysReg(r);
}
}
const A64SysRegInfo* GetSysReg(uint32_t encoded_op) {
decltype(sysreg_table)::iterator it = sysreg_table.find(encoded_op);
if (it == sysreg_table.end()) {
return NULL;
}
return it->second;
}
static void DisasSystem(uint32_t insn, DisasCallback *cb) {
unsigned int l, op0, op1, crn, crm, op2, rt;
const A64SysRegInfo *ri;
l = extract32(insn, 21, 1);
op0 = extract32(insn, 19, 2);
op1 = extract32(insn, 16, 3);
crn = extract32(insn, 12, 4);
crm = extract32(insn, 8, 4);
op2 = extract32(insn, 5, 3);
rt = extract32(insn, 0, 5);
if (op0 == 0) {
if (l || rt != 31) {
UnallocatedOp (insn);
return;
}
switch (crn) {
case 2: /* HINT (including allocated hints like NOP, YIELD, etc) */
UnsupportedOp ("HINT");
break;
case 3: /* CLREX, DSB, DMB, ISB */
UnsupportedOp ("SYNC");
//handle_sync(s, insn, op1, op2, crm);
break;
case 4: /* MSR (immediate) */
UnsupportedOp ("MSR immediate");
//handle_msr_i(s, insn, op1, op2, crm);
break;
default:
UnallocatedOp (insn);
break;
}
return;
}
bool isread = l;
ri = GetSysReg(ENCODE_SYSTEM_REG(CP_REG_ARM64_SYSREG_CP,
crn, crm, op0, op1, op2));
if (!ri) {
ns_abort("Unknown system register\n");
}
/* Handle special cases first */
switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
case ARM_CP_NOP:
return;
case ARM_CP_NZCV:
cb->ReadWriteNZCV (rt, isread);
return;
case ARM_CP_CURRENTEL:
UnsupportedOp ("MSR/MRS Current EL");
return;
case ARM_CP_DC_ZVA:
UnsupportedOp ("MSR/MRS ZVA");
return;
}
cb->ReadWriteSysReg(rt, ri->offset, isread);
}
static void DisasBranchExcSys(uint32_t insn, DisasCallback *cb) {
switch (extract32(insn, 25, 7)) {
case 0x0a: case 0x0b:
@ -418,9 +537,7 @@ static void DisasBranchExcSys(uint32_t insn, DisasCallback *cb) {
break;
case 0x6a: /* Exception generation / System */
if (insn & (1 << 24)) {
//TODO:
//DisasSystem (insn, cb);
UnsupportedOp ("System");
DisasSystem (insn, cb);
} else {
DisasException (insn, cb);
}
@ -1380,4 +1497,8 @@ void DisasA64(uint32_t insn, DisasCallback *cb) {
}
}
void Init() {
DefineSysRegs(cp_reginfo);
}
};

View file

@ -4,6 +4,10 @@
Interpreter *Interpreter::inst = nullptr;
IntprCallback *Interpreter::disas_cb = nullptr;
void Interpreter::Init() {
Disassembler::Init();
}
int Interpreter::SingleStep() {
uint32_t inst = ARMv8::ReadInst (PC);
debug_print ("Run Code: 0x%lx: 0x%08lx\n", PC, inst);
@ -523,7 +527,7 @@ void IntprCallback::ExtendReg(unsigned int rd_idx, unsigned int rn_idx, unsigned
}
/* Load/Store */
static void _LoadReg(unsigned int rd_idx, uint64_t addr, int size, bool is_sign, bool extend) {
void IntprCallback::_LoadReg(unsigned int rd_idx, uint64_t addr, int size, bool is_sign, bool extend) {
debug_print ("Read from addr:0x%lx(%d)\n", addr, size);
if (size == 0) {
X(rd_idx) = ARMv8::ReadU8 (addr);
@ -546,7 +550,7 @@ static void _LoadReg(unsigned int rd_idx, uint64_t addr, int size, bool is_sign,
}
}
static void _StoreReg(unsigned int rd_idx, uint64_t addr, int size, bool is_sign, bool extend) {
void IntprCallback::_StoreReg(unsigned int rd_idx, uint64_t addr, int size, bool is_sign, bool extend) {
debug_print ("Write to addr:0x%lx(%d)\n", addr, size);
if (size == 0) {
ARMv8::WriteU8 (addr, (uint8_t) (W(rd_idx) & 0xff));
@ -842,6 +846,24 @@ void IntprCallback::DupVecRegFromGen(unsigned int vd_idx, unsigned int rn_idx, i
}
}
/* Read/Write Sysreg */
void IntprCallback::ReadWriteSysReg(unsigned int rd_idx, int offset, bool read) {
uint64_t *sysr = (uint64_t *)(&SYSR + offset);
if (read) {
X(rd_idx) = *sysr;
} else {
*sysr = X(rd_idx);
}
}
/* Read/Write NZCV */
void IntprCallback::ReadWriteNZCV(unsigned int rd_idx, bool read) {
if (read) {
X(rd_idx) = NZCV;
} else {
NZCV = (uint32_t)(X(rd_idx) & 0xffffffff);
}
}
/* Write to FP register */
void IntprCallback::WriteFpReg(unsigned int fd_idx, unsigned int fn_idx) {
D(fd_idx) = D(fn_idx);

View file

@ -27,6 +27,14 @@ struct ARMv8State {
vreg_t vreg[33];
uint32_t nzcv; // flag register
/* System register */
struct SysReg {
union {
uint64_t tpidr_el[4];
};
uint64_t tpidrro_el[1];
} sysr;
};
extern ARMv8State arm_state;
@ -43,6 +51,7 @@ extern ARMv8State arm_state;
#define GPR(r) ARMv8::arm_state.gpr[r]
#define VREG(r) ARMv8::arm_state.vreg[r] // SIMD registers
#define SYSR (ARMv8::arm_state.sysr)
#define X(r) GPR(r).x
#define W(r) GPR(r).w[0]

View file

@ -53,6 +53,8 @@ virtual void LoadReg(unsigned int rd_idx, unsigned int base_idx, unsigned int rm
virtual void LoadRegI64(unsigned int rd_idx, unsigned int ad_idx, int size, bool is_sign, bool extend) = 0;
virtual void StoreReg(unsigned int rd_idx, unsigned int base_idx, unsigned int rm_idx, int size, bool is_sign, bool extend, bool post, bool bit64) = 0;
virtual void StoreRegI64(unsigned int rd_idx, unsigned int ad_idx, int size, bool is_sign, bool extend) = 0;
virtual void _LoadReg(unsigned int rd_idx, uint64_t addr, int size, bool is_sign, bool extend) = 0;
virtual void _StoreReg(unsigned int rd_idx, uint64_t addr, int size, bool is_sign, bool extend) = 0;
/* Bitfield Signed/Unsigned Extract... with Immediate value */
virtual void SExtractI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int pos, unsigned int len, bool bit64) = 0;
@ -99,6 +101,11 @@ virtual void DupVecReg(unsigned int vd_idx, unsigned int vn_idx, unsigned int in
/* Duplicate an general register into vector register */
virtual void DupVecRegFromGen(unsigned int vd_idx, unsigned int rn_idx, int size, int dstsize) = 0;
/* Read/Write Sysreg */
virtual void ReadWriteSysReg(unsigned int rd_idx, int offset, bool read) = 0;
/* Read/Write NZCV */
virtual void ReadWriteNZCV(unsigned int rd_idx, bool read) = 0;
/* Write to FP register */
virtual void WriteFpReg(unsigned int fd_idx, unsigned int fn_idx) = 0;
virtual void WriteFpRegI64(unsigned int fd_idx, uint64_t imm) = 0;
@ -145,15 +152,111 @@ enum CondType {
CondType_NV
};
#define CP_REG_ARM64 0x6000000000000000ULL
#define CP_REG_ARM_COPROC_MASK 0x000000000FFF0000
#define CP_REG_ARM_COPROC_SHIFT 16
#define CP_REG_ARM64_SYSREG (0x0013 << CP_REG_ARM_COPROC_SHIFT)
#define CP_REG_ARM64_SYSREG_OP0_MASK 0x000000000000c000
#define CP_REG_ARM64_SYSREG_OP0_SHIFT 14
#define CP_REG_ARM64_SYSREG_OP1_MASK 0x0000000000003800
#define CP_REG_ARM64_SYSREG_OP1_SHIFT 11
#define CP_REG_ARM64_SYSREG_CRN_MASK 0x0000000000000780
#define CP_REG_ARM64_SYSREG_CRN_SHIFT 7
#define CP_REG_ARM64_SYSREG_CRM_MASK 0x0000000000000078
#define CP_REG_ARM64_SYSREG_CRM_SHIFT 3
#define CP_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007
#define CP_REG_ARM64_SYSREG_OP2_SHIFT 0
#define CP_REG_ARM64_SYSREG_CP (CP_REG_ARM64_SYSREG >> CP_REG_ARM_COPROC_SHIFT)
#define CP_REG_AA64_SHIFT 28
#define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
#define CP_ANY 0xff
#define ARM_CP_SPECIAL 0x0001
#define ARM_CP_CONST 0x0002
#define ARM_CP_64BIT 0x0004
#define ARM_CP_SUPPRESS_TB_END 0x0008
#define ARM_CP_OVERRIDE 0x0010
#define ARM_CP_ALIAS 0x0020
#define ARM_CP_IO 0x0040
#define ARM_CP_NO_RAW 0x0080
#define ARM_CP_NOP (ARM_CP_SPECIAL | 0x0100)
#define ARM_CP_WFI (ARM_CP_SPECIAL | 0x0200)
#define ARM_CP_NZCV (ARM_CP_SPECIAL | 0x0300)
#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | 0x0400)
#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | 0x0500)
#define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
#define ARM_CP_FPU 0x1000
#define ARM_CP_SVE 0x2000
#define ARM_CP_SENTINEL 0xffff
#define ARM_CP_FLAG_MASK 0x30ff
enum {
ARM_CP_STATE_AA32 = 0,
ARM_CP_STATE_AA64 = 1,
ARM_CP_STATE_BOTH = 2,
};
enum {
ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */
ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */
};
#define PL3_R 0x80
#define PL3_W 0x40
#define PL2_R (0x20 | PL3_R)
#define PL2_W (0x10 | PL3_W)
#define PL1_R (0x08 | PL2_R)
#define PL1_W (0x04 | PL2_W)
#define PL0_R (0x02 | PL1_R)
#define PL0_W (0x01 | PL1_W)
#define PL3_RW (PL3_R | PL3_W)
#define PL2_RW (PL2_R | PL2_W)
#define PL1_RW (PL1_R | PL1_W)
#define PL0_RW (PL0_R | PL0_W)
#define ENCODE_SYSTEM_REG(cp, crn, crm, op0, op1, op2) \
(CP_REG_AA64_MASK | \
((cp) << CP_REG_ARM_COPROC_SHIFT) | \
((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) | \
((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) | \
((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) | \
((crm) << CP_REG_ARM64_SYSREG_CRM_SHIFT) | \
((op2) << CP_REG_ARM64_SYSREG_OP2_SHIFT))
typedef void A64DecodeFn(uint32_t insn, DisasCallback *cb);
class A64SysRegInfo {
public:
std::string name;
uint8_t cp;
uint8_t crn;
uint8_t crm;
uint8_t opc0;
uint8_t opc1;
uint8_t opc2;
int access;
int state;
int type;
int offset;
A64SysRegInfo (std::string _name, int _state, uint8_t _cp, uint8_t _opc0, uint8_t _opc1, uint8_t _opc2,
uint8_t _crn, uint8_t _crm, int _o) : name(_name), state(_state), cp(_cp), crn(_crn),
crm(_crm), opc0(_opc0), opc1(_opc1), opc2(_opc2), offset(_o) {}
A64SysRegInfo (std::string _name, int _state, uint8_t _opc0, uint8_t _opc1, uint8_t _opc2,
uint8_t _crn, uint8_t _crm, int _o) : name(_name), state(_state),
opc0(_opc0), opc1(_opc1), opc2(_opc2), crn(_crn), crm(_crm), offset(_o) {}
A64SysRegInfo (int _type) : type(_type) {}
};
typedef struct AArch64DecodeTable {
uint32_t pattern;
uint32_t mask;
A64DecodeFn *disas_fn;
uint32_t pattern;
uint32_t mask;
A64DecodeFn *disas_fn;
} A64DecodeTable;
void DisasA64(uint32_t insn, DisasCallback *cb);
void Init();
};
#endif

View file

@ -53,6 +53,8 @@ void LoadReg(unsigned int rd_idx, unsigned int base_idx, unsigned int rm_idx, in
void LoadRegI64(unsigned int rd_idx, unsigned int ad_idx, int size, bool is_sign, bool extend);
void StoreReg(unsigned int rd_idx, unsigned int base_idx, unsigned int rm_idx, int size, bool is_sign, bool extend, bool post, bool bit64);
void StoreRegI64(unsigned int rd_idx, unsigned int ad_idx, int size, bool is_sign, bool extend);
void _LoadReg(unsigned int rd_idx, uint64_t addr, int size, bool is_sign, bool extend);
void _StoreReg(unsigned int rd_idx, uint64_t addr, int size, bool is_sign, bool extend);
/* Bitfield Signed/Unsigned Extract... with Immediate value */
void SExtractI64(unsigned int rd_idx, unsigned int rn_idx, unsigned int pos, unsigned int len, bool bit64);
@ -98,6 +100,11 @@ void DupVecReg(unsigned int vd_idx, unsigned int vn_idx, unsigned int index, int
/* Duplicate an general register into vector register */
void DupVecRegFromGen(unsigned int vd_idx, unsigned int rn_idx, int size, int dstsize);
/* Read/Write Sysreg */
void ReadWriteSysReg(unsigned int rd_idx, int offset, bool read);
/* Read/Write NZCV */
void ReadWriteNZCV(unsigned int rd_idx, bool read);
/* Write to FP register */
void WriteFpReg(unsigned int fd_idx, unsigned int fn_idx);
void WriteFpRegI64(unsigned int fd_idx, uint64_t imm);
@ -118,6 +125,8 @@ Interpreter& operator=(const Interpreter&) = delete;
Interpreter(Interpreter&&) = delete;
Interpreter& operator=(Interpreter&&) = delete;
void Init();
static Interpreter *get_instance() {
return inst;
}