arm64: introduce aarch64_insn_gen_comp_branch_imm()
Introduce function to generate compare & branch (immediate) instructions. Signed-off-by: Zi Shen Lim <zlim.lnx@gmail.com> Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
* Copyright (C) 2013 Huawei Ltd.
|
||||
* Author: Jiang Liu <liuj97@gmail.com>
|
||||
*
|
||||
* Copyright (C) 2014 Zi Shen Lim <zlim.lnx@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
@@ -23,6 +25,8 @@
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/insn.h>
|
||||
|
||||
#define AARCH64_INSN_SF_BIT BIT(31)
|
||||
|
||||
static int aarch64_insn_encoding_class[] = {
|
||||
AARCH64_INSN_CLS_UNKNOWN,
|
||||
AARCH64_INSN_CLS_UNKNOWN,
|
||||
@@ -264,10 +268,36 @@ u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
|
||||
return insn;
|
||||
}
|
||||
|
||||
u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
|
||||
enum aarch64_insn_branch_type type)
|
||||
static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
|
||||
u32 insn,
|
||||
enum aarch64_insn_register reg)
|
||||
{
|
||||
int shift;
|
||||
|
||||
if (reg < AARCH64_INSN_REG_0 || reg > AARCH64_INSN_REG_SP) {
|
||||
pr_err("%s: unknown register encoding %d\n", __func__, reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case AARCH64_INSN_REGTYPE_RT:
|
||||
shift = 0;
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: unknown register type encoding %d\n", __func__,
|
||||
type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
insn &= ~(GENMASK(4, 0) << shift);
|
||||
insn |= reg << shift;
|
||||
|
||||
return insn;
|
||||
}
|
||||
|
||||
static inline long branch_imm_common(unsigned long pc, unsigned long addr,
|
||||
long range)
|
||||
{
|
||||
u32 insn;
|
||||
long offset;
|
||||
|
||||
/*
|
||||
@@ -276,13 +306,24 @@ u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
|
||||
*/
|
||||
BUG_ON((pc & 0x3) || (addr & 0x3));
|
||||
|
||||
offset = ((long)addr - (long)pc);
|
||||
BUG_ON(offset < -range || offset >= range);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
|
||||
enum aarch64_insn_branch_type type)
|
||||
{
|
||||
u32 insn;
|
||||
long offset;
|
||||
|
||||
/*
|
||||
* B/BL support [-128M, 128M) offset
|
||||
* ARM64 virtual address arrangement guarantees all kernel and module
|
||||
* texts are within +/-128M.
|
||||
*/
|
||||
offset = ((long)addr - (long)pc);
|
||||
BUG_ON(offset < -SZ_128M || offset >= SZ_128M);
|
||||
offset = branch_imm_common(pc, addr, SZ_128M);
|
||||
|
||||
if (type == AARCH64_INSN_BRANCH_LINK)
|
||||
insn = aarch64_insn_get_bl_value();
|
||||
@@ -293,6 +334,43 @@ u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
|
||||
offset >> 2);
|
||||
}
|
||||
|
||||
u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
|
||||
enum aarch64_insn_register reg,
|
||||
enum aarch64_insn_variant variant,
|
||||
enum aarch64_insn_branch_type type)
|
||||
{
|
||||
u32 insn;
|
||||
long offset;
|
||||
|
||||
offset = branch_imm_common(pc, addr, SZ_1M);
|
||||
|
||||
switch (type) {
|
||||
case AARCH64_INSN_BRANCH_COMP_ZERO:
|
||||
insn = aarch64_insn_get_cbz_value();
|
||||
break;
|
||||
case AARCH64_INSN_BRANCH_COMP_NONZERO:
|
||||
insn = aarch64_insn_get_cbnz_value();
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
|
||||
switch (variant) {
|
||||
case AARCH64_INSN_VARIANT_32BIT:
|
||||
break;
|
||||
case AARCH64_INSN_VARIANT_64BIT:
|
||||
insn |= AARCH64_INSN_SF_BIT;
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
|
||||
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, reg);
|
||||
|
||||
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn,
|
||||
offset >> 2);
|
||||
}
|
||||
|
||||
u32 __kprobes aarch64_insn_gen_hint(enum aarch64_insn_hint_op op)
|
||||
{
|
||||
return aarch64_insn_get_hint_value() | op;
|
||||
|
Reference in New Issue
Block a user