Skip to content

Commit 3e6665d

Browse files
committed
Implement coprocessor register read/write for arm64
1 parent 8bc1489 commit 3e6665d

File tree

4 files changed

+159
-14
lines changed

4 files changed

+159
-14
lines changed

include/unicorn/arm64.h

+17-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ typedef enum uc_cpu_aarch64 {
2323
UC_CPU_AARCH64_MAX
2424
} uc_cpu_aarch64;
2525

26+
// ARM64 coprocessor registers, use this with UC_ARM64_REG_CP_REG to
27+
// in call to uc_reg_write/read() to access the registers.
28+
typedef struct uc_arm64_cp_reg {
29+
int crn; // Coprocessor register number
30+
int crm; // Coprocessor register number
31+
int op0; // Opcode0
32+
int op1; // Opcode1
33+
int op2; // Opcode2
34+
uint64_t val; // The value to read/write
35+
} uc_arm64_cp_reg;
36+
2637
//> ARM64 registers
2738
typedef enum uc_arm64_reg {
2839
UC_ARM64_REG_INVALID = 0,
@@ -293,26 +304,26 @@ typedef enum uc_arm64_reg {
293304

294305
UC_ARM64_REG_CPACR_EL1,
295306

296-
//> thread registers
307+
//> thread registers, depreciated, use UC_ARM64_REG_CP_REG instead
297308
UC_ARM64_REG_TPIDR_EL0,
298309
UC_ARM64_REG_TPIDRRO_EL0,
299310
UC_ARM64_REG_TPIDR_EL1,
300311

301312
UC_ARM64_REG_PSTATE,
302313

303-
//> exception link registers
314+
//> exception link registers, depreciated, use UC_ARM64_REG_CP_REG instead
304315
UC_ARM64_REG_ELR_EL0,
305316
UC_ARM64_REG_ELR_EL1,
306317
UC_ARM64_REG_ELR_EL2,
307318
UC_ARM64_REG_ELR_EL3,
308319

309-
//> stack pointers registers
320+
//> stack pointers registers, depreciated, use UC_ARM64_REG_CP_REG instead
310321
UC_ARM64_REG_SP_EL0,
311322
UC_ARM64_REG_SP_EL1,
312323
UC_ARM64_REG_SP_EL2,
313324
UC_ARM64_REG_SP_EL3,
314325

315-
//> other CP15 registers
326+
//> other CP15 registers, depreciated, use UC_ARM64_REG_CP_REG instead
316327
UC_ARM64_REG_TTBR0_EL1,
317328
UC_ARM64_REG_TTBR1_EL1,
318329

@@ -335,6 +346,8 @@ typedef enum uc_arm64_reg {
335346
UC_ARM64_REG_VBAR_EL2,
336347
UC_ARM64_REG_VBAR_EL3,
337348

349+
UC_ARM64_REG_CP_REG,
350+
338351
UC_ARM64_REG_ENDING, // <-- mark the end of the list of registers
339352

340353
//> alias registers

qemu/target/arm/unicorn_aarch64.c

+79-10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "unicorn/unicorn.h"
77
#include "sysemu/cpus.h"
88
#include "cpu.h"
9+
#include "kvm-consts.h"
910
#include "unicorn_common.h"
1011
#include "uc_priv.h"
1112
#include "unicorn.h"
@@ -90,8 +91,52 @@ void arm64_reg_reset(struct uc_struct *uc)
9091
env->pc = 0;
9192
}
9293

93-
static void reg_read(CPUARMState *env, unsigned int regid, void *value)
94+
static uc_err read_cp_reg(CPUARMState *env, uc_arm64_cp_reg *cp)
9495
{
96+
ARMCPU *cpu = ARM_CPU(env->uc->cpu);
97+
const ARMCPRegInfo *ri = get_arm_cp_reginfo(
98+
cpu->cp_regs, ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, cp->crn,
99+
cp->crm, cp->op0, cp->op1, cp->op2));
100+
101+
if (!ri) {
102+
return UC_ERR_ARG;
103+
}
104+
105+
cp->val = read_raw_cp_reg(env, ri);
106+
107+
return UC_ERR_OK;
108+
}
109+
110+
static uc_err write_cp_reg(CPUARMState *env, uc_arm64_cp_reg *cp)
111+
{
112+
ARMCPU *cpu = ARM_CPU(env->uc->cpu);
113+
const ARMCPRegInfo *ri = get_arm_cp_reginfo(
114+
cpu->cp_regs, ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, cp->crn,
115+
cp->crm, cp->op0, cp->op1, cp->op2));
116+
117+
if (!ri) {
118+
return UC_ERR_ARG;
119+
}
120+
121+
if (ri->raw_writefn) {
122+
ri->raw_writefn(env, ri, cp->val);
123+
} else if (ri->writefn) {
124+
ri->writefn(env, ri, cp->val);
125+
} else {
126+
if (cpreg_field_is_64bit(ri)) {
127+
CPREG_FIELD64(env, ri) = cp->val;
128+
} else {
129+
CPREG_FIELD32(env, ri) = cp->val;
130+
}
131+
}
132+
133+
return UC_ERR_OK;
134+
}
135+
136+
static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value)
137+
{
138+
uc_err ret = UC_ERR_OK;
139+
95140
if (regid >= UC_ARM64_REG_V0 && regid <= UC_ARM64_REG_V31) {
96141
regid += UC_ARM64_REG_Q0 - UC_ARM64_REG_V0;
97142
}
@@ -172,14 +217,19 @@ static void reg_read(CPUARMState *env, unsigned int regid, void *value)
172217
case UC_ARM64_REG_MAIR_EL1:
173218
*(uint64_t *)value = env->cp15.mair_el[1];
174219
break;
220+
case UC_ARM64_REG_CP_REG:
221+
ret = read_cp_reg(env, (uc_arm64_cp_reg *)value);
222+
break;
175223
}
176224
}
177225

178-
return;
226+
return ret;
179227
}
180228

181-
static void reg_write(CPUARMState *env, unsigned int regid, const void *value)
229+
static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value)
182230
{
231+
uc_err ret = UC_ERR_OK;
232+
183233
if (regid >= UC_ARM64_REG_V0 && regid <= UC_ARM64_REG_V31) {
184234
regid += UC_ARM64_REG_Q0 - UC_ARM64_REG_V0;
185235
}
@@ -260,45 +310,56 @@ static void reg_write(CPUARMState *env, unsigned int regid, const void *value)
260310
case UC_ARM64_REG_MAIR_EL1:
261311
env->cp15.mair_el[1] = *(uint64_t *)value;
262312
break;
313+
case UC_ARM64_REG_CP_REG:
314+
ret = write_cp_reg(env, (uc_arm64_cp_reg *)value);
315+
break;
263316
}
264317
}
265318

266-
return;
319+
return ret;
267320
}
268321

269322
int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
270323
int count)
271324
{
272325
CPUARMState *env = &(ARM_CPU(uc->cpu)->env);
273326
int i;
327+
uc_err err;
274328

275329
for (i = 0; i < count; i++) {
276330
unsigned int regid = regs[i];
277331
void *value = vals[i];
278-
reg_read(env, regid, value);
332+
err = reg_read(env, regid, value);
333+
if (err) {
334+
return err;
335+
}
279336
}
280337

281-
return 0;
338+
return UC_ERR_OK;
282339
}
283340

284341
int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
285342
int count)
286343
{
287344
CPUARMState *env = &(ARM_CPU(uc->cpu)->env);
288345
int i;
346+
uc_err err;
289347

290348
for (i = 0; i < count; i++) {
291349
unsigned int regid = regs[i];
292350
const void *value = vals[i];
293-
reg_write(env, regid, value);
351+
err = reg_write(env, regid, value);
352+
if (err) {
353+
return err;
354+
}
294355
if (regid == UC_ARM64_REG_PC) {
295356
// force to quit execution and flush TB
296357
uc->quit_request = true;
297358
uc_emu_stop(uc);
298359
}
299360
}
300361

301-
return 0;
362+
return UC_ERR_OK;
302363
}
303364

304365
DEFAULT_VISIBILITY
@@ -312,11 +373,15 @@ int arm64_context_reg_read(struct uc_context *ctx, unsigned int *regs,
312373
{
313374
CPUARMState *env = (CPUARMState *)ctx->data;
314375
int i;
376+
uc_err err;
315377

316378
for (i = 0; i < count; i++) {
317379
unsigned int regid = regs[i];
318380
void *value = vals[i];
319-
reg_read(env, regid, value);
381+
err = reg_read(env, regid, value);
382+
if (err) {
383+
return err;
384+
}
320385
}
321386

322387
return 0;
@@ -333,11 +398,15 @@ int arm64_context_reg_write(struct uc_context *ctx, unsigned int *regs,
333398
{
334399
CPUARMState *env = (CPUARMState *)ctx->data;
335400
int i;
401+
uc_err err;
336402

337403
for (i = 0; i < count; i++) {
338404
unsigned int regid = regs[i];
339405
const void *value = vals[i];
340-
reg_write(env, regid, value);
406+
err = reg_write(env, regid, value);
407+
if (err) {
408+
return err;
409+
}
341410
}
342411

343412
return 0;

samples/sample_arm64.c

+41
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,44 @@ static void test_arm64eb(void)
194194
uc_close(uc);
195195
}
196196

197+
static void test_arm64_sctlr()
198+
{
199+
uc_engine *uc;
200+
uc_err err;
201+
uc_arm64_cp_reg reg;
202+
203+
printf("Read the SCTLR register.\n");
204+
205+
err = uc_open(UC_ARCH_ARM64, UC_MODE_LITTLE_ENDIAN | UC_MODE_ARM, &uc);
206+
if (err != UC_ERR_OK) {
207+
printf("Failed on uc_emu_start() with error returned: %u\n", err);
208+
}
209+
210+
// SCTLR_EL1. See arm reference.
211+
reg.crn = 1;
212+
reg.crm = 0;
213+
reg.op0 = 0b11;
214+
reg.op1 = 0;
215+
reg.op2 = 0;
216+
217+
err = uc_reg_read(uc, UC_ARM64_REG_CP_REG, &reg);
218+
if (err != UC_ERR_OK) {
219+
printf("Failed on uc_reg_read() with error returned: %u\n", err);
220+
}
221+
222+
printf(">>> SCTLR_EL1 = 0x%" PRIx64 "\n", reg.val);
223+
224+
reg.op1 = 0b100;
225+
err = uc_reg_read(uc, UC_ARM64_REG_CP_REG, &reg);
226+
if (err != UC_ERR_OK) {
227+
printf("Failed on uc_reg_read() with error returned: %u\n", err);
228+
}
229+
230+
printf(">>> SCTLR_EL2 = 0x%" PRIx64 "\n", reg.val);
231+
232+
uc_close(uc);
233+
}
234+
197235
int main(int argc, char **argv, char **envp)
198236
{
199237
test_arm64_mem_fetch();
@@ -202,5 +240,8 @@ int main(int argc, char **argv, char **envp)
202240
printf("-------------------------\n");
203241
test_arm64eb();
204242

243+
printf("-------------------------\n");
244+
test_arm64_sctlr();
245+
205246
return 0;
206247
}

tests/unit/test_arm64.c

+22
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,30 @@ static void test_arm64_v8_pac()
138138
OK(uc_close(uc));
139139
}
140140

141+
static void test_arm64_read_sctlr()
142+
{
143+
uc_engine *uc;
144+
uc_arm64_cp_reg reg;
145+
146+
OK(uc_open(UC_ARCH_ARM64, UC_MODE_LITTLE_ENDIAN | UC_MODE_ARM, &uc));
147+
148+
// SCTLR_EL1. See arm reference.
149+
reg.crn = 1;
150+
reg.crm = 0;
151+
reg.op0 = 0b11;
152+
reg.op1 = 0;
153+
reg.op2 = 0;
154+
155+
OK(uc_reg_read(uc, UC_ARM64_REG_CP_REG, &reg));
156+
157+
TEST_CHECK((reg.val >> 58) == 0);
158+
159+
OK(uc_close(uc));
160+
}
161+
141162
TEST_LIST = {{"test_arm64_until", test_arm64_until},
142163
{"test_arm64_code_patching", test_arm64_code_patching},
143164
{"test_arm64_code_patching_count", test_arm64_code_patching_count},
144165
{"test_arm64_v8_pac", test_arm64_v8_pac},
166+
{"test_arm64_read_sctlr", test_arm64_read_sctlr},
145167
{NULL, NULL}};

0 commit comments

Comments
 (0)