Page MenuHomeFreeBSD

D56988.id.diff
No OneTemporary

D56988.id.diff

diff --git a/sys/cddl/dev/kinst/aarch64/kinst_isa.h b/sys/cddl/dev/kinst/aarch64/kinst_isa.h
--- a/sys/cddl/dev/kinst/aarch64/kinst_isa.h
+++ b/sys/cddl/dev/kinst/aarch64/kinst_isa.h
@@ -19,8 +19,21 @@
typedef uint32_t kinst_patchval_t;
+enum kinst_instr {
+ KINST_INSTR_ADR, /* adr/adrp */
+ KINST_INSTR_B,
+ KINST_INSTR_BCOND,
+ KINST_INSTR_BL,
+ KINST_INSTR_CBZ, /* cbz/cbnz */
+ KINST_INSTR_TBZ, /* tbnz/tbz */
+ KINST_INSTR_LDR_LITERAL,
+ KINST_INSTR_LDX,
+ KINST_INSTR_STX,
+ KINST_INSTR_COMMON,
+};
+
struct kinst_probe_md {
- bool emulate; /* emulate in sw */
+ enum kinst_instr kp_type;
};
#endif /* _KINST_ISA_H_ */
diff --git a/sys/cddl/dev/kinst/aarch64/kinst_isa.c b/sys/cddl/dev/kinst/aarch64/kinst_isa.c
--- a/sys/cddl/dev/kinst/aarch64/kinst_isa.c
+++ b/sys/cddl/dev/kinst/aarch64/kinst_isa.c
@@ -18,6 +18,30 @@
DPCPU_DEFINE_STATIC(struct kinst_cpu_state, kinst_state);
+static enum kinst_instr
+kinst_instr_type(kinst_patchval_t instr)
+{
+ if (((instr >> 22) & 0xff) == 0b00100001)
+ return (KINST_INSTR_LDX);
+ else if (((instr >> 22) & 0xff) == 0b00100000)
+ return (KINST_INSTR_STX);
+ if (((instr >> 24) & 0x1f) == 0b10000)
+ return (KINST_INSTR_ADR);
+ else if (((instr >> 26) & 0x3f) == 0b000101)
+ return (KINST_INSTR_B);
+ else if (((instr >> 24) & 0xff) == 0b01010100)
+ return (KINST_INSTR_BCOND);
+ else if (((instr >> 26) & 0x3f) == 0b100101)
+ return (KINST_INSTR_BL);
+ else if (((instr >> 25) & 0x3f) == 0b011010)
+ return (KINST_INSTR_CBZ);
+ else if (((instr >> 25) & 0x3f) == 0b011011)
+ return (KINST_INSTR_TBZ);
+ else if (((instr >> 24) & 0xbf) == 0b11000)
+ return (KINST_INSTR_LDR_LITERAL);
+ return (KINST_INSTR_COMMON);
+}
+
static void
kinst_emulate(struct trapframe *frame, const struct kinst_probe *kp)
{
@@ -26,8 +50,8 @@
uint8_t cond, reg, bitpos;
bool res;
- if (((instr >> 24) & 0x1f) == 0b10000) {
- /* adr/adrp */
+ switch (kp->kp_md.kp_type) {
+ case KINST_INSTR_ADR:
reg = instr & 0x1f;
imm = (instr >> 29) & 0x3;
imm |= ((instr >> 5) & 0x0007ffff) << 2;
@@ -44,14 +68,14 @@
frame->tf_x[reg] = (frame->tf_elr & ~0xfff) + imm;
}
frame->tf_elr += INSN_SIZE;
- } else if (((instr >> 26) & 0x3f) == 0b000101) {
- /* b */
+ break;
+ case KINST_INSTR_B:
imm = instr & 0x03ffffff;
if (imm & 0x0000000002000000)
imm |= 0xfffffffffe000000;
frame->tf_elr += imm << 2;
- } else if (((instr >> 24) & 0xff) == 0b01010100) {
- /* b.cond */
+ break;
+ case KINST_INSTR_BCOND:
imm = (instr >> 5) & 0x0007ffff;
if (imm & 0x0000000000040000)
imm |= 0xfffffffffffc0000;
@@ -92,15 +116,15 @@
frame->tf_elr += imm << 2;
else
frame->tf_elr += INSN_SIZE;
- } else if (((instr >> 26) & 0x3f) == 0b100101) {
- /* bl */
+ break;
+ case KINST_INSTR_BL:
imm = instr & 0x03ffffff;
if (imm & 0x0000000002000000)
imm |= 0xfffffffffe000000;
frame->tf_lr = frame->tf_elr + INSN_SIZE;
frame->tf_elr += imm << 2;
- } else if (((instr >> 25) & 0x3f) == 0b011010) {
- /* cbnz/cbz */
+ break;
+ case KINST_INSTR_CBZ:
cond = (instr >> 24) & 0x1;
reg = instr & 0x1f;
imm = (instr >> 5) & 0x0007ffff;
@@ -114,8 +138,8 @@
frame->tf_elr += imm << 2;
else
frame->tf_elr += INSN_SIZE;
- } else if (((instr >> 25) & 0x3f) == 0b011011) {
- /* tbnz/tbz */
+ break;
+ case KINST_INSTR_TBZ:
cond = (instr >> 24) & 0x1;
reg = instr & 0x1f;
bitpos = (instr >> 19) & 0x1f;
@@ -131,6 +155,9 @@
frame->tf_elr += imm << 2;
else
frame->tf_elr += INSN_SIZE;
+ break;
+ default:
+ __assert_unreachable();
}
}
@@ -211,7 +238,7 @@
dtrace_probe(kp->kp_id, 0, 0, 0, 0, 0);
cpu->cpu_dtrace_caller = 0;
- if (kp->kp_md.emulate) {
+ if (kp->kp_md.kp_type != KINST_INSTR_COMMON) {
kinst_emulate(frame, kp);
} else {
ks->state = KINST_PROBE_FIRED;
@@ -245,50 +272,6 @@
cpu_icache_sync_range(kp->kp_patchpoint, INSN_SIZE);
}
-static void
-kinst_instr_dissect(struct kinst_probe *kp)
-{
- struct kinst_probe_md *kpmd;
- kinst_patchval_t instr = kp->kp_savedval;
-
- kpmd = &kp->kp_md;
- kpmd->emulate = false;
-
- if (((instr >> 24) & 0x1f) == 0b10000)
- kpmd->emulate = true; /* adr/adrp */
- else if (((instr >> 26) & 0x3f) == 0b000101)
- kpmd->emulate = true; /* b */
- else if (((instr >> 24) & 0xff) == 0b01010100)
- kpmd->emulate = true; /* b.cond */
- else if (((instr >> 26) & 0x3f) == 0b100101)
- kpmd->emulate = true; /* bl */
- else if (((instr >> 25) & 0x3f) == 0b011010)
- kpmd->emulate = true; /* cbnz/cbz */
- else if (((instr >> 25) & 0x3f) == 0b011011)
- kpmd->emulate = true; /* tbnz/tbz */
-
- if (!kpmd->emulate)
- kinst_trampoline_populate(kp);
-}
-
-static bool
-kinst_instr_ldx(kinst_patchval_t instr)
-{
- if (((instr >> 22) & 0xff) == 0b00100001)
- return (true);
-
- return (false);
-}
-
-static bool
-kinst_instr_stx(kinst_patchval_t instr)
-{
- if (((instr >> 22) & 0xff) == 0b00100000)
- return (true);
-
- return (false);
-}
-
int
kinst_make_probe(linker_file_t lf, int symindx, linker_symval_t *symval,
void *opaque)
@@ -359,6 +342,8 @@
ldxstx_block = false;
for (n = 0; instr < limit; instr++) {
+ enum kinst_instr type;
+
off = (int)((uint8_t *)instr - (uint8_t *)symval->value);
/*
@@ -366,9 +351,10 @@
* breakpoint is placed in a LDX/STX block, we violate the
* operation and the loop might fail.
*/
- if (kinst_instr_ldx(*instr))
+ type = kinst_instr_type(*instr);
+ if (type == KINST_INSTR_LDX)
ldxstx_block = true;
- else if (kinst_instr_stx(*instr)) {
+ else if (type == KINST_INSTR_STX) {
ldxstx_block = false;
continue;
}
@@ -376,13 +362,14 @@
continue;
/*
- * XXX: Skip ADR and ADRP instructions. The arm64 exception
- * handler has a micro-optimization where it doesn't restore
- * callee-saved registers when returning from exceptions in
- * EL1. This results in a panic when the kinst emulation code
- * modifies one of those registers.
+ * XXX: The arm64 exception handler has a micro-optimization
+ * where it doesn't restore callee-saved registers when
+ * returning from exceptions in EL1. As a result, instruction
+ * emulation doesn't work if a (callee-saved) register is
+ * modified. Hence, exclude the position-dependent ADR/ADRP and
+ * LDR <literal> instructions.
*/
- if (((*instr >> 24) & 0x1f) == 0b10000)
+ if (type == KINST_INSTR_ADR || type == KINST_INSTR_LDR_LITERAL)
continue;
if (pd->kpd_off != -1 && off != pd->kpd_off)
@@ -408,12 +395,14 @@
kp->kp_patchpoint = instr;
kp->kp_savedval = *instr;
kp->kp_patchval = KINST_PATCHVAL;
+ kp->kp_md.kp_type = type;
if ((kp->kp_tramp = kinst_trampoline_alloc(M_WAITOK)) == NULL) {
KINST_LOG("cannot allocate trampoline for %p", instr);
return (ENOMEM);
}
+ if (kp->kp_md.kp_type == KINST_INSTR_COMMON)
+ kinst_trampoline_populate(kp);
- kinst_instr_dissect(kp);
kinst_probe_create(kp, lf);
}
if (ldxstx_block)

File Metadata

Mime Type
text/plain
Expires
Tue, Jul 21, 4:21 PM (5 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33397758
Default Alt Text
D56988.id.diff (6 KB)

Event Timeline