1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
graphic: 0.957
semantic: 0.941
performance: 0.936
hypervisor: 0.935
debug: 0.934
risc-v: 0.934
mistranslation: 0.930
ppc: 0.927
virtual: 0.926
socket: 0.921
arm: 0.920
vnc: 0.919
PID: 0.912
network: 0.910
peripherals: 0.908
KVM: 0.905
user-level: 0.902
device: 0.901
VMM: 0.900
register: 0.898
kernel: 0.893
assembly: 0.890
permissions: 0.885
TCG: 0.883
x86: 0.881
boot: 0.881
architecture: 0.874
i386: 0.844
files: 0.815
qemu-system-arm doesn't honour CPACR.ASEDIS, D32DIS
Description of problem:
We used differential testing to compared the instruction consistency (ARMv7) between QEMU and raspberry pi 2B in system level and some inconsistency in SIMD instruction was detected.
We compiled the kernel with options `-mcpu=cortex-a7 -march=armv7ve -mfloat-abi=hard -mfpu=vfpv4 `. Some SIMD instructions are considered as **undefined** instructions in raspi2b, but run successfully in the QEMU.
We checked that the CPACR.ASEDIS=1, which disables Advanced SIMD functionality, according to ARMv7-a manual B4.1.40. The manual says "All instruction encodings identified in the Alphabetical list of instructions on page A8-300 as being Advanced SIMD instructions, but that are not VFPv3 or VFPv4
instructions, are UNDEFINED when accessed from PL1 and PL0 modes."
Tested instruction samples are shown as follows:
- VMAX_int_T1A1_A 11110010010010110000011010100100 0xf24b06a4
- VMUL_scalar_A1_A 11110010101001001100100 001000011 0xf2a4c843
- VADD_int_T1A1_A 11110010000111111010100000001100 0xf21fa80c
...
Some checks of the SIMD instructions may be needed before the execution of the instructions in function ` do_3same` etc. in target/arm/translate-neon.c.
Steps to reproduce:
1. Compile a kernel module to run the test instruction in PL1.
2. Hook a undefined handler in kernel module to catch the undefined instructions. A kernel module template we used to test is as follows
```c
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/traps.h>
MODULE_LICENSE("GPL");
#pragma GCC optimize ("O0")
// instr is undefined instruction value
static int undef_instr_handler(struct pt_regs *regs, u32 instr)
{
printk(KERN_INFO "get undefined instruction\n");
// Just skip over to the next instruction.
regs->ARM_pc += 4;
return 0; // All fine!
}
static struct undef_hook uh = {
.instr_mask = 0x0, // any instruction
.instr_val = 0x0, // any instruction
.cpsr_mask = 0x0, // any pstate
.cpsr_val = 0x0, // any pstate
.fn = undef_instr_handler
};
int init_module(void) {
// Lookup wanted symbols.
register_undef_hook(&uh);
__asm__ __volatile__("push {R0-R12}");
__asm__ __volatile__(
".global inialize_location\n"
"inialize_location:\n"
"mov r0, %[reg_init] \n"
"mov r1, %[reg_init] \n"
"mov r2, %[reg_init] \n"
"mov r3, %[reg_init] \n"
"mov r4, %[reg_init] \n"
"mov r5, %[reg_init] \n"
"mov r6, %[reg_init] \n"
"mov r7, %[reg_init] \n"
"mov r8, %[reg_init] \n"
"mov r9, %[reg_init] \n"
"mov r10, %[reg_init] \n"
"mov r11, %[reg_init] \n"
"mov r12, %[reg_init] \n"
:
: [reg_init] "n"(0)
);
// =======TODO=======
// replace nop with test instruction
__asm__ __volatile__(
".global inst_location\n"
"inst_location:\n"
"nop\n"
);
// kgdb_breakpoint();
__asm__ __volatile__(
".global finish_location\n"
"finish_location:\n"
);
__asm__ __volatile__("pop {R0-R12}");
return 0;
}
void cleanup_module(void) {
unregister_undef_hook(&uh);
}
```
Additional information:
|