18 changes: 18 additions & 0 deletions target/arm/tcg/mte_helper.c
Expand Up @@ -785,6 +785,24 @@ uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra)

uint64_t HELPER(mte_check)(CPUARMState *env, uint32_t desc, uint64_t ptr)
{
/*
* R_XCHFJ: Alignment check not caused by memory type is priority 1,
* higher than any translation fault. When MTE is disabled, tcg
* performs the alignment check during the code generated for the
* memory access. With MTE enabled, we must check this here before
* raising any translation fault in allocation_tag_mem.
*/
unsigned align = FIELD_EX32(desc, MTEDESC, ALIGN);
if (unlikely(align)) {
align = (1u << align) - 1;
if (unlikely(ptr & align)) {
int idx = FIELD_EX32(desc, MTEDESC, MIDX);
bool w = FIELD_EX32(desc, MTEDESC, WRITE);
MMUAccessType type = w ? MMU_DATA_STORE : MMU_DATA_LOAD;
arm_cpu_do_unaligned_access(env_cpu(env), ptr, type, idx, GETPC());
}
}

return mte_check(env, desc, ptr, GETPC());
}

Expand Down
477 changes: 321 additions & 156 deletions target/arm/tcg/translate-a64.c

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions target/arm/tcg/translate-a64.h
Expand Up @@ -49,9 +49,9 @@ static inline bool sme_smza_enabled_check(DisasContext *s)

TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr);
TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write,
bool tag_checked, int log2_size);
bool tag_checked, MemOp memop);
TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write,
bool tag_checked, int size);
bool tag_checked, int total_size, MemOp memop);

/* We should have at some point before trying to access an FP register
* done the necessary access check, so assert that
Expand Down
106 changes: 76 additions & 30 deletions target/arm/tcg/translate-sve.c
Expand Up @@ -4167,15 +4167,16 @@ TRANS_FEAT(UCVTF_dd, aa64_sve, gen_gvec_fpst_arg_zpz,
void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
int len, int rn, int imm)
{
int len_align = QEMU_ALIGN_DOWN(len, 8);
int len_remain = len % 8;
int nparts = len / 8 + ctpop8(len_remain);
int len_align = QEMU_ALIGN_DOWN(len, 16);
int len_remain = len % 16;
int nparts = len / 16 + ctpop8(len_remain);
int midx = get_mem_index(s);
TCGv_i64 dirty_addr, clean_addr, t0, t1;
TCGv_i128 t16;

dirty_addr = tcg_temp_new_i64();
tcg_gen_addi_i64(dirty_addr, cpu_reg_sp(s, rn), imm);
clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len);
clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len, MO_8);

/*
* Note that unpredicated load/store of vector/predicate registers
Expand All @@ -4188,10 +4189,16 @@ void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
int i;

t0 = tcg_temp_new_i64();
for (i = 0; i < len_align; i += 8) {
tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUQ);
t1 = tcg_temp_new_i64();
t16 = tcg_temp_new_i128();

for (i = 0; i < len_align; i += 16) {
tcg_gen_qemu_ld_i128(t16, clean_addr, midx,
MO_LE | MO_128 | MO_ATOM_NONE);
tcg_gen_extr_i128_i64(t0, t1, t16);
tcg_gen_st_i64(t0, base, vofs + i);
tcg_gen_addi_i64(clean_addr, clean_addr, 8);
tcg_gen_st_i64(t1, base, vofs + i + 8);
tcg_gen_addi_i64(clean_addr, clean_addr, 16);
}
} else {
TCGLabel *loop = gen_new_label();
Expand All @@ -4200,14 +4207,21 @@ void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
tcg_gen_movi_ptr(i, 0);
gen_set_label(loop);

t0 = tcg_temp_new_i64();
tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUQ);
tcg_gen_addi_i64(clean_addr, clean_addr, 8);
t16 = tcg_temp_new_i128();
tcg_gen_qemu_ld_i128(t16, clean_addr, midx,
MO_LE | MO_128 | MO_ATOM_NONE);
tcg_gen_addi_i64(clean_addr, clean_addr, 16);

tp = tcg_temp_new_ptr();
tcg_gen_add_ptr(tp, base, i);
tcg_gen_addi_ptr(i, i, 8);
tcg_gen_addi_ptr(i, i, 16);

t0 = tcg_temp_new_i64();
t1 = tcg_temp_new_i64();
tcg_gen_extr_i128_i64(t0, t1, t16);

tcg_gen_st_i64(t0, tp, vofs);
tcg_gen_st_i64(t1, tp, vofs + 8);

tcg_gen_brcondi_ptr(TCG_COND_LTU, i, len_align, loop);
}
Expand All @@ -4216,21 +4230,31 @@ void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
* Predicate register loads can be any multiple of 2.
* Note that we still store the entire 64-bit unit into cpu_env.
*/
if (len_remain >= 8) {
t0 = tcg_temp_new_i64();
tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUQ | MO_ATOM_NONE);
tcg_gen_st_i64(t0, base, vofs + len_align);
len_remain -= 8;
len_align += 8;
if (len_remain) {
tcg_gen_addi_i64(clean_addr, clean_addr, 8);
}
}
if (len_remain) {
t0 = tcg_temp_new_i64();
switch (len_remain) {
case 2:
case 4:
case 8:
tcg_gen_qemu_ld_i64(t0, clean_addr, midx,
MO_LE | ctz32(len_remain));
MO_LE | ctz32(len_remain) | MO_ATOM_NONE);
break;

case 6:
t1 = tcg_temp_new_i64();
tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUL);
tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUL | MO_ATOM_NONE);
tcg_gen_addi_i64(clean_addr, clean_addr, 4);
tcg_gen_qemu_ld_i64(t1, clean_addr, midx, MO_LEUW);
tcg_gen_qemu_ld_i64(t1, clean_addr, midx, MO_LEUW | MO_ATOM_NONE);
tcg_gen_deposit_i64(t0, t0, t1, 32, 32);
break;

Expand All @@ -4245,15 +4269,16 @@ void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
void gen_sve_str(DisasContext *s, TCGv_ptr base, int vofs,
int len, int rn, int imm)
{
int len_align = QEMU_ALIGN_DOWN(len, 8);
int len_remain = len % 8;
int nparts = len / 8 + ctpop8(len_remain);
int len_align = QEMU_ALIGN_DOWN(len, 16);
int len_remain = len % 16;
int nparts = len / 16 + ctpop8(len_remain);
int midx = get_mem_index(s);
TCGv_i64 dirty_addr, clean_addr, t0;
TCGv_i64 dirty_addr, clean_addr, t0, t1;
TCGv_i128 t16;

dirty_addr = tcg_temp_new_i64();
tcg_gen_addi_i64(dirty_addr, cpu_reg_sp(s, rn), imm);
clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len);
clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len, MO_8);

/* Note that unpredicated load/store of vector/predicate registers
* are defined as a stream of bytes, which equates to little-endian
Expand All @@ -4267,10 +4292,15 @@ void gen_sve_str(DisasContext *s, TCGv_ptr base, int vofs,
int i;

t0 = tcg_temp_new_i64();
t1 = tcg_temp_new_i64();
t16 = tcg_temp_new_i128();
for (i = 0; i < len_align; i += 8) {
tcg_gen_ld_i64(t0, base, vofs + i);
tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUQ);
tcg_gen_addi_i64(clean_addr, clean_addr, 8);
tcg_gen_ld_i64(t1, base, vofs + i + 8);
tcg_gen_concat_i64_i128(t16, t0, t1);
tcg_gen_qemu_st_i128(t16, clean_addr, midx,
MO_LE | MO_128 | MO_ATOM_NONE);
tcg_gen_addi_i64(clean_addr, clean_addr, 16);
}
} else {
TCGLabel *loop = gen_new_label();
Expand All @@ -4280,18 +4310,33 @@ void gen_sve_str(DisasContext *s, TCGv_ptr base, int vofs,
gen_set_label(loop);

t0 = tcg_temp_new_i64();
t1 = tcg_temp_new_i64();
tp = tcg_temp_new_ptr();
tcg_gen_add_ptr(tp, base, i);
tcg_gen_ld_i64(t0, tp, vofs);
tcg_gen_addi_ptr(i, i, 8);
tcg_gen_ld_i64(t1, tp, vofs + 8);
tcg_gen_addi_ptr(i, i, 16);

tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUQ);
tcg_gen_addi_i64(clean_addr, clean_addr, 8);
t16 = tcg_temp_new_i128();
tcg_gen_concat_i64_i128(t16, t0, t1);

tcg_gen_qemu_st_i128(t16, clean_addr, midx, MO_LEUQ);
tcg_gen_addi_i64(clean_addr, clean_addr, 16);

tcg_gen_brcondi_ptr(TCG_COND_LTU, i, len_align, loop);
}

/* Predicate register stores can be any multiple of 2. */
if (len_remain >= 8) {
t0 = tcg_temp_new_i64();
tcg_gen_st_i64(t0, base, vofs + len_align);
tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUQ | MO_ATOM_NONE);
len_remain -= 8;
len_align += 8;
if (len_remain) {
tcg_gen_addi_i64(clean_addr, clean_addr, 8);
}
}
if (len_remain) {
t0 = tcg_temp_new_i64();
tcg_gen_ld_i64(t0, base, vofs + len_align);
Expand All @@ -4301,14 +4346,14 @@ void gen_sve_str(DisasContext *s, TCGv_ptr base, int vofs,
case 4:
case 8:
tcg_gen_qemu_st_i64(t0, clean_addr, midx,
MO_LE | ctz32(len_remain));
MO_LE | ctz32(len_remain) | MO_ATOM_NONE);
break;

case 6:
tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUL);
tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUL | MO_ATOM_NONE);
tcg_gen_addi_i64(clean_addr, clean_addr, 4);
tcg_gen_shri_i64(t0, t0, 32);
tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUW);
tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUW | MO_ATOM_NONE);
break;

default:
Expand Down Expand Up @@ -4964,6 +5009,7 @@ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a)
unsigned msz = dtype_msz(a->dtype);
TCGLabel *over;
TCGv_i64 temp, clean_addr;
MemOp memop;

if (!dc_isar_feature(aa64_sve, s)) {
return false;
Expand Down Expand Up @@ -4993,10 +5039,10 @@ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a)
/* Load the data. */
temp = tcg_temp_new_i64();
tcg_gen_addi_i64(temp, cpu_reg_sp(s, a->rn), a->imm << msz);
clean_addr = gen_mte_check1(s, temp, false, true, msz);

tcg_gen_qemu_ld_i64(temp, clean_addr, get_mem_index(s),
finalize_memop(s, dtype_mop[a->dtype]));
memop = finalize_memop(s, dtype_mop[a->dtype]);
clean_addr = gen_mte_check1(s, temp, false, true, memop);
tcg_gen_qemu_ld_i64(temp, clean_addr, get_mem_index(s), memop);

/* Broadcast to *all* elements. */
tcg_gen_gvec_dup_i64(esz, vec_full_reg_offset(s, a->rd),
Expand Down
1 change: 1 addition & 0 deletions target/arm/tcg/translate.c
Expand Up @@ -9168,6 +9168,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
dc->sme_trap_nonstreaming =
EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING);
}
dc->lse2 = false; /* applies only to aarch64 */
dc->cp_regs = cpu->cp_regs;
dc->features = env->features;

Expand Down
65 changes: 60 additions & 5 deletions target/arm/tcg/translate.h
Expand Up @@ -90,6 +90,7 @@ typedef struct DisasContext {
uint64_t features; /* CPU features bits */
bool aarch64;
bool thumb;
bool lse2;
/* Because unallocated encodings generate different exception syndrome
* information from traps due to FP being disabled, we can't do a single
* "is fp access disabled" check at a high level in the decode tree.
Expand Down Expand Up @@ -141,6 +142,8 @@ typedef struct DisasContext {
bool fgt_eret;
/* True if fine-grained trap on SVC is enabled */
bool fgt_svc;
/* True if FEAT_LSE2 SCTLR_ELx.nAA is set */
bool naa;
/*
* >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
* < 0, set by the current instruction.
Expand Down Expand Up @@ -557,12 +560,13 @@ static inline TCGv_ptr fpstatus_ptr(ARMFPStatusFlavour flavour)
}

/**
* finalize_memop:
* finalize_memop_atom:
* @s: DisasContext
* @opc: size+sign+align of the memory operation
* @atom: atomicity of the memory operation
*
* Build the complete MemOp for a memory operation, including alignment
* and endianness.
* Build the complete MemOp for a memory operation, including alignment,
* endianness, and atomicity.
*
* If (op & MO_AMASK) then the operation already contains the required
* alignment, e.g. for AccType_ATOMIC. Otherwise, this an optionally
Expand All @@ -572,12 +576,63 @@ static inline TCGv_ptr fpstatus_ptr(ARMFPStatusFlavour flavour)
* and this is applied here. Note that there is no way to indicate that
* no alignment should ever be enforced; this must be handled manually.
*/
static inline MemOp finalize_memop(DisasContext *s, MemOp opc)
static inline MemOp finalize_memop_atom(DisasContext *s, MemOp opc, MemOp atom)
{
if (s->align_mem && !(opc & MO_AMASK)) {
opc |= MO_ALIGN;
}
return opc | s->be_data;
return opc | atom | s->be_data;
}

/**
* finalize_memop:
* @s: DisasContext
* @opc: size+sign+align of the memory operation
*
* Like finalize_memop_atom, but with default atomicity.
*/
static inline MemOp finalize_memop(DisasContext *s, MemOp opc)
{
MemOp atom = s->lse2 ? MO_ATOM_WITHIN16 : MO_ATOM_IFALIGN;
return finalize_memop_atom(s, opc, atom);
}

/**
* finalize_memop_pair:
* @s: DisasContext
* @opc: size+sign+align of the memory operation
*
* Like finalize_memop_atom, but with atomicity for a pair.
* C.f. Pseudocode for Mem[], operand ispair.
*/
static inline MemOp finalize_memop_pair(DisasContext *s, MemOp opc)
{
MemOp atom = s->lse2 ? MO_ATOM_WITHIN16_PAIR : MO_ATOM_IFALIGN_PAIR;
return finalize_memop_atom(s, opc, atom);
}

/**
* finalize_memop_asimd:
* @s: DisasContext
* @opc: size+sign+align of the memory operation
*
* Like finalize_memop_atom, but with atomicity of AccessType_ASIMD.
*/
static inline MemOp finalize_memop_asimd(DisasContext *s, MemOp opc)
{
/*
* In the pseudocode for Mem[], with AccessType_ASIMD, size == 16,
* if IsAligned(8), the first case provides separate atomicity for
* the pair of 64-bit accesses. If !IsAligned(8), the middle cases
* do not apply, and we're left with the final case of no atomicity.
* Thus MO_ATOM_IFALIGN_PAIR.
*
* For other sizes, normal LSE2 rules apply.
*/
if ((opc & MO_SIZE) == MO_128) {
return finalize_memop_atom(s, opc, MO_ATOM_IFALIGN_PAIR);
}
return finalize_memop(s, opc);
}

/**
Expand Down
33 changes: 33 additions & 0 deletions target/i386/hvf/hvf.c
Expand Up @@ -679,3 +679,36 @@ int hvf_vcpu_exec(CPUState *cpu)

return ret;
}

int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp)
{
return -ENOSYS;
}

int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp)
{
return -ENOSYS;
}

int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type)
{
return -ENOSYS;
}

int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int type)
{
return -ENOSYS;
}

void hvf_arch_remove_all_hw_breakpoints(void)
{
}

void hvf_arch_update_guest_debug(CPUState *cpu)
{
}

inline bool hvf_arch_supports_guest_debug(void)
{
return false;
}
176 changes: 176 additions & 0 deletions tests/avocado/boot_linux_console.py
Expand Up @@ -769,6 +769,182 @@ def test_arm_quanta_gsj_initrd(self):
self.wait_for_console_pattern(
'Give root password for system maintenance')

def test_arm_bpim2u(self):
"""
:avocado: tags=arch:arm
:avocado: tags=machine:bpim2u
:avocado: tags=accel:tcg
"""
deb_url = ('https://apt.armbian.com/pool/main/l/linux-5.10.16-sunxi/'
'linux-image-current-sunxi_21.02.2_armhf.deb')
deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
kernel_path = self.extract_from_deb(deb_path,
'/boot/vmlinuz-5.10.16-sunxi')
dtb_path = ('/usr/lib/linux-image-current-sunxi/'
'sun8i-r40-bananapi-m2-ultra.dtb')
dtb_path = self.extract_from_deb(deb_path, dtb_path)

self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyS0,115200n8 '
'earlycon=uart,mmio32,0x1c28000')
self.vm.add_args('-kernel', kernel_path,
'-dtb', dtb_path,
'-append', kernel_command_line)
self.vm.launch()
console_pattern = 'Kernel command line: %s' % kernel_command_line
self.wait_for_console_pattern(console_pattern)

def test_arm_bpim2u_initrd(self):
"""
:avocado: tags=arch:arm
:avocado: tags=accel:tcg
:avocado: tags=machine:bpim2u
"""
deb_url = ('https://apt.armbian.com/pool/main/l/linux-5.10.16-sunxi/'
'linux-image-current-sunxi_21.02.2_armhf.deb')
deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
kernel_path = self.extract_from_deb(deb_path,
'/boot/vmlinuz-5.10.16-sunxi')
dtb_path = ('/usr/lib/linux-image-current-sunxi/'
'sun8i-r40-bananapi-m2-ultra.dtb')
dtb_path = self.extract_from_deb(deb_path, dtb_path)
initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
'2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
'arm/rootfs-armv7a.cpio.gz')
initrd_hash = '604b2e45cdf35045846b8bbfbf2129b1891bdc9c'
initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
archive.gzip_uncompress(initrd_path_gz, initrd_path)

self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyS0,115200 '
'panic=-1 noreboot')
self.vm.add_args('-kernel', kernel_path,
'-dtb', dtb_path,
'-initrd', initrd_path,
'-append', kernel_command_line,
'-no-reboot')
self.vm.launch()
self.wait_for_console_pattern('Boot successful.')

exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
'Allwinner sun8i Family')
exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
'system-control@1c00000')
exec_command_and_wait_for_pattern(self, 'reboot',
'reboot: Restarting system')
# Wait for VM to shut down gracefully
self.vm.wait()

def test_arm_bpim2u_gmac(self):
"""
:avocado: tags=arch:arm
:avocado: tags=accel:tcg
:avocado: tags=machine:bpim2u
:avocado: tags=device:sd
"""
self.require_netdev('user')

deb_url = ('https://apt.armbian.com/pool/main/l/linux-5.10.16-sunxi/'
'linux-image-current-sunxi_21.02.2_armhf.deb')
deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
kernel_path = self.extract_from_deb(deb_path,
'/boot/vmlinuz-5.10.16-sunxi')
dtb_path = ('/usr/lib/linux-image-current-sunxi/'
'sun8i-r40-bananapi-m2-ultra.dtb')
dtb_path = self.extract_from_deb(deb_path, dtb_path)
rootfs_url = ('http://storage.kernelci.org/images/rootfs/buildroot/'
'buildroot-baseline/20221116.0/armel/rootfs.ext2.xz')
rootfs_hash = 'fae32f337c7b87547b10f42599acf109da8b6d9a'
rootfs_path_xz = self.fetch_asset(rootfs_url, asset_hash=rootfs_hash)
rootfs_path = os.path.join(self.workdir, 'rootfs.cpio')
archive.lzma_uncompress(rootfs_path_xz, rootfs_path)
image_pow2ceil_expand(rootfs_path)

self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyS0,115200 '
'root=/dev/mmcblk0 rootwait rw '
'panic=-1 noreboot')
self.vm.add_args('-kernel', kernel_path,
'-dtb', dtb_path,
'-drive', 'file=' + rootfs_path + ',if=sd,format=raw',
'-net', 'nic,model=gmac,netdev=host_gmac',
'-netdev', 'user,id=host_gmac',
'-append', kernel_command_line,
'-no-reboot')
self.vm.launch()
shell_ready = "/bin/sh: can't access tty; job control turned off"
self.wait_for_console_pattern(shell_ready)

exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
'Allwinner sun8i Family')
exec_command_and_wait_for_pattern(self, 'cat /proc/partitions',
'mmcblk0')
exec_command_and_wait_for_pattern(self, 'ifconfig eth0 up',
'eth0: Link is Up')
exec_command_and_wait_for_pattern(self, 'udhcpc eth0',
'udhcpc: lease of 10.0.2.15 obtained')
exec_command_and_wait_for_pattern(self, 'ping -c 3 10.0.2.2',
'3 packets transmitted, 3 packets received, 0% packet loss')
exec_command_and_wait_for_pattern(self, 'reboot',
'reboot: Restarting system')
# Wait for VM to shut down gracefully
self.vm.wait()

@skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
def test_arm_bpim2u_openwrt_22_03_3(self):
"""
:avocado: tags=arch:arm
:avocado: tags=machine:bpim2u
:avocado: tags=device:sd
"""

# This test download a 8.9 MiB compressed image and expand it
# to 127 MiB.
image_url = ('https://downloads.openwrt.org/releases/22.03.3/targets/'
'sunxi/cortexa7/openwrt-22.03.3-sunxi-cortexa7-'
'sinovoip_bananapi-m2-ultra-ext4-sdcard.img.gz')
image_hash = ('5b41b4e11423e562c6011640f9a7cd3b'
'dd0a3d42b83430f7caa70a432e6cd82c')
image_path_gz = self.fetch_asset(image_url, asset_hash=image_hash,
algorithm='sha256')
image_path = archive.extract(image_path_gz, self.workdir)
image_pow2ceil_expand(image_path)

self.vm.set_console()
self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw',
'-nic', 'user',
'-no-reboot')
self.vm.launch()

kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'usbcore.nousb '
'noreboot')

self.wait_for_console_pattern('U-Boot SPL')

interrupt_interactive_console_until_pattern(
self, 'Hit any key to stop autoboot:', '=>')
exec_command_and_wait_for_pattern(self, "setenv extraargs '" +
kernel_command_line + "'", '=>')
exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...');

self.wait_for_console_pattern(
'Please press Enter to activate this console.')

exec_command_and_wait_for_pattern(self, ' ', 'root@')

exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
'Allwinner sun8i Family')
exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
'system-control@1c00000')

def test_arm_orangepi(self):
"""
:avocado: tags=arch:arm
Expand Down
1 change: 1 addition & 0 deletions tests/qtest/meson.build
Expand Up @@ -216,6 +216,7 @@ qtests_aarch64 = \
(config_all.has_key('CONFIG_TCG') and config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? \
['tpm-tis-device-test', 'tpm-tis-device-swtpm-test'] : []) + \
(config_all_devices.has_key('CONFIG_XLNX_ZYNQMP_ARM') ? ['xlnx-can-test', 'fuzz-xlnx-dp-test'] : []) + \
(config_all_devices.has_key('CONFIG_XLNX_VERSAL') ? ['xlnx-canfd-test'] : []) + \
(config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test'] : []) + \
(config_all.has_key('CONFIG_TCG') and \
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
Expand Down
423 changes: 423 additions & 0 deletions tests/qtest/xlnx-canfd-test.c

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions tests/tcg/aarch64/Makefile.target
Expand Up @@ -21,12 +21,23 @@ config-cc.mak: Makefile
$(quiet-@)( \
$(call cc-option,-march=armv8.1-a+sve, CROSS_CC_HAS_SVE); \
$(call cc-option,-march=armv8.1-a+sve2, CROSS_CC_HAS_SVE2); \
$(call cc-option,-march=armv8.2-a, CROSS_CC_HAS_ARMV8_2); \
$(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3); \
$(call cc-option,-march=armv8.5-a, CROSS_CC_HAS_ARMV8_5); \
$(call cc-option,-mbranch-protection=standard, CROSS_CC_HAS_ARMV8_BTI); \
$(call cc-option,-march=armv8.5-a+memtag, CROSS_CC_HAS_ARMV8_MTE); \
$(call cc-option,-march=armv9-a+sme, CROSS_CC_HAS_ARMV9_SME)) 3> config-cc.mak
-include config-cc.mak

ifneq ($(CROSS_CC_HAS_ARMV8_2),)
AARCH64_TESTS += dcpop
dcpop: CFLAGS += -march=armv8.2-a
endif
ifneq ($(CROSS_CC_HAS_ARMV8_5),)
AARCH64_TESTS += dcpodp
dcpodp: CFLAGS += -march=armv8.5-a
endif

# Pauth Tests
ifneq ($(CROSS_CC_HAS_ARMV8_3),)
AARCH64_TESTS += pauth-1 pauth-2 pauth-4 pauth-5
Expand Down
63 changes: 63 additions & 0 deletions tests/tcg/aarch64/dcpodp.c
@@ -0,0 +1,63 @@
/*
* Test execution of DC CVADP instruction.
*
* Copyright (c) 2023 Zhuojia Shen <chaosdefinition@hotmail.com>
* SPDX-License-Identifier: GPL-2.0-or-later
*/

#include <asm/hwcap.h>
#include <sys/auxv.h>

#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#ifndef HWCAP2_DCPODP
#define HWCAP2_DCPODP (1 << 0)
#endif

bool should_fail = false;

static void signal_handler(int sig, siginfo_t *si, void *data)
{
ucontext_t *uc = (ucontext_t *)data;

if (should_fail) {
uc->uc_mcontext.pc += 4;
} else {
exit(EXIT_FAILURE);
}
}

static int do_dc_cvadp(void)
{
struct sigaction sa = {
.sa_flags = SA_SIGINFO,
.sa_sigaction = signal_handler,
};

sigemptyset(&sa.sa_mask);
if (sigaction(SIGSEGV, &sa, NULL) < 0) {
perror("sigaction");
return EXIT_FAILURE;
}

asm volatile("dc cvadp, %0\n\t" :: "r"(&sa));

should_fail = true;
asm volatile("dc cvadp, %0\n\t" :: "r"(NULL));
should_fail = false;

return EXIT_SUCCESS;
}

int main(void)
{
if (getauxval(AT_HWCAP2) & HWCAP2_DCPODP) {
return do_dc_cvadp();
} else {
printf("SKIP: no HWCAP2_DCPODP on this system\n");
return EXIT_SUCCESS;
}
}
63 changes: 63 additions & 0 deletions tests/tcg/aarch64/dcpop.c
@@ -0,0 +1,63 @@
/*
* Test execution of DC CVAP instruction.
*
* Copyright (c) 2023 Zhuojia Shen <chaosdefinition@hotmail.com>
* SPDX-License-Identifier: GPL-2.0-or-later
*/

#include <asm/hwcap.h>
#include <sys/auxv.h>

#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#ifndef HWCAP_DCPOP
#define HWCAP_DCPOP (1 << 16)
#endif

bool should_fail = false;

static void signal_handler(int sig, siginfo_t *si, void *data)
{
ucontext_t *uc = (ucontext_t *)data;

if (should_fail) {
uc->uc_mcontext.pc += 4;
} else {
exit(EXIT_FAILURE);
}
}

static int do_dc_cvap(void)
{
struct sigaction sa = {
.sa_flags = SA_SIGINFO,
.sa_sigaction = signal_handler,
};

sigemptyset(&sa.sa_mask);
if (sigaction(SIGSEGV, &sa, NULL) < 0) {
perror("sigaction");
return EXIT_FAILURE;
}

asm volatile("dc cvap, %0\n\t" :: "r"(&sa));

should_fail = true;
asm volatile("dc cvap, %0\n\t" :: "r"(NULL));
should_fail = false;

return EXIT_SUCCESS;
}

int main(void)
{
if (getauxval(AT_HWCAP) & HWCAP_DCPOP) {
return do_dc_cvap();
} else {
printf("SKIP: no HWCAP_DCPOP on this system\n");
return EXIT_SUCCESS;
}
}
3 changes: 1 addition & 2 deletions tests/tcg/aarch64/mte-7.c
Expand Up @@ -19,8 +19,7 @@ int main(int ac, char **av)
p = (void *)((unsigned long)p | (1ul << 56));

/* Store tag in sequential granules. */
asm("stg %0, [%0]" : : "r"(p + 0x0ff0));
asm("stg %0, [%0]" : : "r"(p + 0x1000));
asm("stz2g %0, [%0]" : : "r"(p + 0x0ff0));

/*
* Perform an unaligned store with tag 1 crossing the pages.
Expand Down
13 changes: 9 additions & 4 deletions tests/tcg/multiarch/sigbus.c
Expand Up @@ -6,8 +6,13 @@
#include <endian.h>


unsigned long long x = 0x8877665544332211ull;
void * volatile p = (void *)&x + 1;
char x[32] __attribute__((aligned(16))) = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
};
void * volatile p = (void *)&x + 15;

void sigbus(int sig, siginfo_t *info, void *uc)
{
Expand Down Expand Up @@ -60,9 +65,9 @@ int main()
* We might as well validate the unaligned load worked.
*/
if (BYTE_ORDER == LITTLE_ENDIAN) {
assert(tmp == 0x55443322);
assert(tmp == 0x13121110);
} else {
assert(tmp == 0x77665544);
assert(tmp == 0x10111213);
}
return EXIT_SUCCESS;
}