aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2015-03-27 09:09:21 -0400
committerWill Deacon <will.deacon@arm.com>2015-03-30 06:03:42 -0400
commit0978fb25f86b7595821cee6955679250d47c6438 (patch)
tree3f4bafcc51a1df7f4adac354bd8956f77bd66e58 /arch/arm64/kernel
parent849176c96dab827548176e851525bd1c3fff5a6a (diff)
arm64: insn: Add aarch64_insn_decode_immediate
Patching an instruction sometimes requires extracting the immediate field from this instruction. To facilitate this, and avoid potential duplication of code, add aarch64_insn_decode_immediate as the reciprocal to aarch64_insn_encode_immediate. Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm64/kernel')
-rw-r--r--arch/arm64/kernel/insn.c81
1 files changed, 65 insertions, 16 deletions
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index c8eca88f12e6..924902083e47 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -265,23 +265,13 @@ int __kprobes aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt)
265 return aarch64_insn_patch_text_sync(addrs, insns, cnt); 265 return aarch64_insn_patch_text_sync(addrs, insns, cnt);
266} 266}
267 267
268u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, 268static int __kprobes aarch64_get_imm_shift_mask(enum aarch64_insn_imm_type type,
269 u32 insn, u64 imm) 269 u32 *maskp, int *shiftp)
270{ 270{
271 u32 immlo, immhi, lomask, himask, mask; 271 u32 mask;
272 int shift; 272 int shift;
273 273
274 switch (type) { 274 switch (type) {
275 case AARCH64_INSN_IMM_ADR:
276 lomask = 0x3;
277 himask = 0x7ffff;
278 immlo = imm & lomask;
279 imm >>= 2;
280 immhi = imm & himask;
281 imm = (immlo << 24) | (immhi);
282 mask = (lomask << 24) | (himask);
283 shift = 5;
284 break;
285 case AARCH64_INSN_IMM_26: 275 case AARCH64_INSN_IMM_26:
286 mask = BIT(26) - 1; 276 mask = BIT(26) - 1;
287 shift = 0; 277 shift = 0;
@@ -320,9 +310,68 @@ u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
320 shift = 16; 310 shift = 16;
321 break; 311 break;
322 default: 312 default:
323 pr_err("aarch64_insn_encode_immediate: unknown immediate encoding %d\n", 313 return -EINVAL;
324 type); 314 }
325 return 0; 315
316 *maskp = mask;
317 *shiftp = shift;
318
319 return 0;
320}
321
322#define ADR_IMM_HILOSPLIT 2
323#define ADR_IMM_SIZE SZ_2M
324#define ADR_IMM_LOMASK ((1 << ADR_IMM_HILOSPLIT) - 1)
325#define ADR_IMM_HIMASK ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
326#define ADR_IMM_LOSHIFT 29
327#define ADR_IMM_HISHIFT 5
328
329u64 aarch64_insn_decode_immediate(enum aarch64_insn_imm_type type, u32 insn)
330{
331 u32 immlo, immhi, mask;
332 int shift;
333
334 switch (type) {
335 case AARCH64_INSN_IMM_ADR:
336 shift = 0;
337 immlo = (insn >> ADR_IMM_LOSHIFT) & ADR_IMM_LOMASK;
338 immhi = (insn >> ADR_IMM_HISHIFT) & ADR_IMM_HIMASK;
339 insn = (immhi << ADR_IMM_HILOSPLIT) | immlo;
340 mask = ADR_IMM_SIZE - 1;
341 break;
342 default:
343 if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) {
344 pr_err("aarch64_insn_decode_immediate: unknown immediate encoding %d\n",
345 type);
346 return 0;
347 }
348 }
349
350 return (insn >> shift) & mask;
351}
352
353u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
354 u32 insn, u64 imm)
355{
356 u32 immlo, immhi, mask;
357 int shift;
358
359 switch (type) {
360 case AARCH64_INSN_IMM_ADR:
361 shift = 0;
362 immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
363 imm >>= ADR_IMM_HILOSPLIT;
364 immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
365 imm = immlo | immhi;
366 mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
367 (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));
368 break;
369 default:
370 if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) {
371 pr_err("aarch64_insn_encode_immediate: unknown immediate encoding %d\n",
372 type);
373 return 0;
374 }
326 } 375 }
327 376
328 /* Update the immediate field. */ 377 /* Update the immediate field. */