Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arm64 xzr sp support tests #1

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
132 changes: 90 additions & 42 deletions sys/arm64/arm64/disassem.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,23 @@ __FBSDID("$FreeBSD$");
#define OP_MULT_4 (1UL << 2) /* Multiply immediate by 4 */
#define OP_SF32 (1UL << 3) /* Force 32-bit access */
#define OP_SF_INV (1UL << 6) /* SF is inverted (1 means 32 bit access) */
#define OP_RD_SP (1UL << 7) /* Use sp for RD otherwise xzr */
#define OP_RT_SP (1UL << 8) /* Use sp for RT otherwise xzr */
#define OP_RN_SP (1UL << 9) /* Use sp for RN otherwise xzr */
#define OP_RM_SP (1UL << 10) /* Use sp for RM otherwise xzr */

static const char *w_reg[] = {
"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
"w24", "w25", "w26", "w27", "w28", "w29", "w30", "wSP",
"w24", "w25", "w26", "w27", "w28", "w29", "w30"
};

static const char *x_reg[] = {
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
"x24", "x25", "x26", "x27", "x28", "x29", "LR", "SP",
"x24", "x25", "x26", "x27", "x28", "x29", "LR"
};

static const char *shift_2[] = {
Expand Down Expand Up @@ -131,51 +135,69 @@ struct arm64_insn {
*/
static struct arm64_insn arm64_i[] = {
{ "add", "SF(1)|0001011|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)",
TYPE_01, 0 },
TYPE_01, 0 }, /* add shifted register */
{ "mov", "SF(1)|001000100000000000000|RN(5)|RD(5)",
TYPE_01, 0 },
TYPE_01, OP_RD_SP | OP_RN_SP }, /* mov (to/from sp) */
{ "add", "SF(1)|0010001|SHIFT(2)|IMM(12)|RN(5)|RD(5)",
TYPE_01, 0 },
TYPE_01, OP_RD_SP | OP_RN_SP }, /* add immediate */
{ "ldr", "1|SF(1)|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)",
TYPE_02, OP_SIGN_EXT }, /* ldr immediate post/pre index */
TYPE_02, OP_SIGN_EXT | OP_RN_SP }, /* ldr immediate post/pre index */
{ "ldr", "1|SF(1)|11100101|IMM(12)|RN(5)|RT(5)",
TYPE_02, 0 }, /* ldr immediate unsigned */
TYPE_02, OP_RN_SP }, /* ldr immediate unsigned */
{ "ldr", "1|SF(1)|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
TYPE_02, 0 }, /* ldr register */
TYPE_02, OP_RN_SP }, /* ldr register */
{ "ldr", "0|SF(1)|011000|IMM(19)|RT(5)",
TYPE_03, OP_SIGN_EXT | OP_LITERAL | OP_MULT_4 }, /* ldr literal */
{ "ldrb", "00|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)",
TYPE_02, OP_SIGN_EXT | OP_SF32 }, /* ldrb immediate post/pre index */
TYPE_02, OP_SIGN_EXT | OP_SF32 | OP_RN_SP }, /* ldrb immediate post/pre index */
{ "ldrb", "00|11100101|IMM(12)|RN(5)|RT(5)",
TYPE_02, OP_SF32 }, /* ldrb immediate unsigned */
TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrb immediate unsigned */
{ "ldrb", "00|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
TYPE_02, OP_SF32 }, /* ldrb register */
TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrb register */
{ "ldrh", "01|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)", TYPE_02,
OP_SIGN_EXT | OP_SF32 }, /* ldrh immediate post/pre index */
OP_SIGN_EXT | OP_SF32 | OP_RN_SP }, /* ldrh immediate post/pre index */
{ "ldrh", "01|11100101|IMM(12)|RN(5)|RT(5)",
TYPE_02, OP_SF32 }, /* ldrh immediate unsigned */
TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrh immediate unsigned */
{ "ldrh", "01|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
TYPE_02, OP_SF32 }, /* ldrh register */
TYPE_02, OP_SF32 | OP_RN_SP }, /* ldrh register */
{ "ldrsb", "001110001|SF(1)|0|IMM(9)|OPTION(2)|RN(5)|RT(5)",
TYPE_02, OP_SIGN_EXT | OP_SF_INV }, /* ldrsb immediate post/pre index */
TYPE_02, OP_SIGN_EXT | OP_SF_INV | OP_RN_SP }, /* ldrsb immediate post/pre index */
{ "ldrsb", "001110011|SF(1)|IMM(12)|RN(5)|RT(5)",\
TYPE_02, OP_SF_INV}, /* ldrsb immediate unsigned */
TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsb immediate unsigned */
{ "ldrsb", "001110001|SF(1)|1|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
TYPE_02, OP_SF_INV }, /* ldrsb register */
TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsb register */
{ "ldrsh", "011110001|SF(1)|0|IMM(9)|OPTION(2)|RN(5)|RT(5)",
TYPE_02, OP_SIGN_EXT | OP_SF_INV }, /* ldrsh immediate post/pre index */
TYPE_02, OP_SIGN_EXT | OP_SF_INV | OP_RN_SP }, /* ldrsh immediate post/pre index */
{ "ldrsh", "011110011|SF(1)|IMM(12)|RN(5)|RT(5)",
TYPE_02, OP_SF_INV}, /* ldrsh immediate unsigned */
TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsh immediate unsigned */
{ "ldrsh", "011110001|SF(1)|1|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
TYPE_02, OP_SF_INV }, /* ldrsh register */
TYPE_02, OP_SF_INV | OP_RN_SP }, /* ldrsh register */
{ "ldrsw", "10111000100|IMM(9)|OPTION(2)|RN(5)|RT(5)",
TYPE_02, OP_SIGN_EXT }, /* ldrsw immediate post/pre index */
TYPE_02, OP_SIGN_EXT | OP_RN_SP }, /* ldrsw immediate post/pre index */
{ "ldrsw", "1011100110|IMM(12)|RN(5)|RT(5)",
TYPE_02, 0 }, /* ldrsw immediate unsigned */
TYPE_02, OP_RN_SP }, /* ldrsw immediate unsigned */
{ "ldrsw", "10111000101|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
TYPE_02, 0 }, /* ldrsw register */
TYPE_02, OP_RN_SP }, /* ldrsw register */
{ "ldrsw", "10011000|IMM(19)|RT(5)",
TYPE_03, OP_SIGN_EXT | OP_LITERAL | OP_MULT_4 }, /* ldr literal */
TYPE_03, OP_SIGN_EXT | OP_LITERAL | OP_MULT_4 }, /* ldrsw literal */
{ "str", "1|SF(1)|111000000|IMM(9)|OPTION(2)|RN(5)|RT(5)",
TYPE_02, OP_SIGN_EXT | OP_RN_SP }, /* str immediate post/pre index */
{ "str", "1|SF(1)|11100100|IMM(12)|RN(5)|RT(5)",
TYPE_02, OP_RN_SP }, /* str immediate unsigned */
{ "str", "1|SF(1)|111000001|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
TYPE_02, OP_RN_SP }, /* str register */
{ "strb", "00111000000|IMM(9)|OPTION(2)|RN(5)|RT(5)",
TYPE_02, OP_SIGN_EXT | OP_SF32 | OP_RN_SP }, /* strb immediate post/pre index */
{ "strb", "0011100100|IMM(12)|RN(5)|RT(5)",
TYPE_02, OP_SF32 | OP_RN_SP }, /* strb immediate unsigned */
{ "strb", "00111000001|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
TYPE_02, OP_SF32 | OP_RN_SP }, /* strb register */
{ "strh", "01111000000|IMM(9)|OPTION(2)|RN(5)|RT(5)",
TYPE_02, OP_SF32 | OP_SIGN_EXT | OP_RN_SP }, /* strh immediate post/pre index */
{ "strh", "0111100100|IMM(12)|RN(5)|RT(5)",
TYPE_02, OP_SF32 | OP_RN_SP }, /* strh immediate unsigned */
{ "strh", "01111000001|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
TYPE_02, OP_SF32 | OP_RN_SP }, /* strh register */
{ NULL, NULL }
};

Expand Down Expand Up @@ -323,13 +345,27 @@ arm64_disasm_read_token_sign_ext(struct arm64_insn *insn, u_int opcode,
}

static const char *
arm64_reg(int b64, int num)
arm64_w_reg(int num, int wsp)
{
if (num == 31)
return (wsp != 0 ? "wsp" : "wzr");
return (w_reg[num]);
}

if (b64 != 0)
return (x_reg[num]);
static const char *
arm64_x_reg(int num, int sp)
{
if (num == 31)
return (sp != 0 ? "sp" : "xzr");
return (x_reg[num]);
}

return (w_reg[num]);
static const char *
arm64_reg(int b64, int num, int sp)
{
if (b64 != 0)
return (arm64_x_reg(num, sp));
return arm64_w_reg(num, sp);
}

vm_offset_t
Expand All @@ -346,6 +382,8 @@ disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt)
int inside;
/* Print exclamation mark if pre-incremented */
int pre;
/* Indicate if x31 register should be printed as sp or xzr */
int rm_sp, rt_sp, rd_sp, rn_sp;

/* Initialize defaults, all are 0 except SF indicating 64bit access */
shift = rd = rm = rn = imm = idx = option = amount = scale = 0;
Expand Down Expand Up @@ -385,6 +423,11 @@ disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt)
if (i_ptr->special_ops & OP_MULT_4)
imm <<= 2;

rm_sp = i_ptr->special_ops & OP_RM_SP;
rt_sp = i_ptr->special_ops & OP_RT_SP;
rd_sp = i_ptr->special_ops & OP_RD_SP;
rn_sp = i_ptr->special_ops & OP_RN_SP;

/* Print opcode by type */
switch (i_ptr->type) {
case TYPE_01:
Expand All @@ -404,12 +447,12 @@ disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt)
arm64_disasm_read_token(i_ptr, insn, "SHIFT", &shift);
rm_absent = arm64_disasm_read_token(i_ptr, insn, "RM", &rm);

di->di_printf("%s\t%s, %s", i_ptr->name, arm64_reg(sf, rd),
arm64_reg(sf, rn));
di->di_printf("%s\t%s, %s", i_ptr->name,
arm64_reg(sf, rd, rd_sp), arm64_reg(sf, rn, rn_sp));

/* If RM is present use it, otherwise use immediate notation */
if (rm_absent == 0) {
di->di_printf(", %s", arm64_reg(sf, rm));
di->di_printf(", %s", arm64_reg(sf, rm, rm_sp));
if (imm != 0)
di->di_printf(", %s #%d", shift_2[shift], imm);
} else {
Expand Down Expand Up @@ -464,14 +507,15 @@ disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt)
break;
}

di->di_printf("%s\t%s, ", i_ptr->name, arm64_reg(sf, rt));
di->di_printf("%s\t%s, ", i_ptr->name,
arm64_reg(sf, rt, rt_sp));
if (inside != 0) {
di->di_printf("[%s", arm64_reg(1, rn));
di->di_printf("[%s", arm64_reg(1, rn, rn_sp));
if (imm != 0)
di->di_printf(", #%d", imm);
di->di_printf("]");
} else {
di->di_printf("[%s]", arm64_reg(1, rn));
di->di_printf("[%s]", arm64_reg(1, rn, rn_sp));
if (imm != 0)
di->di_printf(", #%d", imm);
}
Expand All @@ -480,12 +524,16 @@ disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt)
} else {
/* Last bit of option field determines 32/64 bit offset */
di->di_printf("%s\t%s, [%s, %s", i_ptr->name,
arm64_reg(sf, rt), arm64_reg(1, rn),
arm64_reg(option & 1, rm));

/* Calculate amount, it's op(31:30) */
amount = (insn >> ARM_INSN_SIZE_OFFSET) &
ARM_INSN_SIZE_MASK;
arm64_reg(sf, rt, rt_sp), arm64_reg(1, rn, rn_sp),
arm64_reg(option & 1, rm, rm_sp));

if (scale == 0)
amount = 0;
else {
/* Calculate amount, it's op(31:30) */
amount = (insn >> ARM_INSN_SIZE_OFFSET) &
ARM_INSN_SIZE_MASK;
}

switch (option) {
case 0x2:
Expand All @@ -499,7 +547,7 @@ disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt)
di->di_printf(", sxtw #%d", amount);
break;
case 0x7:
di->di_printf(", sxts #%d", amount);
di->di_printf(", sxtx #%d", amount);
break;
default:
di->di_printf(", RSVD");
Expand All @@ -521,7 +569,7 @@ disasm(const struct disasm_interface *di, vm_offset_t loc, int altfmt)
goto undefined;
}

di->di_printf("%s\t%s, ", i_ptr->name, arm64_reg(sf, rt));
di->di_printf("%s\t%s, ", i_ptr->name, arm64_reg(sf, rt, rt_sp));
if (i_ptr->special_ops & OP_LITERAL)
di->di_printf("0x%lx", loc + imm);
else
Expand Down
107 changes: 107 additions & 0 deletions sys/arm64/arm64/memcpy.S
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,110 @@ L(copy64_from_start):
EEND(memmove)
END(memcpy)

ENTRY(disasm_str_test)
/* str immediate post-index */
str w0, [x3], #-256
str w1, [sp], #255

str x2, [x4], #1
str x0, [sp], #-1

/* str immedate pre-index */
str w0, [x3, #-256]!
str w1, [sp, #255]!

str x2, [x4, #1]
str x0, [sp, #-1]

/* str immediate unsigned offset */
str w0, [x3]
str w0, [x3, #16380]
str w1, [sp, #16380]

str x0, [x3]
str x2, [x3, #32760]
str x3, [sp, #32760]

/* str register */
str w0, [x1, x2, lsl #2]
str w0, [x1, w2, uxtw #2]
str w0, [sp, w2, sxtw]
str w0, [sp, x2, sxtx #0]

str x0, [x1, x2, lsl #3]
str x0, [x1, w2, uxtw #3]
str x0, [sp, w2, sxtw]
str x0, [sp, x2, sxtx #0]

/* strb immediate post-index */
strb w0, [x3], #-256
strb w1, [sp], #255

/* strb immediate pre-index */
strb w0, [x3, #-256]!
strb w1, [sp, #255]!

/* strb immediate unsigned offset */
strb w0, [x3]
strb w0, [x3, #4095]
strb w1, [sp, #4095]

/* strb register */
strb w0, [x1, x2, sxtx #0]
strb w0, [x1, x2, lsl #0]
strb w0, [x1, w2, uxtw]
strb w0, [sp, w2, sxtw]
strb w0, [sp, x2, sxtx]

/* strh immediate post-index */
strh w0, [x3], #-256
strh w1, [sp], #255

/* strh immediate pre-index */
strh w0, [x3, #-256]!
strh w1, [sp, #255]!

/* strh immediate unsigned offset */
strh w0, [x3]
strh w0, [x3, #8190]
strh w1, [sp, #8190]

/* strh register */
strh w0, [x1, w2, uxtw #1]
strh w0, [x1, x2, lsl #1]
strh w0, [sp, w2, sxtw]
strh w0, [sp, x2, sxtx #0]
strh wzr, [sp, xzr, sxtx #0]
END(disasm_str_test)

ENTRY(disasm_shifted_reg_with_rsv)
/* adds shifted regiser */
adds w0, w1, w3, asr #1
adds x0, x1, x2, lsl #2


/* cmn shifted register, alias of adds */
cmn w0, w4, lsr #31
cmn x1, x10, asr #63

/* subs shifted register */
subs w0, w11, w12, lsr #0
subs x1, x12, x11, lsl #63

/* cmp shifted register, alias of subs */
cmp w0, w1, asr #31
cmp x0, x2, lsl #63

/* negs shifted register, alias of subs */
negs w0, w1, lsr #31
negs x0, x20, asr #0

/* sub shifted register */
sub w0, w1, w2, lsl #1
sub x0, x2, x1, lsl #5

/* neg shifted register */
neg w0, w1, lsl #2
neg x2, x3, asr #8

END(disasm_shifted_reg_with_rsv)