diff options
Diffstat (limited to 'tools')
181 files changed, 7230 insertions, 2272 deletions
diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h index 69d09c39bbcd..cd7359e23d86 100644 --- a/tools/arch/s390/include/uapi/asm/kvm.h +++ b/tools/arch/s390/include/uapi/asm/kvm.h | |||
@@ -88,6 +88,12 @@ struct kvm_s390_io_adapter_req { | |||
88 | /* kvm attributes for KVM_S390_VM_TOD */ | 88 | /* kvm attributes for KVM_S390_VM_TOD */ |
89 | #define KVM_S390_VM_TOD_LOW 0 | 89 | #define KVM_S390_VM_TOD_LOW 0 |
90 | #define KVM_S390_VM_TOD_HIGH 1 | 90 | #define KVM_S390_VM_TOD_HIGH 1 |
91 | #define KVM_S390_VM_TOD_EXT 2 | ||
92 | |||
93 | struct kvm_s390_vm_tod_clock { | ||
94 | __u8 epoch_idx; | ||
95 | __u64 tod; | ||
96 | }; | ||
91 | 97 | ||
92 | /* kvm attributes for KVM_S390_VM_CPU_MODEL */ | 98 | /* kvm attributes for KVM_S390_VM_CPU_MODEL */ |
93 | /* processor related attributes are r/w */ | 99 | /* processor related attributes are r/w */ |
diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 8ea315a11fe0..2519c6c801c9 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h | |||
@@ -196,6 +196,7 @@ | |||
196 | 196 | ||
197 | #define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ | 197 | #define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ |
198 | #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ | 198 | #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ |
199 | #define X86_FEATURE_SME ( 7*32+10) /* AMD Secure Memory Encryption */ | ||
199 | 200 | ||
200 | #define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */ | 201 | #define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */ |
201 | #define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */ | 202 | #define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */ |
@@ -287,6 +288,7 @@ | |||
287 | #define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */ | 288 | #define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */ |
288 | #define X86_FEATURE_AVIC (15*32+13) /* Virtual Interrupt Controller */ | 289 | #define X86_FEATURE_AVIC (15*32+13) /* Virtual Interrupt Controller */ |
289 | #define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* Virtual VMSAVE VMLOAD */ | 290 | #define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* Virtual VMSAVE VMLOAD */ |
291 | #define X86_FEATURE_VGIF (15*32+16) /* Virtual GIF */ | ||
290 | 292 | ||
291 | /* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 16 */ | 293 | /* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 16 */ |
292 | #define X86_FEATURE_AVX512VBMI (16*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/ | 294 | #define X86_FEATURE_AVX512VBMI (16*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/ |
diff --git a/tools/arch/x86/include/asm/disabled-features.h b/tools/arch/x86/include/asm/disabled-features.h index 5dff775af7cd..c10c9128f54e 100644 --- a/tools/arch/x86/include/asm/disabled-features.h +++ b/tools/arch/x86/include/asm/disabled-features.h | |||
@@ -21,11 +21,13 @@ | |||
21 | # define DISABLE_K6_MTRR (1<<(X86_FEATURE_K6_MTRR & 31)) | 21 | # define DISABLE_K6_MTRR (1<<(X86_FEATURE_K6_MTRR & 31)) |
22 | # define DISABLE_CYRIX_ARR (1<<(X86_FEATURE_CYRIX_ARR & 31)) | 22 | # define DISABLE_CYRIX_ARR (1<<(X86_FEATURE_CYRIX_ARR & 31)) |
23 | # define DISABLE_CENTAUR_MCR (1<<(X86_FEATURE_CENTAUR_MCR & 31)) | 23 | # define DISABLE_CENTAUR_MCR (1<<(X86_FEATURE_CENTAUR_MCR & 31)) |
24 | # define DISABLE_PCID 0 | ||
24 | #else | 25 | #else |
25 | # define DISABLE_VME 0 | 26 | # define DISABLE_VME 0 |
26 | # define DISABLE_K6_MTRR 0 | 27 | # define DISABLE_K6_MTRR 0 |
27 | # define DISABLE_CYRIX_ARR 0 | 28 | # define DISABLE_CYRIX_ARR 0 |
28 | # define DISABLE_CENTAUR_MCR 0 | 29 | # define DISABLE_CENTAUR_MCR 0 |
30 | # define DISABLE_PCID (1<<(X86_FEATURE_PCID & 31)) | ||
29 | #endif /* CONFIG_X86_64 */ | 31 | #endif /* CONFIG_X86_64 */ |
30 | 32 | ||
31 | #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS | 33 | #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS |
@@ -49,7 +51,7 @@ | |||
49 | #define DISABLED_MASK1 0 | 51 | #define DISABLED_MASK1 0 |
50 | #define DISABLED_MASK2 0 | 52 | #define DISABLED_MASK2 0 |
51 | #define DISABLED_MASK3 (DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR) | 53 | #define DISABLED_MASK3 (DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR) |
52 | #define DISABLED_MASK4 0 | 54 | #define DISABLED_MASK4 (DISABLE_PCID) |
53 | #define DISABLED_MASK5 0 | 55 | #define DISABLED_MASK5 0 |
54 | #define DISABLED_MASK6 0 | 56 | #define DISABLED_MASK6 0 |
55 | #define DISABLED_MASK7 0 | 57 | #define DISABLED_MASK7 0 |
diff --git a/tools/hv/bondvf.sh b/tools/hv/bondvf.sh deleted file mode 100755 index 89b25068cd98..000000000000 --- a/tools/hv/bondvf.sh +++ /dev/null | |||
@@ -1,232 +0,0 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # This example script creates bonding network devices based on synthetic NIC | ||
4 | # (the virtual network adapter usually provided by Hyper-V) and the matching | ||
5 | # VF NIC (SRIOV virtual function). So the synthetic NIC and VF NIC can | ||
6 | # function as one network device, and fail over to the synthetic NIC if VF is | ||
7 | # down. | ||
8 | # | ||
9 | # Usage: | ||
10 | # - After configured vSwitch and vNIC with SRIOV, start Linux virtual | ||
11 | # machine (VM) | ||
12 | # - Run this scripts on the VM. It will create configuration files in | ||
13 | # distro specific directory. | ||
14 | # - Reboot the VM, so that the bonding config are enabled. | ||
15 | # | ||
16 | # The config files are DHCP by default. You may edit them if you need to change | ||
17 | # to Static IP or change other settings. | ||
18 | # | ||
19 | |||
20 | sysdir=/sys/class/net | ||
21 | netvsc_cls={f8615163-df3e-46c5-913f-f2d2f965ed0e} | ||
22 | bondcnt=0 | ||
23 | |||
24 | # Detect Distro | ||
25 | if [ -f /etc/redhat-release ]; | ||
26 | then | ||
27 | cfgdir=/etc/sysconfig/network-scripts | ||
28 | distro=redhat | ||
29 | elif grep -q 'Ubuntu' /etc/issue | ||
30 | then | ||
31 | cfgdir=/etc/network | ||
32 | distro=ubuntu | ||
33 | elif grep -q 'SUSE' /etc/issue | ||
34 | then | ||
35 | cfgdir=/etc/sysconfig/network | ||
36 | distro=suse | ||
37 | else | ||
38 | echo "Unsupported Distro" | ||
39 | exit 1 | ||
40 | fi | ||
41 | |||
42 | echo Detected Distro: $distro, or compatible | ||
43 | |||
44 | # Get a list of ethernet names | ||
45 | list_eth=(`cd $sysdir && ls -d */ | cut -d/ -f1 | grep -v bond`) | ||
46 | eth_cnt=${#list_eth[@]} | ||
47 | |||
48 | echo List of net devices: | ||
49 | |||
50 | # Get the MAC addresses | ||
51 | for (( i=0; i < $eth_cnt; i++ )) | ||
52 | do | ||
53 | list_mac[$i]=`cat $sysdir/${list_eth[$i]}/address` | ||
54 | echo ${list_eth[$i]}, ${list_mac[$i]} | ||
55 | done | ||
56 | |||
57 | # Find NIC with matching MAC | ||
58 | for (( i=0; i < $eth_cnt-1; i++ )) | ||
59 | do | ||
60 | for (( j=i+1; j < $eth_cnt; j++ )) | ||
61 | do | ||
62 | if [ "${list_mac[$i]}" = "${list_mac[$j]}" ] | ||
63 | then | ||
64 | list_match[$i]=${list_eth[$j]} | ||
65 | break | ||
66 | fi | ||
67 | done | ||
68 | done | ||
69 | |||
70 | function create_eth_cfg_redhat { | ||
71 | local fn=$cfgdir/ifcfg-$1 | ||
72 | |||
73 | rm -f $fn | ||
74 | echo DEVICE=$1 >>$fn | ||
75 | echo TYPE=Ethernet >>$fn | ||
76 | echo BOOTPROTO=none >>$fn | ||
77 | echo UUID=`uuidgen` >>$fn | ||
78 | echo ONBOOT=yes >>$fn | ||
79 | echo PEERDNS=yes >>$fn | ||
80 | echo IPV6INIT=yes >>$fn | ||
81 | echo MASTER=$2 >>$fn | ||
82 | echo SLAVE=yes >>$fn | ||
83 | } | ||
84 | |||
85 | function create_eth_cfg_pri_redhat { | ||
86 | create_eth_cfg_redhat $1 $2 | ||
87 | } | ||
88 | |||
89 | function create_bond_cfg_redhat { | ||
90 | local fn=$cfgdir/ifcfg-$1 | ||
91 | |||
92 | rm -f $fn | ||
93 | echo DEVICE=$1 >>$fn | ||
94 | echo TYPE=Bond >>$fn | ||
95 | echo BOOTPROTO=dhcp >>$fn | ||
96 | echo UUID=`uuidgen` >>$fn | ||
97 | echo ONBOOT=yes >>$fn | ||
98 | echo PEERDNS=yes >>$fn | ||
99 | echo IPV6INIT=yes >>$fn | ||
100 | echo BONDING_MASTER=yes >>$fn | ||
101 | echo BONDING_OPTS=\"mode=active-backup miimon=100 primary=$2\" >>$fn | ||
102 | } | ||
103 | |||
104 | function del_eth_cfg_ubuntu { | ||
105 | local mainfn=$cfgdir/interfaces | ||
106 | local fnlist=( $mainfn ) | ||
107 | |||
108 | local dirlist=(`awk '/^[ \t]*source/{print $2}' $mainfn`) | ||
109 | |||
110 | local i | ||
111 | for i in "${dirlist[@]}" | ||
112 | do | ||
113 | fnlist+=(`ls $i 2>/dev/null`) | ||
114 | done | ||
115 | |||
116 | local tmpfl=$(mktemp) | ||
117 | |||
118 | local nic_start='^[ \t]*(auto|iface|mapping|allow-.*)[ \t]+'$1 | ||
119 | local nic_end='^[ \t]*(auto|iface|mapping|allow-.*|source)' | ||
120 | |||
121 | local fn | ||
122 | for fn in "${fnlist[@]}" | ||
123 | do | ||
124 | awk "/$nic_end/{x=0} x{next} /$nic_start/{x=1;next} 1" \ | ||
125 | $fn >$tmpfl | ||
126 | |||
127 | cp $tmpfl $fn | ||
128 | done | ||
129 | |||
130 | rm $tmpfl | ||
131 | } | ||
132 | |||
133 | function create_eth_cfg_ubuntu { | ||
134 | local fn=$cfgdir/interfaces | ||
135 | |||
136 | del_eth_cfg_ubuntu $1 | ||
137 | echo $'\n'auto $1 >>$fn | ||
138 | echo iface $1 inet manual >>$fn | ||
139 | echo bond-master $2 >>$fn | ||
140 | } | ||
141 | |||
142 | function create_eth_cfg_pri_ubuntu { | ||
143 | local fn=$cfgdir/interfaces | ||
144 | |||
145 | del_eth_cfg_ubuntu $1 | ||
146 | echo $'\n'allow-hotplug $1 >>$fn | ||
147 | echo iface $1 inet manual >>$fn | ||
148 | echo bond-master $2 >>$fn | ||
149 | echo bond-primary $1 >>$fn | ||
150 | } | ||
151 | |||
152 | function create_bond_cfg_ubuntu { | ||
153 | local fn=$cfgdir/interfaces | ||
154 | |||
155 | del_eth_cfg_ubuntu $1 | ||
156 | |||
157 | echo $'\n'auto $1 >>$fn | ||
158 | echo iface $1 inet dhcp >>$fn | ||
159 | echo bond-mode active-backup >>$fn | ||
160 | echo bond-miimon 100 >>$fn | ||
161 | echo bond-slaves none >>$fn | ||
162 | } | ||
163 | |||
164 | function create_eth_cfg_suse { | ||
165 | local fn=$cfgdir/ifcfg-$1 | ||
166 | |||
167 | rm -f $fn | ||
168 | echo BOOTPROTO=none >>$fn | ||
169 | echo STARTMODE=auto >>$fn | ||
170 | } | ||
171 | |||
172 | function create_eth_cfg_pri_suse { | ||
173 | local fn=$cfgdir/ifcfg-$1 | ||
174 | |||
175 | rm -f $fn | ||
176 | echo BOOTPROTO=none >>$fn | ||
177 | echo STARTMODE=hotplug >>$fn | ||
178 | } | ||
179 | |||
180 | function create_bond_cfg_suse { | ||
181 | local fn=$cfgdir/ifcfg-$1 | ||
182 | |||
183 | rm -f $fn | ||
184 | echo BOOTPROTO=dhcp >>$fn | ||
185 | echo STARTMODE=auto >>$fn | ||
186 | echo BONDING_MASTER=yes >>$fn | ||
187 | echo BONDING_SLAVE_0=$2 >>$fn | ||
188 | echo BONDING_SLAVE_1=$3 >>$fn | ||
189 | echo BONDING_MODULE_OPTS=\'mode=active-backup miimon=100 primary=$2\' >>$fn | ||
190 | } | ||
191 | |||
192 | function create_bond { | ||
193 | local bondname=bond$bondcnt | ||
194 | local primary | ||
195 | local secondary | ||
196 | |||
197 | local class_id1=`cat $sysdir/$1/device/class_id 2>/dev/null` | ||
198 | local class_id2=`cat $sysdir/$2/device/class_id 2>/dev/null` | ||
199 | |||
200 | if [ "$class_id1" = "$netvsc_cls" ] | ||
201 | then | ||
202 | primary=$2 | ||
203 | secondary=$1 | ||
204 | elif [ "$class_id2" = "$netvsc_cls" ] | ||
205 | then | ||
206 | primary=$1 | ||
207 | secondary=$2 | ||
208 | else | ||
209 | return 0 | ||
210 | fi | ||
211 | |||
212 | echo $'\nBond name:' $bondname | ||
213 | |||
214 | echo configuring $primary | ||
215 | create_eth_cfg_pri_$distro $primary $bondname | ||
216 | |||
217 | echo configuring $secondary | ||
218 | create_eth_cfg_$distro $secondary $bondname | ||
219 | |||
220 | echo creating: $bondname with primary slave: $primary | ||
221 | create_bond_cfg_$distro $bondname $primary $secondary | ||
222 | |||
223 | let bondcnt=bondcnt+1 | ||
224 | } | ||
225 | |||
226 | for (( i=0; i < $eth_cnt-1; i++ )) | ||
227 | do | ||
228 | if [ -n "${list_match[$i]}" ] | ||
229 | then | ||
230 | create_bond ${list_eth[$i]} ${list_match[$i]} | ||
231 | fi | ||
232 | done | ||
diff --git a/tools/include/asm-generic/hugetlb_encode.h b/tools/include/asm-generic/hugetlb_encode.h new file mode 100644 index 000000000000..e4732d3c2998 --- /dev/null +++ b/tools/include/asm-generic/hugetlb_encode.h | |||
@@ -0,0 +1,34 @@ | |||
1 | #ifndef _ASM_GENERIC_HUGETLB_ENCODE_H_ | ||
2 | #define _ASM_GENERIC_HUGETLB_ENCODE_H_ | ||
3 | |||
4 | /* | ||
5 | * Several system calls take a flag to request "hugetlb" huge pages. | ||
6 | * Without further specification, these system calls will use the | ||
7 | * system's default huge page size. If a system supports multiple | ||
8 | * huge page sizes, the desired huge page size can be specified in | ||
9 | * bits [26:31] of the flag arguments. The value in these 6 bits | ||
10 | * will encode the log2 of the huge page size. | ||
11 | * | ||
12 | * The following definitions are associated with this huge page size | ||
13 | * encoding in flag arguments. System call specific header files | ||
14 | * that use this encoding should include this file. They can then | ||
15 | * provide definitions based on these with their own specific prefix. | ||
16 | * for example: | ||
17 | * #define MAP_HUGE_SHIFT HUGETLB_FLAG_ENCODE_SHIFT | ||
18 | */ | ||
19 | |||
20 | #define HUGETLB_FLAG_ENCODE_SHIFT 26 | ||
21 | #define HUGETLB_FLAG_ENCODE_MASK 0x3f | ||
22 | |||
23 | #define HUGETLB_FLAG_ENCODE_64KB (16 << HUGETLB_FLAG_ENCODE_SHIFT) | ||
24 | #define HUGETLB_FLAG_ENCODE_512KB (19 << HUGETLB_FLAG_ENCODE_SHIFT) | ||
25 | #define HUGETLB_FLAG_ENCODE_1MB (20 << HUGETLB_FLAG_ENCODE_SHIFT) | ||
26 | #define HUGETLB_FLAG_ENCODE_2MB (21 << HUGETLB_FLAG_ENCODE_SHIFT) | ||
27 | #define HUGETLB_FLAG_ENCODE_8MB (23 << HUGETLB_FLAG_ENCODE_SHIFT) | ||
28 | #define HUGETLB_FLAG_ENCODE_16MB (24 << HUGETLB_FLAG_ENCODE_SHIFT) | ||
29 | #define HUGETLB_FLAG_ENCODE_256MB (28 << HUGETLB_FLAG_ENCODE_SHIFT) | ||
30 | #define HUGETLB_FLAG_ENCODE_1GB (30 << HUGETLB_FLAG_ENCODE_SHIFT) | ||
31 | #define HUGETLB_FLAG_ENCODE_2GB (31 << HUGETLB_FLAG_ENCODE_SHIFT) | ||
32 | #define HUGETLB_FLAG_ENCODE_16GB (34 << HUGETLB_FLAG_ENCODE_SHIFT) | ||
33 | |||
34 | #endif /* _ASM_GENERIC_HUGETLB_ENCODE_H_ */ | ||
diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h index bd39b2090ad1..3723b9f8f964 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h | |||
@@ -21,11 +21,14 @@ | |||
21 | #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) | 21 | #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) |
22 | 22 | ||
23 | #define noinline __attribute__((noinline)) | 23 | #define noinline __attribute__((noinline)) |
24 | 24 | #ifndef __packed | |
25 | #define __packed __attribute__((packed)) | 25 | #define __packed __attribute__((packed)) |
26 | 26 | #endif | |
27 | #ifndef __noreturn | ||
27 | #define __noreturn __attribute__((noreturn)) | 28 | #define __noreturn __attribute__((noreturn)) |
28 | 29 | #endif | |
30 | #ifndef __aligned | ||
29 | #define __aligned(x) __attribute__((aligned(x))) | 31 | #define __aligned(x) __attribute__((aligned(x))) |
32 | #endif | ||
30 | #define __printf(a, b) __attribute__((format(printf, a, b))) | 33 | #define __printf(a, b) __attribute__((format(printf, a, b))) |
31 | #define __scanf(a, b) __attribute__((format(scanf, a, b))) | 34 | #define __scanf(a, b) __attribute__((format(scanf, a, b))) |
diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h index 8c27db0c5c08..203268f9231e 100644 --- a/tools/include/uapi/asm-generic/mman-common.h +++ b/tools/include/uapi/asm-generic/mman-common.h | |||
@@ -58,20 +58,12 @@ | |||
58 | overrides the coredump filter bits */ | 58 | overrides the coredump filter bits */ |
59 | #define MADV_DODUMP 17 /* Clear the MADV_DONTDUMP flag */ | 59 | #define MADV_DODUMP 17 /* Clear the MADV_DONTDUMP flag */ |
60 | 60 | ||
61 | #define MADV_WIPEONFORK 18 /* Zero memory on fork, child only */ | ||
62 | #define MADV_KEEPONFORK 19 /* Undo MADV_WIPEONFORK */ | ||
63 | |||
61 | /* compatibility flags */ | 64 | /* compatibility flags */ |
62 | #define MAP_FILE 0 | 65 | #define MAP_FILE 0 |
63 | 66 | ||
64 | /* | ||
65 | * When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. | ||
66 | * This gives us 6 bits, which is enough until someone invents 128 bit address | ||
67 | * spaces. | ||
68 | * | ||
69 | * Assume these are all power of twos. | ||
70 | * When 0 use the default page size. | ||
71 | */ | ||
72 | #define MAP_HUGE_SHIFT 26 | ||
73 | #define MAP_HUGE_MASK 0x3f | ||
74 | |||
75 | #define PKEY_DISABLE_ACCESS 0x1 | 67 | #define PKEY_DISABLE_ACCESS 0x1 |
76 | #define PKEY_DISABLE_WRITE 0x2 | 68 | #define PKEY_DISABLE_WRITE 0x2 |
77 | #define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\ | 69 | #define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\ |
diff --git a/tools/include/uapi/drm/drm.h b/tools/include/uapi/drm/drm.h index 101593ab10ac..97677cd6964d 100644 --- a/tools/include/uapi/drm/drm.h +++ b/tools/include/uapi/drm/drm.h | |||
@@ -700,6 +700,7 @@ struct drm_prime_handle { | |||
700 | 700 | ||
701 | struct drm_syncobj_create { | 701 | struct drm_syncobj_create { |
702 | __u32 handle; | 702 | __u32 handle; |
703 | #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0) | ||
703 | __u32 flags; | 704 | __u32 flags; |
704 | }; | 705 | }; |
705 | 706 | ||
@@ -718,6 +719,24 @@ struct drm_syncobj_handle { | |||
718 | __u32 pad; | 719 | __u32 pad; |
719 | }; | 720 | }; |
720 | 721 | ||
722 | #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0) | ||
723 | #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1) | ||
724 | struct drm_syncobj_wait { | ||
725 | __u64 handles; | ||
726 | /* absolute timeout */ | ||
727 | __s64 timeout_nsec; | ||
728 | __u32 count_handles; | ||
729 | __u32 flags; | ||
730 | __u32 first_signaled; /* only valid when not waiting all */ | ||
731 | __u32 pad; | ||
732 | }; | ||
733 | |||
734 | struct drm_syncobj_array { | ||
735 | __u64 handles; | ||
736 | __u32 count_handles; | ||
737 | __u32 pad; | ||
738 | }; | ||
739 | |||
721 | #if defined(__cplusplus) | 740 | #if defined(__cplusplus) |
722 | } | 741 | } |
723 | #endif | 742 | #endif |
@@ -840,6 +859,9 @@ extern "C" { | |||
840 | #define DRM_IOCTL_SYNCOBJ_DESTROY DRM_IOWR(0xC0, struct drm_syncobj_destroy) | 859 | #define DRM_IOCTL_SYNCOBJ_DESTROY DRM_IOWR(0xC0, struct drm_syncobj_destroy) |
841 | #define DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD DRM_IOWR(0xC1, struct drm_syncobj_handle) | 860 | #define DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD DRM_IOWR(0xC1, struct drm_syncobj_handle) |
842 | #define DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE DRM_IOWR(0xC2, struct drm_syncobj_handle) | 861 | #define DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE DRM_IOWR(0xC2, struct drm_syncobj_handle) |
862 | #define DRM_IOCTL_SYNCOBJ_WAIT DRM_IOWR(0xC3, struct drm_syncobj_wait) | ||
863 | #define DRM_IOCTL_SYNCOBJ_RESET DRM_IOWR(0xC4, struct drm_syncobj_array) | ||
864 | #define DRM_IOCTL_SYNCOBJ_SIGNAL DRM_IOWR(0xC5, struct drm_syncobj_array) | ||
843 | 865 | ||
844 | /** | 866 | /** |
845 | * Device specific ioctls should only be in their respective headers | 867 | * Device specific ioctls should only be in their respective headers |
diff --git a/tools/include/uapi/drm/i915_drm.h b/tools/include/uapi/drm/i915_drm.h index 7ccbd6a2bbe0..6598fb76d2c2 100644 --- a/tools/include/uapi/drm/i915_drm.h +++ b/tools/include/uapi/drm/i915_drm.h | |||
@@ -260,6 +260,8 @@ typedef struct _drm_i915_sarea { | |||
260 | #define DRM_I915_GEM_CONTEXT_GETPARAM 0x34 | 260 | #define DRM_I915_GEM_CONTEXT_GETPARAM 0x34 |
261 | #define DRM_I915_GEM_CONTEXT_SETPARAM 0x35 | 261 | #define DRM_I915_GEM_CONTEXT_SETPARAM 0x35 |
262 | #define DRM_I915_PERF_OPEN 0x36 | 262 | #define DRM_I915_PERF_OPEN 0x36 |
263 | #define DRM_I915_PERF_ADD_CONFIG 0x37 | ||
264 | #define DRM_I915_PERF_REMOVE_CONFIG 0x38 | ||
263 | 265 | ||
264 | #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) | 266 | #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) |
265 | #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) | 267 | #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) |
@@ -315,6 +317,8 @@ typedef struct _drm_i915_sarea { | |||
315 | #define DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_GETPARAM, struct drm_i915_gem_context_param) | 317 | #define DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_GETPARAM, struct drm_i915_gem_context_param) |
316 | #define DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_SETPARAM, struct drm_i915_gem_context_param) | 318 | #define DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_SETPARAM, struct drm_i915_gem_context_param) |
317 | #define DRM_IOCTL_I915_PERF_OPEN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param) | 319 | #define DRM_IOCTL_I915_PERF_OPEN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param) |
320 | #define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config) | ||
321 | #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64) | ||
318 | 322 | ||
319 | /* Allow drivers to submit batchbuffers directly to hardware, relying | 323 | /* Allow drivers to submit batchbuffers directly to hardware, relying |
320 | * on the security mechanisms provided by hardware. | 324 | * on the security mechanisms provided by hardware. |
@@ -431,6 +435,11 @@ typedef struct drm_i915_irq_wait { | |||
431 | */ | 435 | */ |
432 | #define I915_PARAM_HAS_EXEC_BATCH_FIRST 48 | 436 | #define I915_PARAM_HAS_EXEC_BATCH_FIRST 48 |
433 | 437 | ||
438 | /* Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying an array of | ||
439 | * drm_i915_gem_exec_fence structures. See I915_EXEC_FENCE_ARRAY. | ||
440 | */ | ||
441 | #define I915_PARAM_HAS_EXEC_FENCE_ARRAY 49 | ||
442 | |||
434 | typedef struct drm_i915_getparam { | 443 | typedef struct drm_i915_getparam { |
435 | __s32 param; | 444 | __s32 param; |
436 | /* | 445 | /* |
@@ -812,6 +821,17 @@ struct drm_i915_gem_exec_object2 { | |||
812 | __u64 rsvd2; | 821 | __u64 rsvd2; |
813 | }; | 822 | }; |
814 | 823 | ||
824 | struct drm_i915_gem_exec_fence { | ||
825 | /** | ||
826 | * User's handle for a drm_syncobj to wait on or signal. | ||
827 | */ | ||
828 | __u32 handle; | ||
829 | |||
830 | #define I915_EXEC_FENCE_WAIT (1<<0) | ||
831 | #define I915_EXEC_FENCE_SIGNAL (1<<1) | ||
832 | __u32 flags; | ||
833 | }; | ||
834 | |||
815 | struct drm_i915_gem_execbuffer2 { | 835 | struct drm_i915_gem_execbuffer2 { |
816 | /** | 836 | /** |
817 | * List of gem_exec_object2 structs | 837 | * List of gem_exec_object2 structs |
@@ -826,7 +846,11 @@ struct drm_i915_gem_execbuffer2 { | |||
826 | __u32 DR1; | 846 | __u32 DR1; |
827 | __u32 DR4; | 847 | __u32 DR4; |
828 | __u32 num_cliprects; | 848 | __u32 num_cliprects; |
829 | /** This is a struct drm_clip_rect *cliprects */ | 849 | /** |
850 | * This is a struct drm_clip_rect *cliprects if I915_EXEC_FENCE_ARRAY | ||
851 | * is not set. If I915_EXEC_FENCE_ARRAY is set, then this is a | ||
852 | * struct drm_i915_gem_exec_fence *fences. | ||
853 | */ | ||
830 | __u64 cliprects_ptr; | 854 | __u64 cliprects_ptr; |
831 | #define I915_EXEC_RING_MASK (7<<0) | 855 | #define I915_EXEC_RING_MASK (7<<0) |
832 | #define I915_EXEC_DEFAULT (0<<0) | 856 | #define I915_EXEC_DEFAULT (0<<0) |
@@ -927,7 +951,14 @@ struct drm_i915_gem_execbuffer2 { | |||
927 | * element). | 951 | * element). |
928 | */ | 952 | */ |
929 | #define I915_EXEC_BATCH_FIRST (1<<18) | 953 | #define I915_EXEC_BATCH_FIRST (1<<18) |
930 | #define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_BATCH_FIRST<<1)) | 954 | |
955 | /* Setting I915_FENCE_ARRAY implies that num_cliprects and cliprects_ptr | ||
956 | * define an array of i915_gem_exec_fence structures which specify a set of | ||
957 | * dma fences to wait upon or signal. | ||
958 | */ | ||
959 | #define I915_EXEC_FENCE_ARRAY (1<<19) | ||
960 | |||
961 | #define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_ARRAY<<1)) | ||
931 | 962 | ||
932 | #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) | 963 | #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) |
933 | #define i915_execbuffer2_set_context_id(eb2, context) \ | 964 | #define i915_execbuffer2_set_context_id(eb2, context) \ |
@@ -1467,6 +1498,22 @@ enum drm_i915_perf_record_type { | |||
1467 | DRM_I915_PERF_RECORD_MAX /* non-ABI */ | 1498 | DRM_I915_PERF_RECORD_MAX /* non-ABI */ |
1468 | }; | 1499 | }; |
1469 | 1500 | ||
1501 | /** | ||
1502 | * Structure to upload perf dynamic configuration into the kernel. | ||
1503 | */ | ||
1504 | struct drm_i915_perf_oa_config { | ||
1505 | /** String formatted like "%08x-%04x-%04x-%04x-%012x" */ | ||
1506 | char uuid[36]; | ||
1507 | |||
1508 | __u32 n_mux_regs; | ||
1509 | __u32 n_boolean_regs; | ||
1510 | __u32 n_flex_regs; | ||
1511 | |||
1512 | __u64 __user mux_regs_ptr; | ||
1513 | __u64 __user boolean_regs_ptr; | ||
1514 | __u64 __user flex_regs_ptr; | ||
1515 | }; | ||
1516 | |||
1470 | #if defined(__cplusplus) | 1517 | #if defined(__cplusplus) |
1471 | } | 1518 | } |
1472 | #endif | 1519 | #endif |
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e99e3e6f8b37..43ab5c402f98 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h | |||
@@ -30,9 +30,14 @@ | |||
30 | #define BPF_FROM_LE BPF_TO_LE | 30 | #define BPF_FROM_LE BPF_TO_LE |
31 | #define BPF_FROM_BE BPF_TO_BE | 31 | #define BPF_FROM_BE BPF_TO_BE |
32 | 32 | ||
33 | /* jmp encodings */ | ||
33 | #define BPF_JNE 0x50 /* jump != */ | 34 | #define BPF_JNE 0x50 /* jump != */ |
35 | #define BPF_JLT 0xa0 /* LT is unsigned, '<' */ | ||
36 | #define BPF_JLE 0xb0 /* LE is unsigned, '<=' */ | ||
34 | #define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */ | 37 | #define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */ |
35 | #define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */ | 38 | #define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */ |
39 | #define BPF_JSLT 0xc0 /* SLT is signed, '<' */ | ||
40 | #define BPF_JSLE 0xd0 /* SLE is signed, '<=' */ | ||
36 | #define BPF_CALL 0x80 /* function call */ | 41 | #define BPF_CALL 0x80 /* function call */ |
37 | #define BPF_EXIT 0x90 /* function return */ | 42 | #define BPF_EXIT 0x90 /* function return */ |
38 | 43 | ||
@@ -104,6 +109,8 @@ enum bpf_map_type { | |||
104 | BPF_MAP_TYPE_LPM_TRIE, | 109 | BPF_MAP_TYPE_LPM_TRIE, |
105 | BPF_MAP_TYPE_ARRAY_OF_MAPS, | 110 | BPF_MAP_TYPE_ARRAY_OF_MAPS, |
106 | BPF_MAP_TYPE_HASH_OF_MAPS, | 111 | BPF_MAP_TYPE_HASH_OF_MAPS, |
112 | BPF_MAP_TYPE_DEVMAP, | ||
113 | BPF_MAP_TYPE_SOCKMAP, | ||
107 | }; | 114 | }; |
108 | 115 | ||
109 | enum bpf_prog_type { | 116 | enum bpf_prog_type { |
@@ -121,6 +128,7 @@ enum bpf_prog_type { | |||
121 | BPF_PROG_TYPE_LWT_OUT, | 128 | BPF_PROG_TYPE_LWT_OUT, |
122 | BPF_PROG_TYPE_LWT_XMIT, | 129 | BPF_PROG_TYPE_LWT_XMIT, |
123 | BPF_PROG_TYPE_SOCK_OPS, | 130 | BPF_PROG_TYPE_SOCK_OPS, |
131 | BPF_PROG_TYPE_SK_SKB, | ||
124 | }; | 132 | }; |
125 | 133 | ||
126 | enum bpf_attach_type { | 134 | enum bpf_attach_type { |
@@ -128,6 +136,8 @@ enum bpf_attach_type { | |||
128 | BPF_CGROUP_INET_EGRESS, | 136 | BPF_CGROUP_INET_EGRESS, |
129 | BPF_CGROUP_INET_SOCK_CREATE, | 137 | BPF_CGROUP_INET_SOCK_CREATE, |
130 | BPF_CGROUP_SOCK_OPS, | 138 | BPF_CGROUP_SOCK_OPS, |
139 | BPF_SK_SKB_STREAM_PARSER, | ||
140 | BPF_SK_SKB_STREAM_VERDICT, | ||
131 | __MAX_BPF_ATTACH_TYPE | 141 | __MAX_BPF_ATTACH_TYPE |
132 | }; | 142 | }; |
133 | 143 | ||
@@ -153,6 +163,7 @@ enum bpf_attach_type { | |||
153 | #define BPF_NOEXIST 1 /* create new element if it didn't exist */ | 163 | #define BPF_NOEXIST 1 /* create new element if it didn't exist */ |
154 | #define BPF_EXIST 2 /* update existing element */ | 164 | #define BPF_EXIST 2 /* update existing element */ |
155 | 165 | ||
166 | /* flags for BPF_MAP_CREATE command */ | ||
156 | #define BPF_F_NO_PREALLOC (1U << 0) | 167 | #define BPF_F_NO_PREALLOC (1U << 0) |
157 | /* Instead of having one common LRU list in the | 168 | /* Instead of having one common LRU list in the |
158 | * BPF_MAP_TYPE_LRU_[PERCPU_]HASH map, use a percpu LRU list | 169 | * BPF_MAP_TYPE_LRU_[PERCPU_]HASH map, use a percpu LRU list |
@@ -161,6 +172,8 @@ enum bpf_attach_type { | |||
161 | * across different LRU lists. | 172 | * across different LRU lists. |
162 | */ | 173 | */ |
163 | #define BPF_F_NO_COMMON_LRU (1U << 1) | 174 | #define BPF_F_NO_COMMON_LRU (1U << 1) |
175 | /* Specify numa node during map creation */ | ||
176 | #define BPF_F_NUMA_NODE (1U << 2) | ||
164 | 177 | ||
165 | union bpf_attr { | 178 | union bpf_attr { |
166 | struct { /* anonymous struct used by BPF_MAP_CREATE command */ | 179 | struct { /* anonymous struct used by BPF_MAP_CREATE command */ |
@@ -168,8 +181,13 @@ union bpf_attr { | |||
168 | __u32 key_size; /* size of key in bytes */ | 181 | __u32 key_size; /* size of key in bytes */ |
169 | __u32 value_size; /* size of value in bytes */ | 182 | __u32 value_size; /* size of value in bytes */ |
170 | __u32 max_entries; /* max number of entries in a map */ | 183 | __u32 max_entries; /* max number of entries in a map */ |
171 | __u32 map_flags; /* prealloc or not */ | 184 | __u32 map_flags; /* BPF_MAP_CREATE related |
185 | * flags defined above. | ||
186 | */ | ||
172 | __u32 inner_map_fd; /* fd pointing to the inner map */ | 187 | __u32 inner_map_fd; /* fd pointing to the inner map */ |
188 | __u32 numa_node; /* numa node (effective only if | ||
189 | * BPF_F_NUMA_NODE is set). | ||
190 | */ | ||
173 | }; | 191 | }; |
174 | 192 | ||
175 | struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ | 193 | struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ |
@@ -344,9 +362,20 @@ union bpf_attr { | |||
344 | * int bpf_redirect(ifindex, flags) | 362 | * int bpf_redirect(ifindex, flags) |
345 | * redirect to another netdev | 363 | * redirect to another netdev |
346 | * @ifindex: ifindex of the net device | 364 | * @ifindex: ifindex of the net device |
347 | * @flags: bit 0 - if set, redirect to ingress instead of egress | 365 | * @flags: |
348 | * other bits - reserved | 366 | * cls_bpf: |
349 | * Return: TC_ACT_REDIRECT | 367 | * bit 0 - if set, redirect to ingress instead of egress |
368 | * other bits - reserved | ||
369 | * xdp_bpf: | ||
370 | * all bits - reserved | ||
371 | * Return: cls_bpf: TC_ACT_REDIRECT on success or TC_ACT_SHOT on error | ||
372 | * xdp_bfp: XDP_REDIRECT on success or XDP_ABORT on error | ||
373 | * int bpf_redirect_map(map, key, flags) | ||
374 | * redirect to endpoint in map | ||
375 | * @map: pointer to dev map | ||
376 | * @key: index in map to lookup | ||
377 | * @flags: -- | ||
378 | * Return: XDP_REDIRECT on success or XDP_ABORT on error | ||
350 | * | 379 | * |
351 | * u32 bpf_get_route_realm(skb) | 380 | * u32 bpf_get_route_realm(skb) |
352 | * retrieve a dst's tclassid | 381 | * retrieve a dst's tclassid |
@@ -539,6 +568,20 @@ union bpf_attr { | |||
539 | * @mode: operation mode (enum bpf_adj_room_mode) | 568 | * @mode: operation mode (enum bpf_adj_room_mode) |
540 | * @flags: reserved for future use | 569 | * @flags: reserved for future use |
541 | * Return: 0 on success or negative error code | 570 | * Return: 0 on success or negative error code |
571 | * | ||
572 | * int bpf_sk_redirect_map(map, key, flags) | ||
573 | * Redirect skb to a sock in map using key as a lookup key for the | ||
574 | * sock in map. | ||
575 | * @map: pointer to sockmap | ||
576 | * @key: key to lookup sock in map | ||
577 | * @flags: reserved for future use | ||
578 | * Return: SK_REDIRECT | ||
579 | * | ||
580 | * int bpf_sock_map_update(skops, map, key, flags) | ||
581 | * @skops: pointer to bpf_sock_ops | ||
582 | * @map: pointer to sockmap to update | ||
583 | * @key: key to insert/update sock in map | ||
584 | * @flags: same flags as map update elem | ||
542 | */ | 585 | */ |
543 | #define __BPF_FUNC_MAPPER(FN) \ | 586 | #define __BPF_FUNC_MAPPER(FN) \ |
544 | FN(unspec), \ | 587 | FN(unspec), \ |
@@ -591,7 +634,10 @@ union bpf_attr { | |||
591 | FN(get_socket_uid), \ | 634 | FN(get_socket_uid), \ |
592 | FN(set_hash), \ | 635 | FN(set_hash), \ |
593 | FN(setsockopt), \ | 636 | FN(setsockopt), \ |
594 | FN(skb_adjust_room), | 637 | FN(skb_adjust_room), \ |
638 | FN(redirect_map), \ | ||
639 | FN(sk_redirect_map), \ | ||
640 | FN(sock_map_update), \ | ||
595 | 641 | ||
596 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper | 642 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper |
597 | * function eBPF program intends to call | 643 | * function eBPF program intends to call |
@@ -668,6 +714,15 @@ struct __sk_buff { | |||
668 | __u32 data; | 714 | __u32 data; |
669 | __u32 data_end; | 715 | __u32 data_end; |
670 | __u32 napi_id; | 716 | __u32 napi_id; |
717 | |||
718 | /* accessed by BPF_PROG_TYPE_sk_skb types */ | ||
719 | __u32 family; | ||
720 | __u32 remote_ip4; /* Stored in network byte order */ | ||
721 | __u32 local_ip4; /* Stored in network byte order */ | ||
722 | __u32 remote_ip6[4]; /* Stored in network byte order */ | ||
723 | __u32 local_ip6[4]; /* Stored in network byte order */ | ||
724 | __u32 remote_port; /* Stored in network byte order */ | ||
725 | __u32 local_port; /* stored in host byte order */ | ||
671 | }; | 726 | }; |
672 | 727 | ||
673 | struct bpf_tunnel_key { | 728 | struct bpf_tunnel_key { |
@@ -703,20 +758,23 @@ struct bpf_sock { | |||
703 | __u32 family; | 758 | __u32 family; |
704 | __u32 type; | 759 | __u32 type; |
705 | __u32 protocol; | 760 | __u32 protocol; |
761 | __u32 mark; | ||
762 | __u32 priority; | ||
706 | }; | 763 | }; |
707 | 764 | ||
708 | #define XDP_PACKET_HEADROOM 256 | 765 | #define XDP_PACKET_HEADROOM 256 |
709 | 766 | ||
710 | /* User return codes for XDP prog type. | 767 | /* User return codes for XDP prog type. |
711 | * A valid XDP program must return one of these defined values. All other | 768 | * A valid XDP program must return one of these defined values. All other |
712 | * return codes are reserved for future use. Unknown return codes will result | 769 | * return codes are reserved for future use. Unknown return codes will |
713 | * in packet drop. | 770 | * result in packet drops and a warning via bpf_warn_invalid_xdp_action(). |
714 | */ | 771 | */ |
715 | enum xdp_action { | 772 | enum xdp_action { |
716 | XDP_ABORTED = 0, | 773 | XDP_ABORTED = 0, |
717 | XDP_DROP, | 774 | XDP_DROP, |
718 | XDP_PASS, | 775 | XDP_PASS, |
719 | XDP_TX, | 776 | XDP_TX, |
777 | XDP_REDIRECT, | ||
720 | }; | 778 | }; |
721 | 779 | ||
722 | /* user accessible metadata for XDP packet hook | 780 | /* user accessible metadata for XDP packet hook |
@@ -727,6 +785,12 @@ struct xdp_md { | |||
727 | __u32 data_end; | 785 | __u32 data_end; |
728 | }; | 786 | }; |
729 | 787 | ||
788 | enum sk_action { | ||
789 | SK_ABORTED = 0, | ||
790 | SK_DROP, | ||
791 | SK_REDIRECT, | ||
792 | }; | ||
793 | |||
730 | #define BPF_TAG_SIZE 8 | 794 | #define BPF_TAG_SIZE 8 |
731 | 795 | ||
732 | struct bpf_prog_info { | 796 | struct bpf_prog_info { |
diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 6cd63c18708a..838887587411 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h | |||
@@ -711,7 +711,8 @@ struct kvm_ppc_one_seg_page_size { | |||
711 | struct kvm_ppc_smmu_info { | 711 | struct kvm_ppc_smmu_info { |
712 | __u64 flags; | 712 | __u64 flags; |
713 | __u32 slb_size; | 713 | __u32 slb_size; |
714 | __u32 pad; | 714 | __u16 data_keys; /* # storage keys supported for data */ |
715 | __u16 instr_keys; /* # storage keys supported for instructions */ | ||
715 | struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ]; | 716 | struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ]; |
716 | }; | 717 | }; |
717 | 718 | ||
diff --git a/tools/include/uapi/linux/mman.h b/tools/include/uapi/linux/mman.h index 81d8edf11789..a937480d7cd3 100644 --- a/tools/include/uapi/linux/mman.h +++ b/tools/include/uapi/linux/mman.h | |||
@@ -1,7 +1,8 @@ | |||
1 | #ifndef _UAPI_LINUX_MMAN_H | 1 | #ifndef _UAPI_LINUX_MMAN_H |
2 | #define _UAPI_LINUX_MMAN_H | 2 | #define _UAPI_LINUX_MMAN_H |
3 | 3 | ||
4 | #include <uapi/asm/mman.h> | 4 | #include <asm/mman.h> |
5 | #include <asm-generic/hugetlb_encode.h> | ||
5 | 6 | ||
6 | #define MREMAP_MAYMOVE 1 | 7 | #define MREMAP_MAYMOVE 1 |
7 | #define MREMAP_FIXED 2 | 8 | #define MREMAP_FIXED 2 |
@@ -10,4 +11,25 @@ | |||
10 | #define OVERCOMMIT_ALWAYS 1 | 11 | #define OVERCOMMIT_ALWAYS 1 |
11 | #define OVERCOMMIT_NEVER 2 | 12 | #define OVERCOMMIT_NEVER 2 |
12 | 13 | ||
14 | /* | ||
15 | * Huge page size encoding when MAP_HUGETLB is specified, and a huge page | ||
16 | * size other than the default is desired. See hugetlb_encode.h. | ||
17 | * All known huge page size encodings are provided here. It is the | ||
18 | * responsibility of the application to know which sizes are supported on | ||
19 | * the running system. See mmap(2) man page for details. | ||
20 | */ | ||
21 | #define MAP_HUGE_SHIFT HUGETLB_FLAG_ENCODE_SHIFT | ||
22 | #define MAP_HUGE_MASK HUGETLB_FLAG_ENCODE_MASK | ||
23 | |||
24 | #define MAP_HUGE_64KB HUGETLB_FLAG_ENCODE_64KB | ||
25 | #define MAP_HUGE_512KB HUGETLB_FLAG_ENCODE_512KB | ||
26 | #define MAP_HUGE_1MB HUGETLB_FLAG_ENCODE_1MB | ||
27 | #define MAP_HUGE_2MB HUGETLB_FLAG_ENCODE_2MB | ||
28 | #define MAP_HUGE_8MB HUGETLB_FLAG_ENCODE_8MB | ||
29 | #define MAP_HUGE_16MB HUGETLB_FLAG_ENCODE_16MB | ||
30 | #define MAP_HUGE_256MB HUGETLB_FLAG_ENCODE_256MB | ||
31 | #define MAP_HUGE_1GB HUGETLB_FLAG_ENCODE_1GB | ||
32 | #define MAP_HUGE_2GB HUGETLB_FLAG_ENCODE_2GB | ||
33 | #define MAP_HUGE_16GB HUGETLB_FLAG_ENCODE_16GB | ||
34 | |||
13 | #endif /* _UAPI_LINUX_MMAN_H */ | 35 | #endif /* _UAPI_LINUX_MMAN_H */ |
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h index 2a37ae925d85..140ae638cfd6 100644 --- a/tools/include/uapi/linux/perf_event.h +++ b/tools/include/uapi/linux/perf_event.h | |||
@@ -139,8 +139,9 @@ enum perf_event_sample_format { | |||
139 | PERF_SAMPLE_IDENTIFIER = 1U << 16, | 139 | PERF_SAMPLE_IDENTIFIER = 1U << 16, |
140 | PERF_SAMPLE_TRANSACTION = 1U << 17, | 140 | PERF_SAMPLE_TRANSACTION = 1U << 17, |
141 | PERF_SAMPLE_REGS_INTR = 1U << 18, | 141 | PERF_SAMPLE_REGS_INTR = 1U << 18, |
142 | PERF_SAMPLE_PHYS_ADDR = 1U << 19, | ||
142 | 143 | ||
143 | PERF_SAMPLE_MAX = 1U << 19, /* non-ABI */ | 144 | PERF_SAMPLE_MAX = 1U << 20, /* non-ABI */ |
144 | }; | 145 | }; |
145 | 146 | ||
146 | /* | 147 | /* |
@@ -814,6 +815,7 @@ enum perf_event_type { | |||
814 | * { u64 transaction; } && PERF_SAMPLE_TRANSACTION | 815 | * { u64 transaction; } && PERF_SAMPLE_TRANSACTION |
815 | * { u64 abi; # enum perf_sample_regs_abi | 816 | * { u64 abi; # enum perf_sample_regs_abi |
816 | * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR | 817 | * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR |
818 | * { u64 phys_addr;} && PERF_SAMPLE_PHYS_ADDR | ||
817 | * }; | 819 | * }; |
818 | */ | 820 | */ |
819 | PERF_RECORD_SAMPLE = 9, | 821 | PERF_RECORD_SAMPLE = 9, |
diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index 4563ba7ede6f..1e83e3c07448 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile | |||
@@ -17,13 +17,19 @@ MAKEFLAGS += --no-print-directory | |||
17 | LIBFILE = $(OUTPUT)libapi.a | 17 | LIBFILE = $(OUTPUT)libapi.a |
18 | 18 | ||
19 | CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) | 19 | CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) |
20 | CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC | 20 | CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -U_FORTIFY_SOURCE -fPIC |
21 | 21 | ||
22 | ifeq ($(DEBUG),0) | ||
22 | ifeq ($(CC_NO_CLANG), 0) | 23 | ifeq ($(CC_NO_CLANG), 0) |
23 | CFLAGS += -O3 | 24 | CFLAGS += -O3 |
24 | else | 25 | else |
25 | CFLAGS += -O6 | 26 | CFLAGS += -O6 |
26 | endif | 27 | endif |
28 | endif | ||
29 | |||
30 | ifeq ($(DEBUG),0) | ||
31 | CFLAGS += -D_FORTIFY_SOURCE | ||
32 | endif | ||
27 | 33 | ||
28 | # Treat warnings as errors unless directed not to | 34 | # Treat warnings as errors unless directed not to |
29 | ifneq ($(WERROR),0) | 35 | ifneq ($(WERROR),0) |
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 4ed0257dc1f3..d2441db34740 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile | |||
@@ -189,6 +189,10 @@ install_lib: all_cmd | |||
189 | $(call QUIET_INSTALL, $(LIB_FILE)) \ | 189 | $(call QUIET_INSTALL, $(LIB_FILE)) \ |
190 | $(call do_install,$(LIB_FILE),$(libdir_SQ)) | 190 | $(call do_install,$(LIB_FILE),$(libdir_SQ)) |
191 | 191 | ||
192 | install_headers: | ||
193 | $(call QUIET_INSTALL, headers) \ | ||
194 | $(call do_install,bpf.h,$(prefix)/include/bpf,644) | ||
195 | |||
192 | install: install_lib | 196 | install: install_lib |
193 | 197 | ||
194 | ### Cleaning rules | 198 | ### Cleaning rules |
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index e5bbb090bf88..1d6907d379c9 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c | |||
@@ -57,8 +57,9 @@ static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, | |||
57 | return syscall(__NR_bpf, cmd, attr, size); | 57 | return syscall(__NR_bpf, cmd, attr, size); |
58 | } | 58 | } |
59 | 59 | ||
60 | int bpf_create_map(enum bpf_map_type map_type, int key_size, | 60 | int bpf_create_map_node(enum bpf_map_type map_type, int key_size, |
61 | int value_size, int max_entries, __u32 map_flags) | 61 | int value_size, int max_entries, __u32 map_flags, |
62 | int node) | ||
62 | { | 63 | { |
63 | union bpf_attr attr; | 64 | union bpf_attr attr; |
64 | 65 | ||
@@ -69,12 +70,24 @@ int bpf_create_map(enum bpf_map_type map_type, int key_size, | |||
69 | attr.value_size = value_size; | 70 | attr.value_size = value_size; |
70 | attr.max_entries = max_entries; | 71 | attr.max_entries = max_entries; |
71 | attr.map_flags = map_flags; | 72 | attr.map_flags = map_flags; |
73 | if (node >= 0) { | ||
74 | attr.map_flags |= BPF_F_NUMA_NODE; | ||
75 | attr.numa_node = node; | ||
76 | } | ||
72 | 77 | ||
73 | return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); | 78 | return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); |
74 | } | 79 | } |
75 | 80 | ||
76 | int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, | 81 | int bpf_create_map(enum bpf_map_type map_type, int key_size, |
77 | int inner_map_fd, int max_entries, __u32 map_flags) | 82 | int value_size, int max_entries, __u32 map_flags) |
83 | { | ||
84 | return bpf_create_map_node(map_type, key_size, value_size, | ||
85 | max_entries, map_flags, -1); | ||
86 | } | ||
87 | |||
88 | int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, | ||
89 | int inner_map_fd, int max_entries, | ||
90 | __u32 map_flags, int node) | ||
78 | { | 91 | { |
79 | union bpf_attr attr; | 92 | union bpf_attr attr; |
80 | 93 | ||
@@ -86,10 +99,21 @@ int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, | |||
86 | attr.inner_map_fd = inner_map_fd; | 99 | attr.inner_map_fd = inner_map_fd; |
87 | attr.max_entries = max_entries; | 100 | attr.max_entries = max_entries; |
88 | attr.map_flags = map_flags; | 101 | attr.map_flags = map_flags; |
102 | if (node >= 0) { | ||
103 | attr.map_flags |= BPF_F_NUMA_NODE; | ||
104 | attr.numa_node = node; | ||
105 | } | ||
89 | 106 | ||
90 | return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); | 107 | return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); |
91 | } | 108 | } |
92 | 109 | ||
110 | int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, | ||
111 | int inner_map_fd, int max_entries, __u32 map_flags) | ||
112 | { | ||
113 | return bpf_create_map_in_map_node(map_type, key_size, inner_map_fd, | ||
114 | max_entries, map_flags, -1); | ||
115 | } | ||
116 | |||
93 | int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, | 117 | int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, |
94 | size_t insns_cnt, const char *license, | 118 | size_t insns_cnt, const char *license, |
95 | __u32 kern_version, char *log_buf, size_t log_buf_sz) | 119 | __u32 kern_version, char *log_buf, size_t log_buf_sz) |
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 418c86e69bcb..b8ea5843c39e 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h | |||
@@ -24,8 +24,14 @@ | |||
24 | #include <linux/bpf.h> | 24 | #include <linux/bpf.h> |
25 | #include <stddef.h> | 25 | #include <stddef.h> |
26 | 26 | ||
27 | int bpf_create_map_node(enum bpf_map_type map_type, int key_size, | ||
28 | int value_size, int max_entries, __u32 map_flags, | ||
29 | int node); | ||
27 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, | 30 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, |
28 | int max_entries, __u32 map_flags); | 31 | int max_entries, __u32 map_flags); |
32 | int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, | ||
33 | int inner_map_fd, int max_entries, | ||
34 | __u32 map_flags, int node); | ||
29 | int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, | 35 | int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, |
30 | int inner_map_fd, int max_entries, __u32 map_flags); | 36 | int inner_map_fd, int max_entries, __u32 map_flags); |
31 | 37 | ||
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 8c67a90dbd82..35f6dfcdc565 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c | |||
@@ -1745,3 +1745,32 @@ long libbpf_get_error(const void *ptr) | |||
1745 | return PTR_ERR(ptr); | 1745 | return PTR_ERR(ptr); |
1746 | return 0; | 1746 | return 0; |
1747 | } | 1747 | } |
1748 | |||
1749 | int bpf_prog_load(const char *file, enum bpf_prog_type type, | ||
1750 | struct bpf_object **pobj, int *prog_fd) | ||
1751 | { | ||
1752 | struct bpf_program *prog; | ||
1753 | struct bpf_object *obj; | ||
1754 | int err; | ||
1755 | |||
1756 | obj = bpf_object__open(file); | ||
1757 | if (IS_ERR(obj)) | ||
1758 | return -ENOENT; | ||
1759 | |||
1760 | prog = bpf_program__next(NULL, obj); | ||
1761 | if (!prog) { | ||
1762 | bpf_object__close(obj); | ||
1763 | return -ENOENT; | ||
1764 | } | ||
1765 | |||
1766 | bpf_program__set_type(prog, type); | ||
1767 | err = bpf_object__load(obj); | ||
1768 | if (err) { | ||
1769 | bpf_object__close(obj); | ||
1770 | return -EINVAL; | ||
1771 | } | ||
1772 | |||
1773 | *pobj = obj; | ||
1774 | *prog_fd = bpf_program__fd(prog); | ||
1775 | return 0; | ||
1776 | } | ||
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 32c7252f734e..7959086eb9c9 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h | |||
@@ -243,4 +243,6 @@ int bpf_map__pin(struct bpf_map *map, const char *path); | |||
243 | 243 | ||
244 | long libbpf_get_error(const void *ptr); | 244 | long libbpf_get_error(const void *ptr); |
245 | 245 | ||
246 | int bpf_prog_load(const char *file, enum bpf_prog_type type, | ||
247 | struct bpf_object **pobj, int *prog_fd); | ||
246 | #endif | 248 | #endif |
diff --git a/tools/objtool/Documentation/stack-validation.txt b/tools/objtool/Documentation/stack-validation.txt index 6a1af43862df..3995735a878f 100644 --- a/tools/objtool/Documentation/stack-validation.txt +++ b/tools/objtool/Documentation/stack-validation.txt | |||
@@ -194,10 +194,10 @@ they mean, and suggestions for how to fix them. | |||
194 | If it's a GCC-compiled .c file, the error may be because the function | 194 | If it's a GCC-compiled .c file, the error may be because the function |
195 | uses an inline asm() statement which has a "call" instruction. An | 195 | uses an inline asm() statement which has a "call" instruction. An |
196 | asm() statement with a call instruction must declare the use of the | 196 | asm() statement with a call instruction must declare the use of the |
197 | stack pointer in its output operand. For example, on x86_64: | 197 | stack pointer in its output operand. On x86_64, this means adding |
198 | the ASM_CALL_CONSTRAINT as an output constraint: | ||
198 | 199 | ||
199 | register void *__sp asm("rsp"); | 200 | asm volatile("call func" : ASM_CALL_CONSTRAINT); |
200 | asm volatile("call func" : "+r" (__sp)); | ||
201 | 201 | ||
202 | Otherwise the stack frame may not get created before the call. | 202 | Otherwise the stack frame may not get created before the call. |
203 | 203 | ||
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 0e8c8ec4fd4e..34a579f806e3 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c | |||
@@ -208,14 +208,14 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, | |||
208 | break; | 208 | break; |
209 | 209 | ||
210 | case 0x89: | 210 | case 0x89: |
211 | if (rex == 0x48 && modrm == 0xe5) { | 211 | if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) { |
212 | 212 | ||
213 | /* mov %rsp, %rbp */ | 213 | /* mov %rsp, reg */ |
214 | *type = INSN_STACK; | 214 | *type = INSN_STACK; |
215 | op->src.type = OP_SRC_REG; | 215 | op->src.type = OP_SRC_REG; |
216 | op->src.reg = CFI_SP; | 216 | op->src.reg = CFI_SP; |
217 | op->dest.type = OP_DEST_REG; | 217 | op->dest.type = OP_DEST_REG; |
218 | op->dest.reg = CFI_BP; | 218 | op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; |
219 | break; | 219 | break; |
220 | } | 220 | } |
221 | 221 | ||
@@ -284,11 +284,16 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, | |||
284 | case 0x8d: | 284 | case 0x8d: |
285 | if (sib == 0x24 && rex_w && !rex_b && !rex_x) { | 285 | if (sib == 0x24 && rex_w && !rex_b && !rex_x) { |
286 | 286 | ||
287 | /* lea disp(%rsp), reg */ | ||
288 | *type = INSN_STACK; | 287 | *type = INSN_STACK; |
289 | op->src.type = OP_SRC_ADD; | 288 | if (!insn.displacement.value) { |
289 | /* lea (%rsp), reg */ | ||
290 | op->src.type = OP_SRC_REG; | ||
291 | } else { | ||
292 | /* lea disp(%rsp), reg */ | ||
293 | op->src.type = OP_SRC_ADD; | ||
294 | op->src.offset = insn.displacement.value; | ||
295 | } | ||
290 | op->src.reg = CFI_SP; | 296 | op->src.reg = CFI_SP; |
291 | op->src.offset = insn.displacement.value; | ||
292 | op->dest.type = OP_DEST_REG; | 297 | op->dest.type = OP_DEST_REG; |
293 | op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; | 298 | op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; |
294 | 299 | ||
diff --git a/tools/objtool/check.c b/tools/objtool/check.c index f744617c9946..a0c518ecf085 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c | |||
@@ -1203,24 +1203,39 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) | |||
1203 | switch (op->src.type) { | 1203 | switch (op->src.type) { |
1204 | 1204 | ||
1205 | case OP_SRC_REG: | 1205 | case OP_SRC_REG: |
1206 | if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP) { | 1206 | if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP && |
1207 | cfa->base == CFI_SP && | ||
1208 | regs[CFI_BP].base == CFI_CFA && | ||
1209 | regs[CFI_BP].offset == -cfa->offset) { | ||
1210 | |||
1211 | /* mov %rsp, %rbp */ | ||
1212 | cfa->base = op->dest.reg; | ||
1213 | state->bp_scratch = false; | ||
1214 | } | ||
1207 | 1215 | ||
1208 | if (cfa->base == CFI_SP && | 1216 | else if (op->src.reg == CFI_SP && |
1209 | regs[CFI_BP].base == CFI_CFA && | 1217 | op->dest.reg == CFI_BP && state->drap) { |
1210 | regs[CFI_BP].offset == -cfa->offset) { | ||
1211 | 1218 | ||
1212 | /* mov %rsp, %rbp */ | 1219 | /* drap: mov %rsp, %rbp */ |
1213 | cfa->base = op->dest.reg; | 1220 | regs[CFI_BP].base = CFI_BP; |
1214 | state->bp_scratch = false; | 1221 | regs[CFI_BP].offset = -state->stack_size; |
1215 | } | 1222 | state->bp_scratch = false; |
1223 | } | ||
1216 | 1224 | ||
1217 | else if (state->drap) { | 1225 | else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { |
1218 | 1226 | ||
1219 | /* drap: mov %rsp, %rbp */ | 1227 | /* |
1220 | regs[CFI_BP].base = CFI_BP; | 1228 | * mov %rsp, %reg |
1221 | regs[CFI_BP].offset = -state->stack_size; | 1229 | * |
1222 | state->bp_scratch = false; | 1230 | * This is needed for the rare case where GCC |
1223 | } | 1231 | * does: |
1232 | * | ||
1233 | * mov %rsp, %rax | ||
1234 | * ... | ||
1235 | * mov %rax, %rsp | ||
1236 | */ | ||
1237 | state->vals[op->dest.reg].base = CFI_CFA; | ||
1238 | state->vals[op->dest.reg].offset = -state->stack_size; | ||
1224 | } | 1239 | } |
1225 | 1240 | ||
1226 | else if (op->dest.reg == cfa->base) { | 1241 | else if (op->dest.reg == cfa->base) { |
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 6e9f980a7d26..24460155c82c 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c | |||
@@ -175,19 +175,20 @@ static int read_sections(struct elf *elf) | |||
175 | return -1; | 175 | return -1; |
176 | } | 176 | } |
177 | 177 | ||
178 | sec->data = elf_getdata(s, NULL); | 178 | if (sec->sh.sh_size != 0) { |
179 | if (!sec->data) { | 179 | sec->data = elf_getdata(s, NULL); |
180 | WARN_ELF("elf_getdata"); | 180 | if (!sec->data) { |
181 | return -1; | 181 | WARN_ELF("elf_getdata"); |
182 | } | 182 | return -1; |
183 | 183 | } | |
184 | if (sec->data->d_off != 0 || | 184 | if (sec->data->d_off != 0 || |
185 | sec->data->d_size != sec->sh.sh_size) { | 185 | sec->data->d_size != sec->sh.sh_size) { |
186 | WARN("unexpected data attributes for %s", sec->name); | 186 | WARN("unexpected data attributes for %s", |
187 | return -1; | 187 | sec->name); |
188 | return -1; | ||
189 | } | ||
188 | } | 190 | } |
189 | 191 | sec->len = sec->sh.sh_size; | |
190 | sec->len = sec->data->d_size; | ||
191 | } | 192 | } |
192 | 193 | ||
193 | /* sanity check, one more call to elf_nextscn() should return NULL */ | 194 | /* sanity check, one more call to elf_nextscn() should return NULL */ |
@@ -508,6 +509,7 @@ struct section *elf_create_rela_section(struct elf *elf, struct section *base) | |||
508 | strcat(relaname, base->name); | 509 | strcat(relaname, base->name); |
509 | 510 | ||
510 | sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0); | 511 | sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0); |
512 | free(relaname); | ||
511 | if (!sec) | 513 | if (!sec) |
512 | return NULL; | 514 | return NULL; |
513 | 515 | ||
@@ -561,6 +563,7 @@ int elf_write(struct elf *elf) | |||
561 | struct section *sec; | 563 | struct section *sec; |
562 | Elf_Scn *s; | 564 | Elf_Scn *s; |
563 | 565 | ||
566 | /* Update section headers for changed sections: */ | ||
564 | list_for_each_entry(sec, &elf->sections, list) { | 567 | list_for_each_entry(sec, &elf->sections, list) { |
565 | if (sec->changed) { | 568 | if (sec->changed) { |
566 | s = elf_getscn(elf->elf, sec->idx); | 569 | s = elf_getscn(elf->elf, sec->idx); |
@@ -568,13 +571,17 @@ int elf_write(struct elf *elf) | |||
568 | WARN_ELF("elf_getscn"); | 571 | WARN_ELF("elf_getscn"); |
569 | return -1; | 572 | return -1; |
570 | } | 573 | } |
571 | if (!gelf_update_shdr (s, &sec->sh)) { | 574 | if (!gelf_update_shdr(s, &sec->sh)) { |
572 | WARN_ELF("gelf_update_shdr"); | 575 | WARN_ELF("gelf_update_shdr"); |
573 | return -1; | 576 | return -1; |
574 | } | 577 | } |
575 | } | 578 | } |
576 | } | 579 | } |
577 | 580 | ||
581 | /* Make sure the new section header entries get updated properly. */ | ||
582 | elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY); | ||
583 | |||
584 | /* Write all changes to the file. */ | ||
578 | if (elf_update(elf->elf, ELF_C_WRITE) < 0) { | 585 | if (elf_update(elf->elf, ELF_C_WRITE) < 0) { |
579 | WARN_ELF("elf_update"); | 586 | WARN_ELF("elf_update"); |
580 | return -1; | 587 | return -1; |
diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c index ad54a58d7dda..9074b477bff0 100644 --- a/tools/pci/pcitest.c +++ b/tools/pci/pcitest.c | |||
@@ -173,6 +173,7 @@ usage: | |||
173 | "\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n" | 173 | "\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n" |
174 | "\t-b <bar num> BAR test (bar number between 0..5)\n" | 174 | "\t-b <bar num> BAR test (bar number between 0..5)\n" |
175 | "\t-m <msi num> MSI test (msi number between 1..32)\n" | 175 | "\t-m <msi num> MSI test (msi number between 1..32)\n" |
176 | "\t-l Legacy IRQ test\n" | ||
176 | "\t-r Read buffer test\n" | 177 | "\t-r Read buffer test\n" |
177 | "\t-w Write buffer test\n" | 178 | "\t-w Write buffer test\n" |
178 | "\t-c Copy buffer test\n" | 179 | "\t-c Copy buffer test\n" |
diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index ab1b0825130a..76971d2e4164 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt | |||
@@ -873,7 +873,7 @@ amended to take the number of elements as a parameter. | |||
873 | 873 | ||
874 | $ cat ~/.perfconfig | 874 | $ cat ~/.perfconfig |
875 | [intel-pt] | 875 | [intel-pt] |
876 | mispred-all | 876 | mispred-all = on |
877 | 877 | ||
878 | $ perf record -e intel_pt//u ./sort 3000 | 878 | $ perf record -e intel_pt//u ./sort 3000 |
879 | Bubble sorting array of 3000 elements | 879 | Bubble sorting array of 3000 elements |
diff --git a/tools/perf/Documentation/perf-mem.txt b/tools/perf/Documentation/perf-mem.txt index 73496320fca3..4be08a1e3f8d 100644 --- a/tools/perf/Documentation/perf-mem.txt +++ b/tools/perf/Documentation/perf-mem.txt | |||
@@ -59,6 +59,10 @@ OPTIONS | |||
59 | --ldload:: | 59 | --ldload:: |
60 | Specify desired latency for loads event. | 60 | Specify desired latency for loads event. |
61 | 61 | ||
62 | -p:: | ||
63 | --phys-data:: | ||
64 | Record/Report sample physical addresses | ||
65 | |||
62 | SEE ALSO | 66 | SEE ALSO |
63 | -------- | 67 | -------- |
64 | linkperf:perf-record[1], linkperf:perf-report[1] | 68 | linkperf:perf-record[1], linkperf:perf-report[1] |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 9bdea047c5db..e397453e5a46 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -249,7 +249,10 @@ OPTIONS | |||
249 | 249 | ||
250 | -d:: | 250 | -d:: |
251 | --data:: | 251 | --data:: |
252 | Record the sample addresses. | 252 | Record the sample virtual addresses. |
253 | |||
254 | --phys-data:: | ||
255 | Record the sample physical addresses. | ||
253 | 256 | ||
254 | -T:: | 257 | -T:: |
255 | --timestamp:: | 258 | --timestamp:: |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 9fa84617181e..383a98d992ed 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -137,6 +137,7 @@ OPTIONS | |||
137 | - mem: type of memory access for the data at the time of the sample | 137 | - mem: type of memory access for the data at the time of the sample |
138 | - snoop: type of snoop (if any) for the data at the time of the sample | 138 | - snoop: type of snoop (if any) for the data at the time of the sample |
139 | - dcacheline: the cacheline the data address is on at the time of the sample | 139 | - dcacheline: the cacheline the data address is on at the time of the sample |
140 | - phys_daddr: physical address of data being executed on at the time of sample | ||
140 | 141 | ||
141 | And the default sort keys are changed to local_weight, mem, sym, dso, | 142 | And the default sort keys are changed to local_weight, mem, sym, dso, |
142 | symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'. | 143 | symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'. |
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 5ee8796be96e..18dfcfa38454 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -117,7 +117,7 @@ OPTIONS | |||
117 | Comma separated list of fields to print. Options are: | 117 | Comma separated list of fields to print. Options are: |
118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, | 118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, |
119 | srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn, brstackoff, | 119 | srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn, brstackoff, |
120 | callindent, insn, insnlen, synth. | 120 | callindent, insn, insnlen, synth, phys_addr. |
121 | Field list can be prepended with the type, trace, sw or hw, | 121 | Field list can be prepended with the type, trace, sw or hw, |
122 | to indicate to which event type the field list applies. | 122 | to indicate to which event type the field list applies. |
123 | e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace | 123 | e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace |
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index c1e3288a2dfb..d53bea6bd571 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
@@ -37,7 +37,7 @@ OPTIONS | |||
37 | --expr:: | 37 | --expr:: |
38 | --event:: | 38 | --event:: |
39 | List of syscalls and other perf events (tracepoints, HW cache events, | 39 | List of syscalls and other perf events (tracepoints, HW cache events, |
40 | etc) to show. | 40 | etc) to show. Globbing is supported, e.g.: "epoll_*", "*msg*", etc. |
41 | See 'perf list' for a complete list of events. | 41 | See 'perf list' for a complete list of events. |
42 | Prefixing with ! shows all syscalls but the ones specified. You may | 42 | Prefixing with ! shows all syscalls but the ones specified. You may |
43 | need to escape it. | 43 | need to escape it. |
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 62072822dc85..627b7cada144 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -1,34 +1,8 @@ | |||
1 | tools/perf | 1 | tools/perf |
2 | tools/arch/alpha/include/asm/barrier.h | 2 | tools/arch |
3 | tools/arch/arm/include/asm/barrier.h | ||
4 | tools/arch/arm64/include/asm/barrier.h | ||
5 | tools/arch/ia64/include/asm/barrier.h | ||
6 | tools/arch/mips/include/asm/barrier.h | ||
7 | tools/arch/powerpc/include/asm/barrier.h | ||
8 | tools/arch/s390/include/asm/barrier.h | ||
9 | tools/arch/sh/include/asm/barrier.h | ||
10 | tools/arch/sparc/include/asm/barrier.h | ||
11 | tools/arch/sparc/include/asm/barrier_32.h | ||
12 | tools/arch/sparc/include/asm/barrier_64.h | ||
13 | tools/arch/tile/include/asm/barrier.h | ||
14 | tools/arch/x86/include/asm/barrier.h | ||
15 | tools/arch/x86/include/asm/cmpxchg.h | ||
16 | tools/arch/x86/include/asm/cpufeatures.h | ||
17 | tools/arch/x86/include/asm/disabled-features.h | ||
18 | tools/arch/x86/include/asm/required-features.h | ||
19 | tools/arch/x86/include/uapi/asm/svm.h | ||
20 | tools/arch/x86/include/uapi/asm/vmx.h | ||
21 | tools/arch/x86/include/uapi/asm/kvm.h | ||
22 | tools/arch/x86/include/uapi/asm/kvm_perf.h | ||
23 | tools/arch/x86/lib/memcpy_64.S | ||
24 | tools/arch/x86/lib/memset_64.S | ||
25 | tools/arch/s390/include/uapi/asm/kvm_perf.h | ||
26 | tools/arch/s390/include/uapi/asm/sie.h | ||
27 | tools/arch/xtensa/include/asm/barrier.h | ||
28 | tools/scripts | 3 | tools/scripts |
29 | tools/build | 4 | tools/build |
30 | tools/arch/x86/include/asm/atomic.h | 5 | tools/include |
31 | tools/arch/x86/include/asm/rmwcc.h | ||
32 | tools/lib/traceevent | 6 | tools/lib/traceevent |
33 | tools/lib/api | 7 | tools/lib/api |
34 | tools/lib/bpf | 8 | tools/lib/bpf |
@@ -42,60 +16,3 @@ tools/lib/find_bit.c | |||
42 | tools/lib/bitmap.c | 16 | tools/lib/bitmap.c |
43 | tools/lib/str_error_r.c | 17 | tools/lib/str_error_r.c |
44 | tools/lib/vsprintf.c | 18 | tools/lib/vsprintf.c |
45 | tools/include/asm/alternative-asm.h | ||
46 | tools/include/asm/atomic.h | ||
47 | tools/include/asm/barrier.h | ||
48 | tools/include/asm/bug.h | ||
49 | tools/include/asm-generic/atomic-gcc.h | ||
50 | tools/include/asm-generic/barrier.h | ||
51 | tools/include/asm-generic/bitops/arch_hweight.h | ||
52 | tools/include/asm-generic/bitops/atomic.h | ||
53 | tools/include/asm-generic/bitops/const_hweight.h | ||
54 | tools/include/asm-generic/bitops/__ffs.h | ||
55 | tools/include/asm-generic/bitops/__ffz.h | ||
56 | tools/include/asm-generic/bitops/__fls.h | ||
57 | tools/include/asm-generic/bitops/find.h | ||
58 | tools/include/asm-generic/bitops/fls64.h | ||
59 | tools/include/asm-generic/bitops/fls.h | ||
60 | tools/include/asm-generic/bitops/hweight.h | ||
61 | tools/include/asm-generic/bitops.h | ||
62 | tools/include/linux/atomic.h | ||
63 | tools/include/linux/bitops.h | ||
64 | tools/include/linux/compiler.h | ||
65 | tools/include/linux/compiler-gcc.h | ||
66 | tools/include/linux/coresight-pmu.h | ||
67 | tools/include/linux/bug.h | ||
68 | tools/include/linux/filter.h | ||
69 | tools/include/linux/hash.h | ||
70 | tools/include/linux/kernel.h | ||
71 | tools/include/linux/list.h | ||
72 | tools/include/linux/log2.h | ||
73 | tools/include/uapi/asm-generic/fcntl.h | ||
74 | tools/include/uapi/asm-generic/ioctls.h | ||
75 | tools/include/uapi/asm-generic/mman-common.h | ||
76 | tools/include/uapi/asm-generic/mman.h | ||
77 | tools/include/uapi/drm/drm.h | ||
78 | tools/include/uapi/drm/i915_drm.h | ||
79 | tools/include/uapi/linux/bpf.h | ||
80 | tools/include/uapi/linux/bpf_common.h | ||
81 | tools/include/uapi/linux/fcntl.h | ||
82 | tools/include/uapi/linux/hw_breakpoint.h | ||
83 | tools/include/uapi/linux/kvm.h | ||
84 | tools/include/uapi/linux/mman.h | ||
85 | tools/include/uapi/linux/perf_event.h | ||
86 | tools/include/uapi/linux/sched.h | ||
87 | tools/include/uapi/linux/stat.h | ||
88 | tools/include/uapi/linux/vhost.h | ||
89 | tools/include/uapi/sound/asound.h | ||
90 | tools/include/linux/poison.h | ||
91 | tools/include/linux/rbtree.h | ||
92 | tools/include/linux/rbtree_augmented.h | ||
93 | tools/include/linux/refcount.h | ||
94 | tools/include/linux/string.h | ||
95 | tools/include/linux/stringify.h | ||
96 | tools/include/linux/types.h | ||
97 | tools/include/linux/err.h | ||
98 | tools/include/linux/bitmap.h | ||
99 | tools/include/linux/time64.h | ||
100 | tools/arch/*/include/uapi/asm/mman.h | ||
101 | tools/arch/*/include/uapi/asm/perf_regs.h | ||
diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build index bd518b623d7a..5bd7b9260cc0 100644 --- a/tools/perf/arch/s390/util/Build +++ b/tools/perf/arch/s390/util/Build | |||
@@ -1,5 +1,4 @@ | |||
1 | libperf-y += header.o | 1 | libperf-y += header.o |
2 | libperf-y += sym-handling.o | ||
3 | libperf-y += kvm-stat.o | 2 | libperf-y += kvm-stat.o |
4 | 3 | ||
5 | libperf-$(CONFIG_DWARF) += dwarf-regs.o | 4 | libperf-$(CONFIG_DWARF) += dwarf-regs.o |
diff --git a/tools/perf/arch/s390/util/sym-handling.c b/tools/perf/arch/s390/util/sym-handling.c deleted file mode 100644 index e103f6e46afe..000000000000 --- a/tools/perf/arch/s390/util/sym-handling.c +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | /* | ||
2 | * Architecture specific ELF symbol handling and relocation mapping. | ||
3 | * | ||
4 | * Copyright 2017 IBM Corp. | ||
5 | * Author(s): Thomas Richter <tmricht@linux.vnet.ibm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License (version 2 only) | ||
9 | * as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include "symbol.h" | ||
13 | |||
14 | #ifdef HAVE_LIBELF_SUPPORT | ||
15 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) | ||
16 | { | ||
17 | if (ehdr.e_type == ET_EXEC) | ||
18 | return false; | ||
19 | return ehdr.e_type == ET_REL || ehdr.e_type == ET_DYN; | ||
20 | } | ||
21 | |||
22 | void arch__adjust_sym_map_offset(GElf_Sym *sym, | ||
23 | GElf_Shdr *shdr __maybe_unused, | ||
24 | struct map *map) | ||
25 | { | ||
26 | if (map->type == MAP__FUNCTION) | ||
27 | sym->st_value += map->start; | ||
28 | } | ||
29 | #endif | ||
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index 3ddcc6e2abeb..a1d82e33282c 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c | |||
@@ -59,7 +59,7 @@ static int set_config(struct perf_config_set *set, const char *file_name, | |||
59 | fprintf(fp, "[%s]\n", section->name); | 59 | fprintf(fp, "[%s]\n", section->name); |
60 | 60 | ||
61 | perf_config_items__for_each_entry(§ion->items, item) { | 61 | perf_config_items__for_each_entry(§ion->items, item) { |
62 | if (!use_system_config && section->from_system_config) | 62 | if (!use_system_config && item->from_system_config) |
63 | continue; | 63 | continue; |
64 | if (item->value) | 64 | if (item->value) |
65 | fprintf(fp, "\t%s = %s\n", | 65 | fprintf(fp, "\t%s = %s\n", |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index a1497c516d85..24ee68ecdd42 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -627,7 +627,6 @@ static const struct { | |||
627 | { "GFP_HIGHUSER_MOVABLE", "HUM" }, | 627 | { "GFP_HIGHUSER_MOVABLE", "HUM" }, |
628 | { "GFP_HIGHUSER", "HU" }, | 628 | { "GFP_HIGHUSER", "HU" }, |
629 | { "GFP_USER", "U" }, | 629 | { "GFP_USER", "U" }, |
630 | { "GFP_TEMPORARY", "TMP" }, | ||
631 | { "GFP_KERNEL_ACCOUNT", "KAC" }, | 630 | { "GFP_KERNEL_ACCOUNT", "KAC" }, |
632 | { "GFP_KERNEL", "K" }, | 631 | { "GFP_KERNEL", "K" }, |
633 | { "GFP_NOFS", "NF" }, | 632 | { "GFP_NOFS", "NF" }, |
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index e001c0290793..0f15634ef82c 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c | |||
@@ -23,6 +23,7 @@ struct perf_mem { | |||
23 | bool hide_unresolved; | 23 | bool hide_unresolved; |
24 | bool dump_raw; | 24 | bool dump_raw; |
25 | bool force; | 25 | bool force; |
26 | bool phys_addr; | ||
26 | int operation; | 27 | int operation; |
27 | const char *cpu_list; | 28 | const char *cpu_list; |
28 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 29 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
@@ -101,6 +102,9 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) | |||
101 | 102 | ||
102 | rec_argv[i++] = "-d"; | 103 | rec_argv[i++] = "-d"; |
103 | 104 | ||
105 | if (mem->phys_addr) | ||
106 | rec_argv[i++] = "--phys-data"; | ||
107 | |||
104 | for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { | 108 | for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { |
105 | if (!perf_mem_events[j].record) | 109 | if (!perf_mem_events[j].record) |
106 | continue; | 110 | continue; |
@@ -161,30 +165,60 @@ dump_raw_samples(struct perf_tool *tool, | |||
161 | if (al.map != NULL) | 165 | if (al.map != NULL) |
162 | al.map->dso->hit = 1; | 166 | al.map->dso->hit = 1; |
163 | 167 | ||
164 | if (symbol_conf.field_sep) { | 168 | if (mem->phys_addr) { |
165 | fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s%"PRIu64 | 169 | if (symbol_conf.field_sep) { |
166 | "%s0x%"PRIx64"%s%s:%s\n"; | 170 | fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s0x%016"PRIx64 |
171 | "%s%"PRIu64"%s0x%"PRIx64"%s%s:%s\n"; | ||
172 | } else { | ||
173 | fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64 | ||
174 | "%s0x%016"PRIx64"%s%5"PRIu64"%s0x%06"PRIx64 | ||
175 | "%s%s:%s\n"; | ||
176 | symbol_conf.field_sep = " "; | ||
177 | } | ||
178 | |||
179 | printf(fmt, | ||
180 | sample->pid, | ||
181 | symbol_conf.field_sep, | ||
182 | sample->tid, | ||
183 | symbol_conf.field_sep, | ||
184 | sample->ip, | ||
185 | symbol_conf.field_sep, | ||
186 | sample->addr, | ||
187 | symbol_conf.field_sep, | ||
188 | sample->phys_addr, | ||
189 | symbol_conf.field_sep, | ||
190 | sample->weight, | ||
191 | symbol_conf.field_sep, | ||
192 | sample->data_src, | ||
193 | symbol_conf.field_sep, | ||
194 | al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???", | ||
195 | al.sym ? al.sym->name : "???"); | ||
167 | } else { | 196 | } else { |
168 | fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64 | 197 | if (symbol_conf.field_sep) { |
169 | "%s%5"PRIu64"%s0x%06"PRIx64"%s%s:%s\n"; | 198 | fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s%"PRIu64 |
170 | symbol_conf.field_sep = " "; | 199 | "%s0x%"PRIx64"%s%s:%s\n"; |
171 | } | 200 | } else { |
201 | fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64 | ||
202 | "%s%5"PRIu64"%s0x%06"PRIx64"%s%s:%s\n"; | ||
203 | symbol_conf.field_sep = " "; | ||
204 | } | ||
172 | 205 | ||
173 | printf(fmt, | 206 | printf(fmt, |
174 | sample->pid, | 207 | sample->pid, |
175 | symbol_conf.field_sep, | 208 | symbol_conf.field_sep, |
176 | sample->tid, | 209 | sample->tid, |
177 | symbol_conf.field_sep, | 210 | symbol_conf.field_sep, |
178 | sample->ip, | 211 | sample->ip, |
179 | symbol_conf.field_sep, | 212 | symbol_conf.field_sep, |
180 | sample->addr, | 213 | sample->addr, |
181 | symbol_conf.field_sep, | 214 | symbol_conf.field_sep, |
182 | sample->weight, | 215 | sample->weight, |
183 | symbol_conf.field_sep, | 216 | symbol_conf.field_sep, |
184 | sample->data_src, | 217 | sample->data_src, |
185 | symbol_conf.field_sep, | 218 | symbol_conf.field_sep, |
186 | al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???", | 219 | al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???", |
187 | al.sym ? al.sym->name : "???"); | 220 | al.sym ? al.sym->name : "???"); |
221 | } | ||
188 | out_put: | 222 | out_put: |
189 | addr_location__put(&al); | 223 | addr_location__put(&al); |
190 | return 0; | 224 | return 0; |
@@ -224,7 +258,10 @@ static int report_raw_events(struct perf_mem *mem) | |||
224 | if (ret < 0) | 258 | if (ret < 0) |
225 | goto out_delete; | 259 | goto out_delete; |
226 | 260 | ||
227 | printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); | 261 | if (mem->phys_addr) |
262 | printf("# PID, TID, IP, ADDR, PHYS ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); | ||
263 | else | ||
264 | printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); | ||
228 | 265 | ||
229 | ret = perf_session__process_events(session); | 266 | ret = perf_session__process_events(session); |
230 | 267 | ||
@@ -254,9 +291,16 @@ static int report_events(int argc, const char **argv, struct perf_mem *mem) | |||
254 | * there is no weight (cost) associated with stores, so don't print | 291 | * there is no weight (cost) associated with stores, so don't print |
255 | * the column | 292 | * the column |
256 | */ | 293 | */ |
257 | if (!(mem->operation & MEM_OPERATION_LOAD)) | 294 | if (!(mem->operation & MEM_OPERATION_LOAD)) { |
258 | rep_argv[i++] = "--sort=mem,sym,dso,symbol_daddr," | 295 | if (mem->phys_addr) |
259 | "dso_daddr,tlb,locked"; | 296 | rep_argv[i++] = "--sort=mem,sym,dso,symbol_daddr," |
297 | "dso_daddr,tlb,locked,phys_daddr"; | ||
298 | else | ||
299 | rep_argv[i++] = "--sort=mem,sym,dso,symbol_daddr," | ||
300 | "dso_daddr,tlb,locked"; | ||
301 | } else if (mem->phys_addr) | ||
302 | rep_argv[i++] = "--sort=local_weight,mem,sym,dso,symbol_daddr," | ||
303 | "dso_daddr,snoop,tlb,locked,phys_daddr"; | ||
260 | 304 | ||
261 | for (j = 1; j < argc; j++, i++) | 305 | for (j = 1; j < argc; j++, i++) |
262 | rep_argv[i] = argv[j]; | 306 | rep_argv[i] = argv[j]; |
@@ -373,6 +417,7 @@ int cmd_mem(int argc, const char **argv) | |||
373 | "separator for columns, no spaces will be added" | 417 | "separator for columns, no spaces will be added" |
374 | " between columns '.' is reserved."), | 418 | " between columns '.' is reserved."), |
375 | OPT_BOOLEAN('f', "force", &mem.force, "don't complain, do it"), | 419 | OPT_BOOLEAN('f', "force", &mem.force, "don't complain, do it"), |
420 | OPT_BOOLEAN('p', "phys-data", &mem.phys_addr, "Record/Report sample physical addresses"), | ||
376 | OPT_END() | 421 | OPT_END() |
377 | }; | 422 | }; |
378 | const char *const mem_subcommands[] = { "record", "report", NULL }; | 423 | const char *const mem_subcommands[] = { "record", "report", NULL }; |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 36d7117a7562..56f8142ff97f 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -1604,6 +1604,8 @@ static struct option __record_options[] = { | |||
1604 | OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat, | 1604 | OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat, |
1605 | "per thread counts"), | 1605 | "per thread counts"), |
1606 | OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Record the sample addresses"), | 1606 | OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Record the sample addresses"), |
1607 | OPT_BOOLEAN(0, "phys-data", &record.opts.sample_phys_addr, | ||
1608 | "Record the sample physical addresses"), | ||
1607 | OPT_BOOLEAN(0, "sample-cpu", &record.opts.sample_cpu, "Record the sample cpu"), | 1609 | OPT_BOOLEAN(0, "sample-cpu", &record.opts.sample_cpu, "Record the sample cpu"), |
1608 | OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time, | 1610 | OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time, |
1609 | &record.opts.sample_time_set, | 1611 | &record.opts.sample_time_set, |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 378f76cdf923..3d4c3b5e1868 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -87,6 +87,7 @@ enum perf_output_field { | |||
87 | PERF_OUTPUT_BRSTACKINSN = 1U << 23, | 87 | PERF_OUTPUT_BRSTACKINSN = 1U << 23, |
88 | PERF_OUTPUT_BRSTACKOFF = 1U << 24, | 88 | PERF_OUTPUT_BRSTACKOFF = 1U << 24, |
89 | PERF_OUTPUT_SYNTH = 1U << 25, | 89 | PERF_OUTPUT_SYNTH = 1U << 25, |
90 | PERF_OUTPUT_PHYS_ADDR = 1U << 26, | ||
90 | }; | 91 | }; |
91 | 92 | ||
92 | struct output_option { | 93 | struct output_option { |
@@ -119,6 +120,7 @@ struct output_option { | |||
119 | {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN}, | 120 | {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN}, |
120 | {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, | 121 | {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, |
121 | {.str = "synth", .field = PERF_OUTPUT_SYNTH}, | 122 | {.str = "synth", .field = PERF_OUTPUT_SYNTH}, |
123 | {.str = "phys_addr", .field = PERF_OUTPUT_PHYS_ADDR}, | ||
122 | }; | 124 | }; |
123 | 125 | ||
124 | enum { | 126 | enum { |
@@ -175,7 +177,8 @@ static struct { | |||
175 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | 177 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | |
176 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | | 178 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | |
177 | PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR | | 179 | PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR | |
178 | PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT, | 180 | PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT | |
181 | PERF_OUTPUT_PHYS_ADDR, | ||
179 | 182 | ||
180 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, | 183 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, |
181 | }, | 184 | }, |
@@ -382,6 +385,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
382 | PERF_OUTPUT_IREGS)) | 385 | PERF_OUTPUT_IREGS)) |
383 | return -EINVAL; | 386 | return -EINVAL; |
384 | 387 | ||
388 | if (PRINT_FIELD(PHYS_ADDR) && | ||
389 | perf_evsel__check_stype(evsel, PERF_SAMPLE_PHYS_ADDR, "PHYS_ADDR", | ||
390 | PERF_OUTPUT_PHYS_ADDR)) | ||
391 | return -EINVAL; | ||
392 | |||
385 | return 0; | 393 | return 0; |
386 | } | 394 | } |
387 | 395 | ||
@@ -1446,6 +1454,9 @@ static void process_event(struct perf_script *script, | |||
1446 | if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) | 1454 | if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) |
1447 | print_sample_bpf_output(sample); | 1455 | print_sample_bpf_output(sample); |
1448 | print_insn(sample, attr, thread, machine); | 1456 | print_insn(sample, attr, thread, machine); |
1457 | |||
1458 | if (PRINT_FIELD(PHYS_ADDR)) | ||
1459 | printf("%16" PRIx64, sample->phys_addr); | ||
1449 | printf("\n"); | 1460 | printf("\n"); |
1450 | } | 1461 | } |
1451 | 1462 | ||
@@ -2729,7 +2740,7 @@ int cmd_script(int argc, const char **argv) | |||
2729 | "Valid types: hw,sw,trace,raw,synth. " | 2740 | "Valid types: hw,sw,trace,raw,synth. " |
2730 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," | 2741 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
2731 | "addr,symoff,period,iregs,brstack,brstacksym,flags," | 2742 | "addr,symoff,period,iregs,brstack,brstacksym,flags," |
2732 | "bpf-output,callindent,insn,insnlen,brstackinsn,synth", | 2743 | "bpf-output,callindent,insn,insnlen,brstackinsn,synth,phys_addr", |
2733 | parse_output_fields), | 2744 | parse_output_fields), |
2734 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 2745 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
2735 | "system-wide collection from all CPUs"), | 2746 | "system-wide collection from all CPUs"), |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 866da7aa54bf..69523ed55894 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -707,7 +707,7 @@ try_again: | |||
707 | process_interval(); | 707 | process_interval(); |
708 | } | 708 | } |
709 | } | 709 | } |
710 | wait(&status); | 710 | waitpid(child_pid, &status, 0); |
711 | 711 | ||
712 | if (workload_exec_errno) { | 712 | if (workload_exec_errno) { |
713 | const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); | 713 | const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); |
@@ -1257,7 +1257,7 @@ static bool collect_data(struct perf_evsel *counter, | |||
1257 | if (counter->merged_stat) | 1257 | if (counter->merged_stat) |
1258 | return false; | 1258 | return false; |
1259 | cb(counter, data, true); | 1259 | cb(counter, data, true); |
1260 | if (!no_merge) | 1260 | if (!no_merge && counter->auto_merge_stats) |
1261 | collect_all_aliases(counter, cb, data); | 1261 | collect_all_aliases(counter, cb, data); |
1262 | return true; | 1262 | return true; |
1263 | } | 1263 | } |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d59cdadf3a79..771ddab94bb0 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -1261,6 +1261,7 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
1261 | static int trace__validate_ev_qualifier(struct trace *trace) | 1261 | static int trace__validate_ev_qualifier(struct trace *trace) |
1262 | { | 1262 | { |
1263 | int err = 0, i; | 1263 | int err = 0, i; |
1264 | size_t nr_allocated; | ||
1264 | struct str_node *pos; | 1265 | struct str_node *pos; |
1265 | 1266 | ||
1266 | trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier); | 1267 | trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier); |
@@ -1274,13 +1275,18 @@ static int trace__validate_ev_qualifier(struct trace *trace) | |||
1274 | goto out; | 1275 | goto out; |
1275 | } | 1276 | } |
1276 | 1277 | ||
1278 | nr_allocated = trace->ev_qualifier_ids.nr; | ||
1277 | i = 0; | 1279 | i = 0; |
1278 | 1280 | ||
1279 | strlist__for_each_entry(pos, trace->ev_qualifier) { | 1281 | strlist__for_each_entry(pos, trace->ev_qualifier) { |
1280 | const char *sc = pos->s; | 1282 | const char *sc = pos->s; |
1281 | int id = syscalltbl__id(trace->sctbl, sc); | 1283 | int id = syscalltbl__id(trace->sctbl, sc), match_next = -1; |
1282 | 1284 | ||
1283 | if (id < 0) { | 1285 | if (id < 0) { |
1286 | id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next); | ||
1287 | if (id >= 0) | ||
1288 | goto matches; | ||
1289 | |||
1284 | if (err == 0) { | 1290 | if (err == 0) { |
1285 | fputs("Error:\tInvalid syscall ", trace->output); | 1291 | fputs("Error:\tInvalid syscall ", trace->output); |
1286 | err = -EINVAL; | 1292 | err = -EINVAL; |
@@ -1290,13 +1296,37 @@ static int trace__validate_ev_qualifier(struct trace *trace) | |||
1290 | 1296 | ||
1291 | fputs(sc, trace->output); | 1297 | fputs(sc, trace->output); |
1292 | } | 1298 | } |
1293 | 1299 | matches: | |
1294 | trace->ev_qualifier_ids.entries[i++] = id; | 1300 | trace->ev_qualifier_ids.entries[i++] = id; |
1301 | if (match_next == -1) | ||
1302 | continue; | ||
1303 | |||
1304 | while (1) { | ||
1305 | id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next); | ||
1306 | if (id < 0) | ||
1307 | break; | ||
1308 | if (nr_allocated == trace->ev_qualifier_ids.nr) { | ||
1309 | void *entries; | ||
1310 | |||
1311 | nr_allocated += 8; | ||
1312 | entries = realloc(trace->ev_qualifier_ids.entries, | ||
1313 | nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0])); | ||
1314 | if (entries == NULL) { | ||
1315 | err = -ENOMEM; | ||
1316 | fputs("\nError:\t Not enough memory for parsing\n", trace->output); | ||
1317 | goto out_free; | ||
1318 | } | ||
1319 | trace->ev_qualifier_ids.entries = entries; | ||
1320 | } | ||
1321 | trace->ev_qualifier_ids.nr++; | ||
1322 | trace->ev_qualifier_ids.entries[i++] = id; | ||
1323 | } | ||
1295 | } | 1324 | } |
1296 | 1325 | ||
1297 | if (err < 0) { | 1326 | if (err < 0) { |
1298 | fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'" | 1327 | fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'" |
1299 | "\nHint:\tand: 'man syscalls'\n", trace->output); | 1328 | "\nHint:\tand: 'man syscalls'\n", trace->output); |
1329 | out_free: | ||
1300 | zfree(&trace->ev_qualifier_ids.entries); | 1330 | zfree(&trace->ev_qualifier_ids.entries); |
1301 | trace->ev_qualifier_ids.nr = 0; | 1331 | trace->ev_qualifier_ids.nr = 0; |
1302 | } | 1332 | } |
@@ -2814,7 +2844,7 @@ static int trace__parse_events_option(const struct option *opt, const char *str, | |||
2814 | struct trace *trace = (struct trace *)opt->value; | 2844 | struct trace *trace = (struct trace *)opt->value; |
2815 | const char *s = str; | 2845 | const char *s = str; |
2816 | char *sep = NULL, *lists[2] = { NULL, NULL, }; | 2846 | char *sep = NULL, *lists[2] = { NULL, NULL, }; |
2817 | int len = strlen(str) + 1, err = -1, list; | 2847 | int len = strlen(str) + 1, err = -1, list, idx; |
2818 | char *strace_groups_dir = system_path(STRACE_GROUPS_DIR); | 2848 | char *strace_groups_dir = system_path(STRACE_GROUPS_DIR); |
2819 | char group_name[PATH_MAX]; | 2849 | char group_name[PATH_MAX]; |
2820 | 2850 | ||
@@ -2831,7 +2861,8 @@ static int trace__parse_events_option(const struct option *opt, const char *str, | |||
2831 | *sep = '\0'; | 2861 | *sep = '\0'; |
2832 | 2862 | ||
2833 | list = 0; | 2863 | list = 0; |
2834 | if (syscalltbl__id(trace->sctbl, s) >= 0) { | 2864 | if (syscalltbl__id(trace->sctbl, s) >= 0 || |
2865 | syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) { | ||
2835 | list = 1; | 2866 | list = 1; |
2836 | } else { | 2867 | } else { |
2837 | path__join(group_name, sizeof(group_name), strace_groups_dir, s); | 2868 | path__join(group_name, sizeof(group_name), strace_groups_dir, s); |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index e0279babe0c0..2f19e03c5c40 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -467,15 +467,21 @@ int main(int argc, const char **argv) | |||
467 | * - cannot execute it externally (since it would just do | 467 | * - cannot execute it externally (since it would just do |
468 | * the same thing over again) | 468 | * the same thing over again) |
469 | * | 469 | * |
470 | * So we just directly call the internal command handler, and | 470 | * So we just directly call the internal command handler. If that one |
471 | * die if that one cannot handle it. | 471 | * fails to handle this, then maybe we just run a renamed perf binary |
472 | * that contains a dash in its name. To handle this scenario, we just | ||
473 | * fall through and ignore the "xxxx" part of the command string. | ||
472 | */ | 474 | */ |
473 | if (strstarts(cmd, "perf-")) { | 475 | if (strstarts(cmd, "perf-")) { |
474 | cmd += 5; | 476 | cmd += 5; |
475 | argv[0] = cmd; | 477 | argv[0] = cmd; |
476 | handle_internal_command(argc, argv); | 478 | handle_internal_command(argc, argv); |
477 | fprintf(stderr, "cannot handle %s internally", cmd); | 479 | /* |
478 | goto out; | 480 | * If the command is handled, the above function does not |
481 | * return undo changes and fall through in such a case. | ||
482 | */ | ||
483 | cmd -= 5; | ||
484 | argv[0] = cmd; | ||
479 | } | 485 | } |
480 | if (strstarts(cmd, "trace")) { | 486 | if (strstarts(cmd, "trace")) { |
481 | #ifdef HAVE_LIBAUDIT_SUPPORT | 487 | #ifdef HAVE_LIBAUDIT_SUPPORT |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 2c010dd6a79d..dc442ba21bf6 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -43,6 +43,7 @@ struct record_opts { | |||
43 | bool no_samples; | 43 | bool no_samples; |
44 | bool raw_samples; | 44 | bool raw_samples; |
45 | bool sample_address; | 45 | bool sample_address; |
46 | bool sample_phys_addr; | ||
46 | bool sample_weight; | 47 | bool sample_weight; |
47 | bool sample_time; | 48 | bool sample_time; |
48 | bool sample_time_set; | 49 | bool sample_time_set; |
diff --git a/tools/perf/pmu-events/arch/powerpc/power9/frontend.json b/tools/perf/pmu-events/arch/powerpc/power9/frontend.json index 7e62c46d7a20..c63a919eda98 100644 --- a/tools/perf/pmu-events/arch/powerpc/power9/frontend.json +++ b/tools/perf/pmu-events/arch/powerpc/power9/frontend.json | |||
@@ -80,11 +80,6 @@ | |||
80 | "BriefDescription": "Load Missed L1, counted at execution time (can be greater than loads finished). LMQ merges are not included in this count. i.e. if a load instruction misses on an address that is already allocated on the LMQ, this event will not increment for that load). Note that this count is per slice, so if a load spans multiple slices this event will increment multiple times for a single load." | 80 | "BriefDescription": "Load Missed L1, counted at execution time (can be greater than loads finished). LMQ merges are not included in this count. i.e. if a load instruction misses on an address that is already allocated on the LMQ, this event will not increment for that load). Note that this count is per slice, so if a load spans multiple slices this event will increment multiple times for a single load." |
81 | }, | 81 | }, |
82 | {, | 82 | {, |
83 | "EventCode": "0x400F0", | ||
84 | "EventName": "PM_LD_MISS_L1", | ||
85 | "BriefDescription": "Load Missed L1, counted at execution time (can be greater than loads finished). LMQ merges are not included in this count. i.e. if a load instruction misses on an address that is already allocated on the LMQ, this event will not increment for that load). Note that this count is per slice, so if a load spans multiple slices this event will increment multiple times for a single load." | ||
86 | }, | ||
87 | {, | ||
88 | "EventCode": "0x2E01A", | 83 | "EventCode": "0x2E01A", |
89 | "EventName": "PM_CMPLU_STALL_LSU_FLUSH_NEXT", | 84 | "EventName": "PM_CMPLU_STALL_LSU_FLUSH_NEXT", |
90 | "BriefDescription": "Completion stall of one cycle because the LSU requested to flush the next iop in the sequence. It takes 1 cycle for the ISU to process this request before the LSU instruction is allowed to complete" | 85 | "BriefDescription": "Completion stall of one cycle because the LSU requested to flush the next iop in the sequence. It takes 1 cycle for the ISU to process this request before the LSU instruction is allowed to complete" |
@@ -374,4 +369,4 @@ | |||
374 | "EventName": "PM_IPTEG_FROM_L31_ECO_MOD", | 369 | "EventName": "PM_IPTEG_FROM_L31_ECO_MOD", |
375 | "BriefDescription": "A Page Table Entry was loaded into the TLB with Modified (M) data from another core's ECO L3 on the same chip due to a instruction side request" | 370 | "BriefDescription": "A Page Table Entry was loaded into the TLB with Modified (M) data from another core's ECO L3 on the same chip due to a instruction side request" |
376 | } | 371 | } |
377 | ] \ No newline at end of file | 372 | ] |
diff --git a/tools/perf/pmu-events/arch/powerpc/power9/other.json b/tools/perf/pmu-events/arch/powerpc/power9/other.json index 00f3d2a21f31..54cc3be00fc2 100644 --- a/tools/perf/pmu-events/arch/powerpc/power9/other.json +++ b/tools/perf/pmu-events/arch/powerpc/power9/other.json | |||
@@ -605,11 +605,6 @@ | |||
605 | "BriefDescription": "RC retries on PB for any load from core (excludes DCBFs)" | 605 | "BriefDescription": "RC retries on PB for any load from core (excludes DCBFs)" |
606 | }, | 606 | }, |
607 | {, | 607 | {, |
608 | "EventCode": "0x3689E", | ||
609 | "EventName": "PM_L2_RTY_LD", | ||
610 | "BriefDescription": "RC retries on PB for any load from core (excludes DCBFs)" | ||
611 | }, | ||
612 | {, | ||
613 | "EventCode": "0xE08C", | 608 | "EventCode": "0xE08C", |
614 | "EventName": "PM_LSU0_ERAT_HIT", | 609 | "EventName": "PM_LSU0_ERAT_HIT", |
615 | "BriefDescription": "Primary ERAT hit. There is no secondary ERAT" | 610 | "BriefDescription": "Primary ERAT hit. There is no secondary ERAT" |
@@ -715,11 +710,6 @@ | |||
715 | "BriefDescription": "Lifetime, sample of RD machine 0 valid" | 710 | "BriefDescription": "Lifetime, sample of RD machine 0 valid" |
716 | }, | 711 | }, |
717 | {, | 712 | {, |
718 | "EventCode": "0x468B4", | ||
719 | "EventName": "PM_L3_RD0_BUSY", | ||
720 | "BriefDescription": "Lifetime, sample of RD machine 0 valid" | ||
721 | }, | ||
722 | {, | ||
723 | "EventCode": "0x46080", | 713 | "EventCode": "0x46080", |
724 | "EventName": "PM_L2_DISP_ALL_L2MISS", | 714 | "EventName": "PM_L2_DISP_ALL_L2MISS", |
725 | "BriefDescription": "All successful Ld/St dispatches for this thread that were an L2 miss (excludes i_l2mru_tch_reqs)" | 715 | "BriefDescription": "All successful Ld/St dispatches for this thread that were an L2 miss (excludes i_l2mru_tch_reqs)" |
@@ -850,21 +840,11 @@ | |||
850 | "BriefDescription": "RC mach 0 Busy. Used by PMU to sample ave RC lifetime (mach0 used as sample point)" | 840 | "BriefDescription": "RC mach 0 Busy. Used by PMU to sample ave RC lifetime (mach0 used as sample point)" |
851 | }, | 841 | }, |
852 | {, | 842 | {, |
853 | "EventCode": "0x2608C", | ||
854 | "EventName": "PM_RC0_BUSY", | ||
855 | "BriefDescription": "RC mach 0 Busy. Used by PMU to sample ave RC lifetime (mach0 used as sample point)" | ||
856 | }, | ||
857 | {, | ||
858 | "EventCode": "0x36082", | 843 | "EventCode": "0x36082", |
859 | "EventName": "PM_L2_LD_DISP", | 844 | "EventName": "PM_L2_LD_DISP", |
860 | "BriefDescription": "All successful I-or-D side load dispatches for this thread (excludes i_l2mru_tch_reqs)." | 845 | "BriefDescription": "All successful I-or-D side load dispatches for this thread (excludes i_l2mru_tch_reqs)." |
861 | }, | 846 | }, |
862 | {, | 847 | {, |
863 | "EventCode": "0x1609E", | ||
864 | "EventName": "PM_L2_LD_DISP", | ||
865 | "BriefDescription": "All successful D side load dispatches for this thread (L2 miss + L2 hits)" | ||
866 | }, | ||
867 | {, | ||
868 | "EventCode": "0xF8B0", | 848 | "EventCode": "0xF8B0", |
869 | "EventName": "PM_L3_SW_PREF", | 849 | "EventName": "PM_L3_SW_PREF", |
870 | "BriefDescription": "L3 load prefetch, sourced from a software prefetch stream, was sent to the nest" | 850 | "BriefDescription": "L3 load prefetch, sourced from a software prefetch stream, was sent to the nest" |
@@ -1040,11 +1020,6 @@ | |||
1040 | "BriefDescription": "L3 castouts in Mepf state for this thread" | 1020 | "BriefDescription": "L3 castouts in Mepf state for this thread" |
1041 | }, | 1021 | }, |
1042 | {, | 1022 | {, |
1043 | "EventCode": "0x168A0", | ||
1044 | "EventName": "PM_L3_CO_MEPF", | ||
1045 | "BriefDescription": "L3 CO of line in Mep state (includes casthrough to memory). The Mepf state indicates that a line was brought in to satisfy an L3 prefetch request" | ||
1046 | }, | ||
1047 | {, | ||
1048 | "EventCode": "0x460A2", | 1023 | "EventCode": "0x460A2", |
1049 | "EventName": "PM_L3_LAT_CI_HIT", | 1024 | "EventName": "PM_L3_LAT_CI_HIT", |
1050 | "BriefDescription": "L3 Lateral Castins Hit" | 1025 | "BriefDescription": "L3 Lateral Castins Hit" |
@@ -1150,11 +1125,6 @@ | |||
1150 | "BriefDescription": "RC retries on PB for any store from core (excludes DCBFs)" | 1125 | "BriefDescription": "RC retries on PB for any store from core (excludes DCBFs)" |
1151 | }, | 1126 | }, |
1152 | {, | 1127 | {, |
1153 | "EventCode": "0x4689E", | ||
1154 | "EventName": "PM_L2_RTY_ST", | ||
1155 | "BriefDescription": "RC retries on PB for any store from core (excludes DCBFs)" | ||
1156 | }, | ||
1157 | {, | ||
1158 | "EventCode": "0x24040", | 1128 | "EventCode": "0x24040", |
1159 | "EventName": "PM_INST_FROM_L2_MEPF", | 1129 | "EventName": "PM_INST_FROM_L2_MEPF", |
1160 | "BriefDescription": "The processor's Instruction cache was reloaded from local core's L2 hit without dispatch conflicts on Mepf state. due to an instruction fetch (not prefetch)" | 1130 | "BriefDescription": "The processor's Instruction cache was reloaded from local core's L2 hit without dispatch conflicts on Mepf state. due to an instruction fetch (not prefetch)" |
@@ -1255,11 +1225,6 @@ | |||
1255 | "BriefDescription": "CO mach 0 Busy. Used by PMU to sample ave CO lifetime (mach0 used as sample point)" | 1225 | "BriefDescription": "CO mach 0 Busy. Used by PMU to sample ave CO lifetime (mach0 used as sample point)" |
1256 | }, | 1226 | }, |
1257 | {, | 1227 | {, |
1258 | "EventCode": "0x4608C", | ||
1259 | "EventName": "PM_CO0_BUSY", | ||
1260 | "BriefDescription": "CO mach 0 Busy. Used by PMU to sample ave CO lifetime (mach0 used as sample point)" | ||
1261 | }, | ||
1262 | {, | ||
1263 | "EventCode": "0x2C122", | 1228 | "EventCode": "0x2C122", |
1264 | "EventName": "PM_MRK_DATA_FROM_L3_DISP_CONFLICT_CYC", | 1229 | "EventName": "PM_MRK_DATA_FROM_L3_DISP_CONFLICT_CYC", |
1265 | "BriefDescription": "Duration in cycles to reload from local core's L3 with dispatch conflict due to a marked load" | 1230 | "BriefDescription": "Duration in cycles to reload from local core's L3 with dispatch conflict due to a marked load" |
@@ -1395,11 +1360,6 @@ | |||
1395 | "BriefDescription": "A Page Table Entry was loaded into the TLB from the local chip's Memory due to a instruction side request" | 1360 | "BriefDescription": "A Page Table Entry was loaded into the TLB from the local chip's Memory due to a instruction side request" |
1396 | }, | 1361 | }, |
1397 | {, | 1362 | {, |
1398 | "EventCode": "0x40006", | ||
1399 | "EventName": "PM_ISLB_MISS", | ||
1400 | "BriefDescription": "Number of ISLB misses for this thread" | ||
1401 | }, | ||
1402 | {, | ||
1403 | "EventCode": "0xD8A8", | 1363 | "EventCode": "0xD8A8", |
1404 | "EventName": "PM_ISLB_MISS", | 1364 | "EventName": "PM_ISLB_MISS", |
1405 | "BriefDescription": "Instruction SLB miss - Total of all segment sizes" | 1365 | "BriefDescription": "Instruction SLB miss - Total of all segment sizes" |
@@ -1515,11 +1475,6 @@ | |||
1515 | "BriefDescription": "All successful I-side dispatches for this thread (excludes i_l2mru_tch reqs)." | 1475 | "BriefDescription": "All successful I-side dispatches for this thread (excludes i_l2mru_tch reqs)." |
1516 | }, | 1476 | }, |
1517 | {, | 1477 | {, |
1518 | "EventCode": "0x3609E", | ||
1519 | "EventName": "PM_L2_INST", | ||
1520 | "BriefDescription": "All successful I-side dispatches that were an L2 miss for this thread (excludes i_l2mru_tch reqs)" | ||
1521 | }, | ||
1522 | {, | ||
1523 | "EventCode": "0x3504C", | 1478 | "EventCode": "0x3504C", |
1524 | "EventName": "PM_IPTEG_FROM_DL4", | 1479 | "EventName": "PM_IPTEG_FROM_DL4", |
1525 | "BriefDescription": "A Page Table Entry was loaded into the TLB from another chip's L4 on a different Node or Group (Distant) due to a instruction side request" | 1480 | "BriefDescription": "A Page Table Entry was loaded into the TLB from another chip's L4 on a different Node or Group (Distant) due to a instruction side request" |
@@ -1690,11 +1645,6 @@ | |||
1690 | "BriefDescription": "All successful I-or-D side load dispatches for this thread that were L2 hits (excludes i_l2mru_tch_reqs)" | 1645 | "BriefDescription": "All successful I-or-D side load dispatches for this thread that were L2 hits (excludes i_l2mru_tch_reqs)" |
1691 | }, | 1646 | }, |
1692 | {, | 1647 | {, |
1693 | "EventCode": "0x2609E", | ||
1694 | "EventName": "PM_L2_LD_HIT", | ||
1695 | "BriefDescription": "All successful D side load dispatches for this thread that were L2 hits for this thread" | ||
1696 | }, | ||
1697 | {, | ||
1698 | "EventCode": "0x168AC", | 1648 | "EventCode": "0x168AC", |
1699 | "EventName": "PM_L3_CI_USAGE", | 1649 | "EventName": "PM_L3_CI_USAGE", |
1700 | "BriefDescription": "Rotating sample of 16 CI or CO actives" | 1650 | "BriefDescription": "Rotating sample of 16 CI or CO actives" |
@@ -1795,21 +1745,11 @@ | |||
1795 | "BriefDescription": "Rotating sample of 8 WI valid" | 1745 | "BriefDescription": "Rotating sample of 8 WI valid" |
1796 | }, | 1746 | }, |
1797 | {, | 1747 | {, |
1798 | "EventCode": "0x260B6", | ||
1799 | "EventName": "PM_L3_WI0_BUSY", | ||
1800 | "BriefDescription": "Rotating sample of 8 WI valid (duplicate)" | ||
1801 | }, | ||
1802 | {, | ||
1803 | "EventCode": "0x368AC", | 1748 | "EventCode": "0x368AC", |
1804 | "EventName": "PM_L3_CO0_BUSY", | 1749 | "EventName": "PM_L3_CO0_BUSY", |
1805 | "BriefDescription": "Lifetime, sample of CO machine 0 valid" | 1750 | "BriefDescription": "Lifetime, sample of CO machine 0 valid" |
1806 | }, | 1751 | }, |
1807 | {, | 1752 | {, |
1808 | "EventCode": "0x468AC", | ||
1809 | "EventName": "PM_L3_CO0_BUSY", | ||
1810 | "BriefDescription": "Lifetime, sample of CO machine 0 valid" | ||
1811 | }, | ||
1812 | {, | ||
1813 | "EventCode": "0x2E040", | 1753 | "EventCode": "0x2E040", |
1814 | "EventName": "PM_DPTEG_FROM_L2_MEPF", | 1754 | "EventName": "PM_DPTEG_FROM_L2_MEPF", |
1815 | "BriefDescription": "A Page Table Entry was loaded into the TLB from local core's L2 hit without dispatch conflicts on Mepf state. due to a data side request. When using Radix Page Translation, this count excludes PDE reloads. Only PTE reloads are included" | 1755 | "BriefDescription": "A Page Table Entry was loaded into the TLB from local core's L2 hit without dispatch conflicts on Mepf state. due to a data side request. When using Radix Page Translation, this count excludes PDE reloads. Only PTE reloads are included" |
@@ -1840,11 +1780,6 @@ | |||
1840 | "BriefDescription": "L3 PF received retry port 0, every retry counted" | 1780 | "BriefDescription": "L3 PF received retry port 0, every retry counted" |
1841 | }, | 1781 | }, |
1842 | {, | 1782 | {, |
1843 | "EventCode": "0x260AE", | ||
1844 | "EventName": "PM_L3_P0_PF_RTY", | ||
1845 | "BriefDescription": "L3 PF received retry port 0, every retry counted" | ||
1846 | }, | ||
1847 | {, | ||
1848 | "EventCode": "0x268B2", | 1783 | "EventCode": "0x268B2", |
1849 | "EventName": "PM_L3_LOC_GUESS_WRONG", | 1784 | "EventName": "PM_L3_LOC_GUESS_WRONG", |
1850 | "BriefDescription": "Initial scope=node (LNS) but data from out side local node (near or far or rem). Prediction too Low" | 1785 | "BriefDescription": "Initial scope=node (LNS) but data from out side local node (near or far or rem). Prediction too Low" |
@@ -1895,11 +1830,6 @@ | |||
1895 | "BriefDescription": "Lifetime, sample of snooper machine 0 valid" | 1830 | "BriefDescription": "Lifetime, sample of snooper machine 0 valid" |
1896 | }, | 1831 | }, |
1897 | {, | 1832 | {, |
1898 | "EventCode": "0x460AC", | ||
1899 | "EventName": "PM_L3_SN0_BUSY", | ||
1900 | "BriefDescription": "Lifetime, sample of snooper machine 0 valid" | ||
1901 | }, | ||
1902 | {, | ||
1903 | "EventCode": "0x3005C", | 1833 | "EventCode": "0x3005C", |
1904 | "EventName": "PM_BFU_BUSY", | 1834 | "EventName": "PM_BFU_BUSY", |
1905 | "BriefDescription": "Cycles in which all 4 Binary Floating Point units are busy. The BFU is running at capacity" | 1835 | "BriefDescription": "Cycles in which all 4 Binary Floating Point units are busy. The BFU is running at capacity" |
@@ -1935,11 +1865,6 @@ | |||
1935 | "BriefDescription": "Lifetime, sample of PF machine 0 valid" | 1865 | "BriefDescription": "Lifetime, sample of PF machine 0 valid" |
1936 | }, | 1866 | }, |
1937 | {, | 1867 | {, |
1938 | "EventCode": "0x460B4", | ||
1939 | "EventName": "PM_L3_PF0_BUSY", | ||
1940 | "BriefDescription": "Lifetime, sample of PF machine 0 valid" | ||
1941 | }, | ||
1942 | {, | ||
1943 | "EventCode": "0xC0B0", | 1868 | "EventCode": "0xC0B0", |
1944 | "EventName": "PM_LSU_FLUSH_UE", | 1869 | "EventName": "PM_LSU_FLUSH_UE", |
1945 | "BriefDescription": "Correctable ECC error on reload data, reported at critical data forward time" | 1870 | "BriefDescription": "Correctable ECC error on reload data, reported at critical data forward time" |
@@ -2085,11 +2010,6 @@ | |||
2085 | "BriefDescription": "L3 CO received retry port 1 (memory only), every retry counted" | 2010 | "BriefDescription": "L3 CO received retry port 1 (memory only), every retry counted" |
2086 | }, | 2011 | }, |
2087 | {, | 2012 | {, |
2088 | "EventCode": "0x468AE", | ||
2089 | "EventName": "PM_L3_P1_CO_RTY", | ||
2090 | "BriefDescription": "L3 CO received retry port 3 (memory only), every retry counted" | ||
2091 | }, | ||
2092 | {, | ||
2093 | "EventCode": "0xC0AC", | 2013 | "EventCode": "0xC0AC", |
2094 | "EventName": "PM_LSU_FLUSH_EMSH", | 2014 | "EventName": "PM_LSU_FLUSH_EMSH", |
2095 | "BriefDescription": "An ERAT miss was detected after a set-p hit. Erat tracker indicates fail due to tlbmiss and the instruction gets flushed because the instruction was working on the wrong address" | 2015 | "BriefDescription": "An ERAT miss was detected after a set-p hit. Erat tracker indicates fail due to tlbmiss and the instruction gets flushed because the instruction was working on the wrong address" |
@@ -2195,11 +2115,6 @@ | |||
2195 | "BriefDescription": "SNP dispatched for a write and was M (true M); for DMA cacheinj this will pulse if rty/push is required (won't pulse if cacheinj is accepted)" | 2115 | "BriefDescription": "SNP dispatched for a write and was M (true M); for DMA cacheinj this will pulse if rty/push is required (won't pulse if cacheinj is accepted)" |
2196 | }, | 2116 | }, |
2197 | {, | 2117 | {, |
2198 | "EventCode": "0x46886", | ||
2199 | "EventName": "PM_L2_SN_M_WR_DONE", | ||
2200 | "BriefDescription": "SNP dispatched for a write and was M (true M); for DMA cacheinj this will pulse if rty/push is required (won't pulse if cacheinj is accepted)" | ||
2201 | }, | ||
2202 | {, | ||
2203 | "EventCode": "0x489C", | 2118 | "EventCode": "0x489C", |
2204 | "EventName": "PM_BR_CORECT_PRED_TAKEN_CMPL", | 2119 | "EventName": "PM_BR_CORECT_PRED_TAKEN_CMPL", |
2205 | "BriefDescription": "Conditional Branch Completed in which the HW correctly predicted the direction as taken. Counted at completion time" | 2120 | "BriefDescription": "Conditional Branch Completed in which the HW correctly predicted the direction as taken. Counted at completion time" |
@@ -2290,21 +2205,11 @@ | |||
2290 | "BriefDescription": "SN mach 0 Busy. Used by PMU to sample ave SN lifetime (mach0 used as sample point)" | 2205 | "BriefDescription": "SN mach 0 Busy. Used by PMU to sample ave SN lifetime (mach0 used as sample point)" |
2291 | }, | 2206 | }, |
2292 | {, | 2207 | {, |
2293 | "EventCode": "0x26090", | ||
2294 | "EventName": "PM_SN0_BUSY", | ||
2295 | "BriefDescription": "SN mach 0 Busy. Used by PMU to sample ave SN lifetime (mach0 used as sample point)" | ||
2296 | }, | ||
2297 | {, | ||
2298 | "EventCode": "0x360AE", | 2208 | "EventCode": "0x360AE", |
2299 | "EventName": "PM_L3_P0_CO_RTY", | 2209 | "EventName": "PM_L3_P0_CO_RTY", |
2300 | "BriefDescription": "L3 CO received retry port 0 (memory only), every retry counted" | 2210 | "BriefDescription": "L3 CO received retry port 0 (memory only), every retry counted" |
2301 | }, | 2211 | }, |
2302 | {, | 2212 | {, |
2303 | "EventCode": "0x460AE", | ||
2304 | "EventName": "PM_L3_P0_CO_RTY", | ||
2305 | "BriefDescription": "L3 CO received retry port 0 (memory only), every retry counted" | ||
2306 | }, | ||
2307 | {, | ||
2308 | "EventCode": "0x168A8", | 2213 | "EventCode": "0x168A8", |
2309 | "EventName": "PM_L3_WI_USAGE", | 2214 | "EventName": "PM_L3_WI_USAGE", |
2310 | "BriefDescription": "Lifetime, sample of Write Inject machine 0 valid" | 2215 | "BriefDescription": "Lifetime, sample of Write Inject machine 0 valid" |
@@ -2340,26 +2245,11 @@ | |||
2340 | "BriefDescription": "L3 PF received retry port 1, every retry counted" | 2245 | "BriefDescription": "L3 PF received retry port 1, every retry counted" |
2341 | }, | 2246 | }, |
2342 | {, | 2247 | {, |
2343 | "EventCode": "0x268AE", | ||
2344 | "EventName": "PM_L3_P1_PF_RTY", | ||
2345 | "BriefDescription": "L3 PF received retry port 3, every retry counted" | ||
2346 | }, | ||
2347 | {, | ||
2348 | "EventCode": "0x46082", | 2248 | "EventCode": "0x46082", |
2349 | "EventName": "PM_L2_ST_DISP", | 2249 | "EventName": "PM_L2_ST_DISP", |
2350 | "BriefDescription": "All successful D-side store dispatches for this thread " | 2250 | "BriefDescription": "All successful D-side store dispatches for this thread " |
2351 | }, | 2251 | }, |
2352 | {, | 2252 | {, |
2353 | "EventCode": "0x1689E", | ||
2354 | "EventName": "PM_L2_ST_DISP", | ||
2355 | "BriefDescription": "All successful D-side store dispatches for this thread (L2 miss + L2 hits)" | ||
2356 | }, | ||
2357 | {, | ||
2358 | "EventCode": "0x36880", | ||
2359 | "EventName": "PM_L2_INST_MISS", | ||
2360 | "BriefDescription": "All successful I-side dispatches that were an L2 miss for this thread (excludes i_l2mru_tch reqs)" | ||
2361 | }, | ||
2362 | {, | ||
2363 | "EventCode": "0x4609E", | 2253 | "EventCode": "0x4609E", |
2364 | "EventName": "PM_L2_INST_MISS", | 2254 | "EventName": "PM_L2_INST_MISS", |
2365 | "BriefDescription": "All successful I-side dispatches that were an L2 miss for this thread (excludes i_l2mru_tch reqs)" | 2255 | "BriefDescription": "All successful I-side dispatches that were an L2 miss for this thread (excludes i_l2mru_tch reqs)" |
@@ -2430,11 +2320,6 @@ | |||
2430 | "BriefDescription": "# PPC Dispatched" | 2320 | "BriefDescription": "# PPC Dispatched" |
2431 | }, | 2321 | }, |
2432 | {, | 2322 | {, |
2433 | "EventCode": "0x300F2", | ||
2434 | "EventName": "PM_INST_DISP", | ||
2435 | "BriefDescription": "# PPC Dispatched" | ||
2436 | }, | ||
2437 | {, | ||
2438 | "EventCode": "0x4E05E", | 2323 | "EventCode": "0x4E05E", |
2439 | "EventName": "PM_TM_OUTER_TBEGIN_DISP", | 2324 | "EventName": "PM_TM_OUTER_TBEGIN_DISP", |
2440 | "BriefDescription": "Number of outer tbegin instructions dispatched. The dispatch unit determines whether the tbegin instruction is outer or nested. This is a speculative count, which includes flushed instructions" | 2325 | "BriefDescription": "Number of outer tbegin instructions dispatched. The dispatch unit determines whether the tbegin instruction is outer or nested. This is a speculative count, which includes flushed instructions" |
@@ -2460,11 +2345,6 @@ | |||
2460 | "BriefDescription": "All successful D-side store dispatches for this thread that were L2 hits" | 2345 | "BriefDescription": "All successful D-side store dispatches for this thread that were L2 hits" |
2461 | }, | 2346 | }, |
2462 | {, | 2347 | {, |
2463 | "EventCode": "0x2689E", | ||
2464 | "EventName": "PM_L2_ST_HIT", | ||
2465 | "BriefDescription": "All successful D-side store dispatches that were L2 hits for this thread" | ||
2466 | }, | ||
2467 | {, | ||
2468 | "EventCode": "0x360A8", | 2348 | "EventCode": "0x360A8", |
2469 | "EventName": "PM_L3_CO", | 2349 | "EventName": "PM_L3_CO", |
2470 | "BriefDescription": "L3 castout occurring (does not include casthrough or log writes (cinj/dmaw))" | 2350 | "BriefDescription": "L3 castout occurring (does not include casthrough or log writes (cinj/dmaw))" |
diff --git a/tools/perf/pmu-events/arch/powerpc/power9/pipeline.json b/tools/perf/pmu-events/arch/powerpc/power9/pipeline.json index 47a82568a8df..bc2db636dabf 100644 --- a/tools/perf/pmu-events/arch/powerpc/power9/pipeline.json +++ b/tools/perf/pmu-events/arch/powerpc/power9/pipeline.json | |||
@@ -420,11 +420,6 @@ | |||
420 | "BriefDescription": "Final Pump Scope (Group) ended up larger than Initial Pump Scope (Chip) for an instruction fetch" | 420 | "BriefDescription": "Final Pump Scope (Group) ended up larger than Initial Pump Scope (Chip) for an instruction fetch" |
421 | }, | 421 | }, |
422 | {, | 422 | {, |
423 | "EventCode": "0x10016", | ||
424 | "EventName": "PM_DSLB_MISS", | ||
425 | "BriefDescription": "Data SLB Miss - Total of all segment sizes" | ||
426 | }, | ||
427 | {, | ||
428 | "EventCode": "0xD0A8", | 423 | "EventCode": "0xD0A8", |
429 | "EventName": "PM_DSLB_MISS", | 424 | "EventName": "PM_DSLB_MISS", |
430 | "BriefDescription": "Data SLB Miss - Total of all segment sizes" | 425 | "BriefDescription": "Data SLB Miss - Total of all segment sizes" |
@@ -554,4 +549,4 @@ | |||
554 | "EventName": "PM_MRK_DATA_FROM_L21_SHR_CYC", | 549 | "EventName": "PM_MRK_DATA_FROM_L21_SHR_CYC", |
555 | "BriefDescription": "Duration in cycles to reload with Shared (S) data from another core's L2 on the same chip due to a marked load" | 550 | "BriefDescription": "Duration in cycles to reload with Shared (S) data from another core's L2 on the same chip due to a marked load" |
556 | } | 551 | } |
557 | ] \ No newline at end of file | 552 | ] |
diff --git a/tools/perf/pmu-events/arch/powerpc/power9/pmc.json b/tools/perf/pmu-events/arch/powerpc/power9/pmc.json index a2c95a99e168..3ef8a10aac86 100644 --- a/tools/perf/pmu-events/arch/powerpc/power9/pmc.json +++ b/tools/perf/pmu-events/arch/powerpc/power9/pmc.json | |||
@@ -5,11 +5,6 @@ | |||
5 | "BriefDescription": "Branches that are not strongly biased" | 5 | "BriefDescription": "Branches that are not strongly biased" |
6 | }, | 6 | }, |
7 | {, | 7 | {, |
8 | "EventCode": "0x40036", | ||
9 | "EventName": "PM_BR_2PATH", | ||
10 | "BriefDescription": "Branches that are not strongly biased" | ||
11 | }, | ||
12 | {, | ||
13 | "EventCode": "0x40056", | 8 | "EventCode": "0x40056", |
14 | "EventName": "PM_MEM_LOC_THRESH_LSU_HIGH", | 9 | "EventName": "PM_MEM_LOC_THRESH_LSU_HIGH", |
15 | "BriefDescription": "Local memory above threshold for LSU medium" | 10 | "BriefDescription": "Local memory above threshold for LSU medium" |
@@ -124,4 +119,4 @@ | |||
124 | "EventName": "PM_1FLOP_CMPL", | 119 | "EventName": "PM_1FLOP_CMPL", |
125 | "BriefDescription": "one flop (fadd, fmul, fsub, fcmp, fsel, fabs, fnabs, fres, fsqrte, fneg) operation completed" | 120 | "BriefDescription": "one flop (fadd, fmul, fsub, fcmp, fsel, fabs, fnabs, fres, fsqrte, fneg) operation completed" |
126 | } | 121 | } |
127 | ] \ No newline at end of file | 122 | ] |
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 761c5a448c56..466a462b26d1 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c | |||
@@ -237,6 +237,11 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, | |||
237 | 237 | ||
238 | thread__find_addr_map(thread, cpumode, MAP__FUNCTION, addr, &al); | 238 | thread__find_addr_map(thread, cpumode, MAP__FUNCTION, addr, &al); |
239 | if (!al.map || !al.map->dso) { | 239 | if (!al.map || !al.map->dso) { |
240 | if (cpumode == PERF_RECORD_MISC_HYPERVISOR) { | ||
241 | pr_debug("Hypervisor address can not be resolved - skipping\n"); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
240 | pr_debug("thread__find_addr_map failed\n"); | 245 | pr_debug("thread__find_addr_map failed\n"); |
241 | return -1; | 246 | return -1; |
242 | } | 247 | } |
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index 2a7b9b47bbcb..9ba1d216a89f 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c | |||
@@ -6,7 +6,7 @@ | |||
6 | #include "debug.h" | 6 | #include "debug.h" |
7 | #include "machine.h" | 7 | #include "machine.h" |
8 | #include "event.h" | 8 | #include "event.h" |
9 | #include "unwind.h" | 9 | #include "../util/unwind.h" |
10 | #include "perf_regs.h" | 10 | #include "perf_regs.h" |
11 | #include "map.h" | 11 | #include "map.h" |
12 | #include "thread.h" | 12 | #include "thread.h" |
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c index 6d028f42b3cf..c3858487159d 100644 --- a/tools/perf/tests/sample-parsing.c +++ b/tools/perf/tests/sample-parsing.c | |||
@@ -141,6 +141,9 @@ static bool samples_same(const struct perf_sample *s1, | |||
141 | } | 141 | } |
142 | } | 142 | } |
143 | 143 | ||
144 | if (type & PERF_SAMPLE_PHYS_ADDR) | ||
145 | COMP(phys_addr); | ||
146 | |||
144 | return true; | 147 | return true; |
145 | } | 148 | } |
146 | 149 | ||
@@ -206,6 +209,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) | |||
206 | .mask = sample_regs, | 209 | .mask = sample_regs, |
207 | .regs = regs, | 210 | .regs = regs, |
208 | }, | 211 | }, |
212 | .phys_addr = 113, | ||
209 | }; | 213 | }; |
210 | struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},}; | 214 | struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},}; |
211 | struct perf_sample sample_out; | 215 | struct perf_sample sample_out; |
@@ -305,7 +309,7 @@ int test__sample_parsing(struct test *test __maybe_unused, int subtest __maybe_u | |||
305 | * were added. Please actually update the test rather than just change | 309 | * were added. Please actually update the test rather than just change |
306 | * the condition below. | 310 | * the condition below. |
307 | */ | 311 | */ |
308 | if (PERF_SAMPLE_MAX > PERF_SAMPLE_REGS_INTR << 1) { | 312 | if (PERF_SAMPLE_MAX > PERF_SAMPLE_PHYS_ADDR << 1) { |
309 | pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n"); | 313 | pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n"); |
310 | return -1; | 314 | return -1; |
311 | } | 315 | } |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index ba0aee576a2b..786fecaf578e 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -829,7 +829,8 @@ static int annotate_browser__run(struct annotate_browser *browser, | |||
829 | "q/ESC/CTRL+C Exit\n\n" | 829 | "q/ESC/CTRL+C Exit\n\n" |
830 | "ENTER Go to target\n" | 830 | "ENTER Go to target\n" |
831 | "ESC Exit\n" | 831 | "ESC Exit\n" |
832 | "H Cycle thru hottest instructions\n" | 832 | "H Go to hottest instruction\n" |
833 | "TAB/shift+TAB Cycle thru hottest instructions\n" | ||
833 | "j Toggle showing jump to target arrows\n" | 834 | "j Toggle showing jump to target arrows\n" |
834 | "J Toggle showing number of jump sources on targets\n" | 835 | "J Toggle showing number of jump sources on targets\n" |
835 | "n Search next string\n" | 836 | "n Search next string\n" |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index f4bc2462bc2c..13dfb0a0bdeb 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -931,12 +931,8 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser, | |||
931 | browser->show_dso); | 931 | browser->show_dso); |
932 | 932 | ||
933 | if (symbol_conf.show_branchflag_count) { | 933 | if (symbol_conf.show_branchflag_count) { |
934 | if (need_percent) | 934 | callchain_list_counts__printf_value(chain, NULL, |
935 | callchain_list_counts__printf_value(node, chain, NULL, | 935 | buf, sizeof(buf)); |
936 | buf, sizeof(buf)); | ||
937 | else | ||
938 | callchain_list_counts__printf_value(NULL, chain, NULL, | ||
939 | buf, sizeof(buf)); | ||
940 | 936 | ||
941 | if (asprintf(&alloc_str2, "%s%s", str, buf) < 0) | 937 | if (asprintf(&alloc_str2, "%s%s", str, buf) < 0) |
942 | str = "Not enough memory!"; | 938 | str = "Not enough memory!"; |
diff --git a/tools/perf/ui/progress.c b/tools/perf/ui/progress.c index a0f24c7115c5..ae91c8148edf 100644 --- a/tools/perf/ui/progress.c +++ b/tools/perf/ui/progress.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <linux/kernel.h> | ||
1 | #include "../cache.h" | 2 | #include "../cache.h" |
2 | #include "progress.h" | 3 | #include "progress.h" |
3 | 4 | ||
@@ -14,10 +15,14 @@ struct ui_progress_ops *ui_progress__ops = &null_progress__ops; | |||
14 | 15 | ||
15 | void ui_progress__update(struct ui_progress *p, u64 adv) | 16 | void ui_progress__update(struct ui_progress *p, u64 adv) |
16 | { | 17 | { |
18 | u64 last = p->curr; | ||
19 | |||
17 | p->curr += adv; | 20 | p->curr += adv; |
18 | 21 | ||
19 | if (p->curr >= p->next) { | 22 | if (p->curr >= p->next) { |
20 | p->next += p->step; | 23 | u64 nr = DIV_ROUND_UP(p->curr - last, p->step); |
24 | |||
25 | p->next += nr * p->step; | ||
21 | ui_progress__ops->update(p); | 26 | ui_progress__ops->update(p); |
22 | } | 27 | } |
23 | } | 28 | } |
@@ -25,7 +30,7 @@ void ui_progress__update(struct ui_progress *p, u64 adv) | |||
25 | void ui_progress__init(struct ui_progress *p, u64 total, const char *title) | 30 | void ui_progress__init(struct ui_progress *p, u64 total, const char *title) |
26 | { | 31 | { |
27 | p->curr = 0; | 32 | p->curr = 0; |
28 | p->next = p->step = total / 16; | 33 | p->next = p->step = total / 16 ?: 1; |
29 | p->total = total; | 34 | p->total = total; |
30 | p->title = title; | 35 | p->title = title; |
31 | 36 | ||
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 5c95b8301c67..8bdb7a500181 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -124,12 +124,8 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node, | |||
124 | str = callchain_list__sym_name(chain, bf, sizeof(bf), false); | 124 | str = callchain_list__sym_name(chain, bf, sizeof(bf), false); |
125 | 125 | ||
126 | if (symbol_conf.show_branchflag_count) { | 126 | if (symbol_conf.show_branchflag_count) { |
127 | if (!period) | 127 | callchain_list_counts__printf_value(chain, NULL, |
128 | callchain_list_counts__printf_value(node, chain, NULL, | 128 | buf, sizeof(buf)); |
129 | buf, sizeof(buf)); | ||
130 | else | ||
131 | callchain_list_counts__printf_value(NULL, chain, NULL, | ||
132 | buf, sizeof(buf)); | ||
133 | 129 | ||
134 | if (asprintf(&alloc_str, "%s%s", str, buf) < 0) | 130 | if (asprintf(&alloc_str, "%s%s", str, buf) < 0) |
135 | str = "Not enough memory!"; | 131 | str = "Not enough memory!"; |
@@ -313,7 +309,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, | |||
313 | 309 | ||
314 | if (symbol_conf.show_branchflag_count) | 310 | if (symbol_conf.show_branchflag_count) |
315 | ret += callchain_list_counts__printf_value( | 311 | ret += callchain_list_counts__printf_value( |
316 | NULL, chain, fp, NULL, 0); | 312 | chain, fp, NULL, 0); |
317 | ret += fprintf(fp, "\n"); | 313 | ret += fprintf(fp, "\n"); |
318 | 314 | ||
319 | if (++entries_printed == callchain_param.print_limit) | 315 | if (++entries_printed == callchain_param.print_limit) |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index f320b0777e0d..be09d77cade0 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -65,8 +65,6 @@ static int parse_callchain_mode(const char *value) | |||
65 | callchain_param.mode = CHAIN_FOLDED; | 65 | callchain_param.mode = CHAIN_FOLDED; |
66 | return 0; | 66 | return 0; |
67 | } | 67 | } |
68 | |||
69 | pr_err("Invalid callchain mode: %s\n", value); | ||
70 | return -1; | 68 | return -1; |
71 | } | 69 | } |
72 | 70 | ||
@@ -82,8 +80,6 @@ static int parse_callchain_order(const char *value) | |||
82 | callchain_param.order_set = true; | 80 | callchain_param.order_set = true; |
83 | return 0; | 81 | return 0; |
84 | } | 82 | } |
85 | |||
86 | pr_err("Invalid callchain order: %s\n", value); | ||
87 | return -1; | 83 | return -1; |
88 | } | 84 | } |
89 | 85 | ||
@@ -105,8 +101,6 @@ static int parse_callchain_sort_key(const char *value) | |||
105 | callchain_param.branch_callstack = 1; | 101 | callchain_param.branch_callstack = 1; |
106 | return 0; | 102 | return 0; |
107 | } | 103 | } |
108 | |||
109 | pr_err("Invalid callchain sort key: %s\n", value); | ||
110 | return -1; | 104 | return -1; |
111 | } | 105 | } |
112 | 106 | ||
@@ -124,8 +118,6 @@ static int parse_callchain_value(const char *value) | |||
124 | callchain_param.value = CCVAL_COUNT; | 118 | callchain_param.value = CCVAL_COUNT; |
125 | return 0; | 119 | return 0; |
126 | } | 120 | } |
127 | |||
128 | pr_err("Invalid callchain config key: %s\n", value); | ||
129 | return -1; | 121 | return -1; |
130 | } | 122 | } |
131 | 123 | ||
@@ -319,12 +311,27 @@ int perf_callchain_config(const char *var, const char *value) | |||
319 | 311 | ||
320 | return ret; | 312 | return ret; |
321 | } | 313 | } |
322 | if (!strcmp(var, "print-type")) | 314 | if (!strcmp(var, "print-type")){ |
323 | return parse_callchain_mode(value); | 315 | int ret; |
324 | if (!strcmp(var, "order")) | 316 | ret = parse_callchain_mode(value); |
325 | return parse_callchain_order(value); | 317 | if (ret == -1) |
326 | if (!strcmp(var, "sort-key")) | 318 | pr_err("Invalid callchain mode: %s\n", value); |
327 | return parse_callchain_sort_key(value); | 319 | return ret; |
320 | } | ||
321 | if (!strcmp(var, "order")){ | ||
322 | int ret; | ||
323 | ret = parse_callchain_order(value); | ||
324 | if (ret == -1) | ||
325 | pr_err("Invalid callchain order: %s\n", value); | ||
326 | return ret; | ||
327 | } | ||
328 | if (!strcmp(var, "sort-key")){ | ||
329 | int ret; | ||
330 | ret = parse_callchain_sort_key(value); | ||
331 | if (ret == -1) | ||
332 | pr_err("Invalid callchain sort key: %s\n", value); | ||
333 | return ret; | ||
334 | } | ||
328 | if (!strcmp(var, "threshold")) { | 335 | if (!strcmp(var, "threshold")) { |
329 | callchain_param.min_percent = strtod(value, &endptr); | 336 | callchain_param.min_percent = strtod(value, &endptr); |
330 | if (value == endptr) { | 337 | if (value == endptr) { |
@@ -588,7 +595,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor) | |||
588 | call->cycles_count = | 595 | call->cycles_count = |
589 | cursor_node->branch_flags.cycles; | 596 | cursor_node->branch_flags.cycles; |
590 | call->iter_count = cursor_node->nr_loop_iter; | 597 | call->iter_count = cursor_node->nr_loop_iter; |
591 | call->samples_count = cursor_node->samples; | 598 | call->iter_cycles = cursor_node->iter_cycles; |
592 | } | 599 | } |
593 | } | 600 | } |
594 | 601 | ||
@@ -722,7 +729,7 @@ static enum match_result match_chain(struct callchain_cursor_node *node, | |||
722 | cnode->cycles_count += | 729 | cnode->cycles_count += |
723 | node->branch_flags.cycles; | 730 | node->branch_flags.cycles; |
724 | cnode->iter_count += node->nr_loop_iter; | 731 | cnode->iter_count += node->nr_loop_iter; |
725 | cnode->samples_count += node->samples; | 732 | cnode->iter_cycles += node->iter_cycles; |
726 | } | 733 | } |
727 | } | 734 | } |
728 | 735 | ||
@@ -998,7 +1005,7 @@ int callchain_merge(struct callchain_cursor *cursor, | |||
998 | int callchain_cursor_append(struct callchain_cursor *cursor, | 1005 | int callchain_cursor_append(struct callchain_cursor *cursor, |
999 | u64 ip, struct map *map, struct symbol *sym, | 1006 | u64 ip, struct map *map, struct symbol *sym, |
1000 | bool branch, struct branch_flags *flags, | 1007 | bool branch, struct branch_flags *flags, |
1001 | int nr_loop_iter, int samples, u64 branch_from) | 1008 | int nr_loop_iter, u64 iter_cycles, u64 branch_from) |
1002 | { | 1009 | { |
1003 | struct callchain_cursor_node *node = *cursor->last; | 1010 | struct callchain_cursor_node *node = *cursor->last; |
1004 | 1011 | ||
@@ -1016,7 +1023,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor, | |||
1016 | node->sym = sym; | 1023 | node->sym = sym; |
1017 | node->branch = branch; | 1024 | node->branch = branch; |
1018 | node->nr_loop_iter = nr_loop_iter; | 1025 | node->nr_loop_iter = nr_loop_iter; |
1019 | node->samples = samples; | 1026 | node->iter_cycles = iter_cycles; |
1020 | 1027 | ||
1021 | if (flags) | 1028 | if (flags) |
1022 | memcpy(&node->branch_flags, flags, | 1029 | memcpy(&node->branch_flags, flags, |
@@ -1306,7 +1313,7 @@ static int branch_to_str(char *bf, int bfsize, | |||
1306 | static int branch_from_str(char *bf, int bfsize, | 1313 | static int branch_from_str(char *bf, int bfsize, |
1307 | u64 branch_count, | 1314 | u64 branch_count, |
1308 | u64 cycles_count, u64 iter_count, | 1315 | u64 cycles_count, u64 iter_count, |
1309 | u64 samples_count) | 1316 | u64 iter_cycles) |
1310 | { | 1317 | { |
1311 | int printed = 0, i = 0; | 1318 | int printed = 0, i = 0; |
1312 | u64 cycles; | 1319 | u64 cycles; |
@@ -1318,9 +1325,13 @@ static int branch_from_str(char *bf, int bfsize, | |||
1318 | bf + printed, bfsize - printed); | 1325 | bf + printed, bfsize - printed); |
1319 | } | 1326 | } |
1320 | 1327 | ||
1321 | if (iter_count && samples_count) { | 1328 | if (iter_count) { |
1322 | printed += count_pri64_printf(i++, "iterations", | 1329 | printed += count_pri64_printf(i++, "iter", |
1323 | iter_count / samples_count, | 1330 | iter_count, |
1331 | bf + printed, bfsize - printed); | ||
1332 | |||
1333 | printed += count_pri64_printf(i++, "avg_cycles", | ||
1334 | iter_cycles / iter_count, | ||
1324 | bf + printed, bfsize - printed); | 1335 | bf + printed, bfsize - printed); |
1325 | } | 1336 | } |
1326 | 1337 | ||
@@ -1333,7 +1344,7 @@ static int branch_from_str(char *bf, int bfsize, | |||
1333 | static int counts_str_build(char *bf, int bfsize, | 1344 | static int counts_str_build(char *bf, int bfsize, |
1334 | u64 branch_count, u64 predicted_count, | 1345 | u64 branch_count, u64 predicted_count, |
1335 | u64 abort_count, u64 cycles_count, | 1346 | u64 abort_count, u64 cycles_count, |
1336 | u64 iter_count, u64 samples_count, | 1347 | u64 iter_count, u64 iter_cycles, |
1337 | struct branch_type_stat *brtype_stat) | 1348 | struct branch_type_stat *brtype_stat) |
1338 | { | 1349 | { |
1339 | int printed; | 1350 | int printed; |
@@ -1346,7 +1357,7 @@ static int counts_str_build(char *bf, int bfsize, | |||
1346 | predicted_count, abort_count, brtype_stat); | 1357 | predicted_count, abort_count, brtype_stat); |
1347 | } else { | 1358 | } else { |
1348 | printed = branch_from_str(bf, bfsize, branch_count, | 1359 | printed = branch_from_str(bf, bfsize, branch_count, |
1349 | cycles_count, iter_count, samples_count); | 1360 | cycles_count, iter_count, iter_cycles); |
1350 | } | 1361 | } |
1351 | 1362 | ||
1352 | if (!printed) | 1363 | if (!printed) |
@@ -1358,14 +1369,14 @@ static int counts_str_build(char *bf, int bfsize, | |||
1358 | static int callchain_counts_printf(FILE *fp, char *bf, int bfsize, | 1369 | static int callchain_counts_printf(FILE *fp, char *bf, int bfsize, |
1359 | u64 branch_count, u64 predicted_count, | 1370 | u64 branch_count, u64 predicted_count, |
1360 | u64 abort_count, u64 cycles_count, | 1371 | u64 abort_count, u64 cycles_count, |
1361 | u64 iter_count, u64 samples_count, | 1372 | u64 iter_count, u64 iter_cycles, |
1362 | struct branch_type_stat *brtype_stat) | 1373 | struct branch_type_stat *brtype_stat) |
1363 | { | 1374 | { |
1364 | char str[256]; | 1375 | char str[256]; |
1365 | 1376 | ||
1366 | counts_str_build(str, sizeof(str), branch_count, | 1377 | counts_str_build(str, sizeof(str), branch_count, |
1367 | predicted_count, abort_count, cycles_count, | 1378 | predicted_count, abort_count, cycles_count, |
1368 | iter_count, samples_count, brtype_stat); | 1379 | iter_count, iter_cycles, brtype_stat); |
1369 | 1380 | ||
1370 | if (fp) | 1381 | if (fp) |
1371 | return fprintf(fp, "%s", str); | 1382 | return fprintf(fp, "%s", str); |
@@ -1373,31 +1384,23 @@ static int callchain_counts_printf(FILE *fp, char *bf, int bfsize, | |||
1373 | return scnprintf(bf, bfsize, "%s", str); | 1384 | return scnprintf(bf, bfsize, "%s", str); |
1374 | } | 1385 | } |
1375 | 1386 | ||
1376 | int callchain_list_counts__printf_value(struct callchain_node *node, | 1387 | int callchain_list_counts__printf_value(struct callchain_list *clist, |
1377 | struct callchain_list *clist, | ||
1378 | FILE *fp, char *bf, int bfsize) | 1388 | FILE *fp, char *bf, int bfsize) |
1379 | { | 1389 | { |
1380 | u64 branch_count, predicted_count; | 1390 | u64 branch_count, predicted_count; |
1381 | u64 abort_count, cycles_count; | 1391 | u64 abort_count, cycles_count; |
1382 | u64 iter_count = 0, samples_count = 0; | 1392 | u64 iter_count, iter_cycles; |
1383 | 1393 | ||
1384 | branch_count = clist->branch_count; | 1394 | branch_count = clist->branch_count; |
1385 | predicted_count = clist->predicted_count; | 1395 | predicted_count = clist->predicted_count; |
1386 | abort_count = clist->abort_count; | 1396 | abort_count = clist->abort_count; |
1387 | cycles_count = clist->cycles_count; | 1397 | cycles_count = clist->cycles_count; |
1388 | 1398 | iter_count = clist->iter_count; | |
1389 | if (node) { | 1399 | iter_cycles = clist->iter_cycles; |
1390 | struct callchain_list *call; | ||
1391 | |||
1392 | list_for_each_entry(call, &node->val, list) { | ||
1393 | iter_count += call->iter_count; | ||
1394 | samples_count += call->samples_count; | ||
1395 | } | ||
1396 | } | ||
1397 | 1400 | ||
1398 | return callchain_counts_printf(fp, bf, bfsize, branch_count, | 1401 | return callchain_counts_printf(fp, bf, bfsize, branch_count, |
1399 | predicted_count, abort_count, | 1402 | predicted_count, abort_count, |
1400 | cycles_count, iter_count, samples_count, | 1403 | cycles_count, iter_count, iter_cycles, |
1401 | &clist->brtype_stat); | 1404 | &clist->brtype_stat); |
1402 | } | 1405 | } |
1403 | 1406 | ||
@@ -1523,7 +1526,8 @@ int callchain_cursor__copy(struct callchain_cursor *dst, | |||
1523 | 1526 | ||
1524 | rc = callchain_cursor_append(dst, node->ip, node->map, node->sym, | 1527 | rc = callchain_cursor_append(dst, node->ip, node->map, node->sym, |
1525 | node->branch, &node->branch_flags, | 1528 | node->branch, &node->branch_flags, |
1526 | node->nr_loop_iter, node->samples, | 1529 | node->nr_loop_iter, |
1530 | node->iter_cycles, | ||
1527 | node->branch_from); | 1531 | node->branch_from); |
1528 | if (rc) | 1532 | if (rc) |
1529 | break; | 1533 | break; |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 97738201464a..1ed6fc61d0a5 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -119,7 +119,7 @@ struct callchain_list { | |||
119 | u64 abort_count; | 119 | u64 abort_count; |
120 | u64 cycles_count; | 120 | u64 cycles_count; |
121 | u64 iter_count; | 121 | u64 iter_count; |
122 | u64 samples_count; | 122 | u64 iter_cycles; |
123 | struct branch_type_stat brtype_stat; | 123 | struct branch_type_stat brtype_stat; |
124 | char *srcline; | 124 | char *srcline; |
125 | struct list_head list; | 125 | struct list_head list; |
@@ -139,7 +139,7 @@ struct callchain_cursor_node { | |||
139 | struct branch_flags branch_flags; | 139 | struct branch_flags branch_flags; |
140 | u64 branch_from; | 140 | u64 branch_from; |
141 | int nr_loop_iter; | 141 | int nr_loop_iter; |
142 | int samples; | 142 | u64 iter_cycles; |
143 | struct callchain_cursor_node *next; | 143 | struct callchain_cursor_node *next; |
144 | }; | 144 | }; |
145 | 145 | ||
@@ -201,7 +201,7 @@ static inline void callchain_cursor_reset(struct callchain_cursor *cursor) | |||
201 | int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip, | 201 | int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip, |
202 | struct map *map, struct symbol *sym, | 202 | struct map *map, struct symbol *sym, |
203 | bool branch, struct branch_flags *flags, | 203 | bool branch, struct branch_flags *flags, |
204 | int nr_loop_iter, int samples, u64 branch_from); | 204 | int nr_loop_iter, u64 iter_cycles, u64 branch_from); |
205 | 205 | ||
206 | /* Close a cursor writing session. Initialize for the reader */ | 206 | /* Close a cursor writing session. Initialize for the reader */ |
207 | static inline void callchain_cursor_commit(struct callchain_cursor *cursor) | 207 | static inline void callchain_cursor_commit(struct callchain_cursor *cursor) |
@@ -282,8 +282,7 @@ char *callchain_node__scnprintf_value(struct callchain_node *node, | |||
282 | int callchain_node__fprintf_value(struct callchain_node *node, | 282 | int callchain_node__fprintf_value(struct callchain_node *node, |
283 | FILE *fp, u64 total); | 283 | FILE *fp, u64 total); |
284 | 284 | ||
285 | int callchain_list_counts__printf_value(struct callchain_node *node, | 285 | int callchain_list_counts__printf_value(struct callchain_list *clist, |
286 | struct callchain_list *clist, | ||
287 | FILE *fp, char *bf, int bfsize); | 286 | FILE *fp, char *bf, int bfsize); |
288 | 287 | ||
289 | void free_callchain(struct callchain_root *root); | 288 | void free_callchain(struct callchain_root *root); |
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index e84bbc8ec058..263f5a906ba5 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c | |||
@@ -10,6 +10,16 @@ | |||
10 | #include "util.h" | 10 | #include "util.h" |
11 | #include "debug.h" | 11 | #include "debug.h" |
12 | 12 | ||
13 | #ifndef O_CLOEXEC | ||
14 | #ifdef __sparc__ | ||
15 | #define O_CLOEXEC 0x400000 | ||
16 | #elif defined(__alpha__) || defined(__hppa__) | ||
17 | #define O_CLOEXEC 010000000 | ||
18 | #else | ||
19 | #define O_CLOEXEC 02000000 | ||
20 | #endif | ||
21 | #endif | ||
22 | |||
13 | static bool check_pipe(struct perf_data_file *file) | 23 | static bool check_pipe(struct perf_data_file *file) |
14 | { | 24 | { |
15 | struct stat st; | 25 | struct stat st; |
@@ -96,7 +106,8 @@ static int open_file_write(struct perf_data_file *file) | |||
96 | if (check_backup(file)) | 106 | if (check_backup(file)) |
97 | return -1; | 107 | return -1; |
98 | 108 | ||
99 | fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR); | 109 | fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, |
110 | S_IRUSR|S_IWUSR); | ||
100 | 111 | ||
101 | if (fd < 0) | 112 | if (fd < 0) |
102 | pr_err("failed to open %s : %s\n", file->path, | 113 | pr_err("failed to open %s : %s\n", file->path, |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 423ac82605f3..ee7bcc898d35 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -200,6 +200,7 @@ struct perf_sample { | |||
200 | u32 cpu; | 200 | u32 cpu; |
201 | u32 raw_size; | 201 | u32 raw_size; |
202 | u64 data_src; | 202 | u64 data_src; |
203 | u64 phys_addr; | ||
203 | u32 flags; | 204 | u32 flags; |
204 | u16 insn_len; | 205 | u16 insn_len; |
205 | u8 cpumode; | 206 | u8 cpumode; |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d9bd632ed7db..0dccdb89572c 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -271,12 +271,17 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) | |||
271 | return evsel; | 271 | return evsel; |
272 | } | 272 | } |
273 | 273 | ||
274 | static bool perf_event_can_profile_kernel(void) | ||
275 | { | ||
276 | return geteuid() == 0 || perf_event_paranoid() == -1; | ||
277 | } | ||
278 | |||
274 | struct perf_evsel *perf_evsel__new_cycles(bool precise) | 279 | struct perf_evsel *perf_evsel__new_cycles(bool precise) |
275 | { | 280 | { |
276 | struct perf_event_attr attr = { | 281 | struct perf_event_attr attr = { |
277 | .type = PERF_TYPE_HARDWARE, | 282 | .type = PERF_TYPE_HARDWARE, |
278 | .config = PERF_COUNT_HW_CPU_CYCLES, | 283 | .config = PERF_COUNT_HW_CPU_CYCLES, |
279 | .exclude_kernel = geteuid() != 0, | 284 | .exclude_kernel = !perf_event_can_profile_kernel(), |
280 | }; | 285 | }; |
281 | struct perf_evsel *evsel; | 286 | struct perf_evsel *evsel; |
282 | 287 | ||
@@ -955,6 +960,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, | |||
955 | if (opts->sample_address) | 960 | if (opts->sample_address) |
956 | perf_evsel__set_sample_bit(evsel, DATA_SRC); | 961 | perf_evsel__set_sample_bit(evsel, DATA_SRC); |
957 | 962 | ||
963 | if (opts->sample_phys_addr) | ||
964 | perf_evsel__set_sample_bit(evsel, PHYS_ADDR); | ||
965 | |||
958 | if (opts->no_buffering) { | 966 | if (opts->no_buffering) { |
959 | attr->watermark = 0; | 967 | attr->watermark = 0; |
960 | attr->wakeup_events = 1; | 968 | attr->wakeup_events = 1; |
@@ -1464,7 +1472,7 @@ static void __p_sample_type(char *buf, size_t size, u64 value) | |||
1464 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), | 1472 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), |
1465 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), | 1473 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), |
1466 | bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC), | 1474 | bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC), |
1467 | bit_name(WEIGHT), | 1475 | bit_name(WEIGHT), bit_name(PHYS_ADDR), |
1468 | { .name = NULL, } | 1476 | { .name = NULL, } |
1469 | }; | 1477 | }; |
1470 | #undef bit_name | 1478 | #undef bit_name |
@@ -2206,6 +2214,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | |||
2206 | } | 2214 | } |
2207 | } | 2215 | } |
2208 | 2216 | ||
2217 | data->phys_addr = 0; | ||
2218 | if (type & PERF_SAMPLE_PHYS_ADDR) { | ||
2219 | data->phys_addr = *array; | ||
2220 | array++; | ||
2221 | } | ||
2222 | |||
2209 | return 0; | 2223 | return 0; |
2210 | } | 2224 | } |
2211 | 2225 | ||
@@ -2311,6 +2325,9 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, | |||
2311 | } | 2325 | } |
2312 | } | 2326 | } |
2313 | 2327 | ||
2328 | if (type & PERF_SAMPLE_PHYS_ADDR) | ||
2329 | result += sizeof(u64); | ||
2330 | |||
2314 | return result; | 2331 | return result; |
2315 | } | 2332 | } |
2316 | 2333 | ||
@@ -2500,6 +2517,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, | |||
2500 | } | 2517 | } |
2501 | } | 2518 | } |
2502 | 2519 | ||
2520 | if (type & PERF_SAMPLE_PHYS_ADDR) { | ||
2521 | *array = sample->phys_addr; | ||
2522 | array++; | ||
2523 | } | ||
2524 | |||
2503 | return 0; | 2525 | return 0; |
2504 | } | 2526 | } |
2505 | 2527 | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 351d3b2d8887..dd2c4b5112a5 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -131,6 +131,7 @@ struct perf_evsel { | |||
131 | bool cmdline_group_boundary; | 131 | bool cmdline_group_boundary; |
132 | struct list_head config_terms; | 132 | struct list_head config_terms; |
133 | int bpf_fd; | 133 | int bpf_fd; |
134 | bool auto_merge_stats; | ||
134 | bool merged_stat; | 135 | bool merged_stat; |
135 | const char * metric_expr; | 136 | const char * metric_expr; |
136 | const char * metric_name; | 137 | const char * metric_name; |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 9453b2e27015..e60d8d8ea4c2 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -167,6 +167,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) | |||
167 | symlen = unresolved_col_width + 4 + 2; | 167 | symlen = unresolved_col_width + 4 + 2; |
168 | hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); | 168 | hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); |
169 | } | 169 | } |
170 | |||
171 | hists__new_col_len(hists, HISTC_MEM_PHYS_DADDR, | ||
172 | unresolved_col_width + 4 + 2); | ||
173 | |||
170 | } else { | 174 | } else { |
171 | symlen = unresolved_col_width + 4 + 2; | 175 | symlen = unresolved_col_width + 4 + 2; |
172 | hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen); | 176 | hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen); |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ee3670a388df..e60dda26a920 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -47,6 +47,7 @@ enum hist_column { | |||
47 | HISTC_GLOBAL_WEIGHT, | 47 | HISTC_GLOBAL_WEIGHT, |
48 | HISTC_MEM_DADDR_SYMBOL, | 48 | HISTC_MEM_DADDR_SYMBOL, |
49 | HISTC_MEM_DADDR_DSO, | 49 | HISTC_MEM_DADDR_DSO, |
50 | HISTC_MEM_PHYS_DADDR, | ||
50 | HISTC_MEM_LOCKED, | 51 | HISTC_MEM_LOCKED, |
51 | HISTC_MEM_TLB, | 52 | HISTC_MEM_TLB, |
52 | HISTC_MEM_LVL, | 53 | HISTC_MEM_LVL, |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 5c8eacaca4f4..df709363ef69 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -1635,10 +1635,12 @@ static void ip__resolve_ams(struct thread *thread, | |||
1635 | ams->al_addr = al.addr; | 1635 | ams->al_addr = al.addr; |
1636 | ams->sym = al.sym; | 1636 | ams->sym = al.sym; |
1637 | ams->map = al.map; | 1637 | ams->map = al.map; |
1638 | ams->phys_addr = 0; | ||
1638 | } | 1639 | } |
1639 | 1640 | ||
1640 | static void ip__resolve_data(struct thread *thread, | 1641 | static void ip__resolve_data(struct thread *thread, |
1641 | u8 m, struct addr_map_symbol *ams, u64 addr) | 1642 | u8 m, struct addr_map_symbol *ams, |
1643 | u64 addr, u64 phys_addr) | ||
1642 | { | 1644 | { |
1643 | struct addr_location al; | 1645 | struct addr_location al; |
1644 | 1646 | ||
@@ -1658,6 +1660,7 @@ static void ip__resolve_data(struct thread *thread, | |||
1658 | ams->al_addr = al.addr; | 1660 | ams->al_addr = al.addr; |
1659 | ams->sym = al.sym; | 1661 | ams->sym = al.sym; |
1660 | ams->map = al.map; | 1662 | ams->map = al.map; |
1663 | ams->phys_addr = phys_addr; | ||
1661 | } | 1664 | } |
1662 | 1665 | ||
1663 | struct mem_info *sample__resolve_mem(struct perf_sample *sample, | 1666 | struct mem_info *sample__resolve_mem(struct perf_sample *sample, |
@@ -1669,12 +1672,18 @@ struct mem_info *sample__resolve_mem(struct perf_sample *sample, | |||
1669 | return NULL; | 1672 | return NULL; |
1670 | 1673 | ||
1671 | ip__resolve_ams(al->thread, &mi->iaddr, sample->ip); | 1674 | ip__resolve_ams(al->thread, &mi->iaddr, sample->ip); |
1672 | ip__resolve_data(al->thread, al->cpumode, &mi->daddr, sample->addr); | 1675 | ip__resolve_data(al->thread, al->cpumode, &mi->daddr, |
1676 | sample->addr, sample->phys_addr); | ||
1673 | mi->data_src.val = sample->data_src; | 1677 | mi->data_src.val = sample->data_src; |
1674 | 1678 | ||
1675 | return mi; | 1679 | return mi; |
1676 | } | 1680 | } |
1677 | 1681 | ||
1682 | struct iterations { | ||
1683 | int nr_loop_iter; | ||
1684 | u64 cycles; | ||
1685 | }; | ||
1686 | |||
1678 | static int add_callchain_ip(struct thread *thread, | 1687 | static int add_callchain_ip(struct thread *thread, |
1679 | struct callchain_cursor *cursor, | 1688 | struct callchain_cursor *cursor, |
1680 | struct symbol **parent, | 1689 | struct symbol **parent, |
@@ -1683,11 +1692,12 @@ static int add_callchain_ip(struct thread *thread, | |||
1683 | u64 ip, | 1692 | u64 ip, |
1684 | bool branch, | 1693 | bool branch, |
1685 | struct branch_flags *flags, | 1694 | struct branch_flags *flags, |
1686 | int nr_loop_iter, | 1695 | struct iterations *iter, |
1687 | int samples, | ||
1688 | u64 branch_from) | 1696 | u64 branch_from) |
1689 | { | 1697 | { |
1690 | struct addr_location al; | 1698 | struct addr_location al; |
1699 | int nr_loop_iter = 0; | ||
1700 | u64 iter_cycles = 0; | ||
1691 | 1701 | ||
1692 | al.filtered = 0; | 1702 | al.filtered = 0; |
1693 | al.sym = NULL; | 1703 | al.sym = NULL; |
@@ -1737,9 +1747,15 @@ static int add_callchain_ip(struct thread *thread, | |||
1737 | 1747 | ||
1738 | if (symbol_conf.hide_unresolved && al.sym == NULL) | 1748 | if (symbol_conf.hide_unresolved && al.sym == NULL) |
1739 | return 0; | 1749 | return 0; |
1750 | |||
1751 | if (iter) { | ||
1752 | nr_loop_iter = iter->nr_loop_iter; | ||
1753 | iter_cycles = iter->cycles; | ||
1754 | } | ||
1755 | |||
1740 | return callchain_cursor_append(cursor, al.addr, al.map, al.sym, | 1756 | return callchain_cursor_append(cursor, al.addr, al.map, al.sym, |
1741 | branch, flags, nr_loop_iter, samples, | 1757 | branch, flags, nr_loop_iter, |
1742 | branch_from); | 1758 | iter_cycles, branch_from); |
1743 | } | 1759 | } |
1744 | 1760 | ||
1745 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, | 1761 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, |
@@ -1760,6 +1776,18 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample, | |||
1760 | return bi; | 1776 | return bi; |
1761 | } | 1777 | } |
1762 | 1778 | ||
1779 | static void save_iterations(struct iterations *iter, | ||
1780 | struct branch_entry *be, int nr) | ||
1781 | { | ||
1782 | int i; | ||
1783 | |||
1784 | iter->nr_loop_iter = nr; | ||
1785 | iter->cycles = 0; | ||
1786 | |||
1787 | for (i = 0; i < nr; i++) | ||
1788 | iter->cycles += be[i].flags.cycles; | ||
1789 | } | ||
1790 | |||
1763 | #define CHASHSZ 127 | 1791 | #define CHASHSZ 127 |
1764 | #define CHASHBITS 7 | 1792 | #define CHASHBITS 7 |
1765 | #define NO_ENTRY 0xff | 1793 | #define NO_ENTRY 0xff |
@@ -1767,7 +1795,8 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample, | |||
1767 | #define PERF_MAX_BRANCH_DEPTH 127 | 1795 | #define PERF_MAX_BRANCH_DEPTH 127 |
1768 | 1796 | ||
1769 | /* Remove loops. */ | 1797 | /* Remove loops. */ |
1770 | static int remove_loops(struct branch_entry *l, int nr) | 1798 | static int remove_loops(struct branch_entry *l, int nr, |
1799 | struct iterations *iter) | ||
1771 | { | 1800 | { |
1772 | int i, j, off; | 1801 | int i, j, off; |
1773 | unsigned char chash[CHASHSZ]; | 1802 | unsigned char chash[CHASHSZ]; |
@@ -1792,8 +1821,18 @@ static int remove_loops(struct branch_entry *l, int nr) | |||
1792 | break; | 1821 | break; |
1793 | } | 1822 | } |
1794 | if (is_loop) { | 1823 | if (is_loop) { |
1795 | memmove(l + i, l + i + off, | 1824 | j = nr - (i + off); |
1796 | (nr - (i + off)) * sizeof(*l)); | 1825 | if (j > 0) { |
1826 | save_iterations(iter + i + off, | ||
1827 | l + i, off); | ||
1828 | |||
1829 | memmove(iter + i, iter + i + off, | ||
1830 | j * sizeof(*iter)); | ||
1831 | |||
1832 | memmove(l + i, l + i + off, | ||
1833 | j * sizeof(*l)); | ||
1834 | } | ||
1835 | |||
1797 | nr -= off; | 1836 | nr -= off; |
1798 | } | 1837 | } |
1799 | } | 1838 | } |
@@ -1883,7 +1922,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread, | |||
1883 | 1922 | ||
1884 | err = add_callchain_ip(thread, cursor, parent, | 1923 | err = add_callchain_ip(thread, cursor, parent, |
1885 | root_al, &cpumode, ip, | 1924 | root_al, &cpumode, ip, |
1886 | branch, flags, 0, 0, | 1925 | branch, flags, NULL, |
1887 | branch_from); | 1926 | branch_from); |
1888 | if (err) | 1927 | if (err) |
1889 | return (err < 0) ? err : 0; | 1928 | return (err < 0) ? err : 0; |
@@ -1909,7 +1948,6 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
1909 | int i, j, err, nr_entries; | 1948 | int i, j, err, nr_entries; |
1910 | int skip_idx = -1; | 1949 | int skip_idx = -1; |
1911 | int first_call = 0; | 1950 | int first_call = 0; |
1912 | int nr_loop_iter; | ||
1913 | 1951 | ||
1914 | if (chain) | 1952 | if (chain) |
1915 | chain_nr = chain->nr; | 1953 | chain_nr = chain->nr; |
@@ -1942,6 +1980,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
1942 | if (branch && callchain_param.branch_callstack) { | 1980 | if (branch && callchain_param.branch_callstack) { |
1943 | int nr = min(max_stack, (int)branch->nr); | 1981 | int nr = min(max_stack, (int)branch->nr); |
1944 | struct branch_entry be[nr]; | 1982 | struct branch_entry be[nr]; |
1983 | struct iterations iter[nr]; | ||
1945 | 1984 | ||
1946 | if (branch->nr > PERF_MAX_BRANCH_DEPTH) { | 1985 | if (branch->nr > PERF_MAX_BRANCH_DEPTH) { |
1947 | pr_warning("corrupted branch chain. skipping...\n"); | 1986 | pr_warning("corrupted branch chain. skipping...\n"); |
@@ -1972,38 +2011,21 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
1972 | be[i] = branch->entries[branch->nr - i - 1]; | 2011 | be[i] = branch->entries[branch->nr - i - 1]; |
1973 | } | 2012 | } |
1974 | 2013 | ||
1975 | nr_loop_iter = nr; | 2014 | memset(iter, 0, sizeof(struct iterations) * nr); |
1976 | nr = remove_loops(be, nr); | 2015 | nr = remove_loops(be, nr, iter); |
1977 | |||
1978 | /* | ||
1979 | * Get the number of iterations. | ||
1980 | * It's only approximation, but good enough in practice. | ||
1981 | */ | ||
1982 | if (nr_loop_iter > nr) | ||
1983 | nr_loop_iter = nr_loop_iter - nr + 1; | ||
1984 | else | ||
1985 | nr_loop_iter = 0; | ||
1986 | 2016 | ||
1987 | for (i = 0; i < nr; i++) { | 2017 | for (i = 0; i < nr; i++) { |
1988 | if (i == nr - 1) | 2018 | err = add_callchain_ip(thread, cursor, parent, |
1989 | err = add_callchain_ip(thread, cursor, parent, | 2019 | root_al, |
1990 | root_al, | 2020 | NULL, be[i].to, |
1991 | NULL, be[i].to, | 2021 | true, &be[i].flags, |
1992 | true, &be[i].flags, | 2022 | NULL, be[i].from); |
1993 | nr_loop_iter, 1, | ||
1994 | be[i].from); | ||
1995 | else | ||
1996 | err = add_callchain_ip(thread, cursor, parent, | ||
1997 | root_al, | ||
1998 | NULL, be[i].to, | ||
1999 | true, &be[i].flags, | ||
2000 | 0, 0, be[i].from); | ||
2001 | 2023 | ||
2002 | if (!err) | 2024 | if (!err) |
2003 | err = add_callchain_ip(thread, cursor, parent, root_al, | 2025 | err = add_callchain_ip(thread, cursor, parent, root_al, |
2004 | NULL, be[i].from, | 2026 | NULL, be[i].from, |
2005 | true, &be[i].flags, | 2027 | true, &be[i].flags, |
2006 | 0, 0, 0); | 2028 | &iter[i], 0); |
2007 | if (err == -EINVAL) | 2029 | if (err == -EINVAL) |
2008 | break; | 2030 | break; |
2009 | if (err) | 2031 | if (err) |
@@ -2037,7 +2059,7 @@ check_calls: | |||
2037 | 2059 | ||
2038 | err = add_callchain_ip(thread, cursor, parent, | 2060 | err = add_callchain_ip(thread, cursor, parent, |
2039 | root_al, &cpumode, ip, | 2061 | root_al, &cpumode, ip, |
2040 | false, NULL, 0, 0, 0); | 2062 | false, NULL, NULL, 0); |
2041 | 2063 | ||
2042 | if (err) | 2064 | if (err) |
2043 | return (err < 0) ? err : 0; | 2065 | return (err < 0) ? err : 0; |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index f44aeba51d1f..f6257fb4f08c 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -310,7 +310,7 @@ static struct perf_evsel * | |||
310 | __add_event(struct list_head *list, int *idx, | 310 | __add_event(struct list_head *list, int *idx, |
311 | struct perf_event_attr *attr, | 311 | struct perf_event_attr *attr, |
312 | char *name, struct cpu_map *cpus, | 312 | char *name, struct cpu_map *cpus, |
313 | struct list_head *config_terms) | 313 | struct list_head *config_terms, bool auto_merge_stats) |
314 | { | 314 | { |
315 | struct perf_evsel *evsel; | 315 | struct perf_evsel *evsel; |
316 | 316 | ||
@@ -324,6 +324,7 @@ __add_event(struct list_head *list, int *idx, | |||
324 | evsel->cpus = cpu_map__get(cpus); | 324 | evsel->cpus = cpu_map__get(cpus); |
325 | evsel->own_cpus = cpu_map__get(cpus); | 325 | evsel->own_cpus = cpu_map__get(cpus); |
326 | evsel->system_wide = !!cpus; | 326 | evsel->system_wide = !!cpus; |
327 | evsel->auto_merge_stats = auto_merge_stats; | ||
327 | 328 | ||
328 | if (name) | 329 | if (name) |
329 | evsel->name = strdup(name); | 330 | evsel->name = strdup(name); |
@@ -339,7 +340,7 @@ static int add_event(struct list_head *list, int *idx, | |||
339 | struct perf_event_attr *attr, char *name, | 340 | struct perf_event_attr *attr, char *name, |
340 | struct list_head *config_terms) | 341 | struct list_head *config_terms) |
341 | { | 342 | { |
342 | return __add_event(list, idx, attr, name, NULL, config_terms) ? 0 : -ENOMEM; | 343 | return __add_event(list, idx, attr, name, NULL, config_terms, false) ? 0 : -ENOMEM; |
343 | } | 344 | } |
344 | 345 | ||
345 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) | 346 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) |
@@ -1209,9 +1210,9 @@ int parse_events_add_numeric(struct parse_events_state *parse_state, | |||
1209 | get_config_name(head_config), &config_terms); | 1210 | get_config_name(head_config), &config_terms); |
1210 | } | 1211 | } |
1211 | 1212 | ||
1212 | int parse_events_add_pmu(struct parse_events_state *parse_state, | 1213 | static int __parse_events_add_pmu(struct parse_events_state *parse_state, |
1213 | struct list_head *list, char *name, | 1214 | struct list_head *list, char *name, |
1214 | struct list_head *head_config) | 1215 | struct list_head *head_config, bool auto_merge_stats) |
1215 | { | 1216 | { |
1216 | struct perf_event_attr attr; | 1217 | struct perf_event_attr attr; |
1217 | struct perf_pmu_info info; | 1218 | struct perf_pmu_info info; |
@@ -1232,7 +1233,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, | |||
1232 | 1233 | ||
1233 | if (!head_config) { | 1234 | if (!head_config) { |
1234 | attr.type = pmu->type; | 1235 | attr.type = pmu->type; |
1235 | evsel = __add_event(list, &parse_state->idx, &attr, NULL, pmu->cpus, NULL); | 1236 | evsel = __add_event(list, &parse_state->idx, &attr, NULL, pmu->cpus, NULL, auto_merge_stats); |
1236 | return evsel ? 0 : -ENOMEM; | 1237 | return evsel ? 0 : -ENOMEM; |
1237 | } | 1238 | } |
1238 | 1239 | ||
@@ -1254,7 +1255,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, | |||
1254 | 1255 | ||
1255 | evsel = __add_event(list, &parse_state->idx, &attr, | 1256 | evsel = __add_event(list, &parse_state->idx, &attr, |
1256 | get_config_name(head_config), pmu->cpus, | 1257 | get_config_name(head_config), pmu->cpus, |
1257 | &config_terms); | 1258 | &config_terms, auto_merge_stats); |
1258 | if (evsel) { | 1259 | if (evsel) { |
1259 | evsel->unit = info.unit; | 1260 | evsel->unit = info.unit; |
1260 | evsel->scale = info.scale; | 1261 | evsel->scale = info.scale; |
@@ -1267,6 +1268,13 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, | |||
1267 | return evsel ? 0 : -ENOMEM; | 1268 | return evsel ? 0 : -ENOMEM; |
1268 | } | 1269 | } |
1269 | 1270 | ||
1271 | int parse_events_add_pmu(struct parse_events_state *parse_state, | ||
1272 | struct list_head *list, char *name, | ||
1273 | struct list_head *head_config) | ||
1274 | { | ||
1275 | return __parse_events_add_pmu(parse_state, list, name, head_config, false); | ||
1276 | } | ||
1277 | |||
1270 | int parse_events_multi_pmu_add(struct parse_events_state *parse_state, | 1278 | int parse_events_multi_pmu_add(struct parse_events_state *parse_state, |
1271 | char *str, struct list_head **listp) | 1279 | char *str, struct list_head **listp) |
1272 | { | 1280 | { |
@@ -1296,8 +1304,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, | |||
1296 | return -1; | 1304 | return -1; |
1297 | list_add_tail(&term->list, head); | 1305 | list_add_tail(&term->list, head); |
1298 | 1306 | ||
1299 | if (!parse_events_add_pmu(parse_state, list, | 1307 | if (!__parse_events_add_pmu(parse_state, list, |
1300 | pmu->name, head)) { | 1308 | pmu->name, head, true)) { |
1301 | pr_debug("%s -> %s/%s/\n", str, | 1309 | pr_debug("%s -> %s/%s/\n", str, |
1302 | pmu->name, alias->str); | 1310 | pmu->name, alias->str); |
1303 | ok++; | 1311 | ok++; |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ac863691605f..a7ebd9fe8e40 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1120,6 +1120,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, | |||
1120 | if (sample_type & PERF_SAMPLE_DATA_SRC) | 1120 | if (sample_type & PERF_SAMPLE_DATA_SRC) |
1121 | printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); | 1121 | printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); |
1122 | 1122 | ||
1123 | if (sample_type & PERF_SAMPLE_PHYS_ADDR) | ||
1124 | printf(" .. phys_addr: 0x%"PRIx64"\n", sample->phys_addr); | ||
1125 | |||
1123 | if (sample_type & PERF_SAMPLE_TRANSACTION) | 1126 | if (sample_type & PERF_SAMPLE_TRANSACTION) |
1124 | printf("... transaction: %" PRIx64 "\n", sample->transaction); | 1127 | printf("... transaction: %" PRIx64 "\n", sample->transaction); |
1125 | 1128 | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 12359bd986db..eb3ab902a1c0 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -1316,6 +1316,47 @@ struct sort_entry sort_mem_dcacheline = { | |||
1316 | }; | 1316 | }; |
1317 | 1317 | ||
1318 | static int64_t | 1318 | static int64_t |
1319 | sort__phys_daddr_cmp(struct hist_entry *left, struct hist_entry *right) | ||
1320 | { | ||
1321 | uint64_t l = 0, r = 0; | ||
1322 | |||
1323 | if (left->mem_info) | ||
1324 | l = left->mem_info->daddr.phys_addr; | ||
1325 | if (right->mem_info) | ||
1326 | r = right->mem_info->daddr.phys_addr; | ||
1327 | |||
1328 | return (int64_t)(r - l); | ||
1329 | } | ||
1330 | |||
1331 | static int hist_entry__phys_daddr_snprintf(struct hist_entry *he, char *bf, | ||
1332 | size_t size, unsigned int width) | ||
1333 | { | ||
1334 | uint64_t addr = 0; | ||
1335 | size_t ret = 0; | ||
1336 | size_t len = BITS_PER_LONG / 4; | ||
1337 | |||
1338 | addr = he->mem_info->daddr.phys_addr; | ||
1339 | |||
1340 | ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", he->level); | ||
1341 | |||
1342 | ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", len, addr); | ||
1343 | |||
1344 | ret += repsep_snprintf(bf + ret, size - ret, "%-*s", width - ret, ""); | ||
1345 | |||
1346 | if (ret > width) | ||
1347 | bf[width] = '\0'; | ||
1348 | |||
1349 | return width; | ||
1350 | } | ||
1351 | |||
1352 | struct sort_entry sort_mem_phys_daddr = { | ||
1353 | .se_header = "Data Physical Address", | ||
1354 | .se_cmp = sort__phys_daddr_cmp, | ||
1355 | .se_snprintf = hist_entry__phys_daddr_snprintf, | ||
1356 | .se_width_idx = HISTC_MEM_PHYS_DADDR, | ||
1357 | }; | ||
1358 | |||
1359 | static int64_t | ||
1319 | sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) | 1360 | sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) |
1320 | { | 1361 | { |
1321 | if (!left->branch_info || !right->branch_info) | 1362 | if (!left->branch_info || !right->branch_info) |
@@ -1547,6 +1588,7 @@ static struct sort_dimension memory_sort_dimensions[] = { | |||
1547 | DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), | 1588 | DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), |
1548 | DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), | 1589 | DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), |
1549 | DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline), | 1590 | DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline), |
1591 | DIM(SORT_MEM_PHYS_DADDR, "phys_daddr", sort_mem_phys_daddr), | ||
1550 | }; | 1592 | }; |
1551 | 1593 | ||
1552 | #undef DIM | 1594 | #undef DIM |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index b7c75597e18f..f36dc4980a6c 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -245,6 +245,7 @@ enum sort_type { | |||
245 | SORT_MEM_SNOOP, | 245 | SORT_MEM_SNOOP, |
246 | SORT_MEM_DCACHELINE, | 246 | SORT_MEM_DCACHELINE, |
247 | SORT_MEM_IADDR_SYMBOL, | 247 | SORT_MEM_IADDR_SYMBOL, |
248 | SORT_MEM_PHYS_DADDR, | ||
248 | }; | 249 | }; |
249 | 250 | ||
250 | /* | 251 | /* |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 5c39f420111e..9cf781f0d8a2 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -810,12 +810,6 @@ static u64 ref_reloc(struct kmap *kmap) | |||
810 | void __weak arch__sym_update(struct symbol *s __maybe_unused, | 810 | void __weak arch__sym_update(struct symbol *s __maybe_unused, |
811 | GElf_Sym *sym __maybe_unused) { } | 811 | GElf_Sym *sym __maybe_unused) { } |
812 | 812 | ||
813 | void __weak arch__adjust_sym_map_offset(GElf_Sym *sym, GElf_Shdr *shdr, | ||
814 | struct map *map __maybe_unused) | ||
815 | { | ||
816 | sym->st_value -= shdr->sh_addr - shdr->sh_offset; | ||
817 | } | ||
818 | |||
819 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, | 813 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, |
820 | struct symsrc *runtime_ss, int kmodule) | 814 | struct symsrc *runtime_ss, int kmodule) |
821 | { | 815 | { |
@@ -996,7 +990,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, | |||
996 | 990 | ||
997 | /* Adjust symbol to map to file offset */ | 991 | /* Adjust symbol to map to file offset */ |
998 | if (adjust_kernel_syms) | 992 | if (adjust_kernel_syms) |
999 | arch__adjust_sym_map_offset(&sym, &shdr, map); | 993 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; |
1000 | 994 | ||
1001 | if (strcmp(section_name, | 995 | if (strcmp(section_name, |
1002 | (curr_dso->short_name + | 996 | (curr_dso->short_name + |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index d00a012cfdfb..aad99e7e179b 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -186,6 +186,7 @@ struct addr_map_symbol { | |||
186 | struct symbol *sym; | 186 | struct symbol *sym; |
187 | u64 addr; | 187 | u64 addr; |
188 | u64 al_addr; | 188 | u64 al_addr; |
189 | u64 phys_addr; | ||
189 | }; | 190 | }; |
190 | 191 | ||
191 | struct branch_info { | 192 | struct branch_info { |
@@ -343,9 +344,6 @@ int setup_intlist(struct intlist **list, const char *list_str, | |||
343 | #ifdef HAVE_LIBELF_SUPPORT | 344 | #ifdef HAVE_LIBELF_SUPPORT |
344 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); | 345 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); |
345 | void arch__sym_update(struct symbol *s, GElf_Sym *sym); | 346 | void arch__sym_update(struct symbol *s, GElf_Sym *sym); |
346 | void arch__adjust_sym_map_offset(GElf_Sym *sym, | ||
347 | GElf_Shdr *shdr __maybe_unused, | ||
348 | struct map *map __maybe_unused); | ||
349 | #endif | 347 | #endif |
350 | 348 | ||
351 | #define SYMBOL_A 0 | 349 | #define SYMBOL_A 0 |
diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c index bbb4c1957578..6eea7cff3d4e 100644 --- a/tools/perf/util/syscalltbl.c +++ b/tools/perf/util/syscalltbl.c | |||
@@ -15,10 +15,11 @@ | |||
15 | 15 | ||
16 | #include "syscalltbl.h" | 16 | #include "syscalltbl.h" |
17 | #include <stdlib.h> | 17 | #include <stdlib.h> |
18 | #include <linux/compiler.h> | ||
18 | 19 | ||
19 | #ifdef HAVE_SYSCALL_TABLE | 20 | #ifdef HAVE_SYSCALL_TABLE |
20 | #include <linux/compiler.h> | ||
21 | #include <string.h> | 21 | #include <string.h> |
22 | #include "string2.h" | ||
22 | #include "util.h" | 23 | #include "util.h" |
23 | 24 | ||
24 | #if defined(__x86_64__) | 25 | #if defined(__x86_64__) |
@@ -105,6 +106,27 @@ int syscalltbl__id(struct syscalltbl *tbl, const char *name) | |||
105 | return sc ? sc->id : -1; | 106 | return sc ? sc->id : -1; |
106 | } | 107 | } |
107 | 108 | ||
109 | int syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx) | ||
110 | { | ||
111 | int i; | ||
112 | struct syscall *syscalls = tbl->syscalls.entries; | ||
113 | |||
114 | for (i = *idx + 1; i < tbl->syscalls.nr_entries; ++i) { | ||
115 | if (strglobmatch(syscalls[i].name, syscall_glob)) { | ||
116 | *idx = i; | ||
117 | return syscalls[i].id; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | return -1; | ||
122 | } | ||
123 | |||
124 | int syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx) | ||
125 | { | ||
126 | *idx = -1; | ||
127 | return syscalltbl__strglobmatch_next(tbl, syscall_glob, idx); | ||
128 | } | ||
129 | |||
108 | #else /* HAVE_SYSCALL_TABLE */ | 130 | #else /* HAVE_SYSCALL_TABLE */ |
109 | 131 | ||
110 | #include <libaudit.h> | 132 | #include <libaudit.h> |
@@ -131,4 +153,15 @@ int syscalltbl__id(struct syscalltbl *tbl, const char *name) | |||
131 | { | 153 | { |
132 | return audit_name_to_syscall(name, tbl->audit_machine); | 154 | return audit_name_to_syscall(name, tbl->audit_machine); |
133 | } | 155 | } |
156 | |||
157 | int syscalltbl__strglobmatch_next(struct syscalltbl *tbl __maybe_unused, | ||
158 | const char *syscall_glob __maybe_unused, int *idx __maybe_unused) | ||
159 | { | ||
160 | return -1; | ||
161 | } | ||
162 | |||
163 | int syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx) | ||
164 | { | ||
165 | return syscalltbl__strglobmatch_next(tbl, syscall_glob, idx); | ||
166 | } | ||
134 | #endif /* HAVE_SYSCALL_TABLE */ | 167 | #endif /* HAVE_SYSCALL_TABLE */ |
diff --git a/tools/perf/util/syscalltbl.h b/tools/perf/util/syscalltbl.h index e2951510484f..e9fb8786da7c 100644 --- a/tools/perf/util/syscalltbl.h +++ b/tools/perf/util/syscalltbl.h | |||
@@ -17,4 +17,7 @@ void syscalltbl__delete(struct syscalltbl *tbl); | |||
17 | const char *syscalltbl__name(const struct syscalltbl *tbl, int id); | 17 | const char *syscalltbl__name(const struct syscalltbl *tbl, int id); |
18 | int syscalltbl__id(struct syscalltbl *tbl, const char *name); | 18 | int syscalltbl__id(struct syscalltbl *tbl, const char *name); |
19 | 19 | ||
20 | int syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx); | ||
21 | int syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx); | ||
22 | |||
20 | #endif /* __PERF_SYSCALLTBL_H */ | 23 | #endif /* __PERF_SYSCALLTBL_H */ |
diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index 82a2ff896a95..52a39ecf5ca1 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c | |||
@@ -759,7 +759,7 @@ static acpi_status osl_list_bios_tables(void) | |||
759 | 759 | ||
760 | /* Skip NULL entries in RSDT/XSDT */ | 760 | /* Skip NULL entries in RSDT/XSDT */ |
761 | 761 | ||
762 | if (!table_address) { | 762 | if (table_address == 0) { |
763 | continue; | 763 | continue; |
764 | } | 764 | } |
765 | 765 | ||
@@ -808,7 +808,8 @@ osl_get_bios_table(char *signature, | |||
808 | u8 number_of_tables; | 808 | u8 number_of_tables; |
809 | u8 item_size; | 809 | u8 item_size; |
810 | u32 current_instance = 0; | 810 | u32 current_instance = 0; |
811 | acpi_physical_address table_address = 0; | 811 | acpi_physical_address table_address; |
812 | acpi_physical_address first_table_address = 0; | ||
812 | u32 table_length = 0; | 813 | u32 table_length = 0; |
813 | acpi_status status = AE_OK; | 814 | acpi_status status = AE_OK; |
814 | u32 i; | 815 | u32 i; |
@@ -820,9 +821,10 @@ osl_get_bios_table(char *signature, | |||
820 | ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) || | 821 | ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) || |
821 | ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) || | 822 | ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) || |
822 | ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { | 823 | ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { |
823 | if (instance > 0) { | 824 | |
824 | return (AE_LIMIT); | 825 | find_next_instance: |
825 | } | 826 | |
827 | table_address = 0; | ||
826 | 828 | ||
827 | /* | 829 | /* |
828 | * Get the appropriate address, either 32-bit or 64-bit. Be very | 830 | * Get the appropriate address, either 32-bit or 64-bit. Be very |
@@ -830,41 +832,66 @@ osl_get_bios_table(char *signature, | |||
830 | * Note: The 64-bit addresses have priority. | 832 | * Note: The 64-bit addresses have priority. |
831 | */ | 833 | */ |
832 | if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) { | 834 | if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) { |
833 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) && | 835 | if (current_instance < 2) { |
834 | gbl_fadt->Xdsdt) { | 836 | if ((gbl_fadt->header.length >= |
835 | table_address = | 837 | MIN_FADT_FOR_XDSDT) && gbl_fadt->Xdsdt |
836 | (acpi_physical_address)gbl_fadt->Xdsdt; | 838 | && current_instance == 0) { |
837 | } else | 839 | table_address = |
838 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT) | 840 | (acpi_physical_address)gbl_fadt-> |
839 | && gbl_fadt->dsdt) { | 841 | Xdsdt; |
840 | table_address = | 842 | } else |
841 | (acpi_physical_address)gbl_fadt->dsdt; | 843 | if ((gbl_fadt->header.length >= |
844 | MIN_FADT_FOR_DSDT) | ||
845 | && gbl_fadt->dsdt != | ||
846 | first_table_address) { | ||
847 | table_address = | ||
848 | (acpi_physical_address)gbl_fadt-> | ||
849 | dsdt; | ||
850 | } | ||
842 | } | 851 | } |
843 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { | 852 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { |
844 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) && | 853 | if (current_instance < 2) { |
845 | gbl_fadt->Xfacs) { | 854 | if ((gbl_fadt->header.length >= |
846 | table_address = | 855 | MIN_FADT_FOR_XFACS) && gbl_fadt->Xfacs |
847 | (acpi_physical_address)gbl_fadt->Xfacs; | 856 | && current_instance == 0) { |
848 | } else | 857 | table_address = |
849 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS) | 858 | (acpi_physical_address)gbl_fadt-> |
850 | && gbl_fadt->facs) { | 859 | Xfacs; |
851 | table_address = | 860 | } else |
852 | (acpi_physical_address)gbl_fadt->facs; | 861 | if ((gbl_fadt->header.length >= |
862 | MIN_FADT_FOR_FACS) | ||
863 | && gbl_fadt->facs != | ||
864 | first_table_address) { | ||
865 | table_address = | ||
866 | (acpi_physical_address)gbl_fadt-> | ||
867 | facs; | ||
868 | } | ||
853 | } | 869 | } |
854 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) { | 870 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) { |
855 | if (!gbl_revision) { | 871 | if (!gbl_revision) { |
856 | return (AE_BAD_SIGNATURE); | 872 | return (AE_BAD_SIGNATURE); |
857 | } | 873 | } |
858 | table_address = | 874 | if (current_instance == 0) { |
859 | (acpi_physical_address)gbl_rsdp. | 875 | table_address = |
860 | xsdt_physical_address; | 876 | (acpi_physical_address)gbl_rsdp. |
877 | xsdt_physical_address; | ||
878 | } | ||
861 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) { | 879 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) { |
862 | table_address = | 880 | if (current_instance == 0) { |
863 | (acpi_physical_address)gbl_rsdp. | 881 | table_address = |
864 | rsdt_physical_address; | 882 | (acpi_physical_address)gbl_rsdp. |
883 | rsdt_physical_address; | ||
884 | } | ||
865 | } else { | 885 | } else { |
866 | table_address = (acpi_physical_address)gbl_rsdp_address; | 886 | if (current_instance == 0) { |
867 | signature = ACPI_SIG_RSDP; | 887 | table_address = |
888 | (acpi_physical_address)gbl_rsdp_address; | ||
889 | signature = ACPI_SIG_RSDP; | ||
890 | } | ||
891 | } | ||
892 | |||
893 | if (table_address == 0) { | ||
894 | goto exit_find_table; | ||
868 | } | 895 | } |
869 | 896 | ||
870 | /* Now we can get the requested special table */ | 897 | /* Now we can get the requested special table */ |
@@ -875,6 +902,18 @@ osl_get_bios_table(char *signature, | |||
875 | } | 902 | } |
876 | 903 | ||
877 | table_length = ap_get_table_length(mapped_table); | 904 | table_length = ap_get_table_length(mapped_table); |
905 | if (first_table_address == 0) { | ||
906 | first_table_address = table_address; | ||
907 | } | ||
908 | |||
909 | /* Match table instance */ | ||
910 | |||
911 | if (current_instance != instance) { | ||
912 | osl_unmap_table(mapped_table); | ||
913 | mapped_table = NULL; | ||
914 | current_instance++; | ||
915 | goto find_next_instance; | ||
916 | } | ||
878 | } else { /* Case for a normal ACPI table */ | 917 | } else { /* Case for a normal ACPI table */ |
879 | 918 | ||
880 | if (osl_can_use_xsdt()) { | 919 | if (osl_can_use_xsdt()) { |
@@ -913,7 +952,7 @@ osl_get_bios_table(char *signature, | |||
913 | 952 | ||
914 | /* Skip NULL entries in RSDT/XSDT */ | 953 | /* Skip NULL entries in RSDT/XSDT */ |
915 | 954 | ||
916 | if (!table_address) { | 955 | if (table_address == 0) { |
917 | continue; | 956 | continue; |
918 | } | 957 | } |
919 | 958 | ||
@@ -946,6 +985,8 @@ osl_get_bios_table(char *signature, | |||
946 | } | 985 | } |
947 | } | 986 | } |
948 | 987 | ||
988 | exit_find_table: | ||
989 | |||
949 | if (!mapped_table) { | 990 | if (!mapped_table) { |
950 | return (AE_LIMIT); | 991 | return (AE_LIMIT); |
951 | } | 992 | } |
diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c index 31b5a7f74015..d686e11936c4 100644 --- a/tools/power/acpi/tools/acpidump/apfiles.c +++ b/tools/power/acpi/tools/acpidump/apfiles.c | |||
@@ -61,7 +61,7 @@ static int ap_is_existing_file(char *pathname); | |||
61 | 61 | ||
62 | static int ap_is_existing_file(char *pathname) | 62 | static int ap_is_existing_file(char *pathname) |
63 | { | 63 | { |
64 | #ifndef _GNU_EFI | 64 | #if !defined(_GNU_EFI) && !defined(_EDK2_EFI) |
65 | struct stat stat_info; | 65 | struct stat stat_info; |
66 | 66 | ||
67 | if (!stat(pathname, &stat_info)) { | 67 | if (!stat(pathname, &stat_info)) { |
diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c index dd82afa897bd..943b6b614683 100644 --- a/tools/power/acpi/tools/acpidump/apmain.c +++ b/tools/power/acpi/tools/acpidump/apmain.c | |||
@@ -300,7 +300,7 @@ static int ap_do_options(int argc, char **argv) | |||
300 | * | 300 | * |
301 | ******************************************************************************/ | 301 | ******************************************************************************/ |
302 | 302 | ||
303 | #ifndef _GNU_EFI | 303 | #if !defined(_GNU_EFI) && !defined(_EDK2_EFI) |
304 | int ACPI_SYSTEM_XFACE main(int argc, char *argv[]) | 304 | int ACPI_SYSTEM_XFACE main(int argc, char *argv[]) |
305 | #else | 305 | #else |
306 | int ACPI_SYSTEM_XFACE acpi_main(int argc, char *argv[]) | 306 | int ACPI_SYSTEM_XFACE acpi_main(int argc, char *argv[]) |
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index d6e1c02ddcfe..4c5a481a850c 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile | |||
@@ -26,7 +26,7 @@ endif | |||
26 | 26 | ||
27 | ifneq ($(OUTPUT),) | 27 | ifneq ($(OUTPUT),) |
28 | # check that the output directory actually exists | 28 | # check that the output directory actually exists |
29 | OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) | 29 | OUTDIR := $(realpath $(OUTPUT)) |
30 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) | 30 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) |
31 | endif | 31 | endif |
32 | 32 | ||
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c index 9ea914378985..2dccf4998599 100644 --- a/tools/power/cpupower/utils/cpupower.c +++ b/tools/power/cpupower/utils/cpupower.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <string.h> | 12 | #include <string.h> |
13 | #include <unistd.h> | 13 | #include <unistd.h> |
14 | #include <errno.h> | 14 | #include <errno.h> |
15 | #include <sched.h> | ||
15 | #include <sys/types.h> | 16 | #include <sys/types.h> |
16 | #include <sys/stat.h> | 17 | #include <sys/stat.h> |
17 | #include <sys/utsname.h> | 18 | #include <sys/utsname.h> |
@@ -31,6 +32,7 @@ static int cmd_help(int argc, const char **argv); | |||
31 | */ | 32 | */ |
32 | struct cpupower_cpu_info cpupower_cpu_info; | 33 | struct cpupower_cpu_info cpupower_cpu_info; |
33 | int run_as_root; | 34 | int run_as_root; |
35 | int base_cpu; | ||
34 | /* Affected cpus chosen by -c/--cpu param */ | 36 | /* Affected cpus chosen by -c/--cpu param */ |
35 | struct bitmask *cpus_chosen; | 37 | struct bitmask *cpus_chosen; |
36 | 38 | ||
@@ -174,6 +176,7 @@ int main(int argc, const char *argv[]) | |||
174 | unsigned int i, ret; | 176 | unsigned int i, ret; |
175 | struct stat statbuf; | 177 | struct stat statbuf; |
176 | struct utsname uts; | 178 | struct utsname uts; |
179 | char pathname[32]; | ||
177 | 180 | ||
178 | cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF)); | 181 | cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF)); |
179 | 182 | ||
@@ -198,17 +201,23 @@ int main(int argc, const char *argv[]) | |||
198 | argv[0] = cmd = "help"; | 201 | argv[0] = cmd = "help"; |
199 | } | 202 | } |
200 | 203 | ||
201 | get_cpu_info(0, &cpupower_cpu_info); | 204 | base_cpu = sched_getcpu(); |
205 | if (base_cpu < 0) { | ||
206 | fprintf(stderr, _("No valid cpus found.\n")); | ||
207 | return EXIT_FAILURE; | ||
208 | } | ||
209 | |||
210 | get_cpu_info(&cpupower_cpu_info); | ||
202 | run_as_root = !geteuid(); | 211 | run_as_root = !geteuid(); |
203 | if (run_as_root) { | 212 | if (run_as_root) { |
204 | ret = uname(&uts); | 213 | ret = uname(&uts); |
214 | sprintf(pathname, "/dev/cpu/%d/msr", base_cpu); | ||
205 | if (!ret && !strcmp(uts.machine, "x86_64") && | 215 | if (!ret && !strcmp(uts.machine, "x86_64") && |
206 | stat("/dev/cpu/0/msr", &statbuf) != 0) { | 216 | stat(pathname, &statbuf) != 0) { |
207 | if (system("modprobe msr") == -1) | 217 | if (system("modprobe msr") == -1) |
208 | fprintf(stderr, _("MSR access not available.\n")); | 218 | fprintf(stderr, _("MSR access not available.\n")); |
209 | } | 219 | } |
210 | } | 220 | } |
211 | |||
212 | 221 | ||
213 | for (i = 0; i < ARRAY_SIZE(commands); i++) { | 222 | for (i = 0; i < ARRAY_SIZE(commands); i++) { |
214 | struct cmd_struct *p = commands + i; | 223 | struct cmd_struct *p = commands + i; |
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c index 39c2c7d067bb..32d37c9be791 100644 --- a/tools/power/cpupower/utils/helpers/cpuid.c +++ b/tools/power/cpupower/utils/helpers/cpuid.c | |||
@@ -42,7 +42,7 @@ cpuid_func(edx); | |||
42 | * | 42 | * |
43 | * TBD: Should there be a cpuid alternative for this if /proc is not mounted? | 43 | * TBD: Should there be a cpuid alternative for this if /proc is not mounted? |
44 | */ | 44 | */ |
45 | int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info) | 45 | int get_cpu_info(struct cpupower_cpu_info *cpu_info) |
46 | { | 46 | { |
47 | FILE *fp; | 47 | FILE *fp; |
48 | char value[64]; | 48 | char value[64]; |
@@ -70,7 +70,7 @@ int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info) | |||
70 | if (!strncmp(value, "processor\t: ", 12)) | 70 | if (!strncmp(value, "processor\t: ", 12)) |
71 | sscanf(value, "processor\t: %u", &proc); | 71 | sscanf(value, "processor\t: %u", &proc); |
72 | 72 | ||
73 | if (proc != cpu) | 73 | if (proc != (unsigned int)base_cpu) |
74 | continue; | 74 | continue; |
75 | 75 | ||
76 | /* Get CPU vendor */ | 76 | /* Get CPU vendor */ |
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h index 799a18be60aa..41da392be448 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h | |||
@@ -34,6 +34,7 @@ | |||
34 | /* Internationalization ****************************/ | 34 | /* Internationalization ****************************/ |
35 | 35 | ||
36 | extern int run_as_root; | 36 | extern int run_as_root; |
37 | extern int base_cpu; | ||
37 | extern struct bitmask *cpus_chosen; | 38 | extern struct bitmask *cpus_chosen; |
38 | 39 | ||
39 | /* Global verbose (-d) stuff *********************************/ | 40 | /* Global verbose (-d) stuff *********************************/ |
@@ -87,11 +88,11 @@ struct cpupower_cpu_info { | |||
87 | * | 88 | * |
88 | * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo | 89 | * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo |
89 | * | 90 | * |
90 | * Returns 0 on success or a negativ error code | 91 | * Returns 0 on success or a negative error code |
91 | * Only used on x86, below global's struct values are zero/unknown on | 92 | * Only used on x86, below global's struct values are zero/unknown on |
92 | * other archs | 93 | * other archs |
93 | */ | 94 | */ |
94 | extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info); | 95 | extern int get_cpu_info(struct cpupower_cpu_info *cpu_info); |
95 | extern struct cpupower_cpu_info cpupower_cpu_info; | 96 | extern struct cpupower_cpu_info cpupower_cpu_info; |
96 | /* cpuid and cpuinfo helpers **************************/ | 97 | /* cpuid and cpuinfo helpers **************************/ |
97 | 98 | ||
diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c index 601d719d4e60..a5e7ddf19dbd 100644 --- a/tools/power/cpupower/utils/helpers/misc.c +++ b/tools/power/cpupower/utils/helpers/misc.c | |||
@@ -13,7 +13,7 @@ int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active, | |||
13 | 13 | ||
14 | *support = *active = *states = 0; | 14 | *support = *active = *states = 0; |
15 | 15 | ||
16 | ret = get_cpu_info(0, &cpu_info); | 16 | ret = get_cpu_info(&cpu_info); |
17 | if (ret) | 17 | if (ret) |
18 | return ret; | 18 | return ret; |
19 | 19 | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c index ebeaba6571a3..f794d6bbb7e9 100644 --- a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c +++ b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c | |||
@@ -123,7 +123,7 @@ static int hsw_ext_start(void) | |||
123 | previous_count[num][cpu] = val; | 123 | previous_count[num][cpu] = val; |
124 | } | 124 | } |
125 | } | 125 | } |
126 | hsw_ext_get_count(TSC, &tsc_at_measure_start, 0); | 126 | hsw_ext_get_count(TSC, &tsc_at_measure_start, base_cpu); |
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
@@ -132,7 +132,7 @@ static int hsw_ext_stop(void) | |||
132 | unsigned long long val; | 132 | unsigned long long val; |
133 | int num, cpu; | 133 | int num, cpu; |
134 | 134 | ||
135 | hsw_ext_get_count(TSC, &tsc_at_measure_end, 0); | 135 | hsw_ext_get_count(TSC, &tsc_at_measure_end, base_cpu); |
136 | 136 | ||
137 | for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { | 137 | for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { |
138 | for (cpu = 0; cpu < cpu_count; cpu++) { | 138 | for (cpu = 0; cpu < cpu_count; cpu++) { |
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c index c83f1606970b..d7c2a6d13dea 100644 --- a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c | |||
@@ -80,7 +80,8 @@ static int *is_valid; | |||
80 | static int mperf_get_tsc(unsigned long long *tsc) | 80 | static int mperf_get_tsc(unsigned long long *tsc) |
81 | { | 81 | { |
82 | int ret; | 82 | int ret; |
83 | ret = read_msr(0, MSR_TSC, tsc); | 83 | |
84 | ret = read_msr(base_cpu, MSR_TSC, tsc); | ||
84 | if (ret) | 85 | if (ret) |
85 | dprint("Reading TSC MSR failed, returning %llu\n", *tsc); | 86 | dprint("Reading TSC MSR failed, returning %llu\n", *tsc); |
86 | return ret; | 87 | return ret; |
diff --git a/tools/power/cpupower/utils/idle_monitor/nhm_idle.c b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c index d2a91dd0d563..abf8cb5f7349 100644 --- a/tools/power/cpupower/utils/idle_monitor/nhm_idle.c +++ b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c | |||
@@ -129,7 +129,7 @@ static int nhm_start(void) | |||
129 | int num, cpu; | 129 | int num, cpu; |
130 | unsigned long long dbg, val; | 130 | unsigned long long dbg, val; |
131 | 131 | ||
132 | nhm_get_count(TSC, &tsc_at_measure_start, 0); | 132 | nhm_get_count(TSC, &tsc_at_measure_start, base_cpu); |
133 | 133 | ||
134 | for (num = 0; num < NHM_CSTATE_COUNT; num++) { | 134 | for (num = 0; num < NHM_CSTATE_COUNT; num++) { |
135 | for (cpu = 0; cpu < cpu_count; cpu++) { | 135 | for (cpu = 0; cpu < cpu_count; cpu++) { |
@@ -137,7 +137,7 @@ static int nhm_start(void) | |||
137 | previous_count[num][cpu] = val; | 137 | previous_count[num][cpu] = val; |
138 | } | 138 | } |
139 | } | 139 | } |
140 | nhm_get_count(TSC, &dbg, 0); | 140 | nhm_get_count(TSC, &dbg, base_cpu); |
141 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start); | 141 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start); |
142 | return 0; | 142 | return 0; |
143 | } | 143 | } |
@@ -148,7 +148,7 @@ static int nhm_stop(void) | |||
148 | unsigned long long dbg; | 148 | unsigned long long dbg; |
149 | int num, cpu; | 149 | int num, cpu; |
150 | 150 | ||
151 | nhm_get_count(TSC, &tsc_at_measure_end, 0); | 151 | nhm_get_count(TSC, &tsc_at_measure_end, base_cpu); |
152 | 152 | ||
153 | for (num = 0; num < NHM_CSTATE_COUNT; num++) { | 153 | for (num = 0; num < NHM_CSTATE_COUNT; num++) { |
154 | for (cpu = 0; cpu < cpu_count; cpu++) { | 154 | for (cpu = 0; cpu < cpu_count; cpu++) { |
@@ -156,7 +156,7 @@ static int nhm_stop(void) | |||
156 | current_count[num][cpu] = val; | 156 | current_count[num][cpu] = val; |
157 | } | 157 | } |
158 | } | 158 | } |
159 | nhm_get_count(TSC, &dbg, 0); | 159 | nhm_get_count(TSC, &dbg, base_cpu); |
160 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); | 160 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); |
161 | 161 | ||
162 | return 0; | 162 | return 0; |
diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c index efc8a69c9aba..a2b45219648d 100644 --- a/tools/power/cpupower/utils/idle_monitor/snb_idle.c +++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c | |||
@@ -120,7 +120,7 @@ static int snb_start(void) | |||
120 | previous_count[num][cpu] = val; | 120 | previous_count[num][cpu] = val; |
121 | } | 121 | } |
122 | } | 122 | } |
123 | snb_get_count(TSC, &tsc_at_measure_start, 0); | 123 | snb_get_count(TSC, &tsc_at_measure_start, base_cpu); |
124 | return 0; | 124 | return 0; |
125 | } | 125 | } |
126 | 126 | ||
@@ -129,7 +129,7 @@ static int snb_stop(void) | |||
129 | unsigned long long val; | 129 | unsigned long long val; |
130 | int num, cpu; | 130 | int num, cpu; |
131 | 131 | ||
132 | snb_get_count(TSC, &tsc_at_measure_end, 0); | 132 | snb_get_count(TSC, &tsc_at_measure_end, base_cpu); |
133 | 133 | ||
134 | for (num = 0; num < SNB_CSTATE_COUNT; num++) { | 134 | for (num = 0; num < SNB_CSTATE_COUNT; num++) { |
135 | for (cpu = 0; cpu < cpu_count; cpu++) { | 135 | for (cpu = 0; cpu < cpu_count; cpu++) { |
diff --git a/tools/power/pm-graph/Makefile b/tools/power/pm-graph/Makefile index 4d0ccc89e6c6..32f40eacdafe 100644 --- a/tools/power/pm-graph/Makefile +++ b/tools/power/pm-graph/Makefile | |||
@@ -4,7 +4,7 @@ DESTDIR ?= | |||
4 | all: | 4 | all: |
5 | @echo "Nothing to build" | 5 | @echo "Nothing to build" |
6 | 6 | ||
7 | install : | 7 | install : uninstall |
8 | install -d $(DESTDIR)$(PREFIX)/lib/pm-graph | 8 | install -d $(DESTDIR)$(PREFIX)/lib/pm-graph |
9 | install analyze_suspend.py $(DESTDIR)$(PREFIX)/lib/pm-graph | 9 | install analyze_suspend.py $(DESTDIR)$(PREFIX)/lib/pm-graph |
10 | install analyze_boot.py $(DESTDIR)$(PREFIX)/lib/pm-graph | 10 | install analyze_boot.py $(DESTDIR)$(PREFIX)/lib/pm-graph |
@@ -17,12 +17,15 @@ install : | |||
17 | install sleepgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8 | 17 | install sleepgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8 |
18 | 18 | ||
19 | uninstall : | 19 | uninstall : |
20 | rm $(DESTDIR)$(PREFIX)/share/man/man8/bootgraph.8 | 20 | rm -f $(DESTDIR)$(PREFIX)/share/man/man8/bootgraph.8 |
21 | rm $(DESTDIR)$(PREFIX)/share/man/man8/sleepgraph.8 | 21 | rm -f $(DESTDIR)$(PREFIX)/share/man/man8/sleepgraph.8 |
22 | 22 | ||
23 | rm $(DESTDIR)$(PREFIX)/bin/bootgraph | 23 | rm -f $(DESTDIR)$(PREFIX)/bin/bootgraph |
24 | rm $(DESTDIR)$(PREFIX)/bin/sleepgraph | 24 | rm -f $(DESTDIR)$(PREFIX)/bin/sleepgraph |
25 | 25 | ||
26 | rm $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_boot.py | 26 | rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_boot.py |
27 | rm $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_suspend.py | 27 | rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_suspend.py |
28 | rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph | 28 | rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/*.pyc |
29 | if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph ] ; then \ | ||
30 | rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph; \ | ||
31 | fi; | ||
diff --git a/tools/power/pm-graph/analyze_boot.py b/tools/power/pm-graph/analyze_boot.py index 3e1dcbbf1adc..e83df141a597 100755 --- a/tools/power/pm-graph/analyze_boot.py +++ b/tools/power/pm-graph/analyze_boot.py | |||
@@ -42,7 +42,7 @@ import analyze_suspend as aslib | |||
42 | # store system values and test parameters | 42 | # store system values and test parameters |
43 | class SystemValues(aslib.SystemValues): | 43 | class SystemValues(aslib.SystemValues): |
44 | title = 'BootGraph' | 44 | title = 'BootGraph' |
45 | version = 2.0 | 45 | version = '2.1' |
46 | hostname = 'localhost' | 46 | hostname = 'localhost' |
47 | testtime = '' | 47 | testtime = '' |
48 | kernel = '' | 48 | kernel = '' |
@@ -50,9 +50,14 @@ class SystemValues(aslib.SystemValues): | |||
50 | ftracefile = '' | 50 | ftracefile = '' |
51 | htmlfile = 'bootgraph.html' | 51 | htmlfile = 'bootgraph.html' |
52 | outfile = '' | 52 | outfile = '' |
53 | phoronix = False | 53 | testdir = '' |
54 | addlogs = False | 54 | testdirprefix = 'boot' |
55 | embedded = False | ||
56 | testlog = False | ||
57 | dmesglog = False | ||
58 | ftracelog = False | ||
55 | useftrace = False | 59 | useftrace = False |
60 | usecallgraph = False | ||
56 | usedevsrc = True | 61 | usedevsrc = True |
57 | suspendmode = 'boot' | 62 | suspendmode = 'boot' |
58 | max_graph_depth = 2 | 63 | max_graph_depth = 2 |
@@ -61,10 +66,12 @@ class SystemValues(aslib.SystemValues): | |||
61 | manual = False | 66 | manual = False |
62 | iscronjob = False | 67 | iscronjob = False |
63 | timeformat = '%.6f' | 68 | timeformat = '%.6f' |
69 | bootloader = 'grub' | ||
70 | blexec = [] | ||
64 | def __init__(self): | 71 | def __init__(self): |
65 | if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ): | 72 | if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ): |
66 | self.phoronix = True | 73 | self.embedded = True |
67 | self.addlogs = True | 74 | self.dmesglog = True |
68 | self.outfile = os.environ['LOG_FILE'] | 75 | self.outfile = os.environ['LOG_FILE'] |
69 | self.htmlfile = os.environ['LOG_FILE'] | 76 | self.htmlfile = os.environ['LOG_FILE'] |
70 | self.hostname = platform.node() | 77 | self.hostname = platform.node() |
@@ -76,42 +83,80 @@ class SystemValues(aslib.SystemValues): | |||
76 | self.kernel = self.kernelVersion(val) | 83 | self.kernel = self.kernelVersion(val) |
77 | else: | 84 | else: |
78 | self.kernel = 'unknown' | 85 | self.kernel = 'unknown' |
86 | self.testdir = datetime.now().strftime('boot-%y%m%d-%H%M%S') | ||
79 | def kernelVersion(self, msg): | 87 | def kernelVersion(self, msg): |
80 | return msg.split()[2] | 88 | return msg.split()[2] |
89 | def checkFtraceKernelVersion(self): | ||
90 | val = tuple(map(int, self.kernel.split('-')[0].split('.'))) | ||
91 | if val >= (4, 10, 0): | ||
92 | return True | ||
93 | return False | ||
81 | def kernelParams(self): | 94 | def kernelParams(self): |
82 | cmdline = 'initcall_debug log_buf_len=32M' | 95 | cmdline = 'initcall_debug log_buf_len=32M' |
83 | if self.useftrace: | 96 | if self.useftrace: |
84 | cmdline += ' trace_buf_size=128M trace_clock=global '\ | 97 | if self.cpucount > 0: |
98 | bs = min(self.memtotal / 2, 2*1024*1024) / self.cpucount | ||
99 | else: | ||
100 | bs = 131072 | ||
101 | cmdline += ' trace_buf_size=%dK trace_clock=global '\ | ||
85 | 'trace_options=nooverwrite,funcgraph-abstime,funcgraph-cpu,'\ | 102 | 'trace_options=nooverwrite,funcgraph-abstime,funcgraph-cpu,'\ |
86 | 'funcgraph-duration,funcgraph-proc,funcgraph-tail,'\ | 103 | 'funcgraph-duration,funcgraph-proc,funcgraph-tail,'\ |
87 | 'nofuncgraph-overhead,context-info,graph-time '\ | 104 | 'nofuncgraph-overhead,context-info,graph-time '\ |
88 | 'ftrace=function_graph '\ | 105 | 'ftrace=function_graph '\ |
89 | 'ftrace_graph_max_depth=%d '\ | 106 | 'ftrace_graph_max_depth=%d '\ |
90 | 'ftrace_graph_filter=%s' % \ | 107 | 'ftrace_graph_filter=%s' % \ |
91 | (self.max_graph_depth, self.graph_filter) | 108 | (bs, self.max_graph_depth, self.graph_filter) |
92 | return cmdline | 109 | return cmdline |
93 | def setGraphFilter(self, val): | 110 | def setGraphFilter(self, val): |
94 | fp = open(self.tpath+'available_filter_functions') | 111 | master = self.getBootFtraceFilterFunctions() |
95 | master = fp.read().split('\n') | 112 | fs = '' |
96 | fp.close() | ||
97 | for i in val.split(','): | 113 | for i in val.split(','): |
98 | func = i.strip() | 114 | func = i.strip() |
115 | if func == '': | ||
116 | doError('badly formatted filter function string') | ||
117 | if '[' in func or ']' in func: | ||
118 | doError('loadable module functions not allowed - "%s"' % func) | ||
119 | if ' ' in func: | ||
120 | doError('spaces found in filter functions - "%s"' % func) | ||
99 | if func not in master: | 121 | if func not in master: |
100 | doError('function "%s" not available for ftrace' % func) | 122 | doError('function "%s" not available for ftrace' % func) |
101 | self.graph_filter = val | 123 | if not fs: |
124 | fs = func | ||
125 | else: | ||
126 | fs += ','+func | ||
127 | if not fs: | ||
128 | doError('badly formatted filter function string') | ||
129 | self.graph_filter = fs | ||
130 | def getBootFtraceFilterFunctions(self): | ||
131 | self.rootCheck(True) | ||
132 | fp = open(self.tpath+'available_filter_functions') | ||
133 | fulllist = fp.read().split('\n') | ||
134 | fp.close() | ||
135 | list = [] | ||
136 | for i in fulllist: | ||
137 | if not i or ' ' in i or '[' in i or ']' in i: | ||
138 | continue | ||
139 | list.append(i) | ||
140 | return list | ||
141 | def myCronJob(self, line): | ||
142 | if '@reboot' not in line: | ||
143 | return False | ||
144 | if 'bootgraph' in line or 'analyze_boot.py' in line or '-cronjob' in line: | ||
145 | return True | ||
146 | return False | ||
102 | def cronjobCmdString(self): | 147 | def cronjobCmdString(self): |
103 | cmdline = '%s -cronjob' % os.path.abspath(sys.argv[0]) | 148 | cmdline = '%s -cronjob' % os.path.abspath(sys.argv[0]) |
104 | args = iter(sys.argv[1:]) | 149 | args = iter(sys.argv[1:]) |
105 | for arg in args: | 150 | for arg in args: |
106 | if arg in ['-h', '-v', '-cronjob', '-reboot']: | 151 | if arg in ['-h', '-v', '-cronjob', '-reboot']: |
107 | continue | 152 | continue |
108 | elif arg in ['-o', '-dmesg', '-ftrace', '-filter']: | 153 | elif arg in ['-o', '-dmesg', '-ftrace', '-func']: |
109 | args.next() | 154 | args.next() |
110 | continue | 155 | continue |
111 | cmdline += ' '+arg | 156 | cmdline += ' '+arg |
112 | if self.graph_filter != 'do_one_initcall': | 157 | if self.graph_filter != 'do_one_initcall': |
113 | cmdline += ' -filter "%s"' % self.graph_filter | 158 | cmdline += ' -func "%s"' % self.graph_filter |
114 | cmdline += ' -o "%s"' % os.path.abspath(self.htmlfile) | 159 | cmdline += ' -o "%s"' % os.path.abspath(self.testdir) |
115 | return cmdline | 160 | return cmdline |
116 | def manualRebootRequired(self): | 161 | def manualRebootRequired(self): |
117 | cmdline = self.kernelParams() | 162 | cmdline = self.kernelParams() |
@@ -121,6 +166,39 @@ class SystemValues(aslib.SystemValues): | |||
121 | print '3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n' | 166 | print '3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n' |
122 | print 'CMDLINE="%s"' % cmdline | 167 | print 'CMDLINE="%s"' % cmdline |
123 | sys.exit() | 168 | sys.exit() |
169 | def getExec(self, cmd): | ||
170 | dirlist = ['/sbin', '/bin', '/usr/sbin', '/usr/bin', | ||
171 | '/usr/local/sbin', '/usr/local/bin'] | ||
172 | for path in dirlist: | ||
173 | cmdfull = os.path.join(path, cmd) | ||
174 | if os.path.exists(cmdfull): | ||
175 | return cmdfull | ||
176 | return '' | ||
177 | def blGrub(self): | ||
178 | blcmd = '' | ||
179 | for cmd in ['update-grub', 'grub-mkconfig', 'grub2-mkconfig']: | ||
180 | if blcmd: | ||
181 | break | ||
182 | blcmd = self.getExec(cmd) | ||
183 | if not blcmd: | ||
184 | doError('[GRUB] missing update command') | ||
185 | if not os.path.exists('/etc/default/grub'): | ||
186 | doError('[GRUB] missing /etc/default/grub') | ||
187 | if 'grub2' in blcmd: | ||
188 | cfg = '/boot/grub2/grub.cfg' | ||
189 | else: | ||
190 | cfg = '/boot/grub/grub.cfg' | ||
191 | if not os.path.exists(cfg): | ||
192 | doError('[GRUB] missing %s' % cfg) | ||
193 | if 'update-grub' in blcmd: | ||
194 | self.blexec = [blcmd] | ||
195 | else: | ||
196 | self.blexec = [blcmd, '-o', cfg] | ||
197 | def getBootLoader(self): | ||
198 | if self.bootloader == 'grub': | ||
199 | self.blGrub() | ||
200 | else: | ||
201 | doError('unknown boot loader: %s' % self.bootloader) | ||
124 | 202 | ||
125 | sysvals = SystemValues() | 203 | sysvals = SystemValues() |
126 | 204 | ||
@@ -136,20 +214,23 @@ class Data(aslib.Data): | |||
136 | idstr = '' | 214 | idstr = '' |
137 | html_device_id = 0 | 215 | html_device_id = 0 |
138 | valid = False | 216 | valid = False |
139 | initstart = 0.0 | 217 | tUserMode = 0.0 |
140 | boottime = '' | 218 | boottime = '' |
141 | phases = ['boot'] | 219 | phases = ['kernel', 'user'] |
142 | do_one_initcall = False | 220 | do_one_initcall = False |
143 | def __init__(self, num): | 221 | def __init__(self, num): |
144 | self.testnumber = num | 222 | self.testnumber = num |
145 | self.idstr = 'a' | 223 | self.idstr = 'a' |
146 | self.dmesgtext = [] | 224 | self.dmesgtext = [] |
147 | self.dmesg = { | 225 | self.dmesg = { |
148 | 'boot': {'list': dict(), 'start': -1.0, 'end': -1.0, 'row': 0, 'color': '#dddddd'} | 226 | 'kernel': {'list': dict(), 'start': -1.0, 'end': -1.0, 'row': 0, |
227 | 'order': 0, 'color': 'linear-gradient(to bottom, #fff, #bcf)'}, | ||
228 | 'user': {'list': dict(), 'start': -1.0, 'end': -1.0, 'row': 0, | ||
229 | 'order': 1, 'color': '#fff'} | ||
149 | } | 230 | } |
150 | def deviceTopology(self): | 231 | def deviceTopology(self): |
151 | return '' | 232 | return '' |
152 | def newAction(self, phase, name, start, end, ret, ulen): | 233 | def newAction(self, phase, name, pid, start, end, ret, ulen): |
153 | # new device callback for a specific phase | 234 | # new device callback for a specific phase |
154 | self.html_device_id += 1 | 235 | self.html_device_id += 1 |
155 | devid = '%s%d' % (self.idstr, self.html_device_id) | 236 | devid = '%s%d' % (self.idstr, self.html_device_id) |
@@ -163,41 +244,46 @@ class Data(aslib.Data): | |||
163 | name = '%s[%d]' % (origname, i) | 244 | name = '%s[%d]' % (origname, i) |
164 | i += 1 | 245 | i += 1 |
165 | list[name] = {'name': name, 'start': start, 'end': end, | 246 | list[name] = {'name': name, 'start': start, 'end': end, |
166 | 'pid': 0, 'length': length, 'row': 0, 'id': devid, | 247 | 'pid': pid, 'length': length, 'row': 0, 'id': devid, |
167 | 'ret': ret, 'ulen': ulen } | 248 | 'ret': ret, 'ulen': ulen } |
168 | return name | 249 | return name |
169 | def deviceMatch(self, cg): | 250 | def deviceMatch(self, pid, cg): |
170 | if cg.end - cg.start == 0: | 251 | if cg.end - cg.start == 0: |
171 | return True | 252 | return True |
172 | list = self.dmesg['boot']['list'] | 253 | for p in data.phases: |
173 | for devname in list: | 254 | list = self.dmesg[p]['list'] |
174 | dev = list[devname] | 255 | for devname in list: |
175 | if cg.name == 'do_one_initcall': | 256 | dev = list[devname] |
176 | if(cg.start <= dev['start'] and cg.end >= dev['end'] and dev['length'] > 0): | 257 | if pid != dev['pid']: |
177 | dev['ftrace'] = cg | 258 | continue |
178 | self.do_one_initcall = True | 259 | if cg.name == 'do_one_initcall': |
179 | return True | 260 | if(cg.start <= dev['start'] and cg.end >= dev['end'] and dev['length'] > 0): |
180 | else: | 261 | dev['ftrace'] = cg |
181 | if(cg.start > dev['start'] and cg.end < dev['end']): | 262 | self.do_one_initcall = True |
182 | if 'ftraces' not in dev: | 263 | return True |
183 | dev['ftraces'] = [] | 264 | else: |
184 | dev['ftraces'].append(cg) | 265 | if(cg.start > dev['start'] and cg.end < dev['end']): |
185 | return True | 266 | if 'ftraces' not in dev: |
267 | dev['ftraces'] = [] | ||
268 | dev['ftraces'].append(cg) | ||
269 | return True | ||
186 | return False | 270 | return False |
187 | 271 | ||
188 | # ----------------- FUNCTIONS -------------------- | 272 | # ----------------- FUNCTIONS -------------------- |
189 | 273 | ||
190 | # Function: loadKernelLog | 274 | # Function: parseKernelLog |
191 | # Description: | 275 | # Description: |
192 | # Load a raw kernel log from dmesg | 276 | # parse a kernel log for boot data |
193 | def loadKernelLog(): | 277 | def parseKernelLog(): |
278 | phase = 'kernel' | ||
194 | data = Data(0) | 279 | data = Data(0) |
195 | data.dmesg['boot']['start'] = data.start = ktime = 0.0 | 280 | data.dmesg['kernel']['start'] = data.start = ktime = 0.0 |
196 | sysvals.stamp = { | 281 | sysvals.stamp = { |
197 | 'time': datetime.now().strftime('%B %d %Y, %I:%M:%S %p'), | 282 | 'time': datetime.now().strftime('%B %d %Y, %I:%M:%S %p'), |
198 | 'host': sysvals.hostname, | 283 | 'host': sysvals.hostname, |
199 | 'mode': 'boot', 'kernel': ''} | 284 | 'mode': 'boot', 'kernel': ''} |
200 | 285 | ||
286 | tp = aslib.TestProps() | ||
201 | devtemp = dict() | 287 | devtemp = dict() |
202 | if(sysvals.dmesgfile): | 288 | if(sysvals.dmesgfile): |
203 | lf = open(sysvals.dmesgfile, 'r') | 289 | lf = open(sysvals.dmesgfile, 'r') |
@@ -205,6 +291,13 @@ def loadKernelLog(): | |||
205 | lf = Popen('dmesg', stdout=PIPE).stdout | 291 | lf = Popen('dmesg', stdout=PIPE).stdout |
206 | for line in lf: | 292 | for line in lf: |
207 | line = line.replace('\r\n', '') | 293 | line = line.replace('\r\n', '') |
294 | # grab the stamp and sysinfo | ||
295 | if re.match(tp.stampfmt, line): | ||
296 | tp.stamp = line | ||
297 | continue | ||
298 | elif re.match(tp.sysinfofmt, line): | ||
299 | tp.sysinfo = line | ||
300 | continue | ||
208 | idx = line.find('[') | 301 | idx = line.find('[') |
209 | if idx > 1: | 302 | if idx > 1: |
210 | line = line[idx:] | 303 | line = line[idx:] |
@@ -215,7 +308,6 @@ def loadKernelLog(): | |||
215 | if(ktime > 120): | 308 | if(ktime > 120): |
216 | break | 309 | break |
217 | msg = m.group('msg') | 310 | msg = m.group('msg') |
218 | data.end = data.initstart = ktime | ||
219 | data.dmesgtext.append(line) | 311 | data.dmesgtext.append(line) |
220 | if(ktime == 0.0 and re.match('^Linux version .*', msg)): | 312 | if(ktime == 0.0 and re.match('^Linux version .*', msg)): |
221 | if(not sysvals.stamp['kernel']): | 313 | if(not sysvals.stamp['kernel']): |
@@ -228,43 +320,39 @@ def loadKernelLog(): | |||
228 | data.boottime = bt.strftime('%Y-%m-%d_%H:%M:%S') | 320 | data.boottime = bt.strftime('%Y-%m-%d_%H:%M:%S') |
229 | sysvals.stamp['time'] = bt.strftime('%B %d %Y, %I:%M:%S %p') | 321 | sysvals.stamp['time'] = bt.strftime('%B %d %Y, %I:%M:%S %p') |
230 | continue | 322 | continue |
231 | m = re.match('^calling *(?P<f>.*)\+.*', msg) | 323 | m = re.match('^calling *(?P<f>.*)\+.* @ (?P<p>[0-9]*)', msg) |
232 | if(m): | 324 | if(m): |
233 | devtemp[m.group('f')] = ktime | 325 | func = m.group('f') |
326 | pid = int(m.group('p')) | ||
327 | devtemp[func] = (ktime, pid) | ||
234 | continue | 328 | continue |
235 | m = re.match('^initcall *(?P<f>.*)\+.* returned (?P<r>.*) after (?P<t>.*) usecs', msg) | 329 | m = re.match('^initcall *(?P<f>.*)\+.* returned (?P<r>.*) after (?P<t>.*) usecs', msg) |
236 | if(m): | 330 | if(m): |
237 | data.valid = True | 331 | data.valid = True |
332 | data.end = ktime | ||
238 | f, r, t = m.group('f', 'r', 't') | 333 | f, r, t = m.group('f', 'r', 't') |
239 | if(f in devtemp): | 334 | if(f in devtemp): |
240 | data.newAction('boot', f, devtemp[f], ktime, int(r), int(t)) | 335 | start, pid = devtemp[f] |
241 | data.end = ktime | 336 | data.newAction(phase, f, pid, start, ktime, int(r), int(t)) |
242 | del devtemp[f] | 337 | del devtemp[f] |
243 | continue | 338 | continue |
244 | if(re.match('^Freeing unused kernel memory.*', msg)): | 339 | if(re.match('^Freeing unused kernel memory.*', msg)): |
245 | break | 340 | data.tUserMode = ktime |
246 | 341 | data.dmesg['kernel']['end'] = ktime | |
247 | data.dmesg['boot']['end'] = data.end | 342 | data.dmesg['user']['start'] = ktime |
343 | phase = 'user' | ||
344 | |||
345 | if tp.stamp: | ||
346 | sysvals.stamp = 0 | ||
347 | tp.parseStamp(data, sysvals) | ||
348 | data.dmesg['user']['end'] = data.end | ||
248 | lf.close() | 349 | lf.close() |
249 | return data | 350 | return data |
250 | 351 | ||
251 | # Function: loadTraceLog | 352 | # Function: parseTraceLog |
252 | # Description: | 353 | # Description: |
253 | # Check if trace is available and copy to a temp file | 354 | # Check if trace is available and copy to a temp file |
254 | def loadTraceLog(data): | 355 | def parseTraceLog(data): |
255 | # load the data to a temp file if none given | ||
256 | if not sysvals.ftracefile: | ||
257 | lib = aslib.sysvals | ||
258 | aslib.rootCheck(True) | ||
259 | if not lib.verifyFtrace(): | ||
260 | doError('ftrace not available') | ||
261 | if lib.fgetVal('current_tracer').strip() != 'function_graph': | ||
262 | doError('ftrace not configured for a boot callgraph') | ||
263 | sysvals.ftracefile = '/tmp/boot_ftrace.%s.txt' % os.getpid() | ||
264 | call('cat '+lib.tpath+'trace > '+sysvals.ftracefile, shell=True) | ||
265 | if not sysvals.ftracefile: | ||
266 | doError('No trace data available') | ||
267 | |||
268 | # parse the trace log | 356 | # parse the trace log |
269 | ftemp = dict() | 357 | ftemp = dict() |
270 | tp = aslib.TestProps() | 358 | tp = aslib.TestProps() |
@@ -306,9 +394,29 @@ def loadTraceLog(data): | |||
306 | print('Sanity check failed for %s-%d' % (proc, pid)) | 394 | print('Sanity check failed for %s-%d' % (proc, pid)) |
307 | continue | 395 | continue |
308 | # match cg data to devices | 396 | # match cg data to devices |
309 | if not data.deviceMatch(cg): | 397 | if not data.deviceMatch(pid, cg): |
310 | print ' BAD: %s %s-%d [%f - %f]' % (cg.name, proc, pid, cg.start, cg.end) | 398 | print ' BAD: %s %s-%d [%f - %f]' % (cg.name, proc, pid, cg.start, cg.end) |
311 | 399 | ||
400 | # Function: retrieveLogs | ||
401 | # Description: | ||
402 | # Create copies of dmesg and/or ftrace for later processing | ||
403 | def retrieveLogs(): | ||
404 | # check ftrace is configured first | ||
405 | if sysvals.useftrace: | ||
406 | tracer = sysvals.fgetVal('current_tracer').strip() | ||
407 | if tracer != 'function_graph': | ||
408 | doError('ftrace not configured for a boot callgraph') | ||
409 | # create the folder and get dmesg | ||
410 | sysvals.systemInfo(aslib.dmidecode(sysvals.mempath)) | ||
411 | sysvals.initTestOutput('boot') | ||
412 | sysvals.writeDatafileHeader(sysvals.dmesgfile) | ||
413 | call('dmesg >> '+sysvals.dmesgfile, shell=True) | ||
414 | if not sysvals.useftrace: | ||
415 | return | ||
416 | # get ftrace | ||
417 | sysvals.writeDatafileHeader(sysvals.ftracefile) | ||
418 | call('cat '+sysvals.tpath+'trace >> '+sysvals.ftracefile, shell=True) | ||
419 | |||
312 | # Function: colorForName | 420 | # Function: colorForName |
313 | # Description: | 421 | # Description: |
314 | # Generate a repeatable color from a list for a given name | 422 | # Generate a repeatable color from a list for a given name |
@@ -353,18 +461,19 @@ def cgOverview(cg, minlen): | |||
353 | # testruns: array of Data objects from parseKernelLog or parseTraceLog | 461 | # testruns: array of Data objects from parseKernelLog or parseTraceLog |
354 | # Output: | 462 | # Output: |
355 | # True if the html file was created, false if it failed | 463 | # True if the html file was created, false if it failed |
356 | def createBootGraph(data, embedded): | 464 | def createBootGraph(data): |
357 | # html function templates | 465 | # html function templates |
358 | html_srccall = '<div id={6} title="{5}" class="srccall" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;">{0}</div>\n' | 466 | html_srccall = '<div id={6} title="{5}" class="srccall" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;">{0}</div>\n' |
359 | html_timetotal = '<table class="time1">\n<tr>'\ | 467 | html_timetotal = '<table class="time1">\n<tr>'\ |
360 | '<td class="blue">Time from Kernel Boot to start of User Mode: <b>{0} ms</b></td>'\ | 468 | '<td class="blue">Init process starts @ <b>{0} ms</b></td>'\ |
469 | '<td class="blue">Last initcall ends @ <b>{1} ms</b></td>'\ | ||
361 | '</tr>\n</table>\n' | 470 | '</tr>\n</table>\n' |
362 | 471 | ||
363 | # device timeline | 472 | # device timeline |
364 | devtl = aslib.Timeline(100, 20) | 473 | devtl = aslib.Timeline(100, 20) |
365 | 474 | ||
366 | # write the test title and general info header | 475 | # write the test title and general info header |
367 | devtl.createHeader(sysvals, 'noftrace') | 476 | devtl.createHeader(sysvals) |
368 | 477 | ||
369 | # Generate the header for this timeline | 478 | # Generate the header for this timeline |
370 | t0 = data.start | 479 | t0 = data.start |
@@ -373,84 +482,98 @@ def createBootGraph(data, embedded): | |||
373 | if(tTotal == 0): | 482 | if(tTotal == 0): |
374 | print('ERROR: No timeline data') | 483 | print('ERROR: No timeline data') |
375 | return False | 484 | return False |
376 | boot_time = '%.0f'%(tTotal*1000) | 485 | user_mode = '%.0f'%(data.tUserMode*1000) |
377 | devtl.html += html_timetotal.format(boot_time) | 486 | last_init = '%.0f'%(tTotal*1000) |
487 | devtl.html += html_timetotal.format(user_mode, last_init) | ||
378 | 488 | ||
379 | # determine the maximum number of rows we need to draw | 489 | # determine the maximum number of rows we need to draw |
380 | phase = 'boot' | ||
381 | list = data.dmesg[phase]['list'] | ||
382 | devlist = [] | 490 | devlist = [] |
383 | for devname in list: | 491 | for p in data.phases: |
384 | d = aslib.DevItem(0, phase, list[devname]) | 492 | list = data.dmesg[p]['list'] |
385 | devlist.append(d) | 493 | for devname in list: |
386 | devtl.getPhaseRows(devlist) | 494 | d = aslib.DevItem(0, p, list[devname]) |
495 | devlist.append(d) | ||
496 | devtl.getPhaseRows(devlist, 0, 'start') | ||
387 | devtl.calcTotalRows() | 497 | devtl.calcTotalRows() |
388 | 498 | ||
389 | # draw the timeline background | 499 | # draw the timeline background |
390 | devtl.createZoomBox() | 500 | devtl.createZoomBox() |
391 | boot = data.dmesg[phase] | 501 | devtl.html += devtl.html_tblock.format('boot', '0', '100', devtl.scaleH) |
392 | length = boot['end']-boot['start'] | 502 | for p in data.phases: |
393 | left = '%.3f' % (((boot['start']-t0)*100.0)/tTotal) | 503 | phase = data.dmesg[p] |
394 | width = '%.3f' % ((length*100.0)/tTotal) | 504 | length = phase['end']-phase['start'] |
395 | devtl.html += devtl.html_tblock.format(phase, left, width, devtl.scaleH) | 505 | left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal) |
396 | devtl.html += devtl.html_phase.format('0', '100', \ | 506 | width = '%.3f' % ((length*100.0)/tTotal) |
397 | '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ | 507 | devtl.html += devtl.html_phase.format(left, width, \ |
398 | 'white', '') | 508 | '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ |
509 | phase['color'], '') | ||
399 | 510 | ||
400 | # draw the device timeline | 511 | # draw the device timeline |
401 | num = 0 | 512 | num = 0 |
402 | devstats = dict() | 513 | devstats = dict() |
403 | for devname in sorted(list): | 514 | for phase in data.phases: |
404 | cls, color = colorForName(devname) | 515 | list = data.dmesg[phase]['list'] |
405 | dev = list[devname] | 516 | for devname in sorted(list): |
406 | info = '@|%.3f|%.3f|%.3f|%d' % (dev['start']*1000.0, dev['end']*1000.0, | 517 | cls, color = colorForName(devname) |
407 | dev['ulen']/1000.0, dev['ret']) | 518 | dev = list[devname] |
408 | devstats[dev['id']] = {'info':info} | 519 | info = '@|%.3f|%.3f|%.3f|%d' % (dev['start']*1000.0, dev['end']*1000.0, |
409 | dev['color'] = color | 520 | dev['ulen']/1000.0, dev['ret']) |
410 | height = devtl.phaseRowHeight(0, phase, dev['row']) | 521 | devstats[dev['id']] = {'info':info} |
411 | top = '%.6f' % ((dev['row']*height) + devtl.scaleH) | 522 | dev['color'] = color |
412 | left = '%.6f' % (((dev['start']-t0)*100)/tTotal) | 523 | height = devtl.phaseRowHeight(0, phase, dev['row']) |
413 | width = '%.6f' % (((dev['end']-dev['start'])*100)/tTotal) | 524 | top = '%.6f' % ((dev['row']*height) + devtl.scaleH) |
414 | length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000) | 525 | left = '%.6f' % (((dev['start']-t0)*100)/tTotal) |
415 | devtl.html += devtl.html_device.format(dev['id'], | 526 | width = '%.6f' % (((dev['end']-dev['start'])*100)/tTotal) |
416 | devname+length+'kernel_mode', left, top, '%.3f'%height, | 527 | length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000) |
417 | width, devname, ' '+cls, '') | 528 | devtl.html += devtl.html_device.format(dev['id'], |
418 | rowtop = devtl.phaseRowTop(0, phase, dev['row']) | 529 | devname+length+phase+'_mode', left, top, '%.3f'%height, |
419 | height = '%.6f' % (devtl.rowH / 2) | 530 | width, devname, ' '+cls, '') |
420 | top = '%.6f' % (rowtop + devtl.scaleH + (devtl.rowH / 2)) | 531 | rowtop = devtl.phaseRowTop(0, phase, dev['row']) |
421 | if data.do_one_initcall: | 532 | height = '%.6f' % (devtl.rowH / 2) |
422 | if('ftrace' not in dev): | 533 | top = '%.6f' % (rowtop + devtl.scaleH + (devtl.rowH / 2)) |
534 | if data.do_one_initcall: | ||
535 | if('ftrace' not in dev): | ||
536 | continue | ||
537 | cg = dev['ftrace'] | ||
538 | large, stats = cgOverview(cg, 0.001) | ||
539 | devstats[dev['id']]['fstat'] = stats | ||
540 | for l in large: | ||
541 | left = '%f' % (((l.time-t0)*100)/tTotal) | ||
542 | width = '%f' % (l.length*100/tTotal) | ||
543 | title = '%s (%0.3fms)' % (l.name, l.length * 1000.0) | ||
544 | devtl.html += html_srccall.format(l.name, left, | ||
545 | top, height, width, title, 'x%d'%num) | ||
546 | num += 1 | ||
547 | continue | ||
548 | if('ftraces' not in dev): | ||
423 | continue | 549 | continue |
424 | cg = dev['ftrace'] | 550 | for cg in dev['ftraces']: |
425 | large, stats = cgOverview(cg, 0.001) | 551 | left = '%f' % (((cg.start-t0)*100)/tTotal) |
426 | devstats[dev['id']]['fstat'] = stats | 552 | width = '%f' % ((cg.end-cg.start)*100/tTotal) |
427 | for l in large: | 553 | cglen = (cg.end - cg.start) * 1000.0 |
428 | left = '%f' % (((l.time-t0)*100)/tTotal) | 554 | title = '%s (%0.3fms)' % (cg.name, cglen) |
429 | width = '%f' % (l.length*100/tTotal) | 555 | cg.id = 'x%d' % num |
430 | title = '%s (%0.3fms)' % (l.name, l.length * 1000.0) | 556 | devtl.html += html_srccall.format(cg.name, left, |
431 | devtl.html += html_srccall.format(l.name, left, | 557 | top, height, width, title, dev['id']+cg.id) |
432 | top, height, width, title, 'x%d'%num) | ||
433 | num += 1 | 558 | num += 1 |
434 | continue | ||
435 | if('ftraces' not in dev): | ||
436 | continue | ||
437 | for cg in dev['ftraces']: | ||
438 | left = '%f' % (((cg.start-t0)*100)/tTotal) | ||
439 | width = '%f' % ((cg.end-cg.start)*100/tTotal) | ||
440 | cglen = (cg.end - cg.start) * 1000.0 | ||
441 | title = '%s (%0.3fms)' % (cg.name, cglen) | ||
442 | cg.id = 'x%d' % num | ||
443 | devtl.html += html_srccall.format(cg.name, left, | ||
444 | top, height, width, title, dev['id']+cg.id) | ||
445 | num += 1 | ||
446 | 559 | ||
447 | # draw the time scale, try to make the number of labels readable | 560 | # draw the time scale, try to make the number of labels readable |
448 | devtl.createTimeScale(t0, tMax, tTotal, phase) | 561 | devtl.createTimeScale(t0, tMax, tTotal, 'boot') |
449 | devtl.html += '</div>\n' | 562 | devtl.html += '</div>\n' |
450 | 563 | ||
451 | # timeline is finished | 564 | # timeline is finished |
452 | devtl.html += '</div>\n</div>\n' | 565 | devtl.html += '</div>\n</div>\n' |
453 | 566 | ||
567 | # draw a legend which describes the phases by color | ||
568 | devtl.html += '<div class="legend">\n' | ||
569 | pdelta = 20.0 | ||
570 | pmargin = 36.0 | ||
571 | for phase in data.phases: | ||
572 | order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin) | ||
573 | devtl.html += devtl.html_legend.format(order, \ | ||
574 | data.dmesg[phase]['color'], phase+'_mode', phase[0]) | ||
575 | devtl.html += '</div>\n' | ||
576 | |||
454 | if(sysvals.outfile == sysvals.htmlfile): | 577 | if(sysvals.outfile == sysvals.htmlfile): |
455 | hf = open(sysvals.htmlfile, 'a') | 578 | hf = open(sysvals.htmlfile, 'a') |
456 | else: | 579 | else: |
@@ -474,7 +597,7 @@ def createBootGraph(data, embedded): | |||
474 | .fstat td {text-align:left;width:35px;}\n\ | 597 | .fstat td {text-align:left;width:35px;}\n\ |
475 | .srccall {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\ | 598 | .srccall {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\ |
476 | .srccall:hover {color:white;font-weight:bold;border:1px solid white;}\n' | 599 | .srccall:hover {color:white;font-weight:bold;border:1px solid white;}\n' |
477 | if(not embedded): | 600 | if(not sysvals.embedded): |
478 | aslib.addCSS(hf, sysvals, 1, False, extra) | 601 | aslib.addCSS(hf, sysvals, 1, False, extra) |
479 | 602 | ||
480 | # write the device timeline | 603 | # write the device timeline |
@@ -495,9 +618,11 @@ def createBootGraph(data, embedded): | |||
495 | html = \ | 618 | html = \ |
496 | '<div id="devicedetailtitle"></div>\n'\ | 619 | '<div id="devicedetailtitle"></div>\n'\ |
497 | '<div id="devicedetail" style="display:none;">\n'\ | 620 | '<div id="devicedetail" style="display:none;">\n'\ |
498 | '<div id="devicedetail0">\n'\ | 621 | '<div id="devicedetail0">\n' |
499 | '<div id="kernel_mode" class="phaselet" style="left:0%;width:100%;background:#DDDDDD"></div>\n'\ | 622 | for p in data.phases: |
500 | '</div>\n</div>\n'\ | 623 | phase = data.dmesg[p] |
624 | html += devtl.html_phaselet.format(p+'_mode', '0', '100', phase['color']) | ||
625 | html += '</div>\n</div>\n'\ | ||
501 | '<script type="text/javascript">\n'+statinfo+\ | 626 | '<script type="text/javascript">\n'+statinfo+\ |
502 | '</script>\n' | 627 | '</script>\n' |
503 | hf.write(html) | 628 | hf.write(html) |
@@ -507,21 +632,21 @@ def createBootGraph(data, embedded): | |||
507 | aslib.addCallgraphs(sysvals, hf, data) | 632 | aslib.addCallgraphs(sysvals, hf, data) |
508 | 633 | ||
509 | # add the dmesg log as a hidden div | 634 | # add the dmesg log as a hidden div |
510 | if sysvals.addlogs: | 635 | if sysvals.dmesglog: |
511 | hf.write('<div id="dmesglog" style="display:none;">\n') | 636 | hf.write('<div id="dmesglog" style="display:none;">\n') |
512 | for line in data.dmesgtext: | 637 | for line in data.dmesgtext: |
513 | line = line.replace('<', '<').replace('>', '>') | 638 | line = line.replace('<', '<').replace('>', '>') |
514 | hf.write(line) | 639 | hf.write(line) |
515 | hf.write('</div>\n') | 640 | hf.write('</div>\n') |
516 | 641 | ||
517 | if(not embedded): | 642 | if(not sysvals.embedded): |
518 | # write the footer and close | 643 | # write the footer and close |
519 | aslib.addScriptCode(hf, [data]) | 644 | aslib.addScriptCode(hf, [data]) |
520 | hf.write('</body>\n</html>\n') | 645 | hf.write('</body>\n</html>\n') |
521 | else: | 646 | else: |
522 | # embedded out will be loaded in a page, skip the js | 647 | # embedded out will be loaded in a page, skip the js |
523 | hf.write('<div id=bounds style=display:none>%f,%f</div>' % \ | 648 | hf.write('<div id=bounds style=display:none>%f,%f</div>' % \ |
524 | (data.start*1000, data.initstart*1000)) | 649 | (data.start*1000, data.end*1000)) |
525 | hf.close() | 650 | hf.close() |
526 | return True | 651 | return True |
527 | 652 | ||
@@ -533,17 +658,20 @@ def updateCron(restore=False): | |||
533 | if not restore: | 658 | if not restore: |
534 | sysvals.rootUser(True) | 659 | sysvals.rootUser(True) |
535 | crondir = '/var/spool/cron/crontabs/' | 660 | crondir = '/var/spool/cron/crontabs/' |
536 | cronfile = crondir+'root' | 661 | if not os.path.exists(crondir): |
537 | backfile = crondir+'root-analyze_boot-backup' | 662 | crondir = '/var/spool/cron/' |
538 | if not os.path.exists(crondir): | 663 | if not os.path.exists(crondir): |
539 | doError('%s not found' % crondir) | 664 | doError('%s not found' % crondir) |
540 | out = Popen(['which', 'crontab'], stdout=PIPE).stdout.read() | 665 | cronfile = crondir+'root' |
541 | if not out: | 666 | backfile = crondir+'root-analyze_boot-backup' |
667 | cmd = sysvals.getExec('crontab') | ||
668 | if not cmd: | ||
542 | doError('crontab not found') | 669 | doError('crontab not found') |
543 | # on restore: move the backup cron back into place | 670 | # on restore: move the backup cron back into place |
544 | if restore: | 671 | if restore: |
545 | if os.path.exists(backfile): | 672 | if os.path.exists(backfile): |
546 | shutil.move(backfile, cronfile) | 673 | shutil.move(backfile, cronfile) |
674 | call([cmd, cronfile]) | ||
547 | return | 675 | return |
548 | # backup current cron and install new one with reboot | 676 | # backup current cron and install new one with reboot |
549 | if os.path.exists(cronfile): | 677 | if os.path.exists(cronfile): |
@@ -556,13 +684,13 @@ def updateCron(restore=False): | |||
556 | fp = open(backfile, 'r') | 684 | fp = open(backfile, 'r') |
557 | op = open(cronfile, 'w') | 685 | op = open(cronfile, 'w') |
558 | for line in fp: | 686 | for line in fp: |
559 | if '@reboot' not in line: | 687 | if not sysvals.myCronJob(line): |
560 | op.write(line) | 688 | op.write(line) |
561 | continue | 689 | continue |
562 | fp.close() | 690 | fp.close() |
563 | op.write('@reboot python %s\n' % sysvals.cronjobCmdString()) | 691 | op.write('@reboot python %s\n' % sysvals.cronjobCmdString()) |
564 | op.close() | 692 | op.close() |
565 | res = call('crontab %s' % cronfile, shell=True) | 693 | res = call([cmd, cronfile]) |
566 | except Exception, e: | 694 | except Exception, e: |
567 | print 'Exception: %s' % str(e) | 695 | print 'Exception: %s' % str(e) |
568 | shutil.move(backfile, cronfile) | 696 | shutil.move(backfile, cronfile) |
@@ -577,25 +705,16 @@ def updateGrub(restore=False): | |||
577 | # call update-grub on restore | 705 | # call update-grub on restore |
578 | if restore: | 706 | if restore: |
579 | try: | 707 | try: |
580 | call(['update-grub'], stderr=PIPE, stdout=PIPE, | 708 | call(sysvals.blexec, stderr=PIPE, stdout=PIPE, |
581 | env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'}) | 709 | env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'}) |
582 | except Exception, e: | 710 | except Exception, e: |
583 | print 'Exception: %s\n' % str(e) | 711 | print 'Exception: %s\n' % str(e) |
584 | return | 712 | return |
585 | # verify we can do this | ||
586 | sysvals.rootUser(True) | ||
587 | grubfile = '/etc/default/grub' | ||
588 | if not os.path.exists(grubfile): | ||
589 | print 'ERROR: Unable to set the kernel parameters via grub.\n' | ||
590 | sysvals.manualRebootRequired() | ||
591 | out = Popen(['which', 'update-grub'], stdout=PIPE).stdout.read() | ||
592 | if not out: | ||
593 | print 'ERROR: Unable to set the kernel parameters via grub.\n' | ||
594 | sysvals.manualRebootRequired() | ||
595 | |||
596 | # extract the option and create a grub config without it | 713 | # extract the option and create a grub config without it |
714 | sysvals.rootUser(True) | ||
597 | tgtopt = 'GRUB_CMDLINE_LINUX_DEFAULT' | 715 | tgtopt = 'GRUB_CMDLINE_LINUX_DEFAULT' |
598 | cmdline = '' | 716 | cmdline = '' |
717 | grubfile = '/etc/default/grub' | ||
599 | tempfile = '/etc/default/grub.analyze_boot' | 718 | tempfile = '/etc/default/grub.analyze_boot' |
600 | shutil.move(grubfile, tempfile) | 719 | shutil.move(grubfile, tempfile) |
601 | res = -1 | 720 | res = -1 |
@@ -622,7 +741,7 @@ def updateGrub(restore=False): | |||
622 | # if the target option value is in quotes, strip them | 741 | # if the target option value is in quotes, strip them |
623 | sp = '"' | 742 | sp = '"' |
624 | val = cmdline.strip() | 743 | val = cmdline.strip() |
625 | if val[0] == '\'' or val[0] == '"': | 744 | if val and (val[0] == '\'' or val[0] == '"'): |
626 | sp = val[0] | 745 | sp = val[0] |
627 | val = val.strip(sp) | 746 | val = val.strip(sp) |
628 | cmdline = val | 747 | cmdline = val |
@@ -633,7 +752,7 @@ def updateGrub(restore=False): | |||
633 | # write out the updated target option | 752 | # write out the updated target option |
634 | op.write('\n%s=%s%s%s\n' % (tgtopt, sp, cmdline, sp)) | 753 | op.write('\n%s=%s%s%s\n' % (tgtopt, sp, cmdline, sp)) |
635 | op.close() | 754 | op.close() |
636 | res = call('update-grub') | 755 | res = call(sysvals.blexec) |
637 | os.remove(grubfile) | 756 | os.remove(grubfile) |
638 | except Exception, e: | 757 | except Exception, e: |
639 | print 'Exception: %s' % str(e) | 758 | print 'Exception: %s' % str(e) |
@@ -641,10 +760,18 @@ def updateGrub(restore=False): | |||
641 | # cleanup | 760 | # cleanup |
642 | shutil.move(tempfile, grubfile) | 761 | shutil.move(tempfile, grubfile) |
643 | if res != 0: | 762 | if res != 0: |
644 | doError('update-grub failed') | 763 | doError('update grub failed') |
645 | 764 | ||
646 | # Function: doError | 765 | # Function: updateKernelParams |
647 | # Description: | 766 | # Description: |
767 | # update boot conf for all kernels with our parameters | ||
768 | def updateKernelParams(restore=False): | ||
769 | # find the boot loader | ||
770 | sysvals.getBootLoader() | ||
771 | if sysvals.bootloader == 'grub': | ||
772 | updateGrub(restore) | ||
773 | |||
774 | # Function: doError Description: | ||
648 | # generic error function for catastrphic failures | 775 | # generic error function for catastrphic failures |
649 | # Arguments: | 776 | # Arguments: |
650 | # msg: the error message to print | 777 | # msg: the error message to print |
@@ -660,7 +787,7 @@ def doError(msg, help=False): | |||
660 | # print out the help text | 787 | # print out the help text |
661 | def printHelp(): | 788 | def printHelp(): |
662 | print('') | 789 | print('') |
663 | print('%s v%.1f' % (sysvals.title, sysvals.version)) | 790 | print('%s v%s' % (sysvals.title, sysvals.version)) |
664 | print('Usage: bootgraph <options> <command>') | 791 | print('Usage: bootgraph <options> <command>') |
665 | print('') | 792 | print('') |
666 | print('Description:') | 793 | print('Description:') |
@@ -669,13 +796,19 @@ def printHelp(): | |||
669 | print(' the start of the init process.') | 796 | print(' the start of the init process.') |
670 | print('') | 797 | print('') |
671 | print(' If no specific command is given the tool reads the current dmesg') | 798 | print(' If no specific command is given the tool reads the current dmesg') |
672 | print(' and/or ftrace log and outputs bootgraph.html') | 799 | print(' and/or ftrace log and creates a timeline') |
800 | print('') | ||
801 | print(' Generates output files in subdirectory: boot-yymmdd-HHMMSS') | ||
802 | print(' HTML output: <hostname>_boot.html') | ||
803 | print(' raw dmesg output: <hostname>_boot_dmesg.txt') | ||
804 | print(' raw ftrace output: <hostname>_boot_ftrace.txt') | ||
673 | print('') | 805 | print('') |
674 | print('Options:') | 806 | print('Options:') |
675 | print(' -h Print this help text') | 807 | print(' -h Print this help text') |
676 | print(' -v Print the current tool version') | 808 | print(' -v Print the current tool version') |
677 | print(' -addlogs Add the dmesg log to the html output') | 809 | print(' -addlogs Add the dmesg log to the html output') |
678 | print(' -o file Html timeline name (default: bootgraph.html)') | 810 | print(' -o name Overrides the output subdirectory name when running a new test') |
811 | print(' default: boot-{date}-{time}') | ||
679 | print(' [advanced]') | 812 | print(' [advanced]') |
680 | print(' -f Use ftrace to add function detail (default: disabled)') | 813 | print(' -f Use ftrace to add function detail (default: disabled)') |
681 | print(' -callgraph Add callgraph detail, can be very large (default: disabled)') | 814 | print(' -callgraph Add callgraph detail, can be very large (default: disabled)') |
@@ -683,13 +816,18 @@ def printHelp(): | |||
683 | print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)') | 816 | print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)') |
684 | print(' -timeprec N Number of significant digits in timestamps (0:S, 3:ms, [6:us])') | 817 | print(' -timeprec N Number of significant digits in timestamps (0:S, 3:ms, [6:us])') |
685 | print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)') | 818 | print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)') |
686 | print(' -filter list Limit ftrace to comma-delimited list of functions (default: do_one_initcall)') | 819 | print(' -func list Limit ftrace to comma-delimited list of functions (default: do_one_initcall)') |
687 | print(' [commands]') | 820 | print(' -cgfilter S Filter the callgraph output in the timeline') |
821 | print(' -bl name Use the following boot loader for kernel params (default: grub)') | ||
688 | print(' -reboot Reboot the machine automatically and generate a new timeline') | 822 | print(' -reboot Reboot the machine automatically and generate a new timeline') |
689 | print(' -manual Show the requirements to generate a new timeline manually') | 823 | print(' -manual Show the steps to generate a new timeline manually (used with -reboot)') |
690 | print(' -dmesg file Load a stored dmesg file (used with -ftrace)') | 824 | print('') |
691 | print(' -ftrace file Load a stored ftrace file (used with -dmesg)') | 825 | print('Other commands:') |
692 | print(' -flistall Print all functions capable of being captured in ftrace') | 826 | print(' -flistall Print all functions capable of being captured in ftrace') |
827 | print(' -sysinfo Print out system info extracted from BIOS') | ||
828 | print(' [redo]') | ||
829 | print(' -dmesg file Create HTML output using dmesg input (used with -ftrace)') | ||
830 | print(' -ftrace file Create HTML output using ftrace input (used with -dmesg)') | ||
693 | print('') | 831 | print('') |
694 | return True | 832 | return True |
695 | 833 | ||
@@ -698,14 +836,15 @@ def printHelp(): | |||
698 | if __name__ == '__main__': | 836 | if __name__ == '__main__': |
699 | # loop through the command line arguments | 837 | # loop through the command line arguments |
700 | cmd = '' | 838 | cmd = '' |
701 | simplecmds = ['-updategrub', '-flistall'] | 839 | testrun = True |
840 | simplecmds = ['-sysinfo', '-kpupdate', '-flistall', '-checkbl'] | ||
702 | args = iter(sys.argv[1:]) | 841 | args = iter(sys.argv[1:]) |
703 | for arg in args: | 842 | for arg in args: |
704 | if(arg == '-h'): | 843 | if(arg == '-h'): |
705 | printHelp() | 844 | printHelp() |
706 | sys.exit() | 845 | sys.exit() |
707 | elif(arg == '-v'): | 846 | elif(arg == '-v'): |
708 | print("Version %.1f" % sysvals.version) | 847 | print("Version %s" % sysvals.version) |
709 | sys.exit() | 848 | sys.exit() |
710 | elif(arg in simplecmds): | 849 | elif(arg in simplecmds): |
711 | cmd = arg[1:] | 850 | cmd = arg[1:] |
@@ -716,16 +855,32 @@ if __name__ == '__main__': | |||
716 | sysvals.usecallgraph = True | 855 | sysvals.usecallgraph = True |
717 | elif(arg == '-mincg'): | 856 | elif(arg == '-mincg'): |
718 | sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0) | 857 | sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0) |
858 | elif(arg == '-cgfilter'): | ||
859 | try: | ||
860 | val = args.next() | ||
861 | except: | ||
862 | doError('No callgraph functions supplied', True) | ||
863 | sysvals.setDeviceFilter(val) | ||
864 | elif(arg == '-bl'): | ||
865 | try: | ||
866 | val = args.next() | ||
867 | except: | ||
868 | doError('No boot loader name supplied', True) | ||
869 | if val.lower() not in ['grub']: | ||
870 | doError('Unknown boot loader: %s' % val, True) | ||
871 | sysvals.bootloader = val.lower() | ||
719 | elif(arg == '-timeprec'): | 872 | elif(arg == '-timeprec'): |
720 | sysvals.setPrecision(aslib.getArgInt('-timeprec', args, 0, 6)) | 873 | sysvals.setPrecision(aslib.getArgInt('-timeprec', args, 0, 6)) |
721 | elif(arg == '-maxdepth'): | 874 | elif(arg == '-maxdepth'): |
722 | sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000) | 875 | sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000) |
723 | elif(arg == '-filter'): | 876 | elif(arg == '-func'): |
724 | try: | 877 | try: |
725 | val = args.next() | 878 | val = args.next() |
726 | except: | 879 | except: |
727 | doError('No filter functions supplied', True) | 880 | doError('No filter functions supplied', True) |
728 | aslib.rootCheck(True) | 881 | sysvals.useftrace = True |
882 | sysvals.usecallgraph = True | ||
883 | sysvals.rootCheck(True) | ||
729 | sysvals.setGraphFilter(val) | 884 | sysvals.setGraphFilter(val) |
730 | elif(arg == '-ftrace'): | 885 | elif(arg == '-ftrace'): |
731 | try: | 886 | try: |
@@ -734,9 +889,10 @@ if __name__ == '__main__': | |||
734 | doError('No ftrace file supplied', True) | 889 | doError('No ftrace file supplied', True) |
735 | if(os.path.exists(val) == False): | 890 | if(os.path.exists(val) == False): |
736 | doError('%s does not exist' % val) | 891 | doError('%s does not exist' % val) |
892 | testrun = False | ||
737 | sysvals.ftracefile = val | 893 | sysvals.ftracefile = val |
738 | elif(arg == '-addlogs'): | 894 | elif(arg == '-addlogs'): |
739 | sysvals.addlogs = True | 895 | sysvals.dmesglog = True |
740 | elif(arg == '-expandcg'): | 896 | elif(arg == '-expandcg'): |
741 | sysvals.cgexp = True | 897 | sysvals.cgexp = True |
742 | elif(arg == '-dmesg'): | 898 | elif(arg == '-dmesg'): |
@@ -748,18 +904,15 @@ if __name__ == '__main__': | |||
748 | doError('%s does not exist' % val) | 904 | doError('%s does not exist' % val) |
749 | if(sysvals.htmlfile == val or sysvals.outfile == val): | 905 | if(sysvals.htmlfile == val or sysvals.outfile == val): |
750 | doError('Output filename collision') | 906 | doError('Output filename collision') |
907 | testrun = False | ||
751 | sysvals.dmesgfile = val | 908 | sysvals.dmesgfile = val |
752 | elif(arg == '-o'): | 909 | elif(arg == '-o'): |
753 | try: | 910 | try: |
754 | val = args.next() | 911 | val = args.next() |
755 | except: | 912 | except: |
756 | doError('No HTML filename supplied', True) | 913 | doError('No subdirectory name supplied', True) |
757 | if(sysvals.dmesgfile == val or sysvals.ftracefile == val): | 914 | sysvals.testdir = sysvals.setOutputFolder(val) |
758 | doError('Output filename collision') | ||
759 | sysvals.htmlfile = val | ||
760 | elif(arg == '-reboot'): | 915 | elif(arg == '-reboot'): |
761 | if sysvals.iscronjob: | ||
762 | doError('-reboot and -cronjob are incompatible') | ||
763 | sysvals.reboot = True | 916 | sysvals.reboot = True |
764 | elif(arg == '-manual'): | 917 | elif(arg == '-manual'): |
765 | sysvals.reboot = True | 918 | sysvals.reboot = True |
@@ -767,58 +920,93 @@ if __name__ == '__main__': | |||
767 | # remaining options are only for cron job use | 920 | # remaining options are only for cron job use |
768 | elif(arg == '-cronjob'): | 921 | elif(arg == '-cronjob'): |
769 | sysvals.iscronjob = True | 922 | sysvals.iscronjob = True |
770 | if sysvals.reboot: | ||
771 | doError('-reboot and -cronjob are incompatible') | ||
772 | else: | 923 | else: |
773 | doError('Invalid argument: '+arg, True) | 924 | doError('Invalid argument: '+arg, True) |
774 | 925 | ||
926 | # compatibility errors and access checks | ||
927 | if(sysvals.iscronjob and (sysvals.reboot or \ | ||
928 | sysvals.dmesgfile or sysvals.ftracefile or cmd)): | ||
929 | doError('-cronjob is meant for batch purposes only') | ||
930 | if(sysvals.reboot and (sysvals.dmesgfile or sysvals.ftracefile)): | ||
931 | doError('-reboot and -dmesg/-ftrace are incompatible') | ||
932 | if cmd or sysvals.reboot or sysvals.iscronjob or testrun: | ||
933 | sysvals.rootCheck(True) | ||
934 | if (testrun and sysvals.useftrace) or cmd == 'flistall': | ||
935 | if not sysvals.verifyFtrace(): | ||
936 | doError('Ftrace is not properly enabled') | ||
937 | |||
938 | # run utility commands | ||
939 | sysvals.cpuInfo() | ||
775 | if cmd != '': | 940 | if cmd != '': |
776 | if cmd == 'updategrub': | 941 | if cmd == 'kpupdate': |
777 | updateGrub() | 942 | updateKernelParams() |
778 | elif cmd == 'flistall': | 943 | elif cmd == 'flistall': |
779 | sysvals.getFtraceFilterFunctions(False) | 944 | for f in sysvals.getBootFtraceFilterFunctions(): |
945 | print f | ||
946 | elif cmd == 'checkbl': | ||
947 | sysvals.getBootLoader() | ||
948 | print 'Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec) | ||
949 | elif(cmd == 'sysinfo'): | ||
950 | sysvals.printSystemInfo() | ||
780 | sys.exit() | 951 | sys.exit() |
781 | 952 | ||
782 | # update grub, setup a cronjob, and reboot | 953 | # reboot: update grub, setup a cronjob, and reboot |
783 | if sysvals.reboot: | 954 | if sysvals.reboot: |
955 | if (sysvals.useftrace or sysvals.usecallgraph) and \ | ||
956 | not sysvals.checkFtraceKernelVersion(): | ||
957 | doError('Ftrace functionality requires kernel v4.10 or newer') | ||
784 | if not sysvals.manual: | 958 | if not sysvals.manual: |
785 | updateGrub() | 959 | updateKernelParams() |
786 | updateCron() | 960 | updateCron() |
787 | call('reboot') | 961 | call('reboot') |
788 | else: | 962 | else: |
789 | sysvals.manualRebootRequired() | 963 | sysvals.manualRebootRequired() |
790 | sys.exit() | 964 | sys.exit() |
791 | 965 | ||
792 | # disable the cronjob | 966 | # cronjob: remove the cronjob, grub changes, and disable ftrace |
793 | if sysvals.iscronjob: | 967 | if sysvals.iscronjob: |
794 | updateCron(True) | 968 | updateCron(True) |
795 | updateGrub(True) | 969 | updateKernelParams(True) |
970 | try: | ||
971 | sysvals.fsetVal('0', 'tracing_on') | ||
972 | except: | ||
973 | pass | ||
796 | 974 | ||
797 | data = loadKernelLog() | 975 | # testrun: generate copies of the logs |
798 | if sysvals.useftrace: | 976 | if testrun: |
799 | loadTraceLog(data) | 977 | retrieveLogs() |
800 | if sysvals.iscronjob: | 978 | else: |
801 | try: | 979 | sysvals.setOutputFile() |
802 | sysvals.fsetVal('0', 'tracing_on') | ||
803 | except: | ||
804 | pass | ||
805 | 980 | ||
806 | if(sysvals.outfile and sysvals.phoronix): | 981 | # process the log data |
807 | fp = open(sysvals.outfile, 'w') | 982 | if sysvals.dmesgfile: |
808 | fp.write('pass %s initstart %.3f end %.3f boot %s\n' % | 983 | data = parseKernelLog() |
809 | (data.valid, data.initstart*1000, data.end*1000, data.boottime)) | 984 | if(not data.valid): |
810 | fp.close() | ||
811 | if(not data.valid): | ||
812 | if sysvals.dmesgfile: | ||
813 | doError('No initcall data found in %s' % sysvals.dmesgfile) | 985 | doError('No initcall data found in %s' % sysvals.dmesgfile) |
814 | else: | 986 | if sysvals.useftrace and sysvals.ftracefile: |
815 | doError('No initcall data found, is initcall_debug enabled?') | 987 | parseTraceLog(data) |
988 | else: | ||
989 | doError('dmesg file required') | ||
816 | 990 | ||
817 | print(' Host: %s' % sysvals.hostname) | 991 | print(' Host: %s' % sysvals.hostname) |
818 | print(' Test time: %s' % sysvals.testtime) | 992 | print(' Test time: %s' % sysvals.testtime) |
819 | print(' Boot time: %s' % data.boottime) | 993 | print(' Boot time: %s' % data.boottime) |
820 | print('Kernel Version: %s' % sysvals.kernel) | 994 | print('Kernel Version: %s' % sysvals.kernel) |
821 | print(' Kernel start: %.3f' % (data.start * 1000)) | 995 | print(' Kernel start: %.3f' % (data.start * 1000)) |
822 | print(' init start: %.3f' % (data.initstart * 1000)) | 996 | print('Usermode start: %.3f' % (data.tUserMode * 1000)) |
997 | print('Last Init Call: %.3f' % (data.end * 1000)) | ||
998 | |||
999 | # handle embedded output logs | ||
1000 | if(sysvals.outfile and sysvals.embedded): | ||
1001 | fp = open(sysvals.outfile, 'w') | ||
1002 | fp.write('pass %s initstart %.3f end %.3f boot %s\n' % | ||
1003 | (data.valid, data.tUserMode*1000, data.end*1000, data.boottime)) | ||
1004 | fp.close() | ||
1005 | |||
1006 | createBootGraph(data) | ||
823 | 1007 | ||
824 | createBootGraph(data, sysvals.phoronix) | 1008 | # if running as root, change output dir owner to sudo_user |
1009 | if testrun and os.path.isdir(sysvals.testdir) and \ | ||
1010 | os.getuid() == 0 and 'SUDO_USER' in os.environ: | ||
1011 | cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' | ||
1012 | call(cmd.format(os.environ['SUDO_USER'], sysvals.testdir), shell=True) | ||
diff --git a/tools/power/pm-graph/analyze_suspend.py b/tools/power/pm-graph/analyze_suspend.py index a9206e67fc1f..1b60fe203741 100755 --- a/tools/power/pm-graph/analyze_suspend.py +++ b/tools/power/pm-graph/analyze_suspend.py | |||
@@ -68,10 +68,12 @@ from subprocess import call, Popen, PIPE | |||
68 | # store system values and test parameters | 68 | # store system values and test parameters |
69 | class SystemValues: | 69 | class SystemValues: |
70 | title = 'SleepGraph' | 70 | title = 'SleepGraph' |
71 | version = '4.6' | 71 | version = '4.7' |
72 | ansi = False | 72 | ansi = False |
73 | verbose = False | 73 | verbose = False |
74 | addlogs = False | 74 | testlog = True |
75 | dmesglog = False | ||
76 | ftracelog = False | ||
75 | mindevlen = 0.0 | 77 | mindevlen = 0.0 |
76 | mincglen = 0.0 | 78 | mincglen = 0.0 |
77 | cgphase = '' | 79 | cgphase = '' |
@@ -79,10 +81,11 @@ class SystemValues: | |||
79 | max_graph_depth = 0 | 81 | max_graph_depth = 0 |
80 | callloopmaxgap = 0.0001 | 82 | callloopmaxgap = 0.0001 |
81 | callloopmaxlen = 0.005 | 83 | callloopmaxlen = 0.005 |
84 | cpucount = 0 | ||
85 | memtotal = 204800 | ||
82 | srgap = 0 | 86 | srgap = 0 |
83 | cgexp = False | 87 | cgexp = False |
84 | outdir = '' | 88 | testdir = '' |
85 | testdir = '.' | ||
86 | tpath = '/sys/kernel/debug/tracing/' | 89 | tpath = '/sys/kernel/debug/tracing/' |
87 | fpdtpath = '/sys/firmware/acpi/tables/FPDT' | 90 | fpdtpath = '/sys/firmware/acpi/tables/FPDT' |
88 | epath = '/sys/kernel/debug/tracing/events/power/' | 91 | epath = '/sys/kernel/debug/tracing/events/power/' |
@@ -95,14 +98,17 @@ class SystemValues: | |||
95 | testcommand = '' | 98 | testcommand = '' |
96 | mempath = '/dev/mem' | 99 | mempath = '/dev/mem' |
97 | powerfile = '/sys/power/state' | 100 | powerfile = '/sys/power/state' |
101 | mempowerfile = '/sys/power/mem_sleep' | ||
98 | suspendmode = 'mem' | 102 | suspendmode = 'mem' |
103 | memmode = '' | ||
99 | hostname = 'localhost' | 104 | hostname = 'localhost' |
100 | prefix = 'test' | 105 | prefix = 'test' |
101 | teststamp = '' | 106 | teststamp = '' |
107 | sysstamp = '' | ||
102 | dmesgstart = 0.0 | 108 | dmesgstart = 0.0 |
103 | dmesgfile = '' | 109 | dmesgfile = '' |
104 | ftracefile = '' | 110 | ftracefile = '' |
105 | htmlfile = '' | 111 | htmlfile = 'output.html' |
106 | embedded = False | 112 | embedded = False |
107 | rtcwake = True | 113 | rtcwake = True |
108 | rtcwaketime = 15 | 114 | rtcwaketime = 15 |
@@ -127,9 +133,6 @@ class SystemValues: | |||
127 | devpropfmt = '# Device Properties: .*' | 133 | devpropfmt = '# Device Properties: .*' |
128 | tracertypefmt = '# tracer: (?P<t>.*)' | 134 | tracertypefmt = '# tracer: (?P<t>.*)' |
129 | firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' | 135 | firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' |
130 | stampfmt = '# suspend-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ | ||
131 | '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ | ||
132 | ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' | ||
133 | tracefuncs = { | 136 | tracefuncs = { |
134 | 'sys_sync': dict(), | 137 | 'sys_sync': dict(), |
135 | 'pm_prepare_console': dict(), | 138 | 'pm_prepare_console': dict(), |
@@ -218,7 +221,7 @@ class SystemValues: | |||
218 | # if this is a phoronix test run, set some default options | 221 | # if this is a phoronix test run, set some default options |
219 | if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ): | 222 | if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ): |
220 | self.embedded = True | 223 | self.embedded = True |
221 | self.addlogs = True | 224 | self.dmesglog = self.ftracelog = True |
222 | self.htmlfile = os.environ['LOG_FILE'] | 225 | self.htmlfile = os.environ['LOG_FILE'] |
223 | self.archargs = 'args_'+platform.machine() | 226 | self.archargs = 'args_'+platform.machine() |
224 | self.hostname = platform.node() | 227 | self.hostname = platform.node() |
@@ -233,6 +236,13 @@ class SystemValues: | |||
233 | self.rtcpath = rtc | 236 | self.rtcpath = rtc |
234 | if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): | 237 | if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): |
235 | self.ansi = True | 238 | self.ansi = True |
239 | self.testdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S') | ||
240 | def rootCheck(self, fatal=True): | ||
241 | if(os.access(self.powerfile, os.W_OK)): | ||
242 | return True | ||
243 | if fatal: | ||
244 | doError('This command requires sysfs mount and root access') | ||
245 | return False | ||
236 | def rootUser(self, fatal=False): | 246 | def rootUser(self, fatal=False): |
237 | if 'USER' in os.environ and os.environ['USER'] == 'root': | 247 | if 'USER' in os.environ and os.environ['USER'] == 'root': |
238 | return True | 248 | return True |
@@ -249,30 +259,60 @@ class SystemValues: | |||
249 | args['date'] = n.strftime('%y%m%d') | 259 | args['date'] = n.strftime('%y%m%d') |
250 | args['time'] = n.strftime('%H%M%S') | 260 | args['time'] = n.strftime('%H%M%S') |
251 | args['hostname'] = self.hostname | 261 | args['hostname'] = self.hostname |
252 | self.outdir = value.format(**args) | 262 | return value.format(**args) |
253 | def setOutputFile(self): | 263 | def setOutputFile(self): |
254 | if((self.htmlfile == '') and (self.dmesgfile != '')): | 264 | if self.dmesgfile != '': |
255 | m = re.match('(?P<name>.*)_dmesg\.txt$', self.dmesgfile) | 265 | m = re.match('(?P<name>.*)_dmesg\.txt$', self.dmesgfile) |
256 | if(m): | 266 | if(m): |
257 | self.htmlfile = m.group('name')+'.html' | 267 | self.htmlfile = m.group('name')+'.html' |
258 | if((self.htmlfile == '') and (self.ftracefile != '')): | 268 | if self.ftracefile != '': |
259 | m = re.match('(?P<name>.*)_ftrace\.txt$', self.ftracefile) | 269 | m = re.match('(?P<name>.*)_ftrace\.txt$', self.ftracefile) |
260 | if(m): | 270 | if(m): |
261 | self.htmlfile = m.group('name')+'.html' | 271 | self.htmlfile = m.group('name')+'.html' |
262 | if(self.htmlfile == ''): | 272 | def systemInfo(self, info): |
263 | self.htmlfile = 'output.html' | 273 | p = c = m = b = '' |
264 | def initTestOutput(self, subdir, testpath=''): | 274 | if 'baseboard-manufacturer' in info: |
275 | m = info['baseboard-manufacturer'] | ||
276 | elif 'system-manufacturer' in info: | ||
277 | m = info['system-manufacturer'] | ||
278 | if 'baseboard-product-name' in info: | ||
279 | p = info['baseboard-product-name'] | ||
280 | elif 'system-product-name' in info: | ||
281 | p = info['system-product-name'] | ||
282 | if 'processor-version' in info: | ||
283 | c = info['processor-version'] | ||
284 | if 'bios-version' in info: | ||
285 | b = info['bios-version'] | ||
286 | self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | numcpu:%d | memsz:%d' % \ | ||
287 | (m, p, c, b, self.cpucount, self.memtotal) | ||
288 | def printSystemInfo(self): | ||
289 | self.rootCheck(True) | ||
290 | out = dmidecode(self.mempath, True) | ||
291 | fmt = '%-24s: %s' | ||
292 | for name in sorted(out): | ||
293 | print fmt % (name, out[name]) | ||
294 | print fmt % ('cpucount', ('%d' % self.cpucount)) | ||
295 | print fmt % ('memtotal', ('%d kB' % self.memtotal)) | ||
296 | def cpuInfo(self): | ||
297 | self.cpucount = 0 | ||
298 | fp = open('/proc/cpuinfo', 'r') | ||
299 | for line in fp: | ||
300 | if re.match('^processor[ \t]*:[ \t]*[0-9]*', line): | ||
301 | self.cpucount += 1 | ||
302 | fp.close() | ||
303 | fp = open('/proc/meminfo', 'r') | ||
304 | for line in fp: | ||
305 | m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line) | ||
306 | if m: | ||
307 | self.memtotal = int(m.group('sz')) | ||
308 | break | ||
309 | fp.close() | ||
310 | def initTestOutput(self, name): | ||
265 | self.prefix = self.hostname | 311 | self.prefix = self.hostname |
266 | v = open('/proc/version', 'r').read().strip() | 312 | v = open('/proc/version', 'r').read().strip() |
267 | kver = string.split(v)[2] | 313 | kver = string.split(v)[2] |
268 | n = datetime.now() | 314 | fmt = name+'-%m%d%y-%H%M%S' |
269 | testtime = n.strftime('suspend-%m%d%y-%H%M%S') | 315 | testtime = datetime.now().strftime(fmt) |
270 | if not testpath: | ||
271 | testpath = n.strftime('suspend-%y%m%d-%H%M%S') | ||
272 | if(subdir != "."): | ||
273 | self.testdir = subdir+"/"+testpath | ||
274 | else: | ||
275 | self.testdir = testpath | ||
276 | self.teststamp = \ | 316 | self.teststamp = \ |
277 | '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver | 317 | '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver |
278 | if(self.embedded): | 318 | if(self.embedded): |
@@ -355,7 +395,7 @@ class SystemValues: | |||
355 | continue | 395 | continue |
356 | self.tracefuncs[i] = dict() | 396 | self.tracefuncs[i] = dict() |
357 | def getFtraceFilterFunctions(self, current): | 397 | def getFtraceFilterFunctions(self, current): |
358 | rootCheck(True) | 398 | self.rootCheck(True) |
359 | if not current: | 399 | if not current: |
360 | call('cat '+self.tpath+'available_filter_functions', shell=True) | 400 | call('cat '+self.tpath+'available_filter_functions', shell=True) |
361 | return | 401 | return |
@@ -453,7 +493,7 @@ class SystemValues: | |||
453 | val += '\nr:%s_ret %s $retval\n' % (name, func) | 493 | val += '\nr:%s_ret %s $retval\n' % (name, func) |
454 | return val | 494 | return val |
455 | def addKprobes(self, output=False): | 495 | def addKprobes(self, output=False): |
456 | if len(sysvals.kprobes) < 1: | 496 | if len(self.kprobes) < 1: |
457 | return | 497 | return |
458 | if output: | 498 | if output: |
459 | print(' kprobe functions in this kernel:') | 499 | print(' kprobe functions in this kernel:') |
@@ -525,7 +565,7 @@ class SystemValues: | |||
525 | fp.flush() | 565 | fp.flush() |
526 | fp.close() | 566 | fp.close() |
527 | except: | 567 | except: |
528 | pass | 568 | return False |
529 | return True | 569 | return True |
530 | def fgetVal(self, path): | 570 | def fgetVal(self, path): |
531 | file = self.tpath+path | 571 | file = self.tpath+path |
@@ -566,9 +606,15 @@ class SystemValues: | |||
566 | self.cleanupFtrace() | 606 | self.cleanupFtrace() |
567 | # set the trace clock to global | 607 | # set the trace clock to global |
568 | self.fsetVal('global', 'trace_clock') | 608 | self.fsetVal('global', 'trace_clock') |
569 | # set trace buffer to a huge value | ||
570 | self.fsetVal('nop', 'current_tracer') | 609 | self.fsetVal('nop', 'current_tracer') |
571 | self.fsetVal('131073', 'buffer_size_kb') | 610 | # set trace buffer to a huge value |
611 | if self.usecallgraph or self.usedevsrc: | ||
612 | tgtsize = min(self.memtotal / 2, 2*1024*1024) | ||
613 | maxbuf = '%d' % (tgtsize / max(1, self.cpucount)) | ||
614 | if self.cpucount < 1 or not self.fsetVal(maxbuf, 'buffer_size_kb'): | ||
615 | self.fsetVal('131072', 'buffer_size_kb') | ||
616 | else: | ||
617 | self.fsetVal('16384', 'buffer_size_kb') | ||
572 | # go no further if this is just a status check | 618 | # go no further if this is just a status check |
573 | if testing: | 619 | if testing: |
574 | return | 620 | return |
@@ -641,6 +687,15 @@ class SystemValues: | |||
641 | if not self.ansi: | 687 | if not self.ansi: |
642 | return str | 688 | return str |
643 | return '\x1B[%d;40m%s\x1B[m' % (color, str) | 689 | return '\x1B[%d;40m%s\x1B[m' % (color, str) |
690 | def writeDatafileHeader(self, filename, fwdata=[]): | ||
691 | fp = open(filename, 'w') | ||
692 | fp.write(self.teststamp+'\n') | ||
693 | fp.write(self.sysstamp+'\n') | ||
694 | if(self.suspendmode == 'mem' or self.suspendmode == 'command'): | ||
695 | for fw in fwdata: | ||
696 | if(fw): | ||
697 | fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) | ||
698 | fp.close() | ||
644 | 699 | ||
645 | sysvals = SystemValues() | 700 | sysvals = SystemValues() |
646 | suspendmodename = { | 701 | suspendmodename = { |
@@ -1008,6 +1063,12 @@ class Data: | |||
1008 | else: | 1063 | else: |
1009 | self.trimTime(self.tSuspended, \ | 1064 | self.trimTime(self.tSuspended, \ |
1010 | self.tResumed-self.tSuspended, False) | 1065 | self.tResumed-self.tSuspended, False) |
1066 | def getTimeValues(self): | ||
1067 | sktime = (self.dmesg['suspend_machine']['end'] - \ | ||
1068 | self.tKernSus) * 1000 | ||
1069 | rktime = (self.dmesg['resume_complete']['end'] - \ | ||
1070 | self.dmesg['resume_machine']['start']) * 1000 | ||
1071 | return (sktime, rktime) | ||
1011 | def setPhase(self, phase, ktime, isbegin): | 1072 | def setPhase(self, phase, ktime, isbegin): |
1012 | if(isbegin): | 1073 | if(isbegin): |
1013 | self.dmesg[phase]['start'] = ktime | 1074 | self.dmesg[phase]['start'] = ktime |
@@ -1517,7 +1578,7 @@ class FTraceCallGraph: | |||
1517 | prelinedep += 1 | 1578 | prelinedep += 1 |
1518 | last = 0 | 1579 | last = 0 |
1519 | lasttime = line.time | 1580 | lasttime = line.time |
1520 | virtualfname = 'execution_misalignment' | 1581 | virtualfname = 'missing_function_name' |
1521 | if len(self.list) > 0: | 1582 | if len(self.list) > 0: |
1522 | last = self.list[-1] | 1583 | last = self.list[-1] |
1523 | lasttime = last.time | 1584 | lasttime = last.time |
@@ -1773,24 +1834,30 @@ class Timeline: | |||
1773 | html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n' | 1834 | html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n' |
1774 | html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background:{4}">{5}</div>\n' | 1835 | html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background:{4}">{5}</div>\n' |
1775 | html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' | 1836 | html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' |
1837 | html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}"> {2}</div>\n' | ||
1776 | def __init__(self, rowheight, scaleheight): | 1838 | def __init__(self, rowheight, scaleheight): |
1777 | self.rowH = rowheight | 1839 | self.rowH = rowheight |
1778 | self.scaleH = scaleheight | 1840 | self.scaleH = scaleheight |
1779 | self.html = '' | 1841 | self.html = '' |
1780 | def createHeader(self, sv, suppress=''): | 1842 | def createHeader(self, sv): |
1781 | if(not sv.stamp['time']): | 1843 | if(not sv.stamp['time']): |
1782 | return | 1844 | return |
1783 | self.html += '<div class="version"><a href="https://01.org/suspendresume">%s v%s</a></div>' \ | 1845 | self.html += '<div class="version"><a href="https://01.org/suspendresume">%s v%s</a></div>' \ |
1784 | % (sv.title, sv.version) | 1846 | % (sv.title, sv.version) |
1785 | if sv.logmsg and 'log' not in suppress: | 1847 | if sv.logmsg and sv.testlog: |
1786 | self.html += '<button id="showtest" class="logbtn">log</button>' | 1848 | self.html += '<button id="showtest" class="logbtn btnfmt">log</button>' |
1787 | if sv.addlogs and 'dmesg' not in suppress: | 1849 | if sv.dmesglog: |
1788 | self.html += '<button id="showdmesg" class="logbtn">dmesg</button>' | 1850 | self.html += '<button id="showdmesg" class="logbtn btnfmt">dmesg</button>' |
1789 | if sv.addlogs and sv.ftracefile and 'ftrace' not in suppress: | 1851 | if sv.ftracelog: |
1790 | self.html += '<button id="showftrace" class="logbtn">ftrace</button>' | 1852 | self.html += '<button id="showftrace" class="logbtn btnfmt">ftrace</button>' |
1791 | headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' | 1853 | headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' |
1792 | self.html += headline_stamp.format(sv.stamp['host'], sv.stamp['kernel'], | 1854 | self.html += headline_stamp.format(sv.stamp['host'], sv.stamp['kernel'], |
1793 | sv.stamp['mode'], sv.stamp['time']) | 1855 | sv.stamp['mode'], sv.stamp['time']) |
1856 | if 'man' in sv.stamp and 'plat' in sv.stamp and 'cpu' in sv.stamp: | ||
1857 | headline_sysinfo = '<div class="stamp sysinfo">{0} {1} <i>with</i> {2}</div>\n' | ||
1858 | self.html += headline_sysinfo.format(sv.stamp['man'], | ||
1859 | sv.stamp['plat'], sv.stamp['cpu']) | ||
1860 | |||
1794 | # Function: getDeviceRows | 1861 | # Function: getDeviceRows |
1795 | # Description: | 1862 | # Description: |
1796 | # determine how may rows the device funcs will take | 1863 | # determine how may rows the device funcs will take |
@@ -1839,7 +1906,7 @@ class Timeline: | |||
1839 | # devlist: the list of devices/actions in a group of contiguous phases | 1906 | # devlist: the list of devices/actions in a group of contiguous phases |
1840 | # Output: | 1907 | # Output: |
1841 | # The total number of rows needed to display this phase of the timeline | 1908 | # The total number of rows needed to display this phase of the timeline |
1842 | def getPhaseRows(self, devlist, row=0): | 1909 | def getPhaseRows(self, devlist, row=0, sortby='length'): |
1843 | # clear all rows and set them to undefined | 1910 | # clear all rows and set them to undefined |
1844 | remaining = len(devlist) | 1911 | remaining = len(devlist) |
1845 | rowdata = dict() | 1912 | rowdata = dict() |
@@ -1852,8 +1919,12 @@ class Timeline: | |||
1852 | if tp not in myphases: | 1919 | if tp not in myphases: |
1853 | myphases.append(tp) | 1920 | myphases.append(tp) |
1854 | dev['row'] = -1 | 1921 | dev['row'] = -1 |
1855 | # sort by length 1st, then name 2nd | 1922 | if sortby == 'start': |
1856 | sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name']) | 1923 | # sort by start 1st, then length 2nd |
1924 | sortdict[item] = (-1*float(dev['start']), float(dev['end']) - float(dev['start'])) | ||
1925 | else: | ||
1926 | # sort by length 1st, then name 2nd | ||
1927 | sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name']) | ||
1857 | if 'src' in dev: | 1928 | if 'src' in dev: |
1858 | dev['devrows'] = self.getDeviceRows(dev['src']) | 1929 | dev['devrows'] = self.getDeviceRows(dev['src']) |
1859 | # sort the devlist by length so that large items graph on top | 1930 | # sort the devlist by length so that large items graph on top |
@@ -1995,8 +2066,13 @@ class Timeline: | |||
1995 | # A list of values describing the properties of these test runs | 2066 | # A list of values describing the properties of these test runs |
1996 | class TestProps: | 2067 | class TestProps: |
1997 | stamp = '' | 2068 | stamp = '' |
2069 | sysinfo = '' | ||
1998 | S0i3 = False | 2070 | S0i3 = False |
1999 | fwdata = [] | 2071 | fwdata = [] |
2072 | stampfmt = '# [a-z]*-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ | ||
2073 | '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ | ||
2074 | ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' | ||
2075 | sysinfofmt = '^# sysinfo .*' | ||
2000 | ftrace_line_fmt_fg = \ | 2076 | ftrace_line_fmt_fg = \ |
2001 | '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ | 2077 | '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ |
2002 | ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ | 2078 | ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ |
@@ -2019,6 +2095,36 @@ class TestProps: | |||
2019 | self.ftrace_line_fmt = self.ftrace_line_fmt_nop | 2095 | self.ftrace_line_fmt = self.ftrace_line_fmt_nop |
2020 | else: | 2096 | else: |
2021 | doError('Invalid tracer format: [%s]' % tracer) | 2097 | doError('Invalid tracer format: [%s]' % tracer) |
2098 | def parseStamp(self, data, sv): | ||
2099 | m = re.match(self.stampfmt, self.stamp) | ||
2100 | data.stamp = {'time': '', 'host': '', 'mode': ''} | ||
2101 | dt = datetime(int(m.group('y'))+2000, int(m.group('m')), | ||
2102 | int(m.group('d')), int(m.group('H')), int(m.group('M')), | ||
2103 | int(m.group('S'))) | ||
2104 | data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p') | ||
2105 | data.stamp['host'] = m.group('host') | ||
2106 | data.stamp['mode'] = m.group('mode') | ||
2107 | data.stamp['kernel'] = m.group('kernel') | ||
2108 | if re.match(self.sysinfofmt, self.sysinfo): | ||
2109 | for f in self.sysinfo.split('|'): | ||
2110 | if '#' in f: | ||
2111 | continue | ||
2112 | tmp = f.strip().split(':', 1) | ||
2113 | key = tmp[0] | ||
2114 | val = tmp[1] | ||
2115 | data.stamp[key] = val | ||
2116 | sv.hostname = data.stamp['host'] | ||
2117 | sv.suspendmode = data.stamp['mode'] | ||
2118 | if sv.suspendmode == 'command' and sv.ftracefile != '': | ||
2119 | modes = ['on', 'freeze', 'standby', 'mem'] | ||
2120 | out = Popen(['grep', 'suspend_enter', sv.ftracefile], | ||
2121 | stderr=PIPE, stdout=PIPE).stdout.read() | ||
2122 | m = re.match('.* suspend_enter\[(?P<mode>.*)\]', out) | ||
2123 | if m and m.group('mode') in ['1', '2', '3']: | ||
2124 | sv.suspendmode = modes[int(m.group('mode'))] | ||
2125 | data.stamp['mode'] = sv.suspendmode | ||
2126 | if not sv.stamp: | ||
2127 | sv.stamp = data.stamp | ||
2022 | 2128 | ||
2023 | # Class: TestRun | 2129 | # Class: TestRun |
2024 | # Description: | 2130 | # Description: |
@@ -2090,35 +2196,6 @@ def vprint(msg): | |||
2090 | if(sysvals.verbose): | 2196 | if(sysvals.verbose): |
2091 | print(msg) | 2197 | print(msg) |
2092 | 2198 | ||
2093 | # Function: parseStamp | ||
2094 | # Description: | ||
2095 | # Pull in the stamp comment line from the data file(s), | ||
2096 | # create the stamp, and add it to the global sysvals object | ||
2097 | # Arguments: | ||
2098 | # m: the valid re.match output for the stamp line | ||
2099 | def parseStamp(line, data): | ||
2100 | m = re.match(sysvals.stampfmt, line) | ||
2101 | data.stamp = {'time': '', 'host': '', 'mode': ''} | ||
2102 | dt = datetime(int(m.group('y'))+2000, int(m.group('m')), | ||
2103 | int(m.group('d')), int(m.group('H')), int(m.group('M')), | ||
2104 | int(m.group('S'))) | ||
2105 | data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p') | ||
2106 | data.stamp['host'] = m.group('host') | ||
2107 | data.stamp['mode'] = m.group('mode') | ||
2108 | data.stamp['kernel'] = m.group('kernel') | ||
2109 | sysvals.hostname = data.stamp['host'] | ||
2110 | sysvals.suspendmode = data.stamp['mode'] | ||
2111 | if sysvals.suspendmode == 'command' and sysvals.ftracefile != '': | ||
2112 | modes = ['on', 'freeze', 'standby', 'mem'] | ||
2113 | out = Popen(['grep', 'suspend_enter', sysvals.ftracefile], | ||
2114 | stderr=PIPE, stdout=PIPE).stdout.read() | ||
2115 | m = re.match('.* suspend_enter\[(?P<mode>.*)\]', out) | ||
2116 | if m and m.group('mode') in ['1', '2', '3']: | ||
2117 | sysvals.suspendmode = modes[int(m.group('mode'))] | ||
2118 | data.stamp['mode'] = sysvals.suspendmode | ||
2119 | if not sysvals.stamp: | ||
2120 | sysvals.stamp = data.stamp | ||
2121 | |||
2122 | # Function: doesTraceLogHaveTraceEvents | 2199 | # Function: doesTraceLogHaveTraceEvents |
2123 | # Description: | 2200 | # Description: |
2124 | # Quickly determine if the ftrace log has some or all of the trace events | 2201 | # Quickly determine if the ftrace log has some or all of the trace events |
@@ -2136,11 +2213,6 @@ def doesTraceLogHaveTraceEvents(): | |||
2136 | sysvals.usekprobes = True | 2213 | sysvals.usekprobes = True |
2137 | out = Popen(['head', '-1', sysvals.ftracefile], | 2214 | out = Popen(['head', '-1', sysvals.ftracefile], |
2138 | stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '') | 2215 | stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '') |
2139 | m = re.match(sysvals.stampfmt, out) | ||
2140 | if m and m.group('mode') == 'command': | ||
2141 | sysvals.usetraceeventsonly = True | ||
2142 | sysvals.usetraceevents = True | ||
2143 | return | ||
2144 | # figure out what level of trace events are supported | 2216 | # figure out what level of trace events are supported |
2145 | sysvals.usetraceeventsonly = True | 2217 | sysvals.usetraceeventsonly = True |
2146 | sysvals.usetraceevents = False | 2218 | sysvals.usetraceevents = False |
@@ -2182,11 +2254,13 @@ def appendIncompleteTraceLog(testruns): | |||
2182 | for line in tf: | 2254 | for line in tf: |
2183 | # remove any latent carriage returns | 2255 | # remove any latent carriage returns |
2184 | line = line.replace('\r\n', '') | 2256 | line = line.replace('\r\n', '') |
2185 | # grab the time stamp | 2257 | # grab the stamp and sysinfo |
2186 | m = re.match(sysvals.stampfmt, line) | 2258 | if re.match(tp.stampfmt, line): |
2187 | if(m): | ||
2188 | tp.stamp = line | 2259 | tp.stamp = line |
2189 | continue | 2260 | continue |
2261 | elif re.match(tp.sysinfofmt, line): | ||
2262 | tp.sysinfo = line | ||
2263 | continue | ||
2190 | # determine the trace data type (required for further parsing) | 2264 | # determine the trace data type (required for further parsing) |
2191 | m = re.match(sysvals.tracertypefmt, line) | 2265 | m = re.match(sysvals.tracertypefmt, line) |
2192 | if(m): | 2266 | if(m): |
@@ -2219,7 +2293,7 @@ def appendIncompleteTraceLog(testruns): | |||
2219 | # look for the suspend start marker | 2293 | # look for the suspend start marker |
2220 | if(t.startMarker()): | 2294 | if(t.startMarker()): |
2221 | data = testrun[testidx].data | 2295 | data = testrun[testidx].data |
2222 | parseStamp(tp.stamp, data) | 2296 | tp.parseStamp(data, sysvals) |
2223 | data.setStart(t.time) | 2297 | data.setStart(t.time) |
2224 | continue | 2298 | continue |
2225 | if(not data): | 2299 | if(not data): |
@@ -2389,11 +2463,13 @@ def parseTraceLog(): | |||
2389 | for line in tf: | 2463 | for line in tf: |
2390 | # remove any latent carriage returns | 2464 | # remove any latent carriage returns |
2391 | line = line.replace('\r\n', '') | 2465 | line = line.replace('\r\n', '') |
2392 | # stamp line: each stamp means a new test run | 2466 | # stamp and sysinfo lines |
2393 | m = re.match(sysvals.stampfmt, line) | 2467 | if re.match(tp.stampfmt, line): |
2394 | if(m): | ||
2395 | tp.stamp = line | 2468 | tp.stamp = line |
2396 | continue | 2469 | continue |
2470 | elif re.match(tp.sysinfofmt, line): | ||
2471 | tp.sysinfo = line | ||
2472 | continue | ||
2397 | # firmware line: pull out any firmware data | 2473 | # firmware line: pull out any firmware data |
2398 | m = re.match(sysvals.firmwarefmt, line) | 2474 | m = re.match(sysvals.firmwarefmt, line) |
2399 | if(m): | 2475 | if(m): |
@@ -2439,7 +2515,7 @@ def parseTraceLog(): | |||
2439 | testdata.append(data) | 2515 | testdata.append(data) |
2440 | testrun = TestRun(data) | 2516 | testrun = TestRun(data) |
2441 | testruns.append(testrun) | 2517 | testruns.append(testrun) |
2442 | parseStamp(tp.stamp, data) | 2518 | tp.parseStamp(data, sysvals) |
2443 | data.setStart(t.time) | 2519 | data.setStart(t.time) |
2444 | data.tKernSus = t.time | 2520 | data.tKernSus = t.time |
2445 | continue | 2521 | continue |
@@ -2820,10 +2896,13 @@ def loadKernelLog(justtext=False): | |||
2820 | idx = line.find('[') | 2896 | idx = line.find('[') |
2821 | if idx > 1: | 2897 | if idx > 1: |
2822 | line = line[idx:] | 2898 | line = line[idx:] |
2823 | m = re.match(sysvals.stampfmt, line) | 2899 | # grab the stamp and sysinfo |
2824 | if(m): | 2900 | if re.match(tp.stampfmt, line): |
2825 | tp.stamp = line | 2901 | tp.stamp = line |
2826 | continue | 2902 | continue |
2903 | elif re.match(tp.sysinfofmt, line): | ||
2904 | tp.sysinfo = line | ||
2905 | continue | ||
2827 | m = re.match(sysvals.firmwarefmt, line) | 2906 | m = re.match(sysvals.firmwarefmt, line) |
2828 | if(m): | 2907 | if(m): |
2829 | tp.fwdata.append((int(m.group('s')), int(m.group('r')))) | 2908 | tp.fwdata.append((int(m.group('s')), int(m.group('r')))) |
@@ -2839,7 +2918,7 @@ def loadKernelLog(justtext=False): | |||
2839 | if(data): | 2918 | if(data): |
2840 | testruns.append(data) | 2919 | testruns.append(data) |
2841 | data = Data(len(testruns)) | 2920 | data = Data(len(testruns)) |
2842 | parseStamp(tp.stamp, data) | 2921 | tp.parseStamp(data, sysvals) |
2843 | if len(tp.fwdata) > data.testnumber: | 2922 | if len(tp.fwdata) > data.testnumber: |
2844 | data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber] | 2923 | data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber] |
2845 | if(data.fwSuspend > 0 or data.fwResume > 0): | 2924 | if(data.fwSuspend > 0 or data.fwResume > 0): |
@@ -3170,6 +3249,8 @@ def addCallgraphs(sv, hf, data): | |||
3170 | continue | 3249 | continue |
3171 | list = data.dmesg[p]['list'] | 3250 | list = data.dmesg[p]['list'] |
3172 | for devname in data.sortedDevices(p): | 3251 | for devname in data.sortedDevices(p): |
3252 | if len(sv.devicefilter) > 0 and devname not in sv.devicefilter: | ||
3253 | continue | ||
3173 | dev = list[devname] | 3254 | dev = list[devname] |
3174 | color = 'white' | 3255 | color = 'white' |
3175 | if 'color' in data.dmesg[p]: | 3256 | if 'color' in data.dmesg[p]: |
@@ -3309,7 +3390,6 @@ def createHTML(testruns): | |||
3309 | html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">ERROR→</div>\n' | 3390 | html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">ERROR→</div>\n' |
3310 | html_traceevent = '<div title="{0}" class="traceevent{6}" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;{7}">{5}</div>\n' | 3391 | html_traceevent = '<div title="{0}" class="traceevent{6}" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;{7}">{5}</div>\n' |
3311 | html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n' | 3392 | html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n' |
3312 | html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}"> {2}</div>\n' | ||
3313 | html_timetotal = '<table class="time1">\n<tr>'\ | 3393 | html_timetotal = '<table class="time1">\n<tr>'\ |
3314 | '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ | 3394 | '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ |
3315 | '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ | 3395 | '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ |
@@ -3346,10 +3426,7 @@ def createHTML(testruns): | |||
3346 | # Generate the header for this timeline | 3426 | # Generate the header for this timeline |
3347 | for data in testruns: | 3427 | for data in testruns: |
3348 | tTotal = data.end - data.start | 3428 | tTotal = data.end - data.start |
3349 | sktime = (data.dmesg['suspend_machine']['end'] - \ | 3429 | sktime, rktime = data.getTimeValues() |
3350 | data.tKernSus) * 1000 | ||
3351 | rktime = (data.dmesg['resume_complete']['end'] - \ | ||
3352 | data.dmesg['resume_machine']['start']) * 1000 | ||
3353 | if(tTotal == 0): | 3430 | if(tTotal == 0): |
3354 | print('ERROR: No timeline data') | 3431 | print('ERROR: No timeline data') |
3355 | sys.exit() | 3432 | sys.exit() |
@@ -3581,7 +3658,7 @@ def createHTML(testruns): | |||
3581 | id += tmp[1][0] | 3658 | id += tmp[1][0] |
3582 | order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin) | 3659 | order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin) |
3583 | name = string.replace(phase, '_', ' ') | 3660 | name = string.replace(phase, '_', ' ') |
3584 | devtl.html += html_legend.format(order, \ | 3661 | devtl.html += devtl.html_legend.format(order, \ |
3585 | data.dmesg[phase]['color'], name, id) | 3662 | data.dmesg[phase]['color'], name, id) |
3586 | devtl.html += '</div>\n' | 3663 | devtl.html += '</div>\n' |
3587 | 3664 | ||
@@ -3628,10 +3705,10 @@ def createHTML(testruns): | |||
3628 | addCallgraphs(sysvals, hf, data) | 3705 | addCallgraphs(sysvals, hf, data) |
3629 | 3706 | ||
3630 | # add the test log as a hidden div | 3707 | # add the test log as a hidden div |
3631 | if sysvals.logmsg: | 3708 | if sysvals.testlog and sysvals.logmsg: |
3632 | hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') | 3709 | hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') |
3633 | # add the dmesg log as a hidden div | 3710 | # add the dmesg log as a hidden div |
3634 | if sysvals.addlogs and sysvals.dmesgfile: | 3711 | if sysvals.dmesglog and sysvals.dmesgfile: |
3635 | hf.write('<div id="dmesglog" style="display:none;">\n') | 3712 | hf.write('<div id="dmesglog" style="display:none;">\n') |
3636 | lf = open(sysvals.dmesgfile, 'r') | 3713 | lf = open(sysvals.dmesgfile, 'r') |
3637 | for line in lf: | 3714 | for line in lf: |
@@ -3640,7 +3717,7 @@ def createHTML(testruns): | |||
3640 | lf.close() | 3717 | lf.close() |
3641 | hf.write('</div>\n') | 3718 | hf.write('</div>\n') |
3642 | # add the ftrace log as a hidden div | 3719 | # add the ftrace log as a hidden div |
3643 | if sysvals.addlogs and sysvals.ftracefile: | 3720 | if sysvals.ftracelog and sysvals.ftracefile: |
3644 | hf.write('<div id="ftracelog" style="display:none;">\n') | 3721 | hf.write('<div id="ftracelog" style="display:none;">\n') |
3645 | lf = open(sysvals.ftracefile, 'r') | 3722 | lf = open(sysvals.ftracefile, 'r') |
3646 | for line in lf: | 3723 | for line in lf: |
@@ -3701,6 +3778,7 @@ def addCSS(hf, sv, testcount=1, kerror=False, extra=''): | |||
3701 | <style type=\'text/css\'>\n\ | 3778 | <style type=\'text/css\'>\n\ |
3702 | body {overflow-y:scroll;}\n\ | 3779 | body {overflow-y:scroll;}\n\ |
3703 | .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ | 3780 | .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ |
3781 | .stamp.sysinfo {font:10px Arial;}\n\ | ||
3704 | .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ | 3782 | .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ |
3705 | .callgraph article * {padding-left:28px;}\n\ | 3783 | .callgraph article * {padding-left:28px;}\n\ |
3706 | h1 {color:black;font:bold 30px Times;}\n\ | 3784 | h1 {color:black;font:bold 30px Times;}\n\ |
@@ -3746,7 +3824,7 @@ def addCSS(hf, sv, testcount=1, kerror=False, extra=''): | |||
3746 | .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ | 3824 | .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ |
3747 | .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ | 3825 | .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ |
3748 | button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ | 3826 | button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ |
3749 | .logbtn {position:relative;float:right;height:25px;width:50px;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ | 3827 | .btnfmt {position:relative;float:right;height:25px;width:auto;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ |
3750 | .devlist {position:'+devlistpos+';width:190px;}\n\ | 3828 | .devlist {position:'+devlistpos+';width:190px;}\n\ |
3751 | a:link {color:white;text-decoration:none;}\n\ | 3829 | a:link {color:white;text-decoration:none;}\n\ |
3752 | a:visited {color:white;}\n\ | 3830 | a:visited {color:white;}\n\ |
@@ -4084,8 +4162,6 @@ def addScriptCode(hf, testruns): | |||
4084 | ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\ | 4162 | ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\ |
4085 | ' win.document.close();\n'\ | 4163 | ' win.document.close();\n'\ |
4086 | ' }\n'\ | 4164 | ' }\n'\ |
4087 | ' function onClickPhase(e) {\n'\ | ||
4088 | ' }\n'\ | ||
4089 | ' function onMouseDown(e) {\n'\ | 4165 | ' function onMouseDown(e) {\n'\ |
4090 | ' dragval[0] = e.clientX;\n'\ | 4166 | ' dragval[0] = e.clientX;\n'\ |
4091 | ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\ | 4167 | ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\ |
@@ -4120,9 +4196,6 @@ def addScriptCode(hf, testruns): | |||
4120 | ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ | 4196 | ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ |
4121 | ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ | 4197 | ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ |
4122 | ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ | 4198 | ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ |
4123 | ' var list = document.getElementsByClassName("square");\n'\ | ||
4124 | ' for (var i = 0; i < list.length; i++)\n'\ | ||
4125 | ' list[i].onclick = onClickPhase;\n'\ | ||
4126 | ' var list = document.getElementsByClassName("err");\n'\ | 4199 | ' var list = document.getElementsByClassName("err");\n'\ |
4127 | ' for (var i = 0; i < list.length; i++)\n'\ | 4200 | ' for (var i = 0; i < list.length; i++)\n'\ |
4128 | ' list[i].onclick = errWindow;\n'\ | 4201 | ' list[i].onclick = errWindow;\n'\ |
@@ -4193,8 +4266,14 @@ def executeSuspend(): | |||
4193 | if sysvals.testcommand != '': | 4266 | if sysvals.testcommand != '': |
4194 | call(sysvals.testcommand+' 2>&1', shell=True); | 4267 | call(sysvals.testcommand+' 2>&1', shell=True); |
4195 | else: | 4268 | else: |
4269 | mode = sysvals.suspendmode | ||
4270 | if sysvals.memmode and os.path.exists(sysvals.mempowerfile): | ||
4271 | mode = 'mem' | ||
4272 | pf = open(sysvals.mempowerfile, 'w') | ||
4273 | pf.write(sysvals.memmode) | ||
4274 | pf.close() | ||
4196 | pf = open(sysvals.powerfile, 'w') | 4275 | pf = open(sysvals.powerfile, 'w') |
4197 | pf.write(sysvals.suspendmode) | 4276 | pf.write(mode) |
4198 | # execution will pause here | 4277 | # execution will pause here |
4199 | try: | 4278 | try: |
4200 | pf.close() | 4279 | pf.close() |
@@ -4219,24 +4298,15 @@ def executeSuspend(): | |||
4219 | pm.stop() | 4298 | pm.stop() |
4220 | sysvals.fsetVal('0', 'tracing_on') | 4299 | sysvals.fsetVal('0', 'tracing_on') |
4221 | print('CAPTURING TRACE') | 4300 | print('CAPTURING TRACE') |
4222 | writeDatafileHeader(sysvals.ftracefile, fwdata) | 4301 | sysvals.writeDatafileHeader(sysvals.ftracefile, fwdata) |
4223 | call('cat '+tp+'trace >> '+sysvals.ftracefile, shell=True) | 4302 | call('cat '+tp+'trace >> '+sysvals.ftracefile, shell=True) |
4224 | sysvals.fsetVal('', 'trace') | 4303 | sysvals.fsetVal('', 'trace') |
4225 | devProps() | 4304 | devProps() |
4226 | # grab a copy of the dmesg output | 4305 | # grab a copy of the dmesg output |
4227 | print('CAPTURING DMESG') | 4306 | print('CAPTURING DMESG') |
4228 | writeDatafileHeader(sysvals.dmesgfile, fwdata) | 4307 | sysvals.writeDatafileHeader(sysvals.dmesgfile, fwdata) |
4229 | sysvals.getdmesg() | 4308 | sysvals.getdmesg() |
4230 | 4309 | ||
4231 | def writeDatafileHeader(filename, fwdata): | ||
4232 | fp = open(filename, 'a') | ||
4233 | fp.write(sysvals.teststamp+'\n') | ||
4234 | if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'): | ||
4235 | for fw in fwdata: | ||
4236 | if(fw): | ||
4237 | fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) | ||
4238 | fp.close() | ||
4239 | |||
4240 | # Function: setUSBDevicesAuto | 4310 | # Function: setUSBDevicesAuto |
4241 | # Description: | 4311 | # Description: |
4242 | # Set the autosuspend control parameter of all USB devices to auto | 4312 | # Set the autosuspend control parameter of all USB devices to auto |
@@ -4244,7 +4314,7 @@ def writeDatafileHeader(filename, fwdata): | |||
4244 | # to always-on since the kernel cant determine if the device can | 4314 | # to always-on since the kernel cant determine if the device can |
4245 | # properly autosuspend | 4315 | # properly autosuspend |
4246 | def setUSBDevicesAuto(): | 4316 | def setUSBDevicesAuto(): |
4247 | rootCheck(True) | 4317 | sysvals.rootCheck(True) |
4248 | for dirname, dirnames, filenames in os.walk('/sys/devices'): | 4318 | for dirname, dirnames, filenames in os.walk('/sys/devices'): |
4249 | if(re.match('.*/usb[0-9]*.*', dirname) and | 4319 | if(re.match('.*/usb[0-9]*.*', dirname) and |
4250 | 'idVendor' in filenames and 'idProduct' in filenames): | 4320 | 'idVendor' in filenames and 'idProduct' in filenames): |
@@ -4467,13 +4537,146 @@ def devProps(data=0): | |||
4467 | # Output: | 4537 | # Output: |
4468 | # A string list of the available modes | 4538 | # A string list of the available modes |
4469 | def getModes(): | 4539 | def getModes(): |
4470 | modes = '' | 4540 | modes = [] |
4471 | if(os.path.exists(sysvals.powerfile)): | 4541 | if(os.path.exists(sysvals.powerfile)): |
4472 | fp = open(sysvals.powerfile, 'r') | 4542 | fp = open(sysvals.powerfile, 'r') |
4473 | modes = string.split(fp.read()) | 4543 | modes = string.split(fp.read()) |
4474 | fp.close() | 4544 | fp.close() |
4545 | if(os.path.exists(sysvals.mempowerfile)): | ||
4546 | deep = False | ||
4547 | fp = open(sysvals.mempowerfile, 'r') | ||
4548 | for m in string.split(fp.read()): | ||
4549 | memmode = m.strip('[]') | ||
4550 | if memmode == 'deep': | ||
4551 | deep = True | ||
4552 | else: | ||
4553 | modes.append('mem-%s' % memmode) | ||
4554 | fp.close() | ||
4555 | if 'mem' in modes and not deep: | ||
4556 | modes.remove('mem') | ||
4475 | return modes | 4557 | return modes |
4476 | 4558 | ||
4559 | # Function: dmidecode | ||
4560 | # Description: | ||
4561 | # Read the bios tables and pull out system info | ||
4562 | # Arguments: | ||
4563 | # mempath: /dev/mem or custom mem path | ||
4564 | # fatal: True to exit on error, False to return empty dict | ||
4565 | # Output: | ||
4566 | # A dict object with all available key/values | ||
4567 | def dmidecode(mempath, fatal=False): | ||
4568 | out = dict() | ||
4569 | |||
4570 | # the list of values to retrieve, with hardcoded (type, idx) | ||
4571 | info = { | ||
4572 | 'bios-vendor': (0, 4), | ||
4573 | 'bios-version': (0, 5), | ||
4574 | 'bios-release-date': (0, 8), | ||
4575 | 'system-manufacturer': (1, 4), | ||
4576 | 'system-product-name': (1, 5), | ||
4577 | 'system-version': (1, 6), | ||
4578 | 'system-serial-number': (1, 7), | ||
4579 | 'baseboard-manufacturer': (2, 4), | ||
4580 | 'baseboard-product-name': (2, 5), | ||
4581 | 'baseboard-version': (2, 6), | ||
4582 | 'baseboard-serial-number': (2, 7), | ||
4583 | 'chassis-manufacturer': (3, 4), | ||
4584 | 'chassis-type': (3, 5), | ||
4585 | 'chassis-version': (3, 6), | ||
4586 | 'chassis-serial-number': (3, 7), | ||
4587 | 'processor-manufacturer': (4, 7), | ||
4588 | 'processor-version': (4, 16), | ||
4589 | } | ||
4590 | if(not os.path.exists(mempath)): | ||
4591 | if(fatal): | ||
4592 | doError('file does not exist: %s' % mempath) | ||
4593 | return out | ||
4594 | if(not os.access(mempath, os.R_OK)): | ||
4595 | if(fatal): | ||
4596 | doError('file is not readable: %s' % mempath) | ||
4597 | return out | ||
4598 | |||
4599 | # by default use legacy scan, but try to use EFI first | ||
4600 | memaddr = 0xf0000 | ||
4601 | memsize = 0x10000 | ||
4602 | for ep in ['/sys/firmware/efi/systab', '/proc/efi/systab']: | ||
4603 | if not os.path.exists(ep) or not os.access(ep, os.R_OK): | ||
4604 | continue | ||
4605 | fp = open(ep, 'r') | ||
4606 | buf = fp.read() | ||
4607 | fp.close() | ||
4608 | i = buf.find('SMBIOS=') | ||
4609 | if i >= 0: | ||
4610 | try: | ||
4611 | memaddr = int(buf[i+7:], 16) | ||
4612 | memsize = 0x20 | ||
4613 | except: | ||
4614 | continue | ||
4615 | |||
4616 | # read in the memory for scanning | ||
4617 | fp = open(mempath, 'rb') | ||
4618 | try: | ||
4619 | fp.seek(memaddr) | ||
4620 | buf = fp.read(memsize) | ||
4621 | except: | ||
4622 | if(fatal): | ||
4623 | doError('DMI table is unreachable, sorry') | ||
4624 | else: | ||
4625 | return out | ||
4626 | fp.close() | ||
4627 | |||
4628 | # search for either an SM table or DMI table | ||
4629 | i = base = length = num = 0 | ||
4630 | while(i < memsize): | ||
4631 | if buf[i:i+4] == '_SM_' and i < memsize - 16: | ||
4632 | length = struct.unpack('H', buf[i+22:i+24])[0] | ||
4633 | base, num = struct.unpack('IH', buf[i+24:i+30]) | ||
4634 | break | ||
4635 | elif buf[i:i+5] == '_DMI_': | ||
4636 | length = struct.unpack('H', buf[i+6:i+8])[0] | ||
4637 | base, num = struct.unpack('IH', buf[i+8:i+14]) | ||
4638 | break | ||
4639 | i += 16 | ||
4640 | if base == 0 and length == 0 and num == 0: | ||
4641 | if(fatal): | ||
4642 | doError('Neither SMBIOS nor DMI were found') | ||
4643 | else: | ||
4644 | return out | ||
4645 | |||
4646 | # read in the SM or DMI table | ||
4647 | fp = open(mempath, 'rb') | ||
4648 | try: | ||
4649 | fp.seek(base) | ||
4650 | buf = fp.read(length) | ||
4651 | except: | ||
4652 | if(fatal): | ||
4653 | doError('DMI table is unreachable, sorry') | ||
4654 | else: | ||
4655 | return out | ||
4656 | fp.close() | ||
4657 | |||
4658 | # scan the table for the values we want | ||
4659 | count = i = 0 | ||
4660 | while(count < num and i <= len(buf) - 4): | ||
4661 | type, size, handle = struct.unpack('BBH', buf[i:i+4]) | ||
4662 | n = i + size | ||
4663 | while n < len(buf) - 1: | ||
4664 | if 0 == struct.unpack('H', buf[n:n+2])[0]: | ||
4665 | break | ||
4666 | n += 1 | ||
4667 | data = buf[i+size:n+2].split('\0') | ||
4668 | for name in info: | ||
4669 | itype, idxadr = info[name] | ||
4670 | if itype == type: | ||
4671 | idx = struct.unpack('B', buf[i+idxadr])[0] | ||
4672 | if idx > 0 and idx < len(data) - 1: | ||
4673 | s = data[idx-1].strip() | ||
4674 | if s and s.lower() != 'to be filled by o.e.m.': | ||
4675 | out[name] = data[idx-1] | ||
4676 | i = n + 2 | ||
4677 | count += 1 | ||
4678 | return out | ||
4679 | |||
4477 | # Function: getFPDT | 4680 | # Function: getFPDT |
4478 | # Description: | 4681 | # Description: |
4479 | # Read the acpi bios tables and pull out FPDT, the firmware data | 4682 | # Read the acpi bios tables and pull out FPDT, the firmware data |
@@ -4487,7 +4690,7 @@ def getFPDT(output): | |||
4487 | prectype[0] = 'Basic S3 Resume Performance Record' | 4690 | prectype[0] = 'Basic S3 Resume Performance Record' |
4488 | prectype[1] = 'Basic S3 Suspend Performance Record' | 4691 | prectype[1] = 'Basic S3 Suspend Performance Record' |
4489 | 4692 | ||
4490 | rootCheck(True) | 4693 | sysvals.rootCheck(True) |
4491 | if(not os.path.exists(sysvals.fpdtpath)): | 4694 | if(not os.path.exists(sysvals.fpdtpath)): |
4492 | if(output): | 4695 | if(output): |
4493 | doError('file does not exist: %s' % sysvals.fpdtpath) | 4696 | doError('file does not exist: %s' % sysvals.fpdtpath) |
@@ -4617,7 +4820,7 @@ def statusCheck(probecheck=False): | |||
4617 | 4820 | ||
4618 | # check we have root access | 4821 | # check we have root access |
4619 | res = sysvals.colorText('NO (No features of this tool will work!)') | 4822 | res = sysvals.colorText('NO (No features of this tool will work!)') |
4620 | if(rootCheck(False)): | 4823 | if(sysvals.rootCheck(False)): |
4621 | res = 'YES' | 4824 | res = 'YES' |
4622 | print(' have root access: %s' % res) | 4825 | print(' have root access: %s' % res) |
4623 | if(res != 'YES'): | 4826 | if(res != 'YES'): |
@@ -4716,16 +4919,6 @@ def doError(msg, help=False): | |||
4716 | print('ERROR: %s\n') % msg | 4919 | print('ERROR: %s\n') % msg |
4717 | sys.exit() | 4920 | sys.exit() |
4718 | 4921 | ||
4719 | # Function: rootCheck | ||
4720 | # Description: | ||
4721 | # quick check to see if we have root access | ||
4722 | def rootCheck(fatal): | ||
4723 | if(os.access(sysvals.powerfile, os.W_OK)): | ||
4724 | return True | ||
4725 | if fatal: | ||
4726 | doError('This command requires sysfs mount and root access') | ||
4727 | return False | ||
4728 | |||
4729 | # Function: getArgInt | 4922 | # Function: getArgInt |
4730 | # Description: | 4923 | # Description: |
4731 | # pull out an integer argument from the command line with checks | 4924 | # pull out an integer argument from the command line with checks |
@@ -4779,6 +4972,7 @@ def processData(): | |||
4779 | if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): | 4972 | if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): |
4780 | appendIncompleteTraceLog(testruns) | 4973 | appendIncompleteTraceLog(testruns) |
4781 | createHTML(testruns) | 4974 | createHTML(testruns) |
4975 | return testruns | ||
4782 | 4976 | ||
4783 | # Function: rerunTest | 4977 | # Function: rerunTest |
4784 | # Description: | 4978 | # Description: |
@@ -4790,17 +4984,20 @@ def rerunTest(): | |||
4790 | doError('recreating this html output requires a dmesg file') | 4984 | doError('recreating this html output requires a dmesg file') |
4791 | sysvals.setOutputFile() | 4985 | sysvals.setOutputFile() |
4792 | vprint('Output file: %s' % sysvals.htmlfile) | 4986 | vprint('Output file: %s' % sysvals.htmlfile) |
4793 | if(os.path.exists(sysvals.htmlfile) and not os.access(sysvals.htmlfile, os.W_OK)): | 4987 | if os.path.exists(sysvals.htmlfile): |
4794 | doError('missing permission to write to %s' % sysvals.htmlfile) | 4988 | if not os.path.isfile(sysvals.htmlfile): |
4795 | processData() | 4989 | doError('a directory already exists with this name: %s' % sysvals.htmlfile) |
4990 | elif not os.access(sysvals.htmlfile, os.W_OK): | ||
4991 | doError('missing permission to write to %s' % sysvals.htmlfile) | ||
4992 | return processData() | ||
4796 | 4993 | ||
4797 | # Function: runTest | 4994 | # Function: runTest |
4798 | # Description: | 4995 | # Description: |
4799 | # execute a suspend/resume, gather the logs, and generate the output | 4996 | # execute a suspend/resume, gather the logs, and generate the output |
4800 | def runTest(subdir, testpath=''): | 4997 | def runTest(): |
4801 | # prepare for the test | 4998 | # prepare for the test |
4802 | sysvals.initFtrace() | 4999 | sysvals.initFtrace() |
4803 | sysvals.initTestOutput(subdir, testpath) | 5000 | sysvals.initTestOutput('suspend') |
4804 | vprint('Output files:\n\t%s\n\t%s\n\t%s' % \ | 5001 | vprint('Output files:\n\t%s\n\t%s\n\t%s' % \ |
4805 | (sysvals.dmesgfile, sysvals.ftracefile, sysvals.htmlfile)) | 5002 | (sysvals.dmesgfile, sysvals.ftracefile, sysvals.htmlfile)) |
4806 | 5003 | ||
@@ -4897,7 +5094,7 @@ def configFromFile(file): | |||
4897 | if(opt.lower() == 'verbose'): | 5094 | if(opt.lower() == 'verbose'): |
4898 | sysvals.verbose = checkArgBool(value) | 5095 | sysvals.verbose = checkArgBool(value) |
4899 | elif(opt.lower() == 'addlogs'): | 5096 | elif(opt.lower() == 'addlogs'): |
4900 | sysvals.addlogs = checkArgBool(value) | 5097 | sysvals.dmesglog = sysvals.ftracelog = checkArgBool(value) |
4901 | elif(opt.lower() == 'dev'): | 5098 | elif(opt.lower() == 'dev'): |
4902 | sysvals.usedevsrc = checkArgBool(value) | 5099 | sysvals.usedevsrc = checkArgBool(value) |
4903 | elif(opt.lower() == 'proc'): | 5100 | elif(opt.lower() == 'proc'): |
@@ -4947,7 +5144,7 @@ def configFromFile(file): | |||
4947 | elif(opt.lower() == 'mincg'): | 5144 | elif(opt.lower() == 'mincg'): |
4948 | sysvals.mincglen = getArgFloat('-mincg', value, 0.0, 10000.0, False) | 5145 | sysvals.mincglen = getArgFloat('-mincg', value, 0.0, 10000.0, False) |
4949 | elif(opt.lower() == 'output-dir'): | 5146 | elif(opt.lower() == 'output-dir'): |
4950 | sysvals.setOutputFolder(value) | 5147 | sysvals.testdir = sysvals.setOutputFolder(value) |
4951 | 5148 | ||
4952 | if sysvals.suspendmode == 'command' and not sysvals.testcommand: | 5149 | if sysvals.suspendmode == 'command' and not sysvals.testcommand: |
4953 | doError('No command supplied for mode "command"') | 5150 | doError('No command supplied for mode "command"') |
@@ -5030,8 +5227,6 @@ def configFromFile(file): | |||
5030 | # Description: | 5227 | # Description: |
5031 | # print out the help text | 5228 | # print out the help text |
5032 | def printHelp(): | 5229 | def printHelp(): |
5033 | modes = getModes() | ||
5034 | |||
5035 | print('') | 5230 | print('') |
5036 | print('%s v%s' % (sysvals.title, sysvals.version)) | 5231 | print('%s v%s' % (sysvals.title, sysvals.version)) |
5037 | print('Usage: sudo sleepgraph <options> <commands>') | 5232 | print('Usage: sudo sleepgraph <options> <commands>') |
@@ -5048,7 +5243,7 @@ def printHelp(): | |||
5048 | print(' If no specific command is given, the default behavior is to initiate') | 5243 | print(' If no specific command is given, the default behavior is to initiate') |
5049 | print(' a suspend/resume and capture the dmesg/ftrace output as an html timeline.') | 5244 | print(' a suspend/resume and capture the dmesg/ftrace output as an html timeline.') |
5050 | print('') | 5245 | print('') |
5051 | print(' Generates output files in subdirectory: suspend-mmddyy-HHMMSS') | 5246 | print(' Generates output files in subdirectory: suspend-yymmdd-HHMMSS') |
5052 | print(' HTML output: <hostname>_<mode>.html') | 5247 | print(' HTML output: <hostname>_<mode>.html') |
5053 | print(' raw dmesg output: <hostname>_<mode>_dmesg.txt') | 5248 | print(' raw dmesg output: <hostname>_<mode>_dmesg.txt') |
5054 | print(' raw ftrace output: <hostname>_<mode>_ftrace.txt') | 5249 | print(' raw ftrace output: <hostname>_<mode>_ftrace.txt') |
@@ -5058,8 +5253,9 @@ def printHelp(): | |||
5058 | print(' -v Print the current tool version') | 5253 | print(' -v Print the current tool version') |
5059 | print(' -config fn Pull arguments and config options from file fn') | 5254 | print(' -config fn Pull arguments and config options from file fn') |
5060 | print(' -verbose Print extra information during execution and analysis') | 5255 | print(' -verbose Print extra information during execution and analysis') |
5061 | print(' -m mode Mode to initiate for suspend %s (default: %s)') % (modes, sysvals.suspendmode) | 5256 | print(' -m mode Mode to initiate for suspend (default: %s)') % (sysvals.suspendmode) |
5062 | print(' -o subdir Override the output subdirectory') | 5257 | print(' -o name Overrides the output subdirectory name when running a new test') |
5258 | print(' default: suspend-{date}-{time}') | ||
5063 | print(' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)') | 5259 | print(' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)') |
5064 | print(' -addlogs Add the dmesg and ftrace logs to the html output') | 5260 | print(' -addlogs Add the dmesg and ftrace logs to the html output') |
5065 | print(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)') | 5261 | print(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)') |
@@ -5084,17 +5280,20 @@ def printHelp(): | |||
5084 | print(' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)') | 5280 | print(' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)') |
5085 | print(' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)') | 5281 | print(' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)') |
5086 | print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)') | 5282 | print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)') |
5087 | print(' [commands]') | 5283 | print('') |
5088 | print(' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)') | 5284 | print('Other commands:') |
5089 | print(' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)') | ||
5090 | print(' -summary directory Create a summary of all test in this dir') | ||
5091 | print(' -modes List available suspend modes') | 5285 | print(' -modes List available suspend modes') |
5092 | print(' -status Test to see if the system is enabled to run this tool') | 5286 | print(' -status Test to see if the system is enabled to run this tool') |
5093 | print(' -fpdt Print out the contents of the ACPI Firmware Performance Data Table') | 5287 | print(' -fpdt Print out the contents of the ACPI Firmware Performance Data Table') |
5288 | print(' -sysinfo Print out system info extracted from BIOS') | ||
5094 | print(' -usbtopo Print out the current USB topology with power info') | 5289 | print(' -usbtopo Print out the current USB topology with power info') |
5095 | print(' -usbauto Enable autosuspend for all connected USB devices') | 5290 | print(' -usbauto Enable autosuspend for all connected USB devices') |
5096 | print(' -flist Print the list of functions currently being captured in ftrace') | 5291 | print(' -flist Print the list of functions currently being captured in ftrace') |
5097 | print(' -flistall Print all functions capable of being captured in ftrace') | 5292 | print(' -flistall Print all functions capable of being captured in ftrace') |
5293 | print(' -summary directory Create a summary of all test in this dir') | ||
5294 | print(' [redo]') | ||
5295 | print(' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)') | ||
5296 | print(' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)') | ||
5098 | print('') | 5297 | print('') |
5099 | return True | 5298 | return True |
5100 | 5299 | ||
@@ -5102,9 +5301,9 @@ def printHelp(): | |||
5102 | # exec start (skipped if script is loaded as library) | 5301 | # exec start (skipped if script is loaded as library) |
5103 | if __name__ == '__main__': | 5302 | if __name__ == '__main__': |
5104 | cmd = '' | 5303 | cmd = '' |
5105 | cmdarg = '' | 5304 | outdir = '' |
5106 | multitest = {'run': False, 'count': 0, 'delay': 0} | 5305 | multitest = {'run': False, 'count': 0, 'delay': 0} |
5107 | simplecmds = ['-modes', '-fpdt', '-flist', '-flistall', '-usbtopo', '-usbauto', '-status'] | 5306 | simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall', '-usbtopo', '-usbauto', '-status'] |
5108 | # loop through the command line arguments | 5307 | # loop through the command line arguments |
5109 | args = iter(sys.argv[1:]) | 5308 | args = iter(sys.argv[1:]) |
5110 | for arg in args: | 5309 | for arg in args: |
@@ -5135,7 +5334,7 @@ if __name__ == '__main__': | |||
5135 | elif(arg == '-f'): | 5334 | elif(arg == '-f'): |
5136 | sysvals.usecallgraph = True | 5335 | sysvals.usecallgraph = True |
5137 | elif(arg == '-addlogs'): | 5336 | elif(arg == '-addlogs'): |
5138 | sysvals.addlogs = True | 5337 | sysvals.dmesglog = sysvals.ftracelog = True |
5139 | elif(arg == '-verbose'): | 5338 | elif(arg == '-verbose'): |
5140 | sysvals.verbose = True | 5339 | sysvals.verbose = True |
5141 | elif(arg == '-proc'): | 5340 | elif(arg == '-proc'): |
@@ -5195,7 +5394,7 @@ if __name__ == '__main__': | |||
5195 | val = args.next() | 5394 | val = args.next() |
5196 | except: | 5395 | except: |
5197 | doError('No subdirectory name supplied', True) | 5396 | doError('No subdirectory name supplied', True) |
5198 | sysvals.setOutputFolder(val) | 5397 | outdir = sysvals.setOutputFolder(val) |
5199 | elif(arg == '-config'): | 5398 | elif(arg == '-config'): |
5200 | try: | 5399 | try: |
5201 | val = args.next() | 5400 | val = args.next() |
@@ -5236,7 +5435,7 @@ if __name__ == '__main__': | |||
5236 | except: | 5435 | except: |
5237 | doError('No directory supplied', True) | 5436 | doError('No directory supplied', True) |
5238 | cmd = 'summary' | 5437 | cmd = 'summary' |
5239 | cmdarg = val | 5438 | outdir = val |
5240 | sysvals.notestrun = True | 5439 | sysvals.notestrun = True |
5241 | if(os.path.isdir(val) == False): | 5440 | if(os.path.isdir(val) == False): |
5242 | doError('%s is not accesible' % val) | 5441 | doError('%s is not accesible' % val) |
@@ -5260,11 +5459,14 @@ if __name__ == '__main__': | |||
5260 | sysvals.mincglen = sysvals.mindevlen | 5459 | sysvals.mincglen = sysvals.mindevlen |
5261 | 5460 | ||
5262 | # just run a utility command and exit | 5461 | # just run a utility command and exit |
5462 | sysvals.cpuInfo() | ||
5263 | if(cmd != ''): | 5463 | if(cmd != ''): |
5264 | if(cmd == 'status'): | 5464 | if(cmd == 'status'): |
5265 | statusCheck(True) | 5465 | statusCheck(True) |
5266 | elif(cmd == 'fpdt'): | 5466 | elif(cmd == 'fpdt'): |
5267 | getFPDT(True) | 5467 | getFPDT(True) |
5468 | elif(cmd == 'sysinfo'): | ||
5469 | sysvals.printSystemInfo() | ||
5268 | elif(cmd == 'usbtopo'): | 5470 | elif(cmd == 'usbtopo'): |
5269 | detectUSB() | 5471 | detectUSB() |
5270 | elif(cmd == 'modes'): | 5472 | elif(cmd == 'modes'): |
@@ -5276,7 +5478,7 @@ if __name__ == '__main__': | |||
5276 | elif(cmd == 'usbauto'): | 5478 | elif(cmd == 'usbauto'): |
5277 | setUSBDevicesAuto() | 5479 | setUSBDevicesAuto() |
5278 | elif(cmd == 'summary'): | 5480 | elif(cmd == 'summary'): |
5279 | runSummary(cmdarg, True) | 5481 | runSummary(outdir, True) |
5280 | sys.exit() | 5482 | sys.exit() |
5281 | 5483 | ||
5282 | # if instructed, re-analyze existing data files | 5484 | # if instructed, re-analyze existing data files |
@@ -5289,21 +5491,43 @@ if __name__ == '__main__': | |||
5289 | print('Check FAILED, aborting the test run!') | 5491 | print('Check FAILED, aborting the test run!') |
5290 | sys.exit() | 5492 | sys.exit() |
5291 | 5493 | ||
5494 | # extract mem modes and convert | ||
5495 | mode = sysvals.suspendmode | ||
5496 | if 'mem' == mode[:3]: | ||
5497 | if '-' in mode: | ||
5498 | memmode = mode.split('-')[-1] | ||
5499 | else: | ||
5500 | memmode = 'deep' | ||
5501 | if memmode == 'shallow': | ||
5502 | mode = 'standby' | ||
5503 | elif memmode == 's2idle': | ||
5504 | mode = 'freeze' | ||
5505 | else: | ||
5506 | mode = 'mem' | ||
5507 | sysvals.memmode = memmode | ||
5508 | sysvals.suspendmode = mode | ||
5509 | |||
5510 | sysvals.systemInfo(dmidecode(sysvals.mempath)) | ||
5511 | |||
5292 | if multitest['run']: | 5512 | if multitest['run']: |
5293 | # run multiple tests in a separate subdirectory | 5513 | # run multiple tests in a separate subdirectory |
5294 | s = 'x%d' % multitest['count'] | 5514 | if not outdir: |
5295 | if not sysvals.outdir: | 5515 | s = 'suspend-x%d' % multitest['count'] |
5296 | sysvals.outdir = datetime.now().strftime('suspend-'+s+'-%m%d%y-%H%M%S') | 5516 | outdir = datetime.now().strftime(s+'-%y%m%d-%H%M%S') |
5297 | if not os.path.isdir(sysvals.outdir): | 5517 | if not os.path.isdir(outdir): |
5298 | os.mkdir(sysvals.outdir) | 5518 | os.mkdir(outdir) |
5299 | for i in range(multitest['count']): | 5519 | for i in range(multitest['count']): |
5300 | if(i != 0): | 5520 | if(i != 0): |
5301 | print('Waiting %d seconds...' % (multitest['delay'])) | 5521 | print('Waiting %d seconds...' % (multitest['delay'])) |
5302 | time.sleep(multitest['delay']) | 5522 | time.sleep(multitest['delay']) |
5303 | print('TEST (%d/%d) START' % (i+1, multitest['count'])) | 5523 | print('TEST (%d/%d) START' % (i+1, multitest['count'])) |
5304 | runTest(sysvals.outdir) | 5524 | fmt = 'suspend-%y%m%d-%H%M%S' |
5525 | sysvals.testdir = os.path.join(outdir, datetime.now().strftime(fmt)) | ||
5526 | runTest() | ||
5305 | print('TEST (%d/%d) COMPLETE' % (i+1, multitest['count'])) | 5527 | print('TEST (%d/%d) COMPLETE' % (i+1, multitest['count'])) |
5306 | runSummary(sysvals.outdir, False) | 5528 | runSummary(outdir, False) |
5307 | else: | 5529 | else: |
5530 | if outdir: | ||
5531 | sysvals.testdir = outdir | ||
5308 | # run the test in the current directory | 5532 | # run the test in the current directory |
5309 | runTest('.', sysvals.outdir) | 5533 | runTest() |
diff --git a/tools/power/pm-graph/bootgraph.8 b/tools/power/pm-graph/bootgraph.8 index 55272a67b0e7..dbdafcf546df 100644 --- a/tools/power/pm-graph/bootgraph.8 +++ b/tools/power/pm-graph/bootgraph.8 | |||
@@ -8,14 +8,23 @@ bootgraph \- Kernel boot timing analysis | |||
8 | .RB [ COMMAND ] | 8 | .RB [ COMMAND ] |
9 | .SH DESCRIPTION | 9 | .SH DESCRIPTION |
10 | \fBbootgraph \fP reads the dmesg log from kernel boot and | 10 | \fBbootgraph \fP reads the dmesg log from kernel boot and |
11 | creates an html representation of the initcall timeline up to the start | 11 | creates an html representation of the initcall timeline. It graphs |
12 | of the init process. | 12 | every module init call found, through both kernel and user modes. The |
13 | timeline is split into two phases: kernel mode & user mode. kernel mode | ||
14 | represents a single process run on a single cpu with serial init calls. | ||
15 | Once user mode begins, the init process is called, and the init calls | ||
16 | start working in parallel. | ||
13 | .PP | 17 | .PP |
14 | If no specific command is given, the tool reads the current dmesg log and | 18 | If no specific command is given, the tool reads the current dmesg log and |
15 | outputs bootgraph.html. | 19 | outputs a new timeline. |
16 | .PP | 20 | .PP |
17 | The tool can also augment the timeline with ftrace data on custom target | 21 | The tool can also augment the timeline with ftrace data on custom target |
18 | functions as well as full trace callgraphs. | 22 | functions as well as full trace callgraphs. |
23 | .PP | ||
24 | Generates output files in subdirectory: boot-yymmdd-HHMMSS | ||
25 | html timeline : <hostname>_boot.html | ||
26 | raw dmesg file : <hostname>_boot_dmesg.txt | ||
27 | raw ftrace file : <hostname>_boot_ftrace.txt | ||
19 | .SH OPTIONS | 28 | .SH OPTIONS |
20 | .TP | 29 | .TP |
21 | \fB-h\fR | 30 | \fB-h\fR |
@@ -28,15 +37,18 @@ Print the current tool version | |||
28 | Add the dmesg log to the html output. It will be viewable by | 37 | Add the dmesg log to the html output. It will be viewable by |
29 | clicking a button in the timeline. | 38 | clicking a button in the timeline. |
30 | .TP | 39 | .TP |
31 | \fB-o \fIfile\fR | 40 | \fB-o \fIname\fR |
32 | Override the HTML output filename (default: bootgraph.html) | 41 | Overrides the output subdirectory name when running a new test. |
33 | .SS "Ftrace Debug" | 42 | Use {date}, {time}, {hostname} for current values. |
43 | .sp | ||
44 | e.g. boot-{hostname}-{date}-{time} | ||
45 | .SS "advanced" | ||
34 | .TP | 46 | .TP |
35 | \fB-f\fR | 47 | \fB-f\fR |
36 | Use ftrace to add function detail (default: disabled) | 48 | Use ftrace to add function detail (default: disabled) |
37 | .TP | 49 | .TP |
38 | \fB-callgraph\fR | 50 | \fB-callgraph\fR |
39 | Use ftrace to create initcall callgraphs (default: disabled). If -filter | 51 | Use ftrace to create initcall callgraphs (default: disabled). If -func |
40 | is not used there will be one callgraph per initcall. This can produce | 52 | is not used there will be one callgraph per initcall. This can produce |
41 | very large outputs, i.e. 10MB - 100MB. | 53 | very large outputs, i.e. 10MB - 100MB. |
42 | .TP | 54 | .TP |
@@ -50,16 +62,19 @@ This reduces the html file size as there can be many tiny callgraphs | |||
50 | which are barely visible in the timeline. | 62 | which are barely visible in the timeline. |
51 | The value is a float: e.g. 0.001 represents 1 us. | 63 | The value is a float: e.g. 0.001 represents 1 us. |
52 | .TP | 64 | .TP |
65 | \fB-cgfilter \fI"func1,func2,..."\fR | ||
66 | Reduce callgraph output in the timeline by limiting it to a list of calls. The | ||
67 | argument can be a single function name or a comma delimited list. | ||
68 | (default: none) | ||
69 | .TP | ||
53 | \fB-timeprec \fIn\fR | 70 | \fB-timeprec \fIn\fR |
54 | Number of significant digits in timestamps (0:S, 3:ms, [6:us]) | 71 | Number of significant digits in timestamps (0:S, 3:ms, [6:us]) |
55 | .TP | 72 | .TP |
56 | \fB-expandcg\fR | 73 | \fB-expandcg\fR |
57 | pre-expand the callgraph data in the html output (default: disabled) | 74 | pre-expand the callgraph data in the html output (default: disabled) |
58 | .TP | 75 | .TP |
59 | \fB-filter \fI"func1,func2,..."\fR | 76 | \fB-func \fI"func1,func2,..."\fR |
60 | Instead of tracing each initcall, trace a custom list of functions (default: do_one_initcall) | 77 | Instead of tracing each initcall, trace a custom list of functions (default: do_one_initcall) |
61 | |||
62 | .SH COMMANDS | ||
63 | .TP | 78 | .TP |
64 | \fB-reboot\fR | 79 | \fB-reboot\fR |
65 | Reboot the machine and generate a new timeline automatically. Works in 4 steps. | 80 | Reboot the machine and generate a new timeline automatically. Works in 4 steps. |
@@ -73,16 +88,23 @@ Show the requirements to generate a new timeline manually. Requires 3 steps. | |||
73 | 1. append the string to the kernel command line via your native boot manager. | 88 | 1. append the string to the kernel command line via your native boot manager. |
74 | 2. reboot the system | 89 | 2. reboot the system |
75 | 3. after startup, re-run the tool with the same arguments and no command | 90 | 3. after startup, re-run the tool with the same arguments and no command |
91 | |||
92 | .SH COMMANDS | ||
93 | .SS "rebuild" | ||
76 | .TP | 94 | .TP |
77 | \fB-dmesg \fIfile\fR | 95 | \fB-dmesg \fIfile\fR |
78 | Create HTML output from an existing dmesg file. | 96 | Create HTML output from an existing dmesg file. |
79 | .TP | 97 | .TP |
80 | \fB-ftrace \fIfile\fR | 98 | \fB-ftrace \fIfile\fR |
81 | Create HTML output from an existing ftrace file (used with -dmesg). | 99 | Create HTML output from an existing ftrace file (used with -dmesg). |
100 | .SS "other" | ||
82 | .TP | 101 | .TP |
83 | \fB-flistall\fR | 102 | \fB-flistall\fR |
84 | Print all ftrace functions capable of being captured. These are all the | 103 | Print all ftrace functions capable of being captured. These are all the |
85 | possible values you can add to trace via the -filter argument. | 104 | possible values you can add to trace via the -func argument. |
105 | .TP | ||
106 | \fB-sysinfo\fR | ||
107 | Print out system info extracted from BIOS. Reads /dev/mem directly instead of going through dmidecode. | ||
86 | 108 | ||
87 | .SH EXAMPLES | 109 | .SH EXAMPLES |
88 | Create a timeline using the current dmesg log. | 110 | Create a timeline using the current dmesg log. |
@@ -93,13 +115,13 @@ Create a timeline using the current dmesg and ftrace log. | |||
93 | .IP | 115 | .IP |
94 | \f(CW$ bootgraph -callgraph\fR | 116 | \f(CW$ bootgraph -callgraph\fR |
95 | .PP | 117 | .PP |
96 | Create a timeline using the current dmesg, add the log to the html and change the name. | 118 | Create a timeline using the current dmesg, add the log to the html and change the folder. |
97 | .IP | 119 | .IP |
98 | \f(CW$ bootgraph -addlogs -o myboot.html\fR | 120 | \f(CW$ bootgraph -addlogs -o "myboot-{date}-{time}"\fR |
99 | .PP | 121 | .PP |
100 | Capture a new boot timeline by automatically rebooting the machine. | 122 | Capture a new boot timeline by automatically rebooting the machine. |
101 | .IP | 123 | .IP |
102 | \f(CW$ sudo bootgraph -reboot -addlogs -o latestboot.html\fR | 124 | \f(CW$ sudo bootgraph -reboot -addlogs -o "latest-{hostname)"\fR |
103 | .PP | 125 | .PP |
104 | Capture a new boot timeline with function trace data. | 126 | Capture a new boot timeline with function trace data. |
105 | .IP | 127 | .IP |
@@ -111,7 +133,7 @@ Capture a new boot timeline with trace & callgraph data. Skip callgraphs smaller | |||
111 | .PP | 133 | .PP |
112 | Capture a new boot timeline with callgraph data over custom functions. | 134 | Capture a new boot timeline with callgraph data over custom functions. |
113 | .IP | 135 | .IP |
114 | \f(CW$ sudo bootgraph -reboot -callgraph -filter "acpi_ps_parse_aml,msleep"\fR | 136 | \f(CW$ sudo bootgraph -reboot -callgraph -func "acpi_ps_parse_aml,msleep"\fR |
115 | .PP | 137 | .PP |
116 | Capture a brand new boot timeline with manual reboot. | 138 | Capture a brand new boot timeline with manual reboot. |
117 | .IP | 139 | .IP |
@@ -123,6 +145,15 @@ Capture a brand new boot timeline with manual reboot. | |||
123 | .IP | 145 | .IP |
124 | \f(CW$ sudo bootgraph -callgraph # re-run the tool after restart\fR | 146 | \f(CW$ sudo bootgraph -callgraph # re-run the tool after restart\fR |
125 | .PP | 147 | .PP |
148 | .SS "rebuild timeline from logs" | ||
149 | .PP | ||
150 | Rebuild the html from a previous run's logs, using the same options. | ||
151 | .IP | ||
152 | \f(CW$ bootgraph -dmesg dmesg.txt -ftrace ftrace.txt -callgraph\fR | ||
153 | .PP | ||
154 | Rebuild the html with different options. | ||
155 | .IP | ||
156 | \f(CW$ bootgraph -dmesg dmesg.txt -ftrace ftrace.txt -addlogs\fR | ||
126 | 157 | ||
127 | .SH "SEE ALSO" | 158 | .SH "SEE ALSO" |
128 | dmesg(1), update-grub(8), crontab(1), reboot(8) | 159 | dmesg(1), update-grub(8), crontab(1), reboot(8) |
diff --git a/tools/power/pm-graph/sleepgraph.8 b/tools/power/pm-graph/sleepgraph.8 index 610e72ebbc06..fbe7bd3eae8e 100644 --- a/tools/power/pm-graph/sleepgraph.8 +++ b/tools/power/pm-graph/sleepgraph.8 | |||
@@ -39,8 +39,9 @@ Pull arguments and config options from a file. | |||
39 | \fB-m \fImode\fR | 39 | \fB-m \fImode\fR |
40 | Mode to initiate for suspend e.g. standby, freeze, mem (default: mem). | 40 | Mode to initiate for suspend e.g. standby, freeze, mem (default: mem). |
41 | .TP | 41 | .TP |
42 | \fB-o \fIsubdir\fR | 42 | \fB-o \fIname\fR |
43 | Override the output subdirectory. Use {date}, {time}, {hostname} for current values. | 43 | Overrides the output subdirectory name when running a new test. |
44 | Use {date}, {time}, {hostname} for current values. | ||
44 | .sp | 45 | .sp |
45 | e.g. suspend-{hostname}-{date}-{time} | 46 | e.g. suspend-{hostname}-{date}-{time} |
46 | .TP | 47 | .TP |
@@ -52,7 +53,7 @@ disable rtcwake and require a user keypress to resume. | |||
52 | Add the dmesg and ftrace logs to the html output. They will be viewable by | 53 | Add the dmesg and ftrace logs to the html output. They will be viewable by |
53 | clicking buttons in the timeline. | 54 | clicking buttons in the timeline. |
54 | 55 | ||
55 | .SS "Advanced" | 56 | .SS "advanced" |
56 | .TP | 57 | .TP |
57 | \fB-cmd \fIstr\fR | 58 | \fB-cmd \fIstr\fR |
58 | Run the timeline over a custom suspend command, e.g. pm-suspend. By default | 59 | Run the timeline over a custom suspend command, e.g. pm-suspend. By default |
@@ -91,7 +92,7 @@ Include \fIt\fR ms delay after last resume (default: 0 ms). | |||
91 | Execute \fIn\fR consecutive tests at \fId\fR seconds intervals. The outputs will | 92 | Execute \fIn\fR consecutive tests at \fId\fR seconds intervals. The outputs will |
92 | be created in a new subdirectory with a summary page: suspend-xN-{date}-{time}. | 93 | be created in a new subdirectory with a summary page: suspend-xN-{date}-{time}. |
93 | 94 | ||
94 | .SS "Ftrace Debug" | 95 | .SS "ftrace debug" |
95 | .TP | 96 | .TP |
96 | \fB-f\fR | 97 | \fB-f\fR |
97 | Use ftrace to create device callgraphs (default: disabled). This can produce | 98 | Use ftrace to create device callgraphs (default: disabled). This can produce |
@@ -124,12 +125,6 @@ Number of significant digits in timestamps (0:S, [3:ms], 6:us). | |||
124 | 125 | ||
125 | .SH COMMANDS | 126 | .SH COMMANDS |
126 | .TP | 127 | .TP |
127 | \fB-ftrace \fIfile\fR | ||
128 | Create HTML output from an existing ftrace file. | ||
129 | .TP | ||
130 | \fB-dmesg \fIfile\fR | ||
131 | Create HTML output from an existing dmesg file. | ||
132 | .TP | ||
133 | \fB-summary \fIindir\fR | 128 | \fB-summary \fIindir\fR |
134 | Create a summary page of all tests in \fIindir\fR. Creates summary.html | 129 | Create a summary page of all tests in \fIindir\fR. Creates summary.html |
135 | in the current folder. The output page is a table of tests with | 130 | in the current folder. The output page is a table of tests with |
@@ -146,6 +141,9 @@ with any options you intend to use to see if they will work. | |||
146 | \fB-fpdt\fR | 141 | \fB-fpdt\fR |
147 | Print out the contents of the ACPI Firmware Performance Data Table. | 142 | Print out the contents of the ACPI Firmware Performance Data Table. |
148 | .TP | 143 | .TP |
144 | \fB-sysinfo\fR | ||
145 | Print out system info extracted from BIOS. Reads /dev/mem directly instead of going through dmidecode. | ||
146 | .TP | ||
149 | \fB-usbtopo\fR | 147 | \fB-usbtopo\fR |
150 | Print out the current USB topology with power info. | 148 | Print out the current USB topology with power info. |
151 | .TP | 149 | .TP |
@@ -162,9 +160,16 @@ with -fadd they will also be checked. | |||
162 | \fB-flistall\fR | 160 | \fB-flistall\fR |
163 | Print all ftrace functions capable of being captured. These are all the | 161 | Print all ftrace functions capable of being captured. These are all the |
164 | possible values you can add to trace via the -fadd argument. | 162 | possible values you can add to trace via the -fadd argument. |
163 | .SS "rebuild" | ||
164 | .TP | ||
165 | \fB-ftrace \fIfile\fR | ||
166 | Create HTML output from an existing ftrace file. | ||
167 | .TP | ||
168 | \fB-dmesg \fIfile\fR | ||
169 | Create HTML output from an existing dmesg file. | ||
165 | 170 | ||
166 | .SH EXAMPLES | 171 | .SH EXAMPLES |
167 | .SS "Simple Commands" | 172 | .SS "simple commands" |
168 | Check which suspend modes are currently supported. | 173 | Check which suspend modes are currently supported. |
169 | .IP | 174 | .IP |
170 | \f(CW$ sleepgraph -modes\fR | 175 | \f(CW$ sleepgraph -modes\fR |
@@ -185,12 +190,8 @@ Generate a summary of all timelines in a particular folder. | |||
185 | .IP | 190 | .IP |
186 | \f(CW$ sleepgraph -summary ~/workspace/myresults/\fR | 191 | \f(CW$ sleepgraph -summary ~/workspace/myresults/\fR |
187 | .PP | 192 | .PP |
188 | Re-generate the html output from a previous run's dmesg and ftrace log. | ||
189 | .IP | ||
190 | \f(CW$ sleepgraph -dmesg myhost_mem_dmesg.txt -ftrace myhost_mem_ftrace.txt\fR | ||
191 | .PP | ||
192 | 193 | ||
193 | .SS "Capturing Simple Timelines" | 194 | .SS "capturing basic timelines" |
194 | Execute a mem suspend with a 15 second wakeup. Include the logs in the html. | 195 | Execute a mem suspend with a 15 second wakeup. Include the logs in the html. |
195 | .IP | 196 | .IP |
196 | \f(CW$ sudo sleepgraph -rtcwake 15 -addlogs\fR | 197 | \f(CW$ sudo sleepgraph -rtcwake 15 -addlogs\fR |
@@ -204,7 +205,7 @@ Execute a freeze with no wakeup (require keypress). Change output folder name. | |||
204 | \f(CW$ sudo sleepgraph -m freeze -rtcwake off -o "freeze-{hostname}-{date}-{time}"\fR | 205 | \f(CW$ sudo sleepgraph -m freeze -rtcwake off -o "freeze-{hostname}-{date}-{time}"\fR |
205 | .PP | 206 | .PP |
206 | 207 | ||
207 | .SS "Capturing Advanced Timelines" | 208 | .SS "capturing advanced timelines" |
208 | Execute a suspend & include dev mode source calls, limit callbacks to 5ms or larger. | 209 | Execute a suspend & include dev mode source calls, limit callbacks to 5ms or larger. |
209 | .IP | 210 | .IP |
210 | \f(CW$ sudo sleepgraph -m mem -rtcwake 15 -dev -mindev 5\fR | 211 | \f(CW$ sudo sleepgraph -m mem -rtcwake 15 -dev -mindev 5\fR |
@@ -222,8 +223,7 @@ Execute a suspend using a custom command. | |||
222 | \f(CW$ sudo sleepgraph -cmd "echo mem > /sys/power/state" -rtcwake 15\fR | 223 | \f(CW$ sudo sleepgraph -cmd "echo mem > /sys/power/state" -rtcwake 15\fR |
223 | .PP | 224 | .PP |
224 | 225 | ||
225 | 226 | .SS "adding callgraph data" | |
226 | .SS "Capturing Timelines with Callgraph Data" | ||
227 | Add device callgraphs. Limit the trace depth and only show callgraphs 10ms or larger. | 227 | Add device callgraphs. Limit the trace depth and only show callgraphs 10ms or larger. |
228 | .IP | 228 | .IP |
229 | \f(CW$ sudo sleepgraph -m mem -rtcwake 15 -f -maxdepth 5 -mincg 10\fR | 229 | \f(CW$ sudo sleepgraph -m mem -rtcwake 15 -f -maxdepth 5 -mincg 10\fR |
@@ -235,6 +235,16 @@ Capture a full callgraph across all suspend, then filter the html by a single ph | |||
235 | \f(CW$ sleepgraph -dmesg host_mem_dmesg.txt -ftrace host_mem_ftrace.txt -f -cgphase resume | 235 | \f(CW$ sleepgraph -dmesg host_mem_dmesg.txt -ftrace host_mem_ftrace.txt -f -cgphase resume |
236 | .PP | 236 | .PP |
237 | 237 | ||
238 | .SS "rebuild timeline from logs" | ||
239 | .PP | ||
240 | Rebuild the html from a previous run's logs, using the same options. | ||
241 | .IP | ||
242 | \f(CW$ sleepgraph -dmesg dmesg.txt -ftrace ftrace.txt -callgraph\fR | ||
243 | .PP | ||
244 | Rebuild the html with different options. | ||
245 | .IP | ||
246 | \f(CW$ sleepgraph -dmesg dmesg.txt -ftrace ftrace.txt -addlogs -srgap\fR | ||
247 | |||
238 | .SH "SEE ALSO" | 248 | .SH "SEE ALSO" |
239 | dmesg(1) | 249 | dmesg(1) |
240 | .PP | 250 | .PP |
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index 1e8b6116ba3c..9dc8f078a83c 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include | |||
@@ -1,7 +1,7 @@ | |||
1 | ifneq ($(O),) | 1 | ifneq ($(O),) |
2 | ifeq ($(origin O), command line) | 2 | ifeq ($(origin O), command line) |
3 | dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),) | 3 | ABSOLUTE_O := $(realpath $(O)) |
4 | ABSOLUTE_O := $(shell cd $(O) ; pwd) | 4 | dummy := $(if $(ABSOLUTE_O),,$(error O=$(O) does not exist)) |
5 | OUTPUT := $(ABSOLUTE_O)/$(if $(subdir),$(subdir)/) | 5 | OUTPUT := $(ABSOLUTE_O)/$(if $(subdir),$(subdir)/) |
6 | COMMAND_O := O=$(ABSOLUTE_O) | 6 | COMMAND_O := O=$(ABSOLUTE_O) |
7 | ifeq ($(objtree),) | 7 | ifeq ($(objtree),) |
@@ -12,7 +12,7 @@ endif | |||
12 | 12 | ||
13 | # check that the output directory actually exists | 13 | # check that the output directory actually exists |
14 | ifneq ($(OUTPUT),) | 14 | ifneq ($(OUTPUT),) |
15 | OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) | 15 | OUTDIR := $(realpath $(OUTPUT)) |
16 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) | 16 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) |
17 | endif | 17 | endif |
18 | 18 | ||
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 4c2fa98ef39d..bef419d4266d 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -1527,9 +1527,6 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
1527 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); | 1527 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); |
1528 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); | 1528 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); |
1529 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); | 1529 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); |
1530 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); | ||
1531 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); | ||
1532 | set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); | ||
1533 | } | 1530 | } |
1534 | 1531 | ||
1535 | static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, | 1532 | static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, |
@@ -1546,8 +1543,8 @@ static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, | |||
1546 | else { | 1543 | else { |
1547 | memcpy(iobuf, mmio->addr.base + dpa, len); | 1544 | memcpy(iobuf, mmio->addr.base + dpa, len); |
1548 | 1545 | ||
1549 | /* give us some some coverage of the mmio_flush_range() API */ | 1546 | /* give us some some coverage of the arch_invalidate_pmem() API */ |
1550 | mmio_flush_range(mmio->addr.base + dpa, len); | 1547 | arch_invalidate_pmem(mmio->addr.base + dpa, len); |
1551 | } | 1548 | } |
1552 | nd_region_release_lane(nd_region, lane); | 1549 | nd_region_release_lane(nd_region, lane); |
1553 | 1550 | ||
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 26ce4f7168be..ff805643b5f7 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -52,6 +52,10 @@ override LDFLAGS = | |||
52 | override MAKEFLAGS = | 52 | override MAKEFLAGS = |
53 | endif | 53 | endif |
54 | 54 | ||
55 | ifneq ($(KBUILD_SRC),) | ||
56 | override LDFLAGS = | ||
57 | endif | ||
58 | |||
55 | BUILD := $(O) | 59 | BUILD := $(O) |
56 | ifndef BUILD | 60 | ifndef BUILD |
57 | BUILD := $(KBUILD_OUTPUT) | 61 | BUILD := $(KBUILD_OUTPUT) |
@@ -62,32 +66,32 @@ endif | |||
62 | 66 | ||
63 | export BUILD | 67 | export BUILD |
64 | all: | 68 | all: |
65 | for TARGET in $(TARGETS); do \ | 69 | @for TARGET in $(TARGETS); do \ |
66 | BUILD_TARGET=$$BUILD/$$TARGET; \ | 70 | BUILD_TARGET=$$BUILD/$$TARGET; \ |
67 | mkdir $$BUILD_TARGET -p; \ | 71 | mkdir $$BUILD_TARGET -p; \ |
68 | make OUTPUT=$$BUILD_TARGET -C $$TARGET;\ | 72 | make OUTPUT=$$BUILD_TARGET -C $$TARGET;\ |
69 | done; | 73 | done; |
70 | 74 | ||
71 | run_tests: all | 75 | run_tests: all |
72 | for TARGET in $(TARGETS); do \ | 76 | @for TARGET in $(TARGETS); do \ |
73 | BUILD_TARGET=$$BUILD/$$TARGET; \ | 77 | BUILD_TARGET=$$BUILD/$$TARGET; \ |
74 | make OUTPUT=$$BUILD_TARGET -C $$TARGET run_tests;\ | 78 | make OUTPUT=$$BUILD_TARGET -C $$TARGET run_tests;\ |
75 | done; | 79 | done; |
76 | 80 | ||
77 | hotplug: | 81 | hotplug: |
78 | for TARGET in $(TARGETS_HOTPLUG); do \ | 82 | @for TARGET in $(TARGETS_HOTPLUG); do \ |
79 | BUILD_TARGET=$$BUILD/$$TARGET; \ | 83 | BUILD_TARGET=$$BUILD/$$TARGET; \ |
80 | make OUTPUT=$$BUILD_TARGET -C $$TARGET;\ | 84 | make OUTPUT=$$BUILD_TARGET -C $$TARGET;\ |
81 | done; | 85 | done; |
82 | 86 | ||
83 | run_hotplug: hotplug | 87 | run_hotplug: hotplug |
84 | for TARGET in $(TARGETS_HOTPLUG); do \ | 88 | @for TARGET in $(TARGETS_HOTPLUG); do \ |
85 | BUILD_TARGET=$$BUILD/$$TARGET; \ | 89 | BUILD_TARGET=$$BUILD/$$TARGET; \ |
86 | make OUTPUT=$$BUILD_TARGET -C $$TARGET run_full_test;\ | 90 | make OUTPUT=$$BUILD_TARGET -C $$TARGET run_full_test;\ |
87 | done; | 91 | done; |
88 | 92 | ||
89 | clean_hotplug: | 93 | clean_hotplug: |
90 | for TARGET in $(TARGETS_HOTPLUG); do \ | 94 | @for TARGET in $(TARGETS_HOTPLUG); do \ |
91 | BUILD_TARGET=$$BUILD/$$TARGET; \ | 95 | BUILD_TARGET=$$BUILD/$$TARGET; \ |
92 | make OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\ | 96 | make OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\ |
93 | done; | 97 | done; |
@@ -103,7 +107,7 @@ install: | |||
103 | ifdef INSTALL_PATH | 107 | ifdef INSTALL_PATH |
104 | @# Ask all targets to install their files | 108 | @# Ask all targets to install their files |
105 | mkdir -p $(INSTALL_PATH) | 109 | mkdir -p $(INSTALL_PATH) |
106 | for TARGET in $(TARGETS); do \ | 110 | @for TARGET in $(TARGETS); do \ |
107 | BUILD_TARGET=$$BUILD/$$TARGET; \ | 111 | BUILD_TARGET=$$BUILD/$$TARGET; \ |
108 | make OUTPUT=$$BUILD_TARGET -C $$TARGET INSTALL_PATH=$(INSTALL_PATH)/$$TARGET install; \ | 112 | make OUTPUT=$$BUILD_TARGET -C $$TARGET INSTALL_PATH=$(INSTALL_PATH)/$$TARGET install; \ |
109 | done; | 113 | done; |
@@ -128,7 +132,7 @@ else | |||
128 | endif | 132 | endif |
129 | 133 | ||
130 | clean: | 134 | clean: |
131 | for TARGET in $(TARGETS); do \ | 135 | @for TARGET in $(TARGETS); do \ |
132 | BUILD_TARGET=$$BUILD/$$TARGET; \ | 136 | BUILD_TARGET=$$BUILD/$$TARGET; \ |
133 | make OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\ | 137 | make OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\ |
134 | done; | 138 | done; |
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 153c3a181a4c..f4b23d697448 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile | |||
@@ -15,9 +15,9 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test | |||
15 | test_align | 15 | test_align |
16 | 16 | ||
17 | TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ | 17 | TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ |
18 | test_pkt_md_access.o | 18 | test_pkt_md_access.o test_xdp_redirect.o sockmap_parse_prog.o sockmap_verdict_prog.o |
19 | 19 | ||
20 | TEST_PROGS := test_kmod.sh | 20 | TEST_PROGS := test_kmod.sh test_xdp_redirect.sh |
21 | 21 | ||
22 | include ../lib.mk | 22 | include ../lib.mk |
23 | 23 | ||
diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index d50ac342dc92..36fb9161b34a 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h | |||
@@ -38,6 +38,8 @@ static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = | |||
38 | (void *) BPF_FUNC_clone_redirect; | 38 | (void *) BPF_FUNC_clone_redirect; |
39 | static int (*bpf_redirect)(int ifindex, int flags) = | 39 | static int (*bpf_redirect)(int ifindex, int flags) = |
40 | (void *) BPF_FUNC_redirect; | 40 | (void *) BPF_FUNC_redirect; |
41 | static int (*bpf_redirect_map)(void *map, int key, int flags) = | ||
42 | (void *) BPF_FUNC_redirect_map; | ||
41 | static int (*bpf_perf_event_output)(void *ctx, void *map, | 43 | static int (*bpf_perf_event_output)(void *ctx, void *map, |
42 | unsigned long long flags, void *data, | 44 | unsigned long long flags, void *data, |
43 | int size) = | 45 | int size) = |
@@ -63,6 +65,12 @@ static int (*bpf_xdp_adjust_head)(void *ctx, int offset) = | |||
63 | static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, | 65 | static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, |
64 | int optlen) = | 66 | int optlen) = |
65 | (void *) BPF_FUNC_setsockopt; | 67 | (void *) BPF_FUNC_setsockopt; |
68 | static int (*bpf_sk_redirect_map)(void *map, int key, int flags) = | ||
69 | (void *) BPF_FUNC_sk_redirect_map; | ||
70 | static int (*bpf_sock_map_update)(void *map, void *key, void *value, | ||
71 | unsigned long long flags) = | ||
72 | (void *) BPF_FUNC_sock_map_update; | ||
73 | |||
66 | 74 | ||
67 | /* llvm builtin functions that eBPF C program may use to | 75 | /* llvm builtin functions that eBPF C program may use to |
68 | * emit BPF_LD_ABS and BPF_LD_IND instructions | 76 | * emit BPF_LD_ABS and BPF_LD_IND instructions |
@@ -85,6 +93,7 @@ struct bpf_map_def { | |||
85 | unsigned int max_entries; | 93 | unsigned int max_entries; |
86 | unsigned int map_flags; | 94 | unsigned int map_flags; |
87 | unsigned int inner_map_idx; | 95 | unsigned int inner_map_idx; |
96 | unsigned int numa_node; | ||
88 | }; | 97 | }; |
89 | 98 | ||
90 | static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = | 99 | static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = |
diff --git a/tools/testing/selftests/bpf/bpf_util.h b/tools/testing/selftests/bpf/bpf_util.h index 20ecbaa0d85d..6c53a8906eff 100644 --- a/tools/testing/selftests/bpf/bpf_util.h +++ b/tools/testing/selftests/bpf/bpf_util.h | |||
@@ -12,6 +12,7 @@ static inline unsigned int bpf_num_possible_cpus(void) | |||
12 | unsigned int start, end, possible_cpus = 0; | 12 | unsigned int start, end, possible_cpus = 0; |
13 | char buff[128]; | 13 | char buff[128]; |
14 | FILE *fp; | 14 | FILE *fp; |
15 | int n; | ||
15 | 16 | ||
16 | fp = fopen(fcpu, "r"); | 17 | fp = fopen(fcpu, "r"); |
17 | if (!fp) { | 18 | if (!fp) { |
@@ -20,17 +21,17 @@ static inline unsigned int bpf_num_possible_cpus(void) | |||
20 | } | 21 | } |
21 | 22 | ||
22 | while (fgets(buff, sizeof(buff), fp)) { | 23 | while (fgets(buff, sizeof(buff), fp)) { |
23 | if (sscanf(buff, "%u-%u", &start, &end) == 2) { | 24 | n = sscanf(buff, "%u-%u", &start, &end); |
24 | possible_cpus = start == 0 ? end + 1 : 0; | 25 | if (n == 0) { |
25 | break; | 26 | printf("Failed to retrieve # possible CPUs!\n"); |
27 | exit(1); | ||
28 | } else if (n == 1) { | ||
29 | end = start; | ||
26 | } | 30 | } |
31 | possible_cpus = start == 0 ? end + 1 : 0; | ||
32 | break; | ||
27 | } | 33 | } |
28 | |||
29 | fclose(fp); | 34 | fclose(fp); |
30 | if (!possible_cpus) { | ||
31 | printf("Failed to retrieve # possible CPUs!\n"); | ||
32 | exit(1); | ||
33 | } | ||
34 | 35 | ||
35 | return possible_cpus; | 36 | return possible_cpus; |
36 | } | 37 | } |
diff --git a/tools/testing/selftests/bpf/sockmap_parse_prog.c b/tools/testing/selftests/bpf/sockmap_parse_prog.c new file mode 100644 index 000000000000..fae3b96c3aa4 --- /dev/null +++ b/tools/testing/selftests/bpf/sockmap_parse_prog.c | |||
@@ -0,0 +1,38 @@ | |||
1 | #include <linux/bpf.h> | ||
2 | #include "bpf_helpers.h" | ||
3 | #include "bpf_util.h" | ||
4 | #include "bpf_endian.h" | ||
5 | |||
6 | int _version SEC("version") = 1; | ||
7 | |||
8 | #define bpf_printk(fmt, ...) \ | ||
9 | ({ \ | ||
10 | char ____fmt[] = fmt; \ | ||
11 | bpf_trace_printk(____fmt, sizeof(____fmt), \ | ||
12 | ##__VA_ARGS__); \ | ||
13 | }) | ||
14 | |||
15 | SEC("sk_skb1") | ||
16 | int bpf_prog1(struct __sk_buff *skb) | ||
17 | { | ||
18 | void *data_end = (void *)(long) skb->data_end; | ||
19 | void *data = (void *)(long) skb->data; | ||
20 | __u32 lport = skb->local_port; | ||
21 | __u32 rport = skb->remote_port; | ||
22 | __u8 *d = data; | ||
23 | |||
24 | if (data + 10 > data_end) | ||
25 | return skb->len; | ||
26 | |||
27 | /* This write/read is a bit pointless but tests the verifier and | ||
28 | * strparser handler for read/write pkt data and access into sk | ||
29 | * fields. | ||
30 | */ | ||
31 | d[7] = 1; | ||
32 | |||
33 | bpf_printk("parse: data[0] = (%u): local_port %i remote %i\n", | ||
34 | d[0], lport, bpf_ntohl(rport)); | ||
35 | return skb->len; | ||
36 | } | ||
37 | |||
38 | char _license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/sockmap_verdict_prog.c b/tools/testing/selftests/bpf/sockmap_verdict_prog.c new file mode 100644 index 000000000000..9b99bd10807d --- /dev/null +++ b/tools/testing/selftests/bpf/sockmap_verdict_prog.c | |||
@@ -0,0 +1,68 @@ | |||
1 | #include <linux/bpf.h> | ||
2 | #include "bpf_helpers.h" | ||
3 | #include "bpf_util.h" | ||
4 | #include "bpf_endian.h" | ||
5 | |||
6 | int _version SEC("version") = 1; | ||
7 | |||
8 | #define bpf_printk(fmt, ...) \ | ||
9 | ({ \ | ||
10 | char ____fmt[] = fmt; \ | ||
11 | bpf_trace_printk(____fmt, sizeof(____fmt), \ | ||
12 | ##__VA_ARGS__); \ | ||
13 | }) | ||
14 | |||
15 | struct bpf_map_def SEC("maps") sock_map_rx = { | ||
16 | .type = BPF_MAP_TYPE_SOCKMAP, | ||
17 | .key_size = sizeof(int), | ||
18 | .value_size = sizeof(int), | ||
19 | .max_entries = 20, | ||
20 | }; | ||
21 | |||
22 | struct bpf_map_def SEC("maps") sock_map_tx = { | ||
23 | .type = BPF_MAP_TYPE_SOCKMAP, | ||
24 | .key_size = sizeof(int), | ||
25 | .value_size = sizeof(int), | ||
26 | .max_entries = 20, | ||
27 | }; | ||
28 | |||
29 | struct bpf_map_def SEC("maps") sock_map_break = { | ||
30 | .type = BPF_MAP_TYPE_ARRAY, | ||
31 | .key_size = sizeof(int), | ||
32 | .value_size = sizeof(int), | ||
33 | .max_entries = 20, | ||
34 | }; | ||
35 | |||
36 | SEC("sk_skb2") | ||
37 | int bpf_prog2(struct __sk_buff *skb) | ||
38 | { | ||
39 | void *data_end = (void *)(long) skb->data_end; | ||
40 | void *data = (void *)(long) skb->data; | ||
41 | __u32 lport = skb->local_port; | ||
42 | __u32 rport = skb->remote_port; | ||
43 | __u8 *d = data; | ||
44 | __u8 sk, map; | ||
45 | |||
46 | if (data + 8 > data_end) | ||
47 | return SK_DROP; | ||
48 | |||
49 | map = d[0]; | ||
50 | sk = d[1]; | ||
51 | |||
52 | d[0] = 0xd; | ||
53 | d[1] = 0xe; | ||
54 | d[2] = 0xa; | ||
55 | d[3] = 0xd; | ||
56 | d[4] = 0xb; | ||
57 | d[5] = 0xe; | ||
58 | d[6] = 0xe; | ||
59 | d[7] = 0xf; | ||
60 | |||
61 | bpf_printk("verdict: data[0] = redir(%u:%u)\n", map, sk); | ||
62 | |||
63 | if (!map) | ||
64 | return bpf_sk_redirect_map(&sock_map_rx, sk, 0); | ||
65 | return bpf_sk_redirect_map(&sock_map_tx, sk, 0); | ||
66 | } | ||
67 | |||
68 | char _license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/test_align.c b/tools/testing/selftests/bpf/test_align.c index 29793694cbc7..8591c89c0828 100644 --- a/tools/testing/selftests/bpf/test_align.c +++ b/tools/testing/selftests/bpf/test_align.c | |||
@@ -27,6 +27,11 @@ | |||
27 | #define MAX_INSNS 512 | 27 | #define MAX_INSNS 512 |
28 | #define MAX_MATCHES 16 | 28 | #define MAX_MATCHES 16 |
29 | 29 | ||
30 | struct bpf_reg_match { | ||
31 | unsigned int line; | ||
32 | const char *match; | ||
33 | }; | ||
34 | |||
30 | struct bpf_align_test { | 35 | struct bpf_align_test { |
31 | const char *descr; | 36 | const char *descr; |
32 | struct bpf_insn insns[MAX_INSNS]; | 37 | struct bpf_insn insns[MAX_INSNS]; |
@@ -36,10 +41,14 @@ struct bpf_align_test { | |||
36 | REJECT | 41 | REJECT |
37 | } result; | 42 | } result; |
38 | enum bpf_prog_type prog_type; | 43 | enum bpf_prog_type prog_type; |
39 | const char *matches[MAX_MATCHES]; | 44 | /* Matches must be in order of increasing line */ |
45 | struct bpf_reg_match matches[MAX_MATCHES]; | ||
40 | }; | 46 | }; |
41 | 47 | ||
42 | static struct bpf_align_test tests[] = { | 48 | static struct bpf_align_test tests[] = { |
49 | /* Four tests of known constants. These aren't staggeringly | ||
50 | * interesting since we track exact values now. | ||
51 | */ | ||
43 | { | 52 | { |
44 | .descr = "mov", | 53 | .descr = "mov", |
45 | .insns = { | 54 | .insns = { |
@@ -53,11 +62,13 @@ static struct bpf_align_test tests[] = { | |||
53 | }, | 62 | }, |
54 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 63 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
55 | .matches = { | 64 | .matches = { |
56 | "1: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp", | 65 | {1, "R1=ctx(id=0,off=0,imm=0)"}, |
57 | "2: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp", | 66 | {1, "R10=fp0"}, |
58 | "3: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp", | 67 | {1, "R3=inv2"}, |
59 | "4: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp", | 68 | {2, "R3=inv4"}, |
60 | "5: R1=ctx R3=imm32,min_value=32,max_value=32,min_align=32 R10=fp", | 69 | {3, "R3=inv8"}, |
70 | {4, "R3=inv16"}, | ||
71 | {5, "R3=inv32"}, | ||
61 | }, | 72 | }, |
62 | }, | 73 | }, |
63 | { | 74 | { |
@@ -79,17 +90,19 @@ static struct bpf_align_test tests[] = { | |||
79 | }, | 90 | }, |
80 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 91 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
81 | .matches = { | 92 | .matches = { |
82 | "1: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp", | 93 | {1, "R1=ctx(id=0,off=0,imm=0)"}, |
83 | "2: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp", | 94 | {1, "R10=fp0"}, |
84 | "3: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp", | 95 | {1, "R3=inv1"}, |
85 | "4: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp", | 96 | {2, "R3=inv2"}, |
86 | "5: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp", | 97 | {3, "R3=inv4"}, |
87 | "6: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp", | 98 | {4, "R3=inv8"}, |
88 | "7: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm32,min_value=32,max_value=32,min_align=32 R10=fp", | 99 | {5, "R3=inv16"}, |
89 | "8: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm16,min_value=16,max_value=16,min_align=16 R10=fp", | 100 | {6, "R3=inv1"}, |
90 | "9: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp", | 101 | {7, "R4=inv32"}, |
91 | "10: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm4,min_value=4,max_value=4,min_align=4 R10=fp", | 102 | {8, "R4=inv16"}, |
92 | "11: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm2,min_value=2,max_value=2,min_align=2 R10=fp", | 103 | {9, "R4=inv8"}, |
104 | {10, "R4=inv4"}, | ||
105 | {11, "R4=inv2"}, | ||
93 | }, | 106 | }, |
94 | }, | 107 | }, |
95 | { | 108 | { |
@@ -106,12 +119,14 @@ static struct bpf_align_test tests[] = { | |||
106 | }, | 119 | }, |
107 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 120 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
108 | .matches = { | 121 | .matches = { |
109 | "1: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp", | 122 | {1, "R1=ctx(id=0,off=0,imm=0)"}, |
110 | "2: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=4 R10=fp", | 123 | {1, "R10=fp0"}, |
111 | "3: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R10=fp", | 124 | {1, "R3=inv4"}, |
112 | "4: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp", | 125 | {2, "R3=inv8"}, |
113 | "5: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm12,min_value=12,max_value=12,min_align=4 R10=fp", | 126 | {3, "R3=inv10"}, |
114 | "6: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm14,min_value=14,max_value=14,min_align=2 R10=fp", | 127 | {4, "R4=inv8"}, |
128 | {5, "R4=inv12"}, | ||
129 | {6, "R4=inv14"}, | ||
115 | }, | 130 | }, |
116 | }, | 131 | }, |
117 | { | 132 | { |
@@ -126,13 +141,16 @@ static struct bpf_align_test tests[] = { | |||
126 | }, | 141 | }, |
127 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 142 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
128 | .matches = { | 143 | .matches = { |
129 | "1: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp", | 144 | {1, "R1=ctx(id=0,off=0,imm=0)"}, |
130 | "2: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp", | 145 | {1, "R10=fp0"}, |
131 | "3: R1=ctx R3=imm14,min_value=14,max_value=14,min_align=2 R10=fp", | 146 | {1, "R3=inv7"}, |
132 | "4: R1=ctx R3=imm56,min_value=56,max_value=56,min_align=4 R10=fp", | 147 | {2, "R3=inv7"}, |
148 | {3, "R3=inv14"}, | ||
149 | {4, "R3=inv56"}, | ||
133 | }, | 150 | }, |
134 | }, | 151 | }, |
135 | 152 | ||
153 | /* Tests using unknown values */ | ||
136 | #define PREP_PKT_POINTERS \ | 154 | #define PREP_PKT_POINTERS \ |
137 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \ | 155 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \ |
138 | offsetof(struct __sk_buff, data)), \ | 156 | offsetof(struct __sk_buff, data)), \ |
@@ -166,17 +184,19 @@ static struct bpf_align_test tests[] = { | |||
166 | }, | 184 | }, |
167 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 185 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
168 | .matches = { | 186 | .matches = { |
169 | "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp", | 187 | {7, "R0=pkt(id=0,off=8,r=8,imm=0)"}, |
170 | "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv55,min_align=2 R10=fp", | 188 | {7, "R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"}, |
171 | "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv54,min_align=4 R10=fp", | 189 | {8, "R3=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"}, |
172 | "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv53,min_align=8 R10=fp", | 190 | {9, "R3=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, |
173 | "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv52,min_align=16 R10=fp", | 191 | {10, "R3=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"}, |
174 | "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv56 R10=fp", | 192 | {11, "R3=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"}, |
175 | "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv51,min_align=32 R10=fp", | 193 | {18, "R3=pkt_end(id=0,off=0,imm=0)"}, |
176 | "20: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv52,min_align=16 R10=fp", | 194 | {18, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"}, |
177 | "21: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv53,min_align=8 R10=fp", | 195 | {19, "R4=inv(id=0,umax_value=8160,var_off=(0x0; 0x1fe0))"}, |
178 | "22: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv54,min_align=4 R10=fp", | 196 | {20, "R4=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"}, |
179 | "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv55,min_align=2 R10=fp", | 197 | {21, "R4=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"}, |
198 | {22, "R4=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, | ||
199 | {23, "R4=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"}, | ||
180 | }, | 200 | }, |
181 | }, | 201 | }, |
182 | { | 202 | { |
@@ -197,16 +217,16 @@ static struct bpf_align_test tests[] = { | |||
197 | }, | 217 | }, |
198 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 218 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
199 | .matches = { | 219 | .matches = { |
200 | "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp", | 220 | {7, "R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"}, |
201 | "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp", | 221 | {8, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"}, |
202 | "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv55,min_align=1 R10=fp", | 222 | {9, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"}, |
203 | "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp", | 223 | {10, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"}, |
204 | "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv54,min_align=2 R10=fp", | 224 | {11, "R4=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"}, |
205 | "12: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp", | 225 | {12, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"}, |
206 | "13: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv53,min_align=4 R10=fp", | 226 | {13, "R4=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, |
207 | "14: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp", | 227 | {14, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"}, |
208 | "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv52,min_align=8 R10=fp", | 228 | {15, "R4=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"}, |
209 | "16: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv50,min_align=8 R10=fp" | 229 | {16, "R4=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"}, |
210 | }, | 230 | }, |
211 | }, | 231 | }, |
212 | { | 232 | { |
@@ -237,12 +257,14 @@ static struct bpf_align_test tests[] = { | |||
237 | }, | 257 | }, |
238 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 258 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
239 | .matches = { | 259 | .matches = { |
240 | "4: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=0,r=0) R10=fp", | 260 | {4, "R5=pkt(id=0,off=0,r=0,imm=0)"}, |
241 | "5: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=14,r=0) R10=fp", | 261 | {5, "R5=pkt(id=0,off=14,r=0,imm=0)"}, |
242 | "6: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R4=pkt(id=0,off=14,r=0) R5=pkt(id=0,off=14,r=0) R10=fp", | 262 | {6, "R4=pkt(id=0,off=14,r=0,imm=0)"}, |
243 | "10: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv56 R5=pkt(id=0,off=14,r=18) R10=fp", | 263 | {10, "R2=pkt(id=0,off=0,r=18,imm=0)"}, |
244 | "14: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp", | 264 | {10, "R5=pkt(id=0,off=14,r=18,imm=0)"}, |
245 | "15: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp", | 265 | {10, "R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"}, |
266 | {14, "R4=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff))"}, | ||
267 | {15, "R4=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff))"}, | ||
246 | }, | 268 | }, |
247 | }, | 269 | }, |
248 | { | 270 | { |
@@ -297,62 +319,286 @@ static struct bpf_align_test tests[] = { | |||
297 | /* Calculated offset in R6 has unknown value, but known | 319 | /* Calculated offset in R6 has unknown value, but known |
298 | * alignment of 4. | 320 | * alignment of 4. |
299 | */ | 321 | */ |
300 | "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R6=inv54,min_align=4 R10=fp", | 322 | {8, "R2=pkt(id=0,off=0,r=8,imm=0)"}, |
301 | 323 | {8, "R6=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, | |
302 | /* Offset is added to packet pointer R5, resulting in known | 324 | /* Offset is added to packet pointer R5, resulting in |
303 | * auxiliary alignment and offset. | 325 | * known fixed offset, and variable offset from R6. |
304 | */ | 326 | */ |
305 | "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R5=pkt(id=1,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | 327 | {11, "R5=pkt(id=1,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, |
306 | |||
307 | /* At the time the word size load is performed from R5, | 328 | /* At the time the word size load is performed from R5, |
308 | * it's total offset is NET_IP_ALIGN + reg->off (0) + | 329 | * it's total offset is NET_IP_ALIGN + reg->off (0) + |
309 | * reg->aux_off (14) which is 16. Then the variable | 330 | * reg->aux_off (14) which is 16. Then the variable |
310 | * offset is considered using reg->aux_off_align which | 331 | * offset is considered using reg->aux_off_align which |
311 | * is 4 and meets the load's requirements. | 332 | * is 4 and meets the load's requirements. |
312 | */ | 333 | */ |
313 | "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=1,off=4,r=4),aux_off=14,aux_off_align=4 R5=pkt(id=1,off=0,r=4),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | 334 | {15, "R4=pkt(id=1,off=18,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"}, |
314 | 335 | {15, "R5=pkt(id=1,off=14,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"}, | |
315 | |||
316 | /* Variable offset is added to R5 packet pointer, | 336 | /* Variable offset is added to R5 packet pointer, |
317 | * resulting in auxiliary alignment of 4. | 337 | * resulting in auxiliary alignment of 4. |
318 | */ | 338 | */ |
319 | "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=0,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp", | 339 | {18, "R5=pkt(id=2,off=0,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, |
320 | |||
321 | /* Constant offset is added to R5, resulting in | 340 | /* Constant offset is added to R5, resulting in |
322 | * reg->off of 14. | 341 | * reg->off of 14. |
323 | */ | 342 | */ |
324 | "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=14,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp", | 343 | {19, "R5=pkt(id=2,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, |
325 | |||
326 | /* At the time the word size load is performed from R5, | 344 | /* At the time the word size load is performed from R5, |
327 | * it's total offset is NET_IP_ALIGN + reg->off (14) which | 345 | * its total fixed offset is NET_IP_ALIGN + reg->off |
328 | * is 16. Then the variable offset is considered using | 346 | * (14) which is 16. Then the variable offset is 4-byte |
329 | * reg->aux_off_align which is 4 and meets the load's | 347 | * aligned, so the total offset is 4-byte aligned and |
330 | * requirements. | 348 | * meets the load's requirements. |
331 | */ | 349 | */ |
332 | "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=2,off=18,r=18),aux_off_align=4 R5=pkt(id=2,off=14,r=18),aux_off_align=4 R6=inv54,min_align=4 R10=fp", | 350 | {23, "R4=pkt(id=2,off=18,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"}, |
333 | 351 | {23, "R5=pkt(id=2,off=14,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"}, | |
334 | /* Constant offset is added to R5 packet pointer, | 352 | /* Constant offset is added to R5 packet pointer, |
335 | * resulting in reg->off value of 14. | 353 | * resulting in reg->off value of 14. |
336 | */ | 354 | */ |
337 | "26: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=0,off=14,r=8) R6=inv54,min_align=4 R10=fp", | 355 | {26, "R5=pkt(id=0,off=14,r=8"}, |
338 | /* Variable offset is added to R5, resulting in an | 356 | /* Variable offset is added to R5, resulting in a |
339 | * auxiliary offset of 14, and an auxiliary alignment of 4. | 357 | * variable offset of (4n). |
340 | */ | 358 | */ |
341 | "27: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | 359 | {27, "R5=pkt(id=3,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, |
342 | /* Constant is added to R5 again, setting reg->off to 4. */ | 360 | /* Constant is added to R5 again, setting reg->off to 18. */ |
343 | "28: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=4,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | 361 | {28, "R5=pkt(id=3,off=18,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, |
344 | /* And once more we add a variable, which causes an accumulation | 362 | /* And once more we add a variable; resulting var_off |
345 | * of reg->off into reg->aux_off_align, with resulting value of | 363 | * is still (4n), fixed offset is not changed. |
346 | * 18. The auxiliary alignment stays at 4. | 364 | * Also, we create a new reg->id. |
347 | */ | 365 | */ |
348 | "29: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=4,off=0,r=0),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | 366 | {29, "R5=pkt(id=4,off=18,r=0,umax_value=2040,var_off=(0x0; 0x7fc))"}, |
349 | /* At the time the word size load is performed from R5, | 367 | /* At the time the word size load is performed from R5, |
350 | * it's total offset is NET_IP_ALIGN + reg->off (0) + | 368 | * its total fixed offset is NET_IP_ALIGN + reg->off (18) |
351 | * reg->aux_off (18) which is 20. Then the variable offset | 369 | * which is 20. Then the variable offset is (4n), so |
352 | * is considered using reg->aux_off_align which is 4 and meets | 370 | * the total offset is 4-byte aligned and meets the |
353 | * the load's requirements. | 371 | * load's requirements. |
372 | */ | ||
373 | {33, "R4=pkt(id=4,off=22,r=22,umax_value=2040,var_off=(0x0; 0x7fc))"}, | ||
374 | {33, "R5=pkt(id=4,off=18,r=22,umax_value=2040,var_off=(0x0; 0x7fc))"}, | ||
375 | }, | ||
376 | }, | ||
377 | { | ||
378 | .descr = "packet variable offset 2", | ||
379 | .insns = { | ||
380 | /* Create an unknown offset, (4n+2)-aligned */ | ||
381 | LOAD_UNKNOWN(BPF_REG_6), | ||
382 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2), | ||
383 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 14), | ||
384 | /* Add it to the packet pointer */ | ||
385 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), | ||
386 | BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6), | ||
387 | /* Check bounds and perform a read */ | ||
388 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_5), | ||
389 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), | ||
390 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1), | ||
391 | BPF_EXIT_INSN(), | ||
392 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_5, 0), | ||
393 | /* Make a (4n) offset from the value we just read */ | ||
394 | BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 0xff), | ||
395 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2), | ||
396 | /* Add it to the packet pointer */ | ||
397 | BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6), | ||
398 | /* Check bounds and perform a read */ | ||
399 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_5), | ||
400 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), | ||
401 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1), | ||
402 | BPF_EXIT_INSN(), | ||
403 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_5, 0), | ||
404 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
405 | BPF_EXIT_INSN(), | ||
406 | }, | ||
407 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
408 | .matches = { | ||
409 | /* Calculated offset in R6 has unknown value, but known | ||
410 | * alignment of 4. | ||
411 | */ | ||
412 | {8, "R2=pkt(id=0,off=0,r=8,imm=0)"}, | ||
413 | {8, "R6=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, | ||
414 | /* Adding 14 makes R6 be (4n+2) */ | ||
415 | {9, "R6=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"}, | ||
416 | /* Packet pointer has (4n+2) offset */ | ||
417 | {11, "R5=pkt(id=1,off=0,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"}, | ||
418 | {13, "R4=pkt(id=1,off=4,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"}, | ||
419 | /* At the time the word size load is performed from R5, | ||
420 | * its total fixed offset is NET_IP_ALIGN + reg->off (0) | ||
421 | * which is 2. Then the variable offset is (4n+2), so | ||
422 | * the total offset is 4-byte aligned and meets the | ||
423 | * load's requirements. | ||
424 | */ | ||
425 | {15, "R5=pkt(id=1,off=0,r=4,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"}, | ||
426 | /* Newly read value in R6 was shifted left by 2, so has | ||
427 | * known alignment of 4. | ||
428 | */ | ||
429 | {18, "R6=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, | ||
430 | /* Added (4n) to packet pointer's (4n+2) var_off, giving | ||
431 | * another (4n+2). | ||
432 | */ | ||
433 | {19, "R5=pkt(id=2,off=0,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc))"}, | ||
434 | {21, "R4=pkt(id=2,off=4,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc))"}, | ||
435 | /* At the time the word size load is performed from R5, | ||
436 | * its total fixed offset is NET_IP_ALIGN + reg->off (0) | ||
437 | * which is 2. Then the variable offset is (4n+2), so | ||
438 | * the total offset is 4-byte aligned and meets the | ||
439 | * load's requirements. | ||
440 | */ | ||
441 | {23, "R5=pkt(id=2,off=0,r=4,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc))"}, | ||
442 | }, | ||
443 | }, | ||
444 | { | ||
445 | .descr = "dubious pointer arithmetic", | ||
446 | .insns = { | ||
447 | PREP_PKT_POINTERS, | ||
448 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
449 | /* ptr & const => unknown & const */ | ||
450 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), | ||
451 | BPF_ALU64_IMM(BPF_AND, BPF_REG_5, 0x40), | ||
452 | /* ptr << const => unknown << const */ | ||
453 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), | ||
454 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_5, 2), | ||
455 | /* We have a (4n) value. Let's make a packet offset | ||
456 | * out of it. First add 14, to make it a (4n+2) | ||
457 | */ | ||
458 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14), | ||
459 | /* Then make sure it's nonnegative */ | ||
460 | BPF_JMP_IMM(BPF_JSGE, BPF_REG_5, 0, 1), | ||
461 | BPF_EXIT_INSN(), | ||
462 | /* Add it to packet pointer */ | ||
463 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_2), | ||
464 | BPF_ALU64_REG(BPF_ADD, BPF_REG_6, BPF_REG_5), | ||
465 | /* Check bounds and perform a read */ | ||
466 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_6), | ||
467 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), | ||
468 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1), | ||
469 | BPF_EXIT_INSN(), | ||
470 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_6, 0), | ||
471 | BPF_EXIT_INSN(), | ||
472 | }, | ||
473 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
474 | .result = REJECT, | ||
475 | .matches = { | ||
476 | {4, "R5=pkt(id=0,off=0,r=0,imm=0)"}, | ||
477 | /* ptr & 0x40 == either 0 or 0x40 */ | ||
478 | {5, "R5=inv(id=0,umax_value=64,var_off=(0x0; 0x40))"}, | ||
479 | /* ptr << 2 == unknown, (4n) */ | ||
480 | {7, "R5=inv(id=0,smax_value=9223372036854775804,umax_value=18446744073709551612,var_off=(0x0; 0xfffffffffffffffc))"}, | ||
481 | /* (4n) + 14 == (4n+2). We blow our bounds, because | ||
482 | * the add could overflow. | ||
483 | */ | ||
484 | {8, "R5=inv(id=0,var_off=(0x2; 0xfffffffffffffffc))"}, | ||
485 | /* Checked s>=0 */ | ||
486 | {10, "R5=inv(id=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, | ||
487 | /* packet pointer + nonnegative (4n+2) */ | ||
488 | {12, "R6=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, | ||
489 | {14, "R4=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, | ||
490 | /* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine. | ||
491 | * We checked the bounds, but it might have been able | ||
492 | * to overflow if the packet pointer started in the | ||
493 | * upper half of the address space. | ||
494 | * So we did not get a 'range' on R6, and the access | ||
495 | * attempt will fail. | ||
496 | */ | ||
497 | {16, "R6=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, | ||
498 | } | ||
499 | }, | ||
500 | { | ||
501 | .descr = "variable subtraction", | ||
502 | .insns = { | ||
503 | /* Create an unknown offset, (4n+2)-aligned */ | ||
504 | LOAD_UNKNOWN(BPF_REG_6), | ||
505 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_6), | ||
506 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2), | ||
507 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 14), | ||
508 | /* Create another unknown, (4n)-aligned, and subtract | ||
509 | * it from the first one | ||
510 | */ | ||
511 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 2), | ||
512 | BPF_ALU64_REG(BPF_SUB, BPF_REG_6, BPF_REG_7), | ||
513 | /* Bounds-check the result */ | ||
514 | BPF_JMP_IMM(BPF_JSGE, BPF_REG_6, 0, 1), | ||
515 | BPF_EXIT_INSN(), | ||
516 | /* Add it to the packet pointer */ | ||
517 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), | ||
518 | BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6), | ||
519 | /* Check bounds and perform a read */ | ||
520 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_5), | ||
521 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), | ||
522 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1), | ||
523 | BPF_EXIT_INSN(), | ||
524 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_5, 0), | ||
525 | BPF_EXIT_INSN(), | ||
526 | }, | ||
527 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
528 | .matches = { | ||
529 | /* Calculated offset in R6 has unknown value, but known | ||
530 | * alignment of 4. | ||
531 | */ | ||
532 | {7, "R2=pkt(id=0,off=0,r=8,imm=0)"}, | ||
533 | {9, "R6=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, | ||
534 | /* Adding 14 makes R6 be (4n+2) */ | ||
535 | {10, "R6=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"}, | ||
536 | /* New unknown value in R7 is (4n) */ | ||
537 | {11, "R7=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, | ||
538 | /* Subtracting it from R6 blows our unsigned bounds */ | ||
539 | {12, "R6=inv(id=0,smin_value=-1006,smax_value=1034,var_off=(0x2; 0xfffffffffffffffc))"}, | ||
540 | /* Checked s>= 0 */ | ||
541 | {14, "R6=inv(id=0,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc))"}, | ||
542 | /* At the time the word size load is performed from R5, | ||
543 | * its total fixed offset is NET_IP_ALIGN + reg->off (0) | ||
544 | * which is 2. Then the variable offset is (4n+2), so | ||
545 | * the total offset is 4-byte aligned and meets the | ||
546 | * load's requirements. | ||
547 | */ | ||
548 | {20, "R5=pkt(id=1,off=0,r=4,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc))"}, | ||
549 | }, | ||
550 | }, | ||
551 | { | ||
552 | .descr = "pointer variable subtraction", | ||
553 | .insns = { | ||
554 | /* Create an unknown offset, (4n+2)-aligned and bounded | ||
555 | * to [14,74] | ||
556 | */ | ||
557 | LOAD_UNKNOWN(BPF_REG_6), | ||
558 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_6), | ||
559 | BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 0xf), | ||
560 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2), | ||
561 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 14), | ||
562 | /* Subtract it from the packet pointer */ | ||
563 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), | ||
564 | BPF_ALU64_REG(BPF_SUB, BPF_REG_5, BPF_REG_6), | ||
565 | /* Create another unknown, (4n)-aligned and >= 74. | ||
566 | * That in fact means >= 76, since 74 % 4 == 2 | ||
354 | */ | 567 | */ |
355 | "33: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=4,off=4,r=4),aux_off=18,aux_off_align=4 R5=pkt(id=4,off=0,r=4),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp", | 568 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 2), |
569 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 76), | ||
570 | /* Add it to the packet pointer */ | ||
571 | BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_7), | ||
572 | /* Check bounds and perform a read */ | ||
573 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_5), | ||
574 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), | ||
575 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1), | ||
576 | BPF_EXIT_INSN(), | ||
577 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_5, 0), | ||
578 | BPF_EXIT_INSN(), | ||
579 | }, | ||
580 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
581 | .matches = { | ||
582 | /* Calculated offset in R6 has unknown value, but known | ||
583 | * alignment of 4. | ||
584 | */ | ||
585 | {7, "R2=pkt(id=0,off=0,r=8,imm=0)"}, | ||
586 | {10, "R6=inv(id=0,umax_value=60,var_off=(0x0; 0x3c))"}, | ||
587 | /* Adding 14 makes R6 be (4n+2) */ | ||
588 | {11, "R6=inv(id=0,umin_value=14,umax_value=74,var_off=(0x2; 0x7c))"}, | ||
589 | /* Subtracting from packet pointer overflows ubounds */ | ||
590 | {13, "R5=pkt(id=1,off=0,r=8,umin_value=18446744073709551542,umax_value=18446744073709551602,var_off=(0xffffffffffffff82; 0x7c))"}, | ||
591 | /* New unknown value in R7 is (4n), >= 76 */ | ||
592 | {15, "R7=inv(id=0,umin_value=76,umax_value=1096,var_off=(0x0; 0x7fc))"}, | ||
593 | /* Adding it to packet pointer gives nice bounds again */ | ||
594 | {16, "R5=pkt(id=2,off=0,r=0,umin_value=2,umax_value=1082,var_off=(0x2; 0x7fc))"}, | ||
595 | /* At the time the word size load is performed from R5, | ||
596 | * its total fixed offset is NET_IP_ALIGN + reg->off (0) | ||
597 | * which is 2. Then the variable offset is (4n+2), so | ||
598 | * the total offset is 4-byte aligned and meets the | ||
599 | * load's requirements. | ||
600 | */ | ||
601 | {20, "R5=pkt(id=2,off=0,r=4,umin_value=2,umax_value=1082,var_off=(0x2; 0x7fc))"}, | ||
356 | }, | 602 | }, |
357 | }, | 603 | }, |
358 | }; | 604 | }; |
@@ -373,6 +619,9 @@ static int do_test_single(struct bpf_align_test *test) | |||
373 | { | 619 | { |
374 | struct bpf_insn *prog = test->insns; | 620 | struct bpf_insn *prog = test->insns; |
375 | int prog_type = test->prog_type; | 621 | int prog_type = test->prog_type; |
622 | char bpf_vlog_copy[32768]; | ||
623 | const char *line_ptr; | ||
624 | int cur_line = -1; | ||
376 | int prog_len, i; | 625 | int prog_len, i; |
377 | int fd_prog; | 626 | int fd_prog; |
378 | int ret; | 627 | int ret; |
@@ -381,26 +630,49 @@ static int do_test_single(struct bpf_align_test *test) | |||
381 | fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, | 630 | fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, |
382 | prog, prog_len, 1, "GPL", 0, | 631 | prog, prog_len, 1, "GPL", 0, |
383 | bpf_vlog, sizeof(bpf_vlog), 2); | 632 | bpf_vlog, sizeof(bpf_vlog), 2); |
384 | if (fd_prog < 0) { | 633 | if (fd_prog < 0 && test->result != REJECT) { |
385 | printf("Failed to load program.\n"); | 634 | printf("Failed to load program.\n"); |
386 | printf("%s", bpf_vlog); | 635 | printf("%s", bpf_vlog); |
387 | ret = 1; | 636 | ret = 1; |
637 | } else if (fd_prog >= 0 && test->result == REJECT) { | ||
638 | printf("Unexpected success to load!\n"); | ||
639 | printf("%s", bpf_vlog); | ||
640 | ret = 1; | ||
641 | close(fd_prog); | ||
388 | } else { | 642 | } else { |
389 | ret = 0; | 643 | ret = 0; |
644 | /* We make a local copy so that we can strtok() it */ | ||
645 | strncpy(bpf_vlog_copy, bpf_vlog, sizeof(bpf_vlog_copy)); | ||
646 | line_ptr = strtok(bpf_vlog_copy, "\n"); | ||
390 | for (i = 0; i < MAX_MATCHES; i++) { | 647 | for (i = 0; i < MAX_MATCHES; i++) { |
391 | const char *t, *m = test->matches[i]; | 648 | struct bpf_reg_match m = test->matches[i]; |
392 | 649 | ||
393 | if (!m) | 650 | if (!m.match) |
394 | break; | 651 | break; |
395 | t = strstr(bpf_vlog, m); | 652 | while (line_ptr) { |
396 | if (!t) { | 653 | cur_line = -1; |
397 | printf("Failed to find match: %s\n", m); | 654 | sscanf(line_ptr, "%u: ", &cur_line); |
655 | if (cur_line == m.line) | ||
656 | break; | ||
657 | line_ptr = strtok(NULL, "\n"); | ||
658 | } | ||
659 | if (!line_ptr) { | ||
660 | printf("Failed to find line %u for match: %s\n", | ||
661 | m.line, m.match); | ||
662 | ret = 1; | ||
663 | printf("%s", bpf_vlog); | ||
664 | break; | ||
665 | } | ||
666 | if (!strstr(line_ptr, m.match)) { | ||
667 | printf("Failed to find match %u: %s\n", | ||
668 | m.line, m.match); | ||
398 | ret = 1; | 669 | ret = 1; |
399 | printf("%s", bpf_vlog); | 670 | printf("%s", bpf_vlog); |
400 | break; | 671 | break; |
401 | } | 672 | } |
402 | } | 673 | } |
403 | close(fd_prog); | 674 | if (fd_prog >= 0) |
675 | close(fd_prog); | ||
404 | } | 676 | } |
405 | return ret; | 677 | return ret; |
406 | } | 678 | } |
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 79601c81e169..fe3a443a1102 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/bpf.h> | 22 | #include <linux/bpf.h> |
23 | 23 | ||
24 | #include <bpf/bpf.h> | 24 | #include <bpf/bpf.h> |
25 | #include <bpf/libbpf.h> | ||
25 | #include "bpf_util.h" | 26 | #include "bpf_util.h" |
26 | 27 | ||
27 | static int map_flags; | 28 | static int map_flags; |
@@ -438,6 +439,444 @@ static void test_arraymap_percpu_many_keys(void) | |||
438 | close(fd); | 439 | close(fd); |
439 | } | 440 | } |
440 | 441 | ||
442 | static void test_devmap(int task, void *data) | ||
443 | { | ||
444 | int fd; | ||
445 | __u32 key, value; | ||
446 | |||
447 | fd = bpf_create_map(BPF_MAP_TYPE_DEVMAP, sizeof(key), sizeof(value), | ||
448 | 2, 0); | ||
449 | if (fd < 0) { | ||
450 | printf("Failed to create arraymap '%s'!\n", strerror(errno)); | ||
451 | exit(1); | ||
452 | } | ||
453 | |||
454 | close(fd); | ||
455 | } | ||
456 | |||
457 | #include <sys/socket.h> | ||
458 | #include <sys/ioctl.h> | ||
459 | #include <arpa/inet.h> | ||
460 | #include <sys/select.h> | ||
461 | #include <linux/err.h> | ||
462 | #define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.o" | ||
463 | #define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.o" | ||
464 | static void test_sockmap(int tasks, void *data) | ||
465 | { | ||
466 | int one = 1, map_fd_rx, map_fd_tx, map_fd_break, s, sc, rc; | ||
467 | struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_break; | ||
468 | int ports[] = {50200, 50201, 50202, 50204}; | ||
469 | int err, i, fd, sfd[6] = {0xdeadbeef}; | ||
470 | u8 buf[20] = {0x0, 0x5, 0x3, 0x2, 0x1, 0x0}; | ||
471 | int parse_prog, verdict_prog; | ||
472 | struct sockaddr_in addr; | ||
473 | struct bpf_object *obj; | ||
474 | struct timeval to; | ||
475 | __u32 key, value; | ||
476 | pid_t pid[tasks]; | ||
477 | fd_set w; | ||
478 | |||
479 | /* Create some sockets to use with sockmap */ | ||
480 | for (i = 0; i < 2; i++) { | ||
481 | sfd[i] = socket(AF_INET, SOCK_STREAM, 0); | ||
482 | if (sfd[i] < 0) | ||
483 | goto out; | ||
484 | err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR, | ||
485 | (char *)&one, sizeof(one)); | ||
486 | if (err) { | ||
487 | printf("failed to setsockopt\n"); | ||
488 | goto out; | ||
489 | } | ||
490 | err = ioctl(sfd[i], FIONBIO, (char *)&one); | ||
491 | if (err < 0) { | ||
492 | printf("failed to ioctl\n"); | ||
493 | goto out; | ||
494 | } | ||
495 | memset(&addr, 0, sizeof(struct sockaddr_in)); | ||
496 | addr.sin_family = AF_INET; | ||
497 | addr.sin_addr.s_addr = inet_addr("127.0.0.1"); | ||
498 | addr.sin_port = htons(ports[i]); | ||
499 | err = bind(sfd[i], (struct sockaddr *)&addr, sizeof(addr)); | ||
500 | if (err < 0) { | ||
501 | printf("failed to bind: err %i: %i:%i\n", | ||
502 | err, i, sfd[i]); | ||
503 | goto out; | ||
504 | } | ||
505 | err = listen(sfd[i], 32); | ||
506 | if (err < 0) { | ||
507 | printf("failed to listen\n"); | ||
508 | goto out; | ||
509 | } | ||
510 | } | ||
511 | |||
512 | for (i = 2; i < 4; i++) { | ||
513 | sfd[i] = socket(AF_INET, SOCK_STREAM, 0); | ||
514 | if (sfd[i] < 0) | ||
515 | goto out; | ||
516 | err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR, | ||
517 | (char *)&one, sizeof(one)); | ||
518 | if (err) { | ||
519 | printf("set sock opt\n"); | ||
520 | goto out; | ||
521 | } | ||
522 | memset(&addr, 0, sizeof(struct sockaddr_in)); | ||
523 | addr.sin_family = AF_INET; | ||
524 | addr.sin_addr.s_addr = inet_addr("127.0.0.1"); | ||
525 | addr.sin_port = htons(ports[i - 2]); | ||
526 | err = connect(sfd[i], (struct sockaddr *)&addr, sizeof(addr)); | ||
527 | if (err) { | ||
528 | printf("failed to connect\n"); | ||
529 | goto out; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | |||
534 | for (i = 4; i < 6; i++) { | ||
535 | sfd[i] = accept(sfd[i - 4], NULL, NULL); | ||
536 | if (sfd[i] < 0) { | ||
537 | printf("accept failed\n"); | ||
538 | goto out; | ||
539 | } | ||
540 | } | ||
541 | |||
542 | /* Test sockmap with connected sockets */ | ||
543 | fd = bpf_create_map(BPF_MAP_TYPE_SOCKMAP, | ||
544 | sizeof(key), sizeof(value), | ||
545 | 6, 0); | ||
546 | if (fd < 0) { | ||
547 | printf("Failed to create sockmap %i\n", fd); | ||
548 | goto out_sockmap; | ||
549 | } | ||
550 | |||
551 | /* Test update without programs */ | ||
552 | for (i = 0; i < 6; i++) { | ||
553 | err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY); | ||
554 | if (err) { | ||
555 | printf("Failed noprog update sockmap '%i:%i'\n", | ||
556 | i, sfd[i]); | ||
557 | goto out_sockmap; | ||
558 | } | ||
559 | } | ||
560 | |||
561 | /* Test attaching/detaching bad fds */ | ||
562 | err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_PARSER, 0); | ||
563 | if (!err) { | ||
564 | printf("Failed invalid parser prog attach\n"); | ||
565 | goto out_sockmap; | ||
566 | } | ||
567 | |||
568 | err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_VERDICT, 0); | ||
569 | if (!err) { | ||
570 | printf("Failed invalid verdict prog attach\n"); | ||
571 | goto out_sockmap; | ||
572 | } | ||
573 | |||
574 | err = bpf_prog_attach(-1, fd, __MAX_BPF_ATTACH_TYPE, 0); | ||
575 | if (!err) { | ||
576 | printf("Failed unknown prog attach\n"); | ||
577 | goto out_sockmap; | ||
578 | } | ||
579 | |||
580 | err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_PARSER); | ||
581 | if (err) { | ||
582 | printf("Failed empty parser prog detach\n"); | ||
583 | goto out_sockmap; | ||
584 | } | ||
585 | |||
586 | err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_VERDICT); | ||
587 | if (err) { | ||
588 | printf("Failed empty verdict prog detach\n"); | ||
589 | goto out_sockmap; | ||
590 | } | ||
591 | |||
592 | err = bpf_prog_detach(fd, __MAX_BPF_ATTACH_TYPE); | ||
593 | if (!err) { | ||
594 | printf("Detach invalid prog successful\n"); | ||
595 | goto out_sockmap; | ||
596 | } | ||
597 | |||
598 | /* Load SK_SKB program and Attach */ | ||
599 | err = bpf_prog_load(SOCKMAP_PARSE_PROG, | ||
600 | BPF_PROG_TYPE_SK_SKB, &obj, &parse_prog); | ||
601 | if (err) { | ||
602 | printf("Failed to load SK_SKB parse prog\n"); | ||
603 | goto out_sockmap; | ||
604 | } | ||
605 | |||
606 | err = bpf_prog_load(SOCKMAP_VERDICT_PROG, | ||
607 | BPF_PROG_TYPE_SK_SKB, &obj, &verdict_prog); | ||
608 | if (err) { | ||
609 | printf("Failed to load SK_SKB verdict prog\n"); | ||
610 | goto out_sockmap; | ||
611 | } | ||
612 | |||
613 | bpf_map_rx = bpf_object__find_map_by_name(obj, "sock_map_rx"); | ||
614 | if (IS_ERR(bpf_map_rx)) { | ||
615 | printf("Failed to load map rx from verdict prog\n"); | ||
616 | goto out_sockmap; | ||
617 | } | ||
618 | |||
619 | map_fd_rx = bpf_map__fd(bpf_map_rx); | ||
620 | if (map_fd_rx < 0) { | ||
621 | printf("Failed to get map fd\n"); | ||
622 | goto out_sockmap; | ||
623 | } | ||
624 | |||
625 | bpf_map_tx = bpf_object__find_map_by_name(obj, "sock_map_tx"); | ||
626 | if (IS_ERR(bpf_map_tx)) { | ||
627 | printf("Failed to load map tx from verdict prog\n"); | ||
628 | goto out_sockmap; | ||
629 | } | ||
630 | |||
631 | map_fd_tx = bpf_map__fd(bpf_map_tx); | ||
632 | if (map_fd_tx < 0) { | ||
633 | printf("Failed to get map tx fd\n"); | ||
634 | goto out_sockmap; | ||
635 | } | ||
636 | |||
637 | bpf_map_break = bpf_object__find_map_by_name(obj, "sock_map_break"); | ||
638 | if (IS_ERR(bpf_map_break)) { | ||
639 | printf("Failed to load map tx from verdict prog\n"); | ||
640 | goto out_sockmap; | ||
641 | } | ||
642 | |||
643 | map_fd_break = bpf_map__fd(bpf_map_break); | ||
644 | if (map_fd_break < 0) { | ||
645 | printf("Failed to get map tx fd\n"); | ||
646 | goto out_sockmap; | ||
647 | } | ||
648 | |||
649 | err = bpf_prog_attach(parse_prog, map_fd_break, | ||
650 | BPF_SK_SKB_STREAM_PARSER, 0); | ||
651 | if (!err) { | ||
652 | printf("Allowed attaching SK_SKB program to invalid map\n"); | ||
653 | goto out_sockmap; | ||
654 | } | ||
655 | |||
656 | err = bpf_prog_attach(parse_prog, map_fd_rx, | ||
657 | BPF_SK_SKB_STREAM_PARSER, 0); | ||
658 | if (err) { | ||
659 | printf("Failed stream parser bpf prog attach\n"); | ||
660 | goto out_sockmap; | ||
661 | } | ||
662 | |||
663 | err = bpf_prog_attach(verdict_prog, map_fd_rx, | ||
664 | BPF_SK_SKB_STREAM_VERDICT, 0); | ||
665 | if (err) { | ||
666 | printf("Failed stream verdict bpf prog attach\n"); | ||
667 | goto out_sockmap; | ||
668 | } | ||
669 | |||
670 | err = bpf_prog_attach(verdict_prog, map_fd_rx, | ||
671 | __MAX_BPF_ATTACH_TYPE, 0); | ||
672 | if (!err) { | ||
673 | printf("Attached unknown bpf prog\n"); | ||
674 | goto out_sockmap; | ||
675 | } | ||
676 | |||
677 | /* Test map update elem afterwards fd lives in fd and map_fd */ | ||
678 | for (i = 0; i < 6; i++) { | ||
679 | err = bpf_map_update_elem(map_fd_rx, &i, &sfd[i], BPF_ANY); | ||
680 | if (err) { | ||
681 | printf("Failed map_fd_rx update sockmap %i '%i:%i'\n", | ||
682 | err, i, sfd[i]); | ||
683 | goto out_sockmap; | ||
684 | } | ||
685 | err = bpf_map_update_elem(map_fd_tx, &i, &sfd[i], BPF_ANY); | ||
686 | if (err) { | ||
687 | printf("Failed map_fd_tx update sockmap %i '%i:%i'\n", | ||
688 | err, i, sfd[i]); | ||
689 | goto out_sockmap; | ||
690 | } | ||
691 | } | ||
692 | |||
693 | /* Test map delete elem and remove send/recv sockets */ | ||
694 | for (i = 2; i < 4; i++) { | ||
695 | err = bpf_map_delete_elem(map_fd_rx, &i); | ||
696 | if (err) { | ||
697 | printf("Failed delete sockmap rx %i '%i:%i'\n", | ||
698 | err, i, sfd[i]); | ||
699 | goto out_sockmap; | ||
700 | } | ||
701 | err = bpf_map_delete_elem(map_fd_tx, &i); | ||
702 | if (err) { | ||
703 | printf("Failed delete sockmap tx %i '%i:%i'\n", | ||
704 | err, i, sfd[i]); | ||
705 | goto out_sockmap; | ||
706 | } | ||
707 | } | ||
708 | |||
709 | /* Test map send/recv */ | ||
710 | for (i = 0; i < 2; i++) { | ||
711 | buf[0] = i; | ||
712 | buf[1] = 0x5; | ||
713 | sc = send(sfd[2], buf, 20, 0); | ||
714 | if (sc < 0) { | ||
715 | printf("Failed sockmap send\n"); | ||
716 | goto out_sockmap; | ||
717 | } | ||
718 | |||
719 | FD_ZERO(&w); | ||
720 | FD_SET(sfd[3], &w); | ||
721 | to.tv_sec = 1; | ||
722 | to.tv_usec = 0; | ||
723 | s = select(sfd[3] + 1, &w, NULL, NULL, &to); | ||
724 | if (s == -1) { | ||
725 | perror("Failed sockmap select()"); | ||
726 | goto out_sockmap; | ||
727 | } else if (!s) { | ||
728 | printf("Failed sockmap unexpected timeout\n"); | ||
729 | goto out_sockmap; | ||
730 | } | ||
731 | |||
732 | if (!FD_ISSET(sfd[3], &w)) { | ||
733 | printf("Failed sockmap select/recv\n"); | ||
734 | goto out_sockmap; | ||
735 | } | ||
736 | |||
737 | rc = recv(sfd[3], buf, sizeof(buf), 0); | ||
738 | if (rc < 0) { | ||
739 | printf("Failed sockmap recv\n"); | ||
740 | goto out_sockmap; | ||
741 | } | ||
742 | } | ||
743 | |||
744 | /* Negative null entry lookup from datapath should be dropped */ | ||
745 | buf[0] = 1; | ||
746 | buf[1] = 12; | ||
747 | sc = send(sfd[2], buf, 20, 0); | ||
748 | if (sc < 0) { | ||
749 | printf("Failed sockmap send\n"); | ||
750 | goto out_sockmap; | ||
751 | } | ||
752 | |||
753 | /* Push fd into same slot */ | ||
754 | i = 2; | ||
755 | err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST); | ||
756 | if (!err) { | ||
757 | printf("Failed allowed sockmap dup slot BPF_NOEXIST\n"); | ||
758 | goto out_sockmap; | ||
759 | } | ||
760 | |||
761 | err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY); | ||
762 | if (err) { | ||
763 | printf("Failed sockmap update new slot BPF_ANY\n"); | ||
764 | goto out_sockmap; | ||
765 | } | ||
766 | |||
767 | err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST); | ||
768 | if (err) { | ||
769 | printf("Failed sockmap update new slot BPF_EXIST\n"); | ||
770 | goto out_sockmap; | ||
771 | } | ||
772 | |||
773 | /* Delete the elems without programs */ | ||
774 | for (i = 0; i < 6; i++) { | ||
775 | err = bpf_map_delete_elem(fd, &i); | ||
776 | if (err) { | ||
777 | printf("Failed delete sockmap %i '%i:%i'\n", | ||
778 | err, i, sfd[i]); | ||
779 | } | ||
780 | } | ||
781 | |||
782 | /* Test having multiple maps open and set with programs on same fds */ | ||
783 | err = bpf_prog_attach(parse_prog, fd, | ||
784 | BPF_SK_SKB_STREAM_PARSER, 0); | ||
785 | if (err) { | ||
786 | printf("Failed fd bpf parse prog attach\n"); | ||
787 | goto out_sockmap; | ||
788 | } | ||
789 | err = bpf_prog_attach(verdict_prog, fd, | ||
790 | BPF_SK_SKB_STREAM_VERDICT, 0); | ||
791 | if (err) { | ||
792 | printf("Failed fd bpf verdict prog attach\n"); | ||
793 | goto out_sockmap; | ||
794 | } | ||
795 | |||
796 | for (i = 4; i < 6; i++) { | ||
797 | err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY); | ||
798 | if (!err) { | ||
799 | printf("Failed allowed duplicate programs in update ANY sockmap %i '%i:%i'\n", | ||
800 | err, i, sfd[i]); | ||
801 | goto out_sockmap; | ||
802 | } | ||
803 | err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST); | ||
804 | if (!err) { | ||
805 | printf("Failed allowed duplicate program in update NOEXIST sockmap %i '%i:%i'\n", | ||
806 | err, i, sfd[i]); | ||
807 | goto out_sockmap; | ||
808 | } | ||
809 | err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST); | ||
810 | if (!err) { | ||
811 | printf("Failed allowed duplicate program in update EXIST sockmap %i '%i:%i'\n", | ||
812 | err, i, sfd[i]); | ||
813 | goto out_sockmap; | ||
814 | } | ||
815 | } | ||
816 | |||
817 | /* Test tasks number of forked operations */ | ||
818 | for (i = 0; i < tasks; i++) { | ||
819 | pid[i] = fork(); | ||
820 | if (pid[i] == 0) { | ||
821 | for (i = 0; i < 6; i++) { | ||
822 | bpf_map_delete_elem(map_fd_tx, &i); | ||
823 | bpf_map_delete_elem(map_fd_rx, &i); | ||
824 | bpf_map_update_elem(map_fd_tx, &i, | ||
825 | &sfd[i], BPF_ANY); | ||
826 | bpf_map_update_elem(map_fd_rx, &i, | ||
827 | &sfd[i], BPF_ANY); | ||
828 | } | ||
829 | exit(0); | ||
830 | } else if (pid[i] == -1) { | ||
831 | printf("Couldn't spawn #%d process!\n", i); | ||
832 | exit(1); | ||
833 | } | ||
834 | } | ||
835 | |||
836 | for (i = 0; i < tasks; i++) { | ||
837 | int status; | ||
838 | |||
839 | assert(waitpid(pid[i], &status, 0) == pid[i]); | ||
840 | assert(status == 0); | ||
841 | } | ||
842 | |||
843 | err = bpf_prog_detach(map_fd_rx, __MAX_BPF_ATTACH_TYPE); | ||
844 | if (!err) { | ||
845 | printf("Detached an invalid prog type.\n"); | ||
846 | goto out_sockmap; | ||
847 | } | ||
848 | |||
849 | err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_PARSER); | ||
850 | if (err) { | ||
851 | printf("Failed parser prog detach\n"); | ||
852 | goto out_sockmap; | ||
853 | } | ||
854 | |||
855 | err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_VERDICT); | ||
856 | if (err) { | ||
857 | printf("Failed parser prog detach\n"); | ||
858 | goto out_sockmap; | ||
859 | } | ||
860 | |||
861 | /* Test map close sockets */ | ||
862 | for (i = 0; i < 6; i++) | ||
863 | close(sfd[i]); | ||
864 | close(fd); | ||
865 | close(map_fd_rx); | ||
866 | bpf_object__close(obj); | ||
867 | return; | ||
868 | out: | ||
869 | for (i = 0; i < 6; i++) | ||
870 | close(sfd[i]); | ||
871 | printf("Failed to create sockmap '%i:%s'!\n", i, strerror(errno)); | ||
872 | exit(1); | ||
873 | out_sockmap: | ||
874 | for (i = 0; i < 6; i++) | ||
875 | close(sfd[i]); | ||
876 | close(fd); | ||
877 | exit(1); | ||
878 | } | ||
879 | |||
441 | #define MAP_SIZE (32 * 1024) | 880 | #define MAP_SIZE (32 * 1024) |
442 | 881 | ||
443 | static void test_map_large(void) | 882 | static void test_map_large(void) |
@@ -605,6 +1044,9 @@ static void run_all_tests(void) | |||
605 | 1044 | ||
606 | test_arraymap_percpu_many_keys(); | 1045 | test_arraymap_percpu_many_keys(); |
607 | 1046 | ||
1047 | test_devmap(0, NULL); | ||
1048 | test_sockmap(0, NULL); | ||
1049 | |||
608 | test_map_large(); | 1050 | test_map_large(); |
609 | test_map_parallel(); | 1051 | test_map_parallel(); |
610 | test_map_stress(); | 1052 | test_map_stress(); |
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 1f7dd35551b9..11ee25cea227 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c | |||
@@ -75,39 +75,6 @@ static struct { | |||
75 | __ret; \ | 75 | __ret; \ |
76 | }) | 76 | }) |
77 | 77 | ||
78 | static int bpf_prog_load(const char *file, enum bpf_prog_type type, | ||
79 | struct bpf_object **pobj, int *prog_fd) | ||
80 | { | ||
81 | struct bpf_program *prog; | ||
82 | struct bpf_object *obj; | ||
83 | int err; | ||
84 | |||
85 | obj = bpf_object__open(file); | ||
86 | if (IS_ERR(obj)) { | ||
87 | error_cnt++; | ||
88 | return -ENOENT; | ||
89 | } | ||
90 | |||
91 | prog = bpf_program__next(NULL, obj); | ||
92 | if (!prog) { | ||
93 | bpf_object__close(obj); | ||
94 | error_cnt++; | ||
95 | return -ENOENT; | ||
96 | } | ||
97 | |||
98 | bpf_program__set_type(prog, type); | ||
99 | err = bpf_object__load(obj); | ||
100 | if (err) { | ||
101 | bpf_object__close(obj); | ||
102 | error_cnt++; | ||
103 | return -EINVAL; | ||
104 | } | ||
105 | |||
106 | *pobj = obj; | ||
107 | *prog_fd = bpf_program__fd(prog); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int bpf_find_map(const char *test, struct bpf_object *obj, | 78 | static int bpf_find_map(const char *test, struct bpf_object *obj, |
112 | const char *name) | 79 | const char *name) |
113 | { | 80 | { |
@@ -130,8 +97,10 @@ static void test_pkt_access(void) | |||
130 | int err, prog_fd; | 97 | int err, prog_fd; |
131 | 98 | ||
132 | err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); | 99 | err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); |
133 | if (err) | 100 | if (err) { |
101 | error_cnt++; | ||
134 | return; | 102 | return; |
103 | } | ||
135 | 104 | ||
136 | err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4), | 105 | err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4), |
137 | NULL, NULL, &retval, &duration); | 106 | NULL, NULL, &retval, &duration); |
@@ -162,8 +131,10 @@ static void test_xdp(void) | |||
162 | int err, prog_fd, map_fd; | 131 | int err, prog_fd, map_fd; |
163 | 132 | ||
164 | err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd); | 133 | err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd); |
165 | if (err) | 134 | if (err) { |
135 | error_cnt++; | ||
166 | return; | 136 | return; |
137 | } | ||
167 | 138 | ||
168 | map_fd = bpf_find_map(__func__, obj, "vip2tnl"); | 139 | map_fd = bpf_find_map(__func__, obj, "vip2tnl"); |
169 | if (map_fd < 0) | 140 | if (map_fd < 0) |
@@ -223,8 +194,10 @@ static void test_l4lb(void) | |||
223 | u32 *magic = (u32 *)buf; | 194 | u32 *magic = (u32 *)buf; |
224 | 195 | ||
225 | err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); | 196 | err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); |
226 | if (err) | 197 | if (err) { |
198 | error_cnt++; | ||
227 | return; | 199 | return; |
200 | } | ||
228 | 201 | ||
229 | map_fd = bpf_find_map(__func__, obj, "vip_map"); | 202 | map_fd = bpf_find_map(__func__, obj, "vip_map"); |
230 | if (map_fd < 0) | 203 | if (map_fd < 0) |
@@ -280,8 +253,10 @@ static void test_tcp_estats(void) | |||
280 | 253 | ||
281 | err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd); | 254 | err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd); |
282 | CHECK(err, "", "err %d errno %d\n", err, errno); | 255 | CHECK(err, "", "err %d errno %d\n", err, errno); |
283 | if (err) | 256 | if (err) { |
257 | error_cnt++; | ||
284 | return; | 258 | return; |
259 | } | ||
285 | 260 | ||
286 | bpf_object__close(obj); | 261 | bpf_object__close(obj); |
287 | } | 262 | } |
@@ -304,7 +279,7 @@ static void test_bpf_obj_id(void) | |||
304 | /* +1 to test for the info_len returned by kernel */ | 279 | /* +1 to test for the info_len returned by kernel */ |
305 | struct bpf_prog_info prog_infos[nr_iters + 1]; | 280 | struct bpf_prog_info prog_infos[nr_iters + 1]; |
306 | struct bpf_map_info map_infos[nr_iters + 1]; | 281 | struct bpf_map_info map_infos[nr_iters + 1]; |
307 | char jited_insns[128], xlated_insns[128]; | 282 | char jited_insns[128], xlated_insns[128], zeros[128]; |
308 | __u32 i, next_id, info_len, nr_id_found, duration = 0; | 283 | __u32 i, next_id, info_len, nr_id_found, duration = 0; |
309 | int sysctl_fd, jit_enabled = 0, err = 0; | 284 | int sysctl_fd, jit_enabled = 0, err = 0; |
310 | __u64 array_value; | 285 | __u64 array_value; |
@@ -330,17 +305,22 @@ static void test_bpf_obj_id(void) | |||
330 | objs[i] = NULL; | 305 | objs[i] = NULL; |
331 | 306 | ||
332 | /* Check bpf_obj_get_info_by_fd() */ | 307 | /* Check bpf_obj_get_info_by_fd() */ |
308 | bzero(zeros, sizeof(zeros)); | ||
333 | for (i = 0; i < nr_iters; i++) { | 309 | for (i = 0; i < nr_iters; i++) { |
334 | err = bpf_prog_load(file, BPF_PROG_TYPE_SOCKET_FILTER, | 310 | err = bpf_prog_load(file, BPF_PROG_TYPE_SOCKET_FILTER, |
335 | &objs[i], &prog_fds[i]); | 311 | &objs[i], &prog_fds[i]); |
336 | /* test_obj_id.o is a dumb prog. It should never fail | 312 | /* test_obj_id.o is a dumb prog. It should never fail |
337 | * to load. | 313 | * to load. |
338 | */ | 314 | */ |
315 | if (err) | ||
316 | error_cnt++; | ||
339 | assert(!err); | 317 | assert(!err); |
340 | 318 | ||
341 | /* Check getting prog info */ | 319 | /* Check getting prog info */ |
342 | info_len = sizeof(struct bpf_prog_info) * 2; | 320 | info_len = sizeof(struct bpf_prog_info) * 2; |
343 | bzero(&prog_infos[i], info_len); | 321 | bzero(&prog_infos[i], info_len); |
322 | bzero(jited_insns, sizeof(jited_insns)); | ||
323 | bzero(xlated_insns, sizeof(xlated_insns)); | ||
344 | prog_infos[i].jited_prog_insns = ptr_to_u64(jited_insns); | 324 | prog_infos[i].jited_prog_insns = ptr_to_u64(jited_insns); |
345 | prog_infos[i].jited_prog_len = sizeof(jited_insns); | 325 | prog_infos[i].jited_prog_len = sizeof(jited_insns); |
346 | prog_infos[i].xlated_prog_insns = ptr_to_u64(xlated_insns); | 326 | prog_infos[i].xlated_prog_insns = ptr_to_u64(xlated_insns); |
@@ -351,15 +331,20 @@ static void test_bpf_obj_id(void) | |||
351 | prog_infos[i].type != BPF_PROG_TYPE_SOCKET_FILTER || | 331 | prog_infos[i].type != BPF_PROG_TYPE_SOCKET_FILTER || |
352 | info_len != sizeof(struct bpf_prog_info) || | 332 | info_len != sizeof(struct bpf_prog_info) || |
353 | (jit_enabled && !prog_infos[i].jited_prog_len) || | 333 | (jit_enabled && !prog_infos[i].jited_prog_len) || |
354 | !prog_infos[i].xlated_prog_len, | 334 | (jit_enabled && |
335 | !memcmp(jited_insns, zeros, sizeof(zeros))) || | ||
336 | !prog_infos[i].xlated_prog_len || | ||
337 | !memcmp(xlated_insns, zeros, sizeof(zeros)), | ||
355 | "get-prog-info(fd)", | 338 | "get-prog-info(fd)", |
356 | "err %d errno %d i %d type %d(%d) info_len %u(%lu) jit_enabled %d jited_prog_len %u xlated_prog_len %u\n", | 339 | "err %d errno %d i %d type %d(%d) info_len %u(%lu) jit_enabled %d jited_prog_len %u xlated_prog_len %u jited_prog %d xlated_prog %d\n", |
357 | err, errno, i, | 340 | err, errno, i, |
358 | prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER, | 341 | prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER, |
359 | info_len, sizeof(struct bpf_prog_info), | 342 | info_len, sizeof(struct bpf_prog_info), |
360 | jit_enabled, | 343 | jit_enabled, |
361 | prog_infos[i].jited_prog_len, | 344 | prog_infos[i].jited_prog_len, |
362 | prog_infos[i].xlated_prog_len)) | 345 | prog_infos[i].xlated_prog_len, |
346 | !!memcmp(jited_insns, zeros, sizeof(zeros)), | ||
347 | !!memcmp(xlated_insns, zeros, sizeof(zeros)))) | ||
363 | goto done; | 348 | goto done; |
364 | 349 | ||
365 | map_fds[i] = bpf_find_map(__func__, objs[i], "test_map_id"); | 350 | map_fds[i] = bpf_find_map(__func__, objs[i], "test_map_id"); |
@@ -496,8 +481,10 @@ static void test_pkt_md_access(void) | |||
496 | int err, prog_fd; | 481 | int err, prog_fd; |
497 | 482 | ||
498 | err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); | 483 | err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); |
499 | if (err) | 484 | if (err) { |
485 | error_cnt++; | ||
500 | return; | 486 | return; |
487 | } | ||
501 | 488 | ||
502 | err = bpf_prog_test_run(prog_fd, 10, &pkt_v4, sizeof(pkt_v4), | 489 | err = bpf_prog_test_run(prog_fd, 10, &pkt_v4, sizeof(pkt_v4), |
503 | NULL, NULL, &retval, &duration); | 490 | NULL, NULL, &retval, &duration); |
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index d3ed7324105e..26f3250bdcd2 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c | |||
@@ -422,7 +422,7 @@ static struct bpf_test tests[] = { | |||
422 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0), | 422 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0), |
423 | BPF_EXIT_INSN(), | 423 | BPF_EXIT_INSN(), |
424 | }, | 424 | }, |
425 | .errstr_unpriv = "R1 pointer arithmetic", | 425 | .errstr_unpriv = "R1 subtraction from stack pointer", |
426 | .result_unpriv = REJECT, | 426 | .result_unpriv = REJECT, |
427 | .errstr = "R1 invalid mem access", | 427 | .errstr = "R1 invalid mem access", |
428 | .result = REJECT, | 428 | .result = REJECT, |
@@ -604,8 +604,9 @@ static struct bpf_test tests[] = { | |||
604 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, -4), | 604 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, -4), |
605 | BPF_EXIT_INSN(), | 605 | BPF_EXIT_INSN(), |
606 | }, | 606 | }, |
607 | .errstr = "misaligned access", | 607 | .errstr = "misaligned stack access", |
608 | .result = REJECT, | 608 | .result = REJECT, |
609 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
609 | }, | 610 | }, |
610 | { | 611 | { |
611 | "invalid map_fd for function call", | 612 | "invalid map_fd for function call", |
@@ -651,8 +652,9 @@ static struct bpf_test tests[] = { | |||
651 | BPF_EXIT_INSN(), | 652 | BPF_EXIT_INSN(), |
652 | }, | 653 | }, |
653 | .fixup_map1 = { 3 }, | 654 | .fixup_map1 = { 3 }, |
654 | .errstr = "misaligned access", | 655 | .errstr = "misaligned value access", |
655 | .result = REJECT, | 656 | .result = REJECT, |
657 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
656 | }, | 658 | }, |
657 | { | 659 | { |
658 | "sometimes access memory with incorrect alignment", | 660 | "sometimes access memory with incorrect alignment", |
@@ -673,6 +675,7 @@ static struct bpf_test tests[] = { | |||
673 | .errstr = "R0 invalid mem access", | 675 | .errstr = "R0 invalid mem access", |
674 | .errstr_unpriv = "R0 leaks addr", | 676 | .errstr_unpriv = "R0 leaks addr", |
675 | .result = REJECT, | 677 | .result = REJECT, |
678 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
676 | }, | 679 | }, |
677 | { | 680 | { |
678 | "jump test 1", | 681 | "jump test 1", |
@@ -964,6 +967,256 @@ static struct bpf_test tests[] = { | |||
964 | .result = REJECT, | 967 | .result = REJECT, |
965 | }, | 968 | }, |
966 | { | 969 | { |
970 | "invalid access __sk_buff family", | ||
971 | .insns = { | ||
972 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
973 | offsetof(struct __sk_buff, family)), | ||
974 | BPF_EXIT_INSN(), | ||
975 | }, | ||
976 | .errstr = "invalid bpf_context access", | ||
977 | .result = REJECT, | ||
978 | }, | ||
979 | { | ||
980 | "invalid access __sk_buff remote_ip4", | ||
981 | .insns = { | ||
982 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
983 | offsetof(struct __sk_buff, remote_ip4)), | ||
984 | BPF_EXIT_INSN(), | ||
985 | }, | ||
986 | .errstr = "invalid bpf_context access", | ||
987 | .result = REJECT, | ||
988 | }, | ||
989 | { | ||
990 | "invalid access __sk_buff local_ip4", | ||
991 | .insns = { | ||
992 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
993 | offsetof(struct __sk_buff, local_ip4)), | ||
994 | BPF_EXIT_INSN(), | ||
995 | }, | ||
996 | .errstr = "invalid bpf_context access", | ||
997 | .result = REJECT, | ||
998 | }, | ||
999 | { | ||
1000 | "invalid access __sk_buff remote_ip6", | ||
1001 | .insns = { | ||
1002 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1003 | offsetof(struct __sk_buff, remote_ip6)), | ||
1004 | BPF_EXIT_INSN(), | ||
1005 | }, | ||
1006 | .errstr = "invalid bpf_context access", | ||
1007 | .result = REJECT, | ||
1008 | }, | ||
1009 | { | ||
1010 | "invalid access __sk_buff local_ip6", | ||
1011 | .insns = { | ||
1012 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1013 | offsetof(struct __sk_buff, local_ip6)), | ||
1014 | BPF_EXIT_INSN(), | ||
1015 | }, | ||
1016 | .errstr = "invalid bpf_context access", | ||
1017 | .result = REJECT, | ||
1018 | }, | ||
1019 | { | ||
1020 | "invalid access __sk_buff remote_port", | ||
1021 | .insns = { | ||
1022 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1023 | offsetof(struct __sk_buff, remote_port)), | ||
1024 | BPF_EXIT_INSN(), | ||
1025 | }, | ||
1026 | .errstr = "invalid bpf_context access", | ||
1027 | .result = REJECT, | ||
1028 | }, | ||
1029 | { | ||
1030 | "invalid access __sk_buff remote_port", | ||
1031 | .insns = { | ||
1032 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1033 | offsetof(struct __sk_buff, local_port)), | ||
1034 | BPF_EXIT_INSN(), | ||
1035 | }, | ||
1036 | .errstr = "invalid bpf_context access", | ||
1037 | .result = REJECT, | ||
1038 | }, | ||
1039 | { | ||
1040 | "valid access __sk_buff family", | ||
1041 | .insns = { | ||
1042 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1043 | offsetof(struct __sk_buff, family)), | ||
1044 | BPF_EXIT_INSN(), | ||
1045 | }, | ||
1046 | .result = ACCEPT, | ||
1047 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1048 | }, | ||
1049 | { | ||
1050 | "valid access __sk_buff remote_ip4", | ||
1051 | .insns = { | ||
1052 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1053 | offsetof(struct __sk_buff, remote_ip4)), | ||
1054 | BPF_EXIT_INSN(), | ||
1055 | }, | ||
1056 | .result = ACCEPT, | ||
1057 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1058 | }, | ||
1059 | { | ||
1060 | "valid access __sk_buff local_ip4", | ||
1061 | .insns = { | ||
1062 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1063 | offsetof(struct __sk_buff, local_ip4)), | ||
1064 | BPF_EXIT_INSN(), | ||
1065 | }, | ||
1066 | .result = ACCEPT, | ||
1067 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1068 | }, | ||
1069 | { | ||
1070 | "valid access __sk_buff remote_ip6", | ||
1071 | .insns = { | ||
1072 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1073 | offsetof(struct __sk_buff, remote_ip6[0])), | ||
1074 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1075 | offsetof(struct __sk_buff, remote_ip6[1])), | ||
1076 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1077 | offsetof(struct __sk_buff, remote_ip6[2])), | ||
1078 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1079 | offsetof(struct __sk_buff, remote_ip6[3])), | ||
1080 | BPF_EXIT_INSN(), | ||
1081 | }, | ||
1082 | .result = ACCEPT, | ||
1083 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1084 | }, | ||
1085 | { | ||
1086 | "valid access __sk_buff local_ip6", | ||
1087 | .insns = { | ||
1088 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1089 | offsetof(struct __sk_buff, local_ip6[0])), | ||
1090 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1091 | offsetof(struct __sk_buff, local_ip6[1])), | ||
1092 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1093 | offsetof(struct __sk_buff, local_ip6[2])), | ||
1094 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1095 | offsetof(struct __sk_buff, local_ip6[3])), | ||
1096 | BPF_EXIT_INSN(), | ||
1097 | }, | ||
1098 | .result = ACCEPT, | ||
1099 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1100 | }, | ||
1101 | { | ||
1102 | "valid access __sk_buff remote_port", | ||
1103 | .insns = { | ||
1104 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1105 | offsetof(struct __sk_buff, remote_port)), | ||
1106 | BPF_EXIT_INSN(), | ||
1107 | }, | ||
1108 | .result = ACCEPT, | ||
1109 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1110 | }, | ||
1111 | { | ||
1112 | "valid access __sk_buff remote_port", | ||
1113 | .insns = { | ||
1114 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1115 | offsetof(struct __sk_buff, local_port)), | ||
1116 | BPF_EXIT_INSN(), | ||
1117 | }, | ||
1118 | .result = ACCEPT, | ||
1119 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1120 | }, | ||
1121 | { | ||
1122 | "invalid access of tc_classid for SK_SKB", | ||
1123 | .insns = { | ||
1124 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
1125 | offsetof(struct __sk_buff, tc_classid)), | ||
1126 | BPF_EXIT_INSN(), | ||
1127 | }, | ||
1128 | .result = REJECT, | ||
1129 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1130 | .errstr = "invalid bpf_context access", | ||
1131 | }, | ||
1132 | { | ||
1133 | "check skb->mark is writeable by SK_SKB", | ||
1134 | .insns = { | ||
1135 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
1136 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, | ||
1137 | offsetof(struct __sk_buff, mark)), | ||
1138 | BPF_EXIT_INSN(), | ||
1139 | }, | ||
1140 | .result = ACCEPT, | ||
1141 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1142 | }, | ||
1143 | { | ||
1144 | "check skb->tc_index is writeable by SK_SKB", | ||
1145 | .insns = { | ||
1146 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
1147 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, | ||
1148 | offsetof(struct __sk_buff, tc_index)), | ||
1149 | BPF_EXIT_INSN(), | ||
1150 | }, | ||
1151 | .result = ACCEPT, | ||
1152 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1153 | }, | ||
1154 | { | ||
1155 | "check skb->priority is writeable by SK_SKB", | ||
1156 | .insns = { | ||
1157 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
1158 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, | ||
1159 | offsetof(struct __sk_buff, priority)), | ||
1160 | BPF_EXIT_INSN(), | ||
1161 | }, | ||
1162 | .result = ACCEPT, | ||
1163 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1164 | }, | ||
1165 | { | ||
1166 | "direct packet read for SK_SKB", | ||
1167 | .insns = { | ||
1168 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
1169 | offsetof(struct __sk_buff, data)), | ||
1170 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
1171 | offsetof(struct __sk_buff, data_end)), | ||
1172 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
1173 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
1174 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | ||
1175 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
1176 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
1177 | BPF_EXIT_INSN(), | ||
1178 | }, | ||
1179 | .result = ACCEPT, | ||
1180 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1181 | }, | ||
1182 | { | ||
1183 | "direct packet write for SK_SKB", | ||
1184 | .insns = { | ||
1185 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
1186 | offsetof(struct __sk_buff, data)), | ||
1187 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
1188 | offsetof(struct __sk_buff, data_end)), | ||
1189 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
1190 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
1191 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | ||
1192 | BPF_STX_MEM(BPF_B, BPF_REG_2, BPF_REG_2, 0), | ||
1193 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
1194 | BPF_EXIT_INSN(), | ||
1195 | }, | ||
1196 | .result = ACCEPT, | ||
1197 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1198 | }, | ||
1199 | { | ||
1200 | "overlapping checks for direct packet access SK_SKB", | ||
1201 | .insns = { | ||
1202 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
1203 | offsetof(struct __sk_buff, data)), | ||
1204 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
1205 | offsetof(struct __sk_buff, data_end)), | ||
1206 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
1207 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
1208 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 4), | ||
1209 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
1210 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6), | ||
1211 | BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1), | ||
1212 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_2, 6), | ||
1213 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
1214 | BPF_EXIT_INSN(), | ||
1215 | }, | ||
1216 | .result = ACCEPT, | ||
1217 | .prog_type = BPF_PROG_TYPE_SK_SKB, | ||
1218 | }, | ||
1219 | { | ||
967 | "check skb->mark is not writeable by sockets", | 1220 | "check skb->mark is not writeable by sockets", |
968 | .insns = { | 1221 | .insns = { |
969 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, | 1222 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, |
@@ -1216,8 +1469,9 @@ static struct bpf_test tests[] = { | |||
1216 | offsetof(struct __sk_buff, cb[0]) + 1), | 1469 | offsetof(struct __sk_buff, cb[0]) + 1), |
1217 | BPF_EXIT_INSN(), | 1470 | BPF_EXIT_INSN(), |
1218 | }, | 1471 | }, |
1219 | .errstr = "misaligned access", | 1472 | .errstr = "misaligned context access", |
1220 | .result = REJECT, | 1473 | .result = REJECT, |
1474 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
1221 | }, | 1475 | }, |
1222 | { | 1476 | { |
1223 | "check __sk_buff->hash, offset 0, half store not permitted", | 1477 | "check __sk_buff->hash, offset 0, half store not permitted", |
@@ -1320,8 +1574,9 @@ static struct bpf_test tests[] = { | |||
1320 | offsetof(struct __sk_buff, cb[0]) + 2), | 1574 | offsetof(struct __sk_buff, cb[0]) + 2), |
1321 | BPF_EXIT_INSN(), | 1575 | BPF_EXIT_INSN(), |
1322 | }, | 1576 | }, |
1323 | .errstr = "misaligned access", | 1577 | .errstr = "misaligned context access", |
1324 | .result = REJECT, | 1578 | .result = REJECT, |
1579 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
1325 | }, | 1580 | }, |
1326 | { | 1581 | { |
1327 | "check cb access: word, unaligned 2", | 1582 | "check cb access: word, unaligned 2", |
@@ -1331,8 +1586,9 @@ static struct bpf_test tests[] = { | |||
1331 | offsetof(struct __sk_buff, cb[4]) + 1), | 1586 | offsetof(struct __sk_buff, cb[4]) + 1), |
1332 | BPF_EXIT_INSN(), | 1587 | BPF_EXIT_INSN(), |
1333 | }, | 1588 | }, |
1334 | .errstr = "misaligned access", | 1589 | .errstr = "misaligned context access", |
1335 | .result = REJECT, | 1590 | .result = REJECT, |
1591 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
1336 | }, | 1592 | }, |
1337 | { | 1593 | { |
1338 | "check cb access: word, unaligned 3", | 1594 | "check cb access: word, unaligned 3", |
@@ -1342,8 +1598,9 @@ static struct bpf_test tests[] = { | |||
1342 | offsetof(struct __sk_buff, cb[4]) + 2), | 1598 | offsetof(struct __sk_buff, cb[4]) + 2), |
1343 | BPF_EXIT_INSN(), | 1599 | BPF_EXIT_INSN(), |
1344 | }, | 1600 | }, |
1345 | .errstr = "misaligned access", | 1601 | .errstr = "misaligned context access", |
1346 | .result = REJECT, | 1602 | .result = REJECT, |
1603 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
1347 | }, | 1604 | }, |
1348 | { | 1605 | { |
1349 | "check cb access: word, unaligned 4", | 1606 | "check cb access: word, unaligned 4", |
@@ -1353,8 +1610,9 @@ static struct bpf_test tests[] = { | |||
1353 | offsetof(struct __sk_buff, cb[4]) + 3), | 1610 | offsetof(struct __sk_buff, cb[4]) + 3), |
1354 | BPF_EXIT_INSN(), | 1611 | BPF_EXIT_INSN(), |
1355 | }, | 1612 | }, |
1356 | .errstr = "misaligned access", | 1613 | .errstr = "misaligned context access", |
1357 | .result = REJECT, | 1614 | .result = REJECT, |
1615 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
1358 | }, | 1616 | }, |
1359 | { | 1617 | { |
1360 | "check cb access: double", | 1618 | "check cb access: double", |
@@ -1380,8 +1638,9 @@ static struct bpf_test tests[] = { | |||
1380 | offsetof(struct __sk_buff, cb[1])), | 1638 | offsetof(struct __sk_buff, cb[1])), |
1381 | BPF_EXIT_INSN(), | 1639 | BPF_EXIT_INSN(), |
1382 | }, | 1640 | }, |
1383 | .errstr = "misaligned access", | 1641 | .errstr = "misaligned context access", |
1384 | .result = REJECT, | 1642 | .result = REJECT, |
1643 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
1385 | }, | 1644 | }, |
1386 | { | 1645 | { |
1387 | "check cb access: double, unaligned 2", | 1646 | "check cb access: double, unaligned 2", |
@@ -1391,8 +1650,9 @@ static struct bpf_test tests[] = { | |||
1391 | offsetof(struct __sk_buff, cb[3])), | 1650 | offsetof(struct __sk_buff, cb[3])), |
1392 | BPF_EXIT_INSN(), | 1651 | BPF_EXIT_INSN(), |
1393 | }, | 1652 | }, |
1394 | .errstr = "misaligned access", | 1653 | .errstr = "misaligned context access", |
1395 | .result = REJECT, | 1654 | .result = REJECT, |
1655 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
1396 | }, | 1656 | }, |
1397 | { | 1657 | { |
1398 | "check cb access: double, oob 1", | 1658 | "check cb access: double, oob 1", |
@@ -1524,7 +1784,8 @@ static struct bpf_test tests[] = { | |||
1524 | BPF_EXIT_INSN(), | 1784 | BPF_EXIT_INSN(), |
1525 | }, | 1785 | }, |
1526 | .result = REJECT, | 1786 | .result = REJECT, |
1527 | .errstr = "misaligned access off -6 size 8", | 1787 | .errstr = "misaligned stack access off (0x0; 0x0)+-8+2 size 8", |
1788 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
1528 | }, | 1789 | }, |
1529 | { | 1790 | { |
1530 | "PTR_TO_STACK store/load - bad alignment on reg", | 1791 | "PTR_TO_STACK store/load - bad alignment on reg", |
@@ -1536,7 +1797,8 @@ static struct bpf_test tests[] = { | |||
1536 | BPF_EXIT_INSN(), | 1797 | BPF_EXIT_INSN(), |
1537 | }, | 1798 | }, |
1538 | .result = REJECT, | 1799 | .result = REJECT, |
1539 | .errstr = "misaligned access off -2 size 8", | 1800 | .errstr = "misaligned stack access off (0x0; 0x0)+-10+8 size 8", |
1801 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
1540 | }, | 1802 | }, |
1541 | { | 1803 | { |
1542 | "PTR_TO_STACK store/load - out of bounds low", | 1804 | "PTR_TO_STACK store/load - out of bounds low", |
@@ -1580,8 +1842,6 @@ static struct bpf_test tests[] = { | |||
1580 | BPF_EXIT_INSN(), | 1842 | BPF_EXIT_INSN(), |
1581 | }, | 1843 | }, |
1582 | .result = ACCEPT, | 1844 | .result = ACCEPT, |
1583 | .result_unpriv = REJECT, | ||
1584 | .errstr_unpriv = "R1 pointer arithmetic", | ||
1585 | }, | 1845 | }, |
1586 | { | 1846 | { |
1587 | "unpriv: add pointer to pointer", | 1847 | "unpriv: add pointer to pointer", |
@@ -1592,7 +1852,7 @@ static struct bpf_test tests[] = { | |||
1592 | }, | 1852 | }, |
1593 | .result = ACCEPT, | 1853 | .result = ACCEPT, |
1594 | .result_unpriv = REJECT, | 1854 | .result_unpriv = REJECT, |
1595 | .errstr_unpriv = "R1 pointer arithmetic", | 1855 | .errstr_unpriv = "R1 pointer += pointer", |
1596 | }, | 1856 | }, |
1597 | { | 1857 | { |
1598 | "unpriv: neg pointer", | 1858 | "unpriv: neg pointer", |
@@ -1933,10 +2193,7 @@ static struct bpf_test tests[] = { | |||
1933 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, -8), | 2193 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, -8), |
1934 | BPF_EXIT_INSN(), | 2194 | BPF_EXIT_INSN(), |
1935 | }, | 2195 | }, |
1936 | .errstr_unpriv = "pointer arithmetic prohibited", | 2196 | .result = ACCEPT, |
1937 | .result_unpriv = REJECT, | ||
1938 | .errstr = "R1 invalid mem access", | ||
1939 | .result = REJECT, | ||
1940 | }, | 2197 | }, |
1941 | { | 2198 | { |
1942 | "unpriv: cmp of stack pointer", | 2199 | "unpriv: cmp of stack pointer", |
@@ -2000,7 +2257,7 @@ static struct bpf_test tests[] = { | |||
2000 | BPF_EXIT_INSN(), | 2257 | BPF_EXIT_INSN(), |
2001 | }, | 2258 | }, |
2002 | .result = REJECT, | 2259 | .result = REJECT, |
2003 | .errstr = "invalid stack type R3", | 2260 | .errstr = "R4 min value is negative", |
2004 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2261 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2005 | }, | 2262 | }, |
2006 | { | 2263 | { |
@@ -2017,7 +2274,7 @@ static struct bpf_test tests[] = { | |||
2017 | BPF_EXIT_INSN(), | 2274 | BPF_EXIT_INSN(), |
2018 | }, | 2275 | }, |
2019 | .result = REJECT, | 2276 | .result = REJECT, |
2020 | .errstr = "invalid stack type R3", | 2277 | .errstr = "R4 min value is negative", |
2021 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2278 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2022 | }, | 2279 | }, |
2023 | { | 2280 | { |
@@ -2219,7 +2476,7 @@ static struct bpf_test tests[] = { | |||
2219 | BPF_EXIT_INSN(), | 2476 | BPF_EXIT_INSN(), |
2220 | }, | 2477 | }, |
2221 | .result = REJECT, | 2478 | .result = REJECT, |
2222 | .errstr = "invalid stack type R3 off=-1 access_size=-1", | 2479 | .errstr = "R4 min value is negative", |
2223 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2480 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2224 | }, | 2481 | }, |
2225 | { | 2482 | { |
@@ -2236,7 +2493,7 @@ static struct bpf_test tests[] = { | |||
2236 | BPF_EXIT_INSN(), | 2493 | BPF_EXIT_INSN(), |
2237 | }, | 2494 | }, |
2238 | .result = REJECT, | 2495 | .result = REJECT, |
2239 | .errstr = "invalid stack type R3 off=-1 access_size=2147483647", | 2496 | .errstr = "R4 unbounded memory access, use 'var &= const' or 'if (var < const)'", |
2240 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2497 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2241 | }, | 2498 | }, |
2242 | { | 2499 | { |
@@ -2253,7 +2510,7 @@ static struct bpf_test tests[] = { | |||
2253 | BPF_EXIT_INSN(), | 2510 | BPF_EXIT_INSN(), |
2254 | }, | 2511 | }, |
2255 | .result = REJECT, | 2512 | .result = REJECT, |
2256 | .errstr = "invalid stack type R3 off=-512 access_size=2147483647", | 2513 | .errstr = "R4 unbounded memory access, use 'var &= const' or 'if (var < const)'", |
2257 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2514 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2258 | }, | 2515 | }, |
2259 | { | 2516 | { |
@@ -2324,8 +2581,8 @@ static struct bpf_test tests[] = { | |||
2324 | offsetof(struct __sk_buff, data)), | 2581 | offsetof(struct __sk_buff, data)), |
2325 | BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_4), | 2582 | BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_4), |
2326 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), | 2583 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), |
2327 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 48), | 2584 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 49), |
2328 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 48), | 2585 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 49), |
2329 | BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_2), | 2586 | BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_2), |
2330 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_3), | 2587 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_3), |
2331 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 8), | 2588 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 8), |
@@ -2653,7 +2910,7 @@ static struct bpf_test tests[] = { | |||
2653 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | 2910 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), |
2654 | BPF_JMP_A(-6), | 2911 | BPF_JMP_A(-6), |
2655 | }, | 2912 | }, |
2656 | .errstr = "misaligned packet access off 2+15+-4 size 4", | 2913 | .errstr = "misaligned packet access off 2+(0x0; 0x0)+15+-4 size 4", |
2657 | .result = REJECT, | 2914 | .result = REJECT, |
2658 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2915 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2659 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | 2916 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, |
@@ -2704,11 +2961,11 @@ static struct bpf_test tests[] = { | |||
2704 | BPF_MOV64_IMM(BPF_REG_0, 0xffffffff), | 2961 | BPF_MOV64_IMM(BPF_REG_0, 0xffffffff), |
2705 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), | 2962 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), |
2706 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), | 2963 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), |
2707 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffff), | 2964 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0x7fff), |
2708 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | 2965 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), |
2709 | BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_2), | 2966 | BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_2), |
2710 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_4), | 2967 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_4), |
2711 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 0xffff - 1), | 2968 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 0x7fff - 1), |
2712 | BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1), | 2969 | BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1), |
2713 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_4, 0), | 2970 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_4, 0), |
2714 | BPF_MOV64_IMM(BPF_REG_0, 0), | 2971 | BPF_MOV64_IMM(BPF_REG_0, 0), |
@@ -2730,10 +2987,10 @@ static struct bpf_test tests[] = { | |||
2730 | BPF_MOV64_IMM(BPF_REG_4, 0xffffffff), | 2987 | BPF_MOV64_IMM(BPF_REG_4, 0xffffffff), |
2731 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_4, -8), | 2988 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_4, -8), |
2732 | BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8), | 2989 | BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8), |
2733 | BPF_ALU64_IMM(BPF_AND, BPF_REG_4, 0xffff), | 2990 | BPF_ALU64_IMM(BPF_AND, BPF_REG_4, 0x7fff), |
2734 | BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_2), | 2991 | BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_2), |
2735 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_4), | 2992 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_4), |
2736 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 0xffff - 1), | 2993 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 0x7fff - 1), |
2737 | BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1), | 2994 | BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1), |
2738 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_4, 0), | 2995 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_4, 0), |
2739 | BPF_MOV64_IMM(BPF_REG_0, 0), | 2996 | BPF_MOV64_IMM(BPF_REG_0, 0), |
@@ -2759,7 +3016,7 @@ static struct bpf_test tests[] = { | |||
2759 | BPF_MOV64_IMM(BPF_REG_4, 0xffffffff), | 3016 | BPF_MOV64_IMM(BPF_REG_4, 0xffffffff), |
2760 | BPF_STX_XADD(BPF_DW, BPF_REG_10, BPF_REG_4, -8), | 3017 | BPF_STX_XADD(BPF_DW, BPF_REG_10, BPF_REG_4, -8), |
2761 | BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8), | 3018 | BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8), |
2762 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 48), | 3019 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 49), |
2763 | BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_2), | 3020 | BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_2), |
2764 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_4), | 3021 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_4), |
2765 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 2), | 3022 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 2), |
@@ -2796,7 +3053,7 @@ static struct bpf_test tests[] = { | |||
2796 | }, | 3053 | }, |
2797 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3054 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2798 | .result = REJECT, | 3055 | .result = REJECT, |
2799 | .errstr = "cannot add integer value with 47 upper zero bits to ptr_to_packet", | 3056 | .errstr = "invalid access to packet, off=0 size=8, R5(id=1,off=0,r=0)", |
2800 | }, | 3057 | }, |
2801 | { | 3058 | { |
2802 | "direct packet access: test24 (x += pkt_ptr, 5)", | 3059 | "direct packet access: test24 (x += pkt_ptr, 5)", |
@@ -2814,7 +3071,7 @@ static struct bpf_test tests[] = { | |||
2814 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_4), | 3071 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_4), |
2815 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), | 3072 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), |
2816 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_0), | 3073 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_0), |
2817 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0xffff - 1), | 3074 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x7fff - 1), |
2818 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | 3075 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), |
2819 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_0, 0), | 3076 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_0, 0), |
2820 | BPF_MOV64_IMM(BPF_REG_0, 0), | 3077 | BPF_MOV64_IMM(BPF_REG_0, 0), |
@@ -2824,6 +3081,79 @@ static struct bpf_test tests[] = { | |||
2824 | .result = ACCEPT, | 3081 | .result = ACCEPT, |
2825 | }, | 3082 | }, |
2826 | { | 3083 | { |
3084 | "direct packet access: test25 (marking on <, good access)", | ||
3085 | .insns = { | ||
3086 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
3087 | offsetof(struct __sk_buff, data)), | ||
3088 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
3089 | offsetof(struct __sk_buff, data_end)), | ||
3090 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
3091 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
3092 | BPF_JMP_REG(BPF_JLT, BPF_REG_0, BPF_REG_3, 2), | ||
3093 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
3094 | BPF_EXIT_INSN(), | ||
3095 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
3096 | BPF_JMP_IMM(BPF_JA, 0, 0, -4), | ||
3097 | }, | ||
3098 | .result = ACCEPT, | ||
3099 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
3100 | }, | ||
3101 | { | ||
3102 | "direct packet access: test26 (marking on <, bad access)", | ||
3103 | .insns = { | ||
3104 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
3105 | offsetof(struct __sk_buff, data)), | ||
3106 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
3107 | offsetof(struct __sk_buff, data_end)), | ||
3108 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
3109 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
3110 | BPF_JMP_REG(BPF_JLT, BPF_REG_0, BPF_REG_3, 3), | ||
3111 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
3112 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
3113 | BPF_EXIT_INSN(), | ||
3114 | BPF_JMP_IMM(BPF_JA, 0, 0, -3), | ||
3115 | }, | ||
3116 | .result = REJECT, | ||
3117 | .errstr = "invalid access to packet", | ||
3118 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
3119 | }, | ||
3120 | { | ||
3121 | "direct packet access: test27 (marking on <=, good access)", | ||
3122 | .insns = { | ||
3123 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
3124 | offsetof(struct __sk_buff, data)), | ||
3125 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
3126 | offsetof(struct __sk_buff, data_end)), | ||
3127 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
3128 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
3129 | BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_0, 1), | ||
3130 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
3131 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
3132 | BPF_EXIT_INSN(), | ||
3133 | }, | ||
3134 | .result = ACCEPT, | ||
3135 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
3136 | }, | ||
3137 | { | ||
3138 | "direct packet access: test28 (marking on <=, bad access)", | ||
3139 | .insns = { | ||
3140 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
3141 | offsetof(struct __sk_buff, data)), | ||
3142 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
3143 | offsetof(struct __sk_buff, data_end)), | ||
3144 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
3145 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
3146 | BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_0, 2), | ||
3147 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
3148 | BPF_EXIT_INSN(), | ||
3149 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
3150 | BPF_JMP_IMM(BPF_JA, 0, 0, -4), | ||
3151 | }, | ||
3152 | .result = REJECT, | ||
3153 | .errstr = "invalid access to packet", | ||
3154 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
3155 | }, | ||
3156 | { | ||
2827 | "helper access to packet: test1, valid packet_ptr range", | 3157 | "helper access to packet: test1, valid packet_ptr range", |
2828 | .insns = { | 3158 | .insns = { |
2829 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | 3159 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, |
@@ -3113,7 +3443,7 @@ static struct bpf_test tests[] = { | |||
3113 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3443 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3114 | }, | 3444 | }, |
3115 | { | 3445 | { |
3116 | "helper access to packet: test14, cls helper fail sub", | 3446 | "helper access to packet: test14, cls helper ok sub", |
3117 | .insns = { | 3447 | .insns = { |
3118 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | 3448 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, |
3119 | offsetof(struct __sk_buff, data)), | 3449 | offsetof(struct __sk_buff, data)), |
@@ -3133,12 +3463,36 @@ static struct bpf_test tests[] = { | |||
3133 | BPF_MOV64_IMM(BPF_REG_0, 0), | 3463 | BPF_MOV64_IMM(BPF_REG_0, 0), |
3134 | BPF_EXIT_INSN(), | 3464 | BPF_EXIT_INSN(), |
3135 | }, | 3465 | }, |
3466 | .result = ACCEPT, | ||
3467 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
3468 | }, | ||
3469 | { | ||
3470 | "helper access to packet: test15, cls helper fail sub", | ||
3471 | .insns = { | ||
3472 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | ||
3473 | offsetof(struct __sk_buff, data)), | ||
3474 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, | ||
3475 | offsetof(struct __sk_buff, data_end)), | ||
3476 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), | ||
3477 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
3478 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7), | ||
3479 | BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_7, 6), | ||
3480 | BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 12), | ||
3481 | BPF_MOV64_IMM(BPF_REG_2, 4), | ||
3482 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
3483 | BPF_MOV64_IMM(BPF_REG_4, 0), | ||
3484 | BPF_MOV64_IMM(BPF_REG_5, 0), | ||
3485 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
3486 | BPF_FUNC_csum_diff), | ||
3487 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
3488 | BPF_EXIT_INSN(), | ||
3489 | }, | ||
3136 | .result = REJECT, | 3490 | .result = REJECT, |
3137 | .errstr = "type=inv expected=fp", | 3491 | .errstr = "invalid access to packet", |
3138 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3492 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3139 | }, | 3493 | }, |
3140 | { | 3494 | { |
3141 | "helper access to packet: test15, cls helper fail range 1", | 3495 | "helper access to packet: test16, cls helper fail range 1", |
3142 | .insns = { | 3496 | .insns = { |
3143 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | 3497 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, |
3144 | offsetof(struct __sk_buff, data)), | 3498 | offsetof(struct __sk_buff, data)), |
@@ -3163,7 +3517,7 @@ static struct bpf_test tests[] = { | |||
3163 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3517 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3164 | }, | 3518 | }, |
3165 | { | 3519 | { |
3166 | "helper access to packet: test16, cls helper fail range 2", | 3520 | "helper access to packet: test17, cls helper fail range 2", |
3167 | .insns = { | 3521 | .insns = { |
3168 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | 3522 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, |
3169 | offsetof(struct __sk_buff, data)), | 3523 | offsetof(struct __sk_buff, data)), |
@@ -3184,11 +3538,11 @@ static struct bpf_test tests[] = { | |||
3184 | BPF_EXIT_INSN(), | 3538 | BPF_EXIT_INSN(), |
3185 | }, | 3539 | }, |
3186 | .result = REJECT, | 3540 | .result = REJECT, |
3187 | .errstr = "invalid access to packet", | 3541 | .errstr = "R2 min value is negative", |
3188 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3542 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3189 | }, | 3543 | }, |
3190 | { | 3544 | { |
3191 | "helper access to packet: test17, cls helper fail range 3", | 3545 | "helper access to packet: test18, cls helper fail range 3", |
3192 | .insns = { | 3546 | .insns = { |
3193 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | 3547 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, |
3194 | offsetof(struct __sk_buff, data)), | 3548 | offsetof(struct __sk_buff, data)), |
@@ -3209,11 +3563,11 @@ static struct bpf_test tests[] = { | |||
3209 | BPF_EXIT_INSN(), | 3563 | BPF_EXIT_INSN(), |
3210 | }, | 3564 | }, |
3211 | .result = REJECT, | 3565 | .result = REJECT, |
3212 | .errstr = "invalid access to packet", | 3566 | .errstr = "R2 min value is negative", |
3213 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3567 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3214 | }, | 3568 | }, |
3215 | { | 3569 | { |
3216 | "helper access to packet: test18, cls helper fail range zero", | 3570 | "helper access to packet: test19, cls helper fail range zero", |
3217 | .insns = { | 3571 | .insns = { |
3218 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | 3572 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, |
3219 | offsetof(struct __sk_buff, data)), | 3573 | offsetof(struct __sk_buff, data)), |
@@ -3238,7 +3592,7 @@ static struct bpf_test tests[] = { | |||
3238 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3592 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3239 | }, | 3593 | }, |
3240 | { | 3594 | { |
3241 | "helper access to packet: test19, pkt end as input", | 3595 | "helper access to packet: test20, pkt end as input", |
3242 | .insns = { | 3596 | .insns = { |
3243 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | 3597 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, |
3244 | offsetof(struct __sk_buff, data)), | 3598 | offsetof(struct __sk_buff, data)), |
@@ -3263,7 +3617,7 @@ static struct bpf_test tests[] = { | |||
3263 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3617 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3264 | }, | 3618 | }, |
3265 | { | 3619 | { |
3266 | "helper access to packet: test20, wrong reg", | 3620 | "helper access to packet: test21, wrong reg", |
3267 | .insns = { | 3621 | .insns = { |
3268 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | 3622 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, |
3269 | offsetof(struct __sk_buff, data)), | 3623 | offsetof(struct __sk_buff, data)), |
@@ -3323,7 +3677,7 @@ static struct bpf_test tests[] = { | |||
3323 | BPF_EXIT_INSN(), | 3677 | BPF_EXIT_INSN(), |
3324 | }, | 3678 | }, |
3325 | .fixup_map2 = { 3 }, | 3679 | .fixup_map2 = { 3 }, |
3326 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 3680 | .errstr_unpriv = "R0 leaks addr", |
3327 | .result_unpriv = REJECT, | 3681 | .result_unpriv = REJECT, |
3328 | .result = ACCEPT, | 3682 | .result = ACCEPT, |
3329 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 3683 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -3347,7 +3701,7 @@ static struct bpf_test tests[] = { | |||
3347 | BPF_EXIT_INSN(), | 3701 | BPF_EXIT_INSN(), |
3348 | }, | 3702 | }, |
3349 | .fixup_map2 = { 3 }, | 3703 | .fixup_map2 = { 3 }, |
3350 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 3704 | .errstr_unpriv = "R0 leaks addr", |
3351 | .result_unpriv = REJECT, | 3705 | .result_unpriv = REJECT, |
3352 | .result = ACCEPT, | 3706 | .result = ACCEPT, |
3353 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 3707 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -3375,7 +3729,7 @@ static struct bpf_test tests[] = { | |||
3375 | BPF_EXIT_INSN(), | 3729 | BPF_EXIT_INSN(), |
3376 | }, | 3730 | }, |
3377 | .fixup_map2 = { 3 }, | 3731 | .fixup_map2 = { 3 }, |
3378 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 3732 | .errstr_unpriv = "R0 leaks addr", |
3379 | .result_unpriv = REJECT, | 3733 | .result_unpriv = REJECT, |
3380 | .result = ACCEPT, | 3734 | .result = ACCEPT, |
3381 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 3735 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -3416,9 +3770,7 @@ static struct bpf_test tests[] = { | |||
3416 | BPF_EXIT_INSN(), | 3770 | BPF_EXIT_INSN(), |
3417 | }, | 3771 | }, |
3418 | .fixup_map2 = { 3 }, | 3772 | .fixup_map2 = { 3 }, |
3419 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
3420 | .errstr = "R0 min value is outside of the array range", | 3773 | .errstr = "R0 min value is outside of the array range", |
3421 | .result_unpriv = REJECT, | ||
3422 | .result = REJECT, | 3774 | .result = REJECT, |
3423 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 3775 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
3424 | }, | 3776 | }, |
@@ -3440,9 +3792,7 @@ static struct bpf_test tests[] = { | |||
3440 | BPF_EXIT_INSN(), | 3792 | BPF_EXIT_INSN(), |
3441 | }, | 3793 | }, |
3442 | .fixup_map2 = { 3 }, | 3794 | .fixup_map2 = { 3 }, |
3443 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 3795 | .errstr = "R0 unbounded memory access, make sure to bounds check any array access into a map", |
3444 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | ||
3445 | .result_unpriv = REJECT, | ||
3446 | .result = REJECT, | 3796 | .result = REJECT, |
3447 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 3797 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
3448 | }, | 3798 | }, |
@@ -3456,7 +3806,7 @@ static struct bpf_test tests[] = { | |||
3456 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | 3806 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, |
3457 | BPF_FUNC_map_lookup_elem), | 3807 | BPF_FUNC_map_lookup_elem), |
3458 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7), | 3808 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7), |
3459 | BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), | 3809 | BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0), |
3460 | BPF_MOV32_IMM(BPF_REG_2, MAX_ENTRIES), | 3810 | BPF_MOV32_IMM(BPF_REG_2, MAX_ENTRIES), |
3461 | BPF_JMP_REG(BPF_JSGT, BPF_REG_2, BPF_REG_1, 1), | 3811 | BPF_JMP_REG(BPF_JSGT, BPF_REG_2, BPF_REG_1, 1), |
3462 | BPF_MOV32_IMM(BPF_REG_1, 0), | 3812 | BPF_MOV32_IMM(BPF_REG_1, 0), |
@@ -3467,8 +3817,8 @@ static struct bpf_test tests[] = { | |||
3467 | BPF_EXIT_INSN(), | 3817 | BPF_EXIT_INSN(), |
3468 | }, | 3818 | }, |
3469 | .fixup_map2 = { 3 }, | 3819 | .fixup_map2 = { 3 }, |
3470 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 3820 | .errstr_unpriv = "R0 leaks addr", |
3471 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 3821 | .errstr = "R0 unbounded memory access", |
3472 | .result_unpriv = REJECT, | 3822 | .result_unpriv = REJECT, |
3473 | .result = REJECT, | 3823 | .result = REJECT, |
3474 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 3824 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -3494,7 +3844,7 @@ static struct bpf_test tests[] = { | |||
3494 | BPF_EXIT_INSN(), | 3844 | BPF_EXIT_INSN(), |
3495 | }, | 3845 | }, |
3496 | .fixup_map2 = { 3 }, | 3846 | .fixup_map2 = { 3 }, |
3497 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 3847 | .errstr_unpriv = "R0 leaks addr", |
3498 | .errstr = "invalid access to map value, value_size=48 off=44 size=8", | 3848 | .errstr = "invalid access to map value, value_size=48 off=44 size=8", |
3499 | .result_unpriv = REJECT, | 3849 | .result_unpriv = REJECT, |
3500 | .result = REJECT, | 3850 | .result = REJECT, |
@@ -3524,8 +3874,8 @@ static struct bpf_test tests[] = { | |||
3524 | BPF_EXIT_INSN(), | 3874 | BPF_EXIT_INSN(), |
3525 | }, | 3875 | }, |
3526 | .fixup_map2 = { 3, 11 }, | 3876 | .fixup_map2 = { 3, 11 }, |
3527 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 3877 | .errstr_unpriv = "R0 pointer += pointer", |
3528 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 3878 | .errstr = "R0 invalid mem access 'inv'", |
3529 | .result_unpriv = REJECT, | 3879 | .result_unpriv = REJECT, |
3530 | .result = REJECT, | 3880 | .result = REJECT, |
3531 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 3881 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -3667,34 +4017,6 @@ static struct bpf_test tests[] = { | |||
3667 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 4017 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
3668 | }, | 4018 | }, |
3669 | { | 4019 | { |
3670 | "multiple registers share map_lookup_elem bad reg type", | ||
3671 | .insns = { | ||
3672 | BPF_MOV64_IMM(BPF_REG_1, 10), | ||
3673 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), | ||
3674 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
3675 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
3676 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
3677 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
3678 | BPF_FUNC_map_lookup_elem), | ||
3679 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), | ||
3680 | BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), | ||
3681 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
3682 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_0), | ||
3683 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
3684 | BPF_MOV64_IMM(BPF_REG_1, 1), | ||
3685 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
3686 | BPF_MOV64_IMM(BPF_REG_1, 2), | ||
3687 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_3, 0, 1), | ||
3688 | BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 0), | ||
3689 | BPF_MOV64_IMM(BPF_REG_1, 3), | ||
3690 | BPF_EXIT_INSN(), | ||
3691 | }, | ||
3692 | .fixup_map1 = { 4 }, | ||
3693 | .result = REJECT, | ||
3694 | .errstr = "R3 invalid mem access 'inv'", | ||
3695 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | ||
3696 | }, | ||
3697 | { | ||
3698 | "invalid map access from else condition", | 4020 | "invalid map access from else condition", |
3699 | .insns = { | 4021 | .insns = { |
3700 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | 4022 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
@@ -3712,9 +4034,9 @@ static struct bpf_test tests[] = { | |||
3712 | BPF_EXIT_INSN(), | 4034 | BPF_EXIT_INSN(), |
3713 | }, | 4035 | }, |
3714 | .fixup_map2 = { 3 }, | 4036 | .fixup_map2 = { 3 }, |
3715 | .errstr = "R0 unbounded memory access, make sure to bounds check any array access into a map", | 4037 | .errstr = "R0 unbounded memory access", |
3716 | .result = REJECT, | 4038 | .result = REJECT, |
3717 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 4039 | .errstr_unpriv = "R0 leaks addr", |
3718 | .result_unpriv = REJECT, | 4040 | .result_unpriv = REJECT, |
3719 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 4041 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
3720 | }, | 4042 | }, |
@@ -4092,7 +4414,7 @@ static struct bpf_test tests[] = { | |||
4092 | BPF_EXIT_INSN(), | 4414 | BPF_EXIT_INSN(), |
4093 | }, | 4415 | }, |
4094 | .fixup_map2 = { 3 }, | 4416 | .fixup_map2 = { 3 }, |
4095 | .errstr = "invalid access to map value, value_size=48 off=0 size=-8", | 4417 | .errstr = "R2 min value is negative", |
4096 | .result = REJECT, | 4418 | .result = REJECT, |
4097 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 4419 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
4098 | }, | 4420 | }, |
@@ -4158,7 +4480,7 @@ static struct bpf_test tests[] = { | |||
4158 | BPF_EXIT_INSN(), | 4480 | BPF_EXIT_INSN(), |
4159 | }, | 4481 | }, |
4160 | .fixup_map2 = { 3 }, | 4482 | .fixup_map2 = { 3 }, |
4161 | .errstr = "R1 min value is outside of the array range", | 4483 | .errstr = "invalid access to map value, value_size=48 off=4 size=0", |
4162 | .result = REJECT, | 4484 | .result = REJECT, |
4163 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 4485 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
4164 | }, | 4486 | }, |
@@ -4204,7 +4526,7 @@ static struct bpf_test tests[] = { | |||
4204 | BPF_EXIT_INSN(), | 4526 | BPF_EXIT_INSN(), |
4205 | }, | 4527 | }, |
4206 | .fixup_map2 = { 3 }, | 4528 | .fixup_map2 = { 3 }, |
4207 | .errstr = "invalid access to map value, value_size=48 off=4 size=-8", | 4529 | .errstr = "R2 min value is negative", |
4208 | .result = REJECT, | 4530 | .result = REJECT, |
4209 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 4531 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
4210 | }, | 4532 | }, |
@@ -4226,7 +4548,7 @@ static struct bpf_test tests[] = { | |||
4226 | BPF_EXIT_INSN(), | 4548 | BPF_EXIT_INSN(), |
4227 | }, | 4549 | }, |
4228 | .fixup_map2 = { 3 }, | 4550 | .fixup_map2 = { 3 }, |
4229 | .errstr = "R1 min value is outside of the array range", | 4551 | .errstr = "R2 min value is negative", |
4230 | .result = REJECT, | 4552 | .result = REJECT, |
4231 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 4553 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
4232 | }, | 4554 | }, |
@@ -4342,7 +4664,7 @@ static struct bpf_test tests[] = { | |||
4342 | BPF_EXIT_INSN(), | 4664 | BPF_EXIT_INSN(), |
4343 | }, | 4665 | }, |
4344 | .fixup_map2 = { 3 }, | 4666 | .fixup_map2 = { 3 }, |
4345 | .errstr = "invalid access to map value, value_size=48 off=4 size=-8", | 4667 | .errstr = "R2 min value is negative", |
4346 | .result = REJECT, | 4668 | .result = REJECT, |
4347 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 4669 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
4348 | }, | 4670 | }, |
@@ -4365,7 +4687,7 @@ static struct bpf_test tests[] = { | |||
4365 | BPF_EXIT_INSN(), | 4687 | BPF_EXIT_INSN(), |
4366 | }, | 4688 | }, |
4367 | .fixup_map2 = { 3 }, | 4689 | .fixup_map2 = { 3 }, |
4368 | .errstr = "R1 min value is outside of the array range", | 4690 | .errstr = "R2 min value is negative", |
4369 | .result = REJECT, | 4691 | .result = REJECT, |
4370 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 4692 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
4371 | }, | 4693 | }, |
@@ -4453,13 +4775,13 @@ static struct bpf_test tests[] = { | |||
4453 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | 4775 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
4454 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), | 4776 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), |
4455 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | 4777 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), |
4456 | BPF_MOV64_IMM(BPF_REG_2, 0), | 4778 | BPF_MOV64_IMM(BPF_REG_2, 1), |
4457 | BPF_MOV64_IMM(BPF_REG_3, 0), | 4779 | BPF_MOV64_IMM(BPF_REG_3, 0), |
4458 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 4780 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
4459 | BPF_EXIT_INSN(), | 4781 | BPF_EXIT_INSN(), |
4460 | }, | 4782 | }, |
4461 | .fixup_map2 = { 3 }, | 4783 | .fixup_map2 = { 3 }, |
4462 | .errstr = "R1 min value is negative, either use unsigned index or do a if (index >=0) check", | 4784 | .errstr = "R1 unbounded memory access", |
4463 | .result = REJECT, | 4785 | .result = REJECT, |
4464 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 4786 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
4465 | }, | 4787 | }, |
@@ -4490,6 +4812,246 @@ static struct bpf_test tests[] = { | |||
4490 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 4812 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
4491 | }, | 4813 | }, |
4492 | { | 4814 | { |
4815 | "helper access to map: bounds check using <, good access", | ||
4816 | .insns = { | ||
4817 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4818 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4819 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4820 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4821 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4822 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
4823 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
4824 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), | ||
4825 | BPF_JMP_IMM(BPF_JLT, BPF_REG_3, 32, 2), | ||
4826 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4827 | BPF_EXIT_INSN(), | ||
4828 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | ||
4829 | BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 0), | ||
4830 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4831 | BPF_EXIT_INSN(), | ||
4832 | }, | ||
4833 | .fixup_map2 = { 3 }, | ||
4834 | .result = ACCEPT, | ||
4835 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
4836 | }, | ||
4837 | { | ||
4838 | "helper access to map: bounds check using <, bad access", | ||
4839 | .insns = { | ||
4840 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4841 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4842 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4843 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4844 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4845 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
4846 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
4847 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), | ||
4848 | BPF_JMP_IMM(BPF_JLT, BPF_REG_3, 32, 4), | ||
4849 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | ||
4850 | BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 0), | ||
4851 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4852 | BPF_EXIT_INSN(), | ||
4853 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4854 | BPF_EXIT_INSN(), | ||
4855 | }, | ||
4856 | .fixup_map2 = { 3 }, | ||
4857 | .result = REJECT, | ||
4858 | .errstr = "R1 unbounded memory access", | ||
4859 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
4860 | }, | ||
4861 | { | ||
4862 | "helper access to map: bounds check using <=, good access", | ||
4863 | .insns = { | ||
4864 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4865 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4866 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4867 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4868 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4869 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
4870 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
4871 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), | ||
4872 | BPF_JMP_IMM(BPF_JLE, BPF_REG_3, 32, 2), | ||
4873 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4874 | BPF_EXIT_INSN(), | ||
4875 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | ||
4876 | BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 0), | ||
4877 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4878 | BPF_EXIT_INSN(), | ||
4879 | }, | ||
4880 | .fixup_map2 = { 3 }, | ||
4881 | .result = ACCEPT, | ||
4882 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
4883 | }, | ||
4884 | { | ||
4885 | "helper access to map: bounds check using <=, bad access", | ||
4886 | .insns = { | ||
4887 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4888 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4889 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4890 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4891 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4892 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
4893 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
4894 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), | ||
4895 | BPF_JMP_IMM(BPF_JLE, BPF_REG_3, 32, 4), | ||
4896 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | ||
4897 | BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 0), | ||
4898 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4899 | BPF_EXIT_INSN(), | ||
4900 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4901 | BPF_EXIT_INSN(), | ||
4902 | }, | ||
4903 | .fixup_map2 = { 3 }, | ||
4904 | .result = REJECT, | ||
4905 | .errstr = "R1 unbounded memory access", | ||
4906 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
4907 | }, | ||
4908 | { | ||
4909 | "helper access to map: bounds check using s<, good access", | ||
4910 | .insns = { | ||
4911 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4912 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4913 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4914 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4915 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4916 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
4917 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
4918 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), | ||
4919 | BPF_JMP_IMM(BPF_JSLT, BPF_REG_3, 32, 2), | ||
4920 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4921 | BPF_EXIT_INSN(), | ||
4922 | BPF_JMP_IMM(BPF_JSLT, BPF_REG_3, 0, -3), | ||
4923 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | ||
4924 | BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 0), | ||
4925 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4926 | BPF_EXIT_INSN(), | ||
4927 | }, | ||
4928 | .fixup_map2 = { 3 }, | ||
4929 | .result = ACCEPT, | ||
4930 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
4931 | }, | ||
4932 | { | ||
4933 | "helper access to map: bounds check using s<, good access 2", | ||
4934 | .insns = { | ||
4935 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4936 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4937 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4938 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4939 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4940 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
4941 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
4942 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), | ||
4943 | BPF_JMP_IMM(BPF_JSLT, BPF_REG_3, 32, 2), | ||
4944 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4945 | BPF_EXIT_INSN(), | ||
4946 | BPF_JMP_IMM(BPF_JSLT, BPF_REG_3, -3, -3), | ||
4947 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | ||
4948 | BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 0), | ||
4949 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4950 | BPF_EXIT_INSN(), | ||
4951 | }, | ||
4952 | .fixup_map2 = { 3 }, | ||
4953 | .result = ACCEPT, | ||
4954 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
4955 | }, | ||
4956 | { | ||
4957 | "helper access to map: bounds check using s<, bad access", | ||
4958 | .insns = { | ||
4959 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4960 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4961 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4962 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4963 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4964 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
4965 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
4966 | BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0), | ||
4967 | BPF_JMP_IMM(BPF_JSLT, BPF_REG_3, 32, 2), | ||
4968 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4969 | BPF_EXIT_INSN(), | ||
4970 | BPF_JMP_IMM(BPF_JSLT, BPF_REG_3, -3, -3), | ||
4971 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | ||
4972 | BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 0), | ||
4973 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4974 | BPF_EXIT_INSN(), | ||
4975 | }, | ||
4976 | .fixup_map2 = { 3 }, | ||
4977 | .result = REJECT, | ||
4978 | .errstr = "R1 min value is negative", | ||
4979 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
4980 | }, | ||
4981 | { | ||
4982 | "helper access to map: bounds check using s<=, good access", | ||
4983 | .insns = { | ||
4984 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4985 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4986 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4987 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4988 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4989 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
4990 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
4991 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), | ||
4992 | BPF_JMP_IMM(BPF_JSLE, BPF_REG_3, 32, 2), | ||
4993 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4994 | BPF_EXIT_INSN(), | ||
4995 | BPF_JMP_IMM(BPF_JSLE, BPF_REG_3, 0, -3), | ||
4996 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | ||
4997 | BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 0), | ||
4998 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4999 | BPF_EXIT_INSN(), | ||
5000 | }, | ||
5001 | .fixup_map2 = { 3 }, | ||
5002 | .result = ACCEPT, | ||
5003 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
5004 | }, | ||
5005 | { | ||
5006 | "helper access to map: bounds check using s<=, good access 2", | ||
5007 | .insns = { | ||
5008 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
5009 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
5010 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
5011 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5012 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
5013 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
5014 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
5015 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), | ||
5016 | BPF_JMP_IMM(BPF_JSLE, BPF_REG_3, 32, 2), | ||
5017 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5018 | BPF_EXIT_INSN(), | ||
5019 | BPF_JMP_IMM(BPF_JSLE, BPF_REG_3, -3, -3), | ||
5020 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | ||
5021 | BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 0), | ||
5022 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5023 | BPF_EXIT_INSN(), | ||
5024 | }, | ||
5025 | .fixup_map2 = { 3 }, | ||
5026 | .result = ACCEPT, | ||
5027 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
5028 | }, | ||
5029 | { | ||
5030 | "helper access to map: bounds check using s<=, bad access", | ||
5031 | .insns = { | ||
5032 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
5033 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
5034 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
5035 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5036 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
5037 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
5038 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
5039 | BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0), | ||
5040 | BPF_JMP_IMM(BPF_JSLE, BPF_REG_3, 32, 2), | ||
5041 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5042 | BPF_EXIT_INSN(), | ||
5043 | BPF_JMP_IMM(BPF_JSLE, BPF_REG_3, -3, -3), | ||
5044 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | ||
5045 | BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 0), | ||
5046 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5047 | BPF_EXIT_INSN(), | ||
5048 | }, | ||
5049 | .fixup_map2 = { 3 }, | ||
5050 | .result = REJECT, | ||
5051 | .errstr = "R1 min value is negative", | ||
5052 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
5053 | }, | ||
5054 | { | ||
4493 | "map element value is preserved across register spilling", | 5055 | "map element value is preserved across register spilling", |
4494 | .insns = { | 5056 | .insns = { |
4495 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 5057 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
@@ -4579,7 +5141,7 @@ static struct bpf_test tests[] = { | |||
4579 | BPF_EXIT_INSN(), | 5141 | BPF_EXIT_INSN(), |
4580 | }, | 5142 | }, |
4581 | .fixup_map2 = { 3 }, | 5143 | .fixup_map2 = { 3 }, |
4582 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 5144 | .errstr_unpriv = "R0 leaks addr", |
4583 | .result = ACCEPT, | 5145 | .result = ACCEPT, |
4584 | .result_unpriv = REJECT, | 5146 | .result_unpriv = REJECT, |
4585 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 5147 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -4607,7 +5169,7 @@ static struct bpf_test tests[] = { | |||
4607 | BPF_EXIT_INSN(), | 5169 | BPF_EXIT_INSN(), |
4608 | }, | 5170 | }, |
4609 | .fixup_map2 = { 3 }, | 5171 | .fixup_map2 = { 3 }, |
4610 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 5172 | .errstr_unpriv = "R0 leaks addr", |
4611 | .result = ACCEPT, | 5173 | .result = ACCEPT, |
4612 | .result_unpriv = REJECT, | 5174 | .result_unpriv = REJECT, |
4613 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 5175 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -4626,7 +5188,7 @@ static struct bpf_test tests[] = { | |||
4626 | BPF_EXIT_INSN(), | 5188 | BPF_EXIT_INSN(), |
4627 | }, | 5189 | }, |
4628 | .fixup_map2 = { 3 }, | 5190 | .fixup_map2 = { 3 }, |
4629 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 5191 | .errstr_unpriv = "R0 bitwise operator &= on pointer", |
4630 | .errstr = "invalid mem access 'inv'", | 5192 | .errstr = "invalid mem access 'inv'", |
4631 | .result = REJECT, | 5193 | .result = REJECT, |
4632 | .result_unpriv = REJECT, | 5194 | .result_unpriv = REJECT, |
@@ -4645,7 +5207,7 @@ static struct bpf_test tests[] = { | |||
4645 | BPF_EXIT_INSN(), | 5207 | BPF_EXIT_INSN(), |
4646 | }, | 5208 | }, |
4647 | .fixup_map2 = { 3 }, | 5209 | .fixup_map2 = { 3 }, |
4648 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 5210 | .errstr_unpriv = "R0 32-bit pointer arithmetic prohibited", |
4649 | .errstr = "invalid mem access 'inv'", | 5211 | .errstr = "invalid mem access 'inv'", |
4650 | .result = REJECT, | 5212 | .result = REJECT, |
4651 | .result_unpriv = REJECT, | 5213 | .result_unpriv = REJECT, |
@@ -4664,7 +5226,7 @@ static struct bpf_test tests[] = { | |||
4664 | BPF_EXIT_INSN(), | 5226 | BPF_EXIT_INSN(), |
4665 | }, | 5227 | }, |
4666 | .fixup_map2 = { 3 }, | 5228 | .fixup_map2 = { 3 }, |
4667 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 5229 | .errstr_unpriv = "R0 pointer arithmetic with /= operator", |
4668 | .errstr = "invalid mem access 'inv'", | 5230 | .errstr = "invalid mem access 'inv'", |
4669 | .result = REJECT, | 5231 | .result = REJECT, |
4670 | .result_unpriv = REJECT, | 5232 | .result_unpriv = REJECT, |
@@ -4707,10 +5269,8 @@ static struct bpf_test tests[] = { | |||
4707 | BPF_EXIT_INSN(), | 5269 | BPF_EXIT_INSN(), |
4708 | }, | 5270 | }, |
4709 | .fixup_map2 = { 3 }, | 5271 | .fixup_map2 = { 3 }, |
4710 | .errstr_unpriv = "R0 invalid mem access 'inv'", | ||
4711 | .errstr = "R0 invalid mem access 'inv'", | 5272 | .errstr = "R0 invalid mem access 'inv'", |
4712 | .result = REJECT, | 5273 | .result = REJECT, |
4713 | .result_unpriv = REJECT, | ||
4714 | }, | 5274 | }, |
4715 | { | 5275 | { |
4716 | "map element value is preserved across register spilling", | 5276 | "map element value is preserved across register spilling", |
@@ -4732,7 +5292,7 @@ static struct bpf_test tests[] = { | |||
4732 | BPF_EXIT_INSN(), | 5292 | BPF_EXIT_INSN(), |
4733 | }, | 5293 | }, |
4734 | .fixup_map2 = { 3 }, | 5294 | .fixup_map2 = { 3 }, |
4735 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 5295 | .errstr_unpriv = "R0 leaks addr", |
4736 | .result = ACCEPT, | 5296 | .result = ACCEPT, |
4737 | .result_unpriv = REJECT, | 5297 | .result_unpriv = REJECT, |
4738 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 5298 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -4914,7 +5474,8 @@ static struct bpf_test tests[] = { | |||
4914 | BPF_MOV64_IMM(BPF_REG_0, 0), | 5474 | BPF_MOV64_IMM(BPF_REG_0, 0), |
4915 | BPF_EXIT_INSN(), | 5475 | BPF_EXIT_INSN(), |
4916 | }, | 5476 | }, |
4917 | .errstr = "R2 unbounded memory access", | 5477 | /* because max wasn't checked, signed min is negative */ |
5478 | .errstr = "R2 min value is negative, either use unsigned or 'var &= const'", | ||
4918 | .result = REJECT, | 5479 | .result = REJECT, |
4919 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5480 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
4920 | }, | 5481 | }, |
@@ -5063,6 +5624,20 @@ static struct bpf_test tests[] = { | |||
5063 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5624 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5064 | }, | 5625 | }, |
5065 | { | 5626 | { |
5627 | "helper access to variable memory: size = 0 allowed on NULL", | ||
5628 | .insns = { | ||
5629 | BPF_MOV64_IMM(BPF_REG_1, 0), | ||
5630 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5631 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5632 | BPF_MOV64_IMM(BPF_REG_4, 0), | ||
5633 | BPF_MOV64_IMM(BPF_REG_5, 0), | ||
5634 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), | ||
5635 | BPF_EXIT_INSN(), | ||
5636 | }, | ||
5637 | .result = ACCEPT, | ||
5638 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
5639 | }, | ||
5640 | { | ||
5066 | "helper access to variable memory: size > 0 not allowed on NULL", | 5641 | "helper access to variable memory: size > 0 not allowed on NULL", |
5067 | .insns = { | 5642 | .insns = { |
5068 | BPF_MOV64_IMM(BPF_REG_1, 0), | 5643 | BPF_MOV64_IMM(BPF_REG_1, 0), |
@@ -5076,7 +5651,7 @@ static struct bpf_test tests[] = { | |||
5076 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), | 5651 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), |
5077 | BPF_EXIT_INSN(), | 5652 | BPF_EXIT_INSN(), |
5078 | }, | 5653 | }, |
5079 | .errstr = "R1 type=imm expected=fp", | 5654 | .errstr = "R1 type=inv expected=fp", |
5080 | .result = REJECT, | 5655 | .result = REJECT, |
5081 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 5656 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
5082 | }, | 5657 | }, |
@@ -5161,7 +5736,7 @@ static struct bpf_test tests[] = { | |||
5161 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | 5736 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, |
5162 | BPF_FUNC_map_lookup_elem), | 5737 | BPF_FUNC_map_lookup_elem), |
5163 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | 5738 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), |
5164 | BPF_MOV64_IMM(BPF_REG_1, 6), | 5739 | BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), |
5165 | BPF_ALU64_IMM(BPF_AND, BPF_REG_1, -4), | 5740 | BPF_ALU64_IMM(BPF_AND, BPF_REG_1, -4), |
5166 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2), | 5741 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2), |
5167 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | 5742 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), |
@@ -5170,10 +5745,8 @@ static struct bpf_test tests[] = { | |||
5170 | BPF_EXIT_INSN(), | 5745 | BPF_EXIT_INSN(), |
5171 | }, | 5746 | }, |
5172 | .fixup_map2 = { 3 }, | 5747 | .fixup_map2 = { 3 }, |
5173 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 5748 | .errstr = "R0 max value is outside of the array range", |
5174 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | ||
5175 | .result = REJECT, | 5749 | .result = REJECT, |
5176 | .result_unpriv = REJECT, | ||
5177 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 5750 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
5178 | }, | 5751 | }, |
5179 | { | 5752 | { |
@@ -5202,10 +5775,8 @@ static struct bpf_test tests[] = { | |||
5202 | BPF_EXIT_INSN(), | 5775 | BPF_EXIT_INSN(), |
5203 | }, | 5776 | }, |
5204 | .fixup_map2 = { 3 }, | 5777 | .fixup_map2 = { 3 }, |
5205 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 5778 | .errstr = "R0 max value is outside of the array range", |
5206 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | ||
5207 | .result = REJECT, | 5779 | .result = REJECT, |
5208 | .result_unpriv = REJECT, | ||
5209 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 5780 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
5210 | }, | 5781 | }, |
5211 | { | 5782 | { |
@@ -5252,7 +5823,7 @@ static struct bpf_test tests[] = { | |||
5252 | }, | 5823 | }, |
5253 | .fixup_map_in_map = { 3 }, | 5824 | .fixup_map_in_map = { 3 }, |
5254 | .errstr = "R1 type=inv expected=map_ptr", | 5825 | .errstr = "R1 type=inv expected=map_ptr", |
5255 | .errstr_unpriv = "R1 pointer arithmetic prohibited", | 5826 | .errstr_unpriv = "R1 pointer arithmetic on CONST_PTR_TO_MAP prohibited", |
5256 | .result = REJECT, | 5827 | .result = REJECT, |
5257 | }, | 5828 | }, |
5258 | { | 5829 | { |
@@ -5532,10 +6103,8 @@ static struct bpf_test tests[] = { | |||
5532 | BPF_EXIT_INSN(), | 6103 | BPF_EXIT_INSN(), |
5533 | }, | 6104 | }, |
5534 | .fixup_map1 = { 3 }, | 6105 | .fixup_map1 = { 3 }, |
5535 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
5536 | .errstr = "R0 min value is negative", | 6106 | .errstr = "R0 min value is negative", |
5537 | .result = REJECT, | 6107 | .result = REJECT, |
5538 | .result_unpriv = REJECT, | ||
5539 | }, | 6108 | }, |
5540 | { | 6109 | { |
5541 | "bounds checks mixing signed and unsigned", | 6110 | "bounds checks mixing signed and unsigned", |
@@ -5558,10 +6127,8 @@ static struct bpf_test tests[] = { | |||
5558 | BPF_EXIT_INSN(), | 6127 | BPF_EXIT_INSN(), |
5559 | }, | 6128 | }, |
5560 | .fixup_map1 = { 3 }, | 6129 | .fixup_map1 = { 3 }, |
5561 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
5562 | .errstr = "R0 min value is negative", | 6130 | .errstr = "R0 min value is negative", |
5563 | .result = REJECT, | 6131 | .result = REJECT, |
5564 | .result_unpriv = REJECT, | ||
5565 | }, | 6132 | }, |
5566 | { | 6133 | { |
5567 | "bounds checks mixing signed and unsigned, variant 2", | 6134 | "bounds checks mixing signed and unsigned, variant 2", |
@@ -5586,10 +6153,8 @@ static struct bpf_test tests[] = { | |||
5586 | BPF_EXIT_INSN(), | 6153 | BPF_EXIT_INSN(), |
5587 | }, | 6154 | }, |
5588 | .fixup_map1 = { 3 }, | 6155 | .fixup_map1 = { 3 }, |
5589 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
5590 | .errstr = "R8 invalid mem access 'inv'", | 6156 | .errstr = "R8 invalid mem access 'inv'", |
5591 | .result = REJECT, | 6157 | .result = REJECT, |
5592 | .result_unpriv = REJECT, | ||
5593 | }, | 6158 | }, |
5594 | { | 6159 | { |
5595 | "bounds checks mixing signed and unsigned, variant 3", | 6160 | "bounds checks mixing signed and unsigned, variant 3", |
@@ -5613,10 +6178,8 @@ static struct bpf_test tests[] = { | |||
5613 | BPF_EXIT_INSN(), | 6178 | BPF_EXIT_INSN(), |
5614 | }, | 6179 | }, |
5615 | .fixup_map1 = { 3 }, | 6180 | .fixup_map1 = { 3 }, |
5616 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
5617 | .errstr = "R8 invalid mem access 'inv'", | 6181 | .errstr = "R8 invalid mem access 'inv'", |
5618 | .result = REJECT, | 6182 | .result = REJECT, |
5619 | .result_unpriv = REJECT, | ||
5620 | }, | 6183 | }, |
5621 | { | 6184 | { |
5622 | "bounds checks mixing signed and unsigned, variant 4", | 6185 | "bounds checks mixing signed and unsigned, variant 4", |
@@ -5639,10 +6202,7 @@ static struct bpf_test tests[] = { | |||
5639 | BPF_EXIT_INSN(), | 6202 | BPF_EXIT_INSN(), |
5640 | }, | 6203 | }, |
5641 | .fixup_map1 = { 3 }, | 6204 | .fixup_map1 = { 3 }, |
5642 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 6205 | .result = ACCEPT, |
5643 | .errstr = "R0 min value is negative", | ||
5644 | .result = REJECT, | ||
5645 | .result_unpriv = REJECT, | ||
5646 | }, | 6206 | }, |
5647 | { | 6207 | { |
5648 | "bounds checks mixing signed and unsigned, variant 5", | 6208 | "bounds checks mixing signed and unsigned, variant 5", |
@@ -5666,10 +6226,8 @@ static struct bpf_test tests[] = { | |||
5666 | BPF_EXIT_INSN(), | 6226 | BPF_EXIT_INSN(), |
5667 | }, | 6227 | }, |
5668 | .fixup_map1 = { 3 }, | 6228 | .fixup_map1 = { 3 }, |
5669 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 6229 | .errstr = "R0 min value is negative", |
5670 | .errstr = "R0 invalid mem access", | ||
5671 | .result = REJECT, | 6230 | .result = REJECT, |
5672 | .result_unpriv = REJECT, | ||
5673 | }, | 6231 | }, |
5674 | { | 6232 | { |
5675 | "bounds checks mixing signed and unsigned, variant 6", | 6233 | "bounds checks mixing signed and unsigned, variant 6", |
@@ -5690,10 +6248,8 @@ static struct bpf_test tests[] = { | |||
5690 | BPF_MOV64_IMM(BPF_REG_0, 0), | 6248 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5691 | BPF_EXIT_INSN(), | 6249 | BPF_EXIT_INSN(), |
5692 | }, | 6250 | }, |
5693 | .errstr_unpriv = "R4 min value is negative, either use unsigned", | ||
5694 | .errstr = "R4 min value is negative, either use unsigned", | 6251 | .errstr = "R4 min value is negative, either use unsigned", |
5695 | .result = REJECT, | 6252 | .result = REJECT, |
5696 | .result_unpriv = REJECT, | ||
5697 | }, | 6253 | }, |
5698 | { | 6254 | { |
5699 | "bounds checks mixing signed and unsigned, variant 7", | 6255 | "bounds checks mixing signed and unsigned, variant 7", |
@@ -5716,10 +6272,7 @@ static struct bpf_test tests[] = { | |||
5716 | BPF_EXIT_INSN(), | 6272 | BPF_EXIT_INSN(), |
5717 | }, | 6273 | }, |
5718 | .fixup_map1 = { 3 }, | 6274 | .fixup_map1 = { 3 }, |
5719 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 6275 | .result = ACCEPT, |
5720 | .errstr = "R0 min value is negative", | ||
5721 | .result = REJECT, | ||
5722 | .result_unpriv = REJECT, | ||
5723 | }, | 6276 | }, |
5724 | { | 6277 | { |
5725 | "bounds checks mixing signed and unsigned, variant 8", | 6278 | "bounds checks mixing signed and unsigned, variant 8", |
@@ -5730,32 +6283,6 @@ static struct bpf_test tests[] = { | |||
5730 | BPF_LD_MAP_FD(BPF_REG_1, 0), | 6283 | BPF_LD_MAP_FD(BPF_REG_1, 0), |
5731 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | 6284 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, |
5732 | BPF_FUNC_map_lookup_elem), | 6285 | BPF_FUNC_map_lookup_elem), |
5733 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7), | ||
5734 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8), | ||
5735 | BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16), | ||
5736 | BPF_MOV64_IMM(BPF_REG_2, 1024 * 1024 * 1024 + 1), | ||
5737 | BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_2, 3), | ||
5738 | BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 1, 2), | ||
5739 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
5740 | BPF_ST_MEM(BPF_B, BPF_REG_0, 0, 0), | ||
5741 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5742 | BPF_EXIT_INSN(), | ||
5743 | }, | ||
5744 | .fixup_map1 = { 3 }, | ||
5745 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
5746 | .errstr = "R0 min value is negative", | ||
5747 | .result = REJECT, | ||
5748 | .result_unpriv = REJECT, | ||
5749 | }, | ||
5750 | { | ||
5751 | "bounds checks mixing signed and unsigned, variant 9", | ||
5752 | .insns = { | ||
5753 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
5754 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
5755 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
5756 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5757 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
5758 | BPF_FUNC_map_lookup_elem), | ||
5759 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9), | 6286 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9), |
5760 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8), | 6287 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, -8), |
5761 | BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16), | 6288 | BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -16), |
@@ -5770,13 +6297,11 @@ static struct bpf_test tests[] = { | |||
5770 | BPF_EXIT_INSN(), | 6297 | BPF_EXIT_INSN(), |
5771 | }, | 6298 | }, |
5772 | .fixup_map1 = { 3 }, | 6299 | .fixup_map1 = { 3 }, |
5773 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
5774 | .errstr = "R0 min value is negative", | 6300 | .errstr = "R0 min value is negative", |
5775 | .result = REJECT, | 6301 | .result = REJECT, |
5776 | .result_unpriv = REJECT, | ||
5777 | }, | 6302 | }, |
5778 | { | 6303 | { |
5779 | "bounds checks mixing signed and unsigned, variant 10", | 6304 | "bounds checks mixing signed and unsigned, variant 9", |
5780 | .insns = { | 6305 | .insns = { |
5781 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | 6306 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
5782 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 6307 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
@@ -5798,13 +6323,10 @@ static struct bpf_test tests[] = { | |||
5798 | BPF_EXIT_INSN(), | 6323 | BPF_EXIT_INSN(), |
5799 | }, | 6324 | }, |
5800 | .fixup_map1 = { 3 }, | 6325 | .fixup_map1 = { 3 }, |
5801 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 6326 | .result = ACCEPT, |
5802 | .errstr = "R0 min value is negative", | ||
5803 | .result = REJECT, | ||
5804 | .result_unpriv = REJECT, | ||
5805 | }, | 6327 | }, |
5806 | { | 6328 | { |
5807 | "bounds checks mixing signed and unsigned, variant 11", | 6329 | "bounds checks mixing signed and unsigned, variant 10", |
5808 | .insns = { | 6330 | .insns = { |
5809 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | 6331 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
5810 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 6332 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
@@ -5826,13 +6348,11 @@ static struct bpf_test tests[] = { | |||
5826 | BPF_EXIT_INSN(), | 6348 | BPF_EXIT_INSN(), |
5827 | }, | 6349 | }, |
5828 | .fixup_map1 = { 3 }, | 6350 | .fixup_map1 = { 3 }, |
5829 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
5830 | .errstr = "R0 min value is negative", | 6351 | .errstr = "R0 min value is negative", |
5831 | .result = REJECT, | 6352 | .result = REJECT, |
5832 | .result_unpriv = REJECT, | ||
5833 | }, | 6353 | }, |
5834 | { | 6354 | { |
5835 | "bounds checks mixing signed and unsigned, variant 12", | 6355 | "bounds checks mixing signed and unsigned, variant 11", |
5836 | .insns = { | 6356 | .insns = { |
5837 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | 6357 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
5838 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 6358 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
@@ -5855,13 +6375,11 @@ static struct bpf_test tests[] = { | |||
5855 | BPF_EXIT_INSN(), | 6375 | BPF_EXIT_INSN(), |
5856 | }, | 6376 | }, |
5857 | .fixup_map1 = { 3 }, | 6377 | .fixup_map1 = { 3 }, |
5858 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
5859 | .errstr = "R0 min value is negative", | 6378 | .errstr = "R0 min value is negative", |
5860 | .result = REJECT, | 6379 | .result = REJECT, |
5861 | .result_unpriv = REJECT, | ||
5862 | }, | 6380 | }, |
5863 | { | 6381 | { |
5864 | "bounds checks mixing signed and unsigned, variant 13", | 6382 | "bounds checks mixing signed and unsigned, variant 12", |
5865 | .insns = { | 6383 | .insns = { |
5866 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | 6384 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
5867 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 6385 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
@@ -5883,13 +6401,11 @@ static struct bpf_test tests[] = { | |||
5883 | BPF_EXIT_INSN(), | 6401 | BPF_EXIT_INSN(), |
5884 | }, | 6402 | }, |
5885 | .fixup_map1 = { 3 }, | 6403 | .fixup_map1 = { 3 }, |
5886 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
5887 | .errstr = "R0 min value is negative", | 6404 | .errstr = "R0 min value is negative", |
5888 | .result = REJECT, | 6405 | .result = REJECT, |
5889 | .result_unpriv = REJECT, | ||
5890 | }, | 6406 | }, |
5891 | { | 6407 | { |
5892 | "bounds checks mixing signed and unsigned, variant 14", | 6408 | "bounds checks mixing signed and unsigned, variant 13", |
5893 | .insns = { | 6409 | .insns = { |
5894 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | 6410 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
5895 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 6411 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
@@ -5914,13 +6430,11 @@ static struct bpf_test tests[] = { | |||
5914 | BPF_EXIT_INSN(), | 6430 | BPF_EXIT_INSN(), |
5915 | }, | 6431 | }, |
5916 | .fixup_map1 = { 3 }, | 6432 | .fixup_map1 = { 3 }, |
5917 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
5918 | .errstr = "R0 min value is negative", | 6433 | .errstr = "R0 min value is negative", |
5919 | .result = REJECT, | 6434 | .result = REJECT, |
5920 | .result_unpriv = REJECT, | ||
5921 | }, | 6435 | }, |
5922 | { | 6436 | { |
5923 | "bounds checks mixing signed and unsigned, variant 15", | 6437 | "bounds checks mixing signed and unsigned, variant 14", |
5924 | .insns = { | 6438 | .insns = { |
5925 | BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_1, | 6439 | BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_1, |
5926 | offsetof(struct __sk_buff, mark)), | 6440 | offsetof(struct __sk_buff, mark)), |
@@ -5946,13 +6460,11 @@ static struct bpf_test tests[] = { | |||
5946 | BPF_JMP_IMM(BPF_JA, 0, 0, -7), | 6460 | BPF_JMP_IMM(BPF_JA, 0, 0, -7), |
5947 | }, | 6461 | }, |
5948 | .fixup_map1 = { 4 }, | 6462 | .fixup_map1 = { 4 }, |
5949 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
5950 | .errstr = "R0 min value is negative", | 6463 | .errstr = "R0 min value is negative", |
5951 | .result = REJECT, | 6464 | .result = REJECT, |
5952 | .result_unpriv = REJECT, | ||
5953 | }, | 6465 | }, |
5954 | { | 6466 | { |
5955 | "bounds checks mixing signed and unsigned, variant 16", | 6467 | "bounds checks mixing signed and unsigned, variant 15", |
5956 | .insns = { | 6468 | .insns = { |
5957 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | 6469 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
5958 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 6470 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
@@ -5976,13 +6488,13 @@ static struct bpf_test tests[] = { | |||
5976 | BPF_EXIT_INSN(), | 6488 | BPF_EXIT_INSN(), |
5977 | }, | 6489 | }, |
5978 | .fixup_map1 = { 3 }, | 6490 | .fixup_map1 = { 3 }, |
5979 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 6491 | .errstr_unpriv = "R0 pointer comparison prohibited", |
5980 | .errstr = "R0 min value is negative", | 6492 | .errstr = "R0 min value is negative", |
5981 | .result = REJECT, | 6493 | .result = REJECT, |
5982 | .result_unpriv = REJECT, | 6494 | .result_unpriv = REJECT, |
5983 | }, | 6495 | }, |
5984 | { | 6496 | { |
5985 | "subtraction bounds (map value)", | 6497 | "subtraction bounds (map value) variant 1", |
5986 | .insns = { | 6498 | .insns = { |
5987 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | 6499 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
5988 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 6500 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
@@ -6004,10 +6516,134 @@ static struct bpf_test tests[] = { | |||
6004 | BPF_EXIT_INSN(), | 6516 | BPF_EXIT_INSN(), |
6005 | }, | 6517 | }, |
6006 | .fixup_map1 = { 3 }, | 6518 | .fixup_map1 = { 3 }, |
6007 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 6519 | .errstr = "R0 max value is outside of the array range", |
6520 | .result = REJECT, | ||
6521 | }, | ||
6522 | { | ||
6523 | "subtraction bounds (map value) variant 2", | ||
6524 | .insns = { | ||
6525 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
6526 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
6527 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
6528 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
6529 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6530 | BPF_FUNC_map_lookup_elem), | ||
6531 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 8), | ||
6532 | BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), | ||
6533 | BPF_JMP_IMM(BPF_JGT, BPF_REG_1, 0xff, 6), | ||
6534 | BPF_LDX_MEM(BPF_B, BPF_REG_3, BPF_REG_0, 1), | ||
6535 | BPF_JMP_IMM(BPF_JGT, BPF_REG_3, 0xff, 4), | ||
6536 | BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_3), | ||
6537 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
6538 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), | ||
6539 | BPF_EXIT_INSN(), | ||
6540 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6541 | BPF_EXIT_INSN(), | ||
6542 | }, | ||
6543 | .fixup_map1 = { 3 }, | ||
6008 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 6544 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
6009 | .result = REJECT, | 6545 | .result = REJECT, |
6546 | }, | ||
6547 | { | ||
6548 | "variable-offset ctx access", | ||
6549 | .insns = { | ||
6550 | /* Get an unknown value */ | ||
6551 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), | ||
6552 | /* Make it small and 4-byte aligned */ | ||
6553 | BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), | ||
6554 | /* add it to skb. We now have either &skb->len or | ||
6555 | * &skb->pkt_type, but we don't know which | ||
6556 | */ | ||
6557 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2), | ||
6558 | /* dereference it */ | ||
6559 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), | ||
6560 | BPF_EXIT_INSN(), | ||
6561 | }, | ||
6562 | .errstr = "variable ctx access var_off=(0x0; 0x4)", | ||
6563 | .result = REJECT, | ||
6564 | .prog_type = BPF_PROG_TYPE_LWT_IN, | ||
6565 | }, | ||
6566 | { | ||
6567 | "variable-offset stack access", | ||
6568 | .insns = { | ||
6569 | /* Fill the top 8 bytes of the stack */ | ||
6570 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
6571 | /* Get an unknown value */ | ||
6572 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), | ||
6573 | /* Make it small and 4-byte aligned */ | ||
6574 | BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), | ||
6575 | BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8), | ||
6576 | /* add it to fp. We now have either fp-4 or fp-8, but | ||
6577 | * we don't know which | ||
6578 | */ | ||
6579 | BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), | ||
6580 | /* dereference it */ | ||
6581 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0), | ||
6582 | BPF_EXIT_INSN(), | ||
6583 | }, | ||
6584 | .errstr = "variable stack access var_off=(0xfffffffffffffff8; 0x4)", | ||
6585 | .result = REJECT, | ||
6586 | .prog_type = BPF_PROG_TYPE_LWT_IN, | ||
6587 | }, | ||
6588 | { | ||
6589 | "liveness pruning and write screening", | ||
6590 | .insns = { | ||
6591 | /* Get an unknown value */ | ||
6592 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), | ||
6593 | /* branch conditions teach us nothing about R2 */ | ||
6594 | BPF_JMP_IMM(BPF_JGE, BPF_REG_2, 0, 1), | ||
6595 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6596 | BPF_JMP_IMM(BPF_JGE, BPF_REG_2, 0, 1), | ||
6597 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6598 | BPF_EXIT_INSN(), | ||
6599 | }, | ||
6600 | .errstr = "R0 !read_ok", | ||
6601 | .result = REJECT, | ||
6602 | .prog_type = BPF_PROG_TYPE_LWT_IN, | ||
6603 | }, | ||
6604 | { | ||
6605 | "varlen_map_value_access pruning", | ||
6606 | .insns = { | ||
6607 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
6608 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
6609 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
6610 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
6611 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6612 | BPF_FUNC_map_lookup_elem), | ||
6613 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 8), | ||
6614 | BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0), | ||
6615 | BPF_MOV32_IMM(BPF_REG_2, MAX_ENTRIES), | ||
6616 | BPF_JMP_REG(BPF_JSGT, BPF_REG_2, BPF_REG_1, 1), | ||
6617 | BPF_MOV32_IMM(BPF_REG_1, 0), | ||
6618 | BPF_ALU32_IMM(BPF_LSH, BPF_REG_1, 2), | ||
6619 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
6620 | BPF_JMP_IMM(BPF_JA, 0, 0, 0), | ||
6621 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, | ||
6622 | offsetof(struct test_val, foo)), | ||
6623 | BPF_EXIT_INSN(), | ||
6624 | }, | ||
6625 | .fixup_map2 = { 3 }, | ||
6626 | .errstr_unpriv = "R0 leaks addr", | ||
6627 | .errstr = "R0 unbounded memory access", | ||
6010 | .result_unpriv = REJECT, | 6628 | .result_unpriv = REJECT, |
6629 | .result = REJECT, | ||
6630 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
6631 | }, | ||
6632 | { | ||
6633 | "invalid 64-bit BPF_END", | ||
6634 | .insns = { | ||
6635 | BPF_MOV32_IMM(BPF_REG_0, 0), | ||
6636 | { | ||
6637 | .code = BPF_ALU64 | BPF_END | BPF_TO_LE, | ||
6638 | .dst_reg = BPF_REG_0, | ||
6639 | .src_reg = 0, | ||
6640 | .off = 0, | ||
6641 | .imm = 32, | ||
6642 | }, | ||
6643 | BPF_EXIT_INSN(), | ||
6644 | }, | ||
6645 | .errstr = "BPF_END uses reserved fields", | ||
6646 | .result = REJECT, | ||
6011 | }, | 6647 | }, |
6012 | }; | 6648 | }; |
6013 | 6649 | ||
diff --git a/tools/testing/selftests/bpf/test_xdp_redirect.c b/tools/testing/selftests/bpf/test_xdp_redirect.c new file mode 100644 index 000000000000..ef9e704be140 --- /dev/null +++ b/tools/testing/selftests/bpf/test_xdp_redirect.c | |||
@@ -0,0 +1,28 @@ | |||
1 | /* Copyright (c) 2017 VMware | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of version 2 of the GNU General Public | ||
5 | * License as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, but | ||
8 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
10 | * General Public License for more details. | ||
11 | */ | ||
12 | #include <linux/bpf.h> | ||
13 | #include "bpf_helpers.h" | ||
14 | |||
15 | int _version SEC("version") = 1; | ||
16 | |||
17 | SEC("redirect_to_111") | ||
18 | int xdp_redirect_to_111(struct xdp_md *xdp) | ||
19 | { | ||
20 | return bpf_redirect(111, 0); | ||
21 | } | ||
22 | SEC("redirect_to_222") | ||
23 | int xdp_redirect_to_222(struct xdp_md *xdp) | ||
24 | { | ||
25 | return bpf_redirect(222, 0); | ||
26 | } | ||
27 | |||
28 | char _license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/test_xdp_redirect.sh b/tools/testing/selftests/bpf/test_xdp_redirect.sh new file mode 100755 index 000000000000..344a3656dea6 --- /dev/null +++ b/tools/testing/selftests/bpf/test_xdp_redirect.sh | |||
@@ -0,0 +1,59 @@ | |||
1 | #!/bin/sh | ||
2 | # Create 2 namespaces with two veth peers, and | ||
3 | # forward packets in-between using generic XDP | ||
4 | # | ||
5 | # NS1(veth11) NS2(veth22) | ||
6 | # | | | ||
7 | # | | | ||
8 | # (veth1, ------ (veth2, | ||
9 | # id:111) id:222) | ||
10 | # | xdp forwarding | | ||
11 | # ------------------ | ||
12 | |||
13 | cleanup() | ||
14 | { | ||
15 | if [ "$?" = "0" ]; then | ||
16 | echo "selftests: test_xdp_redirect [PASS]"; | ||
17 | else | ||
18 | echo "selftests: test_xdp_redirect [FAILED]"; | ||
19 | fi | ||
20 | |||
21 | set +e | ||
22 | ip netns del ns1 2> /dev/null | ||
23 | ip netns del ns2 2> /dev/null | ||
24 | } | ||
25 | |||
26 | ip link set dev lo xdpgeneric off 2>/dev/null > /dev/null | ||
27 | if [ $? -ne 0 ];then | ||
28 | echo "selftests: [SKIP] Could not run test without the ip xdpgeneric support" | ||
29 | exit 0 | ||
30 | fi | ||
31 | set -e | ||
32 | |||
33 | ip netns add ns1 | ||
34 | ip netns add ns2 | ||
35 | |||
36 | trap cleanup 0 2 3 6 9 | ||
37 | |||
38 | ip link add veth1 index 111 type veth peer name veth11 | ||
39 | ip link add veth2 index 222 type veth peer name veth22 | ||
40 | |||
41 | ip link set veth11 netns ns1 | ||
42 | ip link set veth22 netns ns2 | ||
43 | |||
44 | ip link set veth1 up | ||
45 | ip link set veth2 up | ||
46 | |||
47 | ip netns exec ns1 ip addr add 10.1.1.11/24 dev veth11 | ||
48 | ip netns exec ns2 ip addr add 10.1.1.22/24 dev veth22 | ||
49 | |||
50 | ip netns exec ns1 ip link set dev veth11 up | ||
51 | ip netns exec ns2 ip link set dev veth22 up | ||
52 | |||
53 | ip link set dev veth1 xdpgeneric obj test_xdp_redirect.o sec redirect_to_222 | ||
54 | ip link set dev veth2 xdpgeneric obj test_xdp_redirect.o sec redirect_to_111 | ||
55 | |||
56 | ip netns exec ns1 ping -c 1 10.1.1.22 | ||
57 | ip netns exec ns2 ping -c 1 10.1.1.11 | ||
58 | |||
59 | exit 0 | ||
diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile index 6b214b7b10fb..247b0a1899d7 100644 --- a/tools/testing/selftests/breakpoints/Makefile +++ b/tools/testing/selftests/breakpoints/Makefile | |||
@@ -2,14 +2,14 @@ | |||
2 | uname_M := $(shell uname -m 2>/dev/null || echo not) | 2 | uname_M := $(shell uname -m 2>/dev/null || echo not) |
3 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) | 3 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) |
4 | 4 | ||
5 | TEST_GEN_PROGS := step_after_suspend_test | ||
6 | |||
5 | ifeq ($(ARCH),x86) | 7 | ifeq ($(ARCH),x86) |
6 | TEST_GEN_PROGS := breakpoint_test | 8 | TEST_GEN_PROGS += breakpoint_test |
7 | endif | 9 | endif |
8 | ifneq (,$(filter $(ARCH),aarch64 arm64)) | 10 | ifneq (,$(filter $(ARCH),aarch64 arm64)) |
9 | TEST_GEN_PROGS := breakpoint_test_arm64 | 11 | TEST_GEN_PROGS += breakpoint_test_arm64 |
10 | endif | 12 | endif |
11 | 13 | ||
12 | TEST_GEN_PROGS += step_after_suspend_test | ||
13 | |||
14 | include ../lib.mk | 14 | include ../lib.mk |
15 | 15 | ||
diff --git a/tools/testing/selftests/breakpoints/breakpoint_test.c b/tools/testing/selftests/breakpoints/breakpoint_test.c index f63356151ad4..901b85ea6a59 100644 --- a/tools/testing/selftests/breakpoints/breakpoint_test.c +++ b/tools/testing/selftests/breakpoints/breakpoint_test.c | |||
@@ -367,11 +367,11 @@ static void launch_tests(void) | |||
367 | 367 | ||
368 | /* Icebp traps */ | 368 | /* Icebp traps */ |
369 | ptrace(PTRACE_CONT, child_pid, NULL, 0); | 369 | ptrace(PTRACE_CONT, child_pid, NULL, 0); |
370 | check_success("Test icebp"); | 370 | check_success("Test icebp\n"); |
371 | 371 | ||
372 | /* Int 3 traps */ | 372 | /* Int 3 traps */ |
373 | ptrace(PTRACE_CONT, child_pid, NULL, 0); | 373 | ptrace(PTRACE_CONT, child_pid, NULL, 0); |
374 | check_success("Test int 3 trap"); | 374 | check_success("Test int 3 trap\n"); |
375 | 375 | ||
376 | ptrace(PTRACE_CONT, child_pid, NULL, 0); | 376 | ptrace(PTRACE_CONT, child_pid, NULL, 0); |
377 | } | 377 | } |
diff --git a/tools/testing/selftests/capabilities/test_execve.c b/tools/testing/selftests/capabilities/test_execve.c index 763f37fecfb8..cf6778441381 100644 --- a/tools/testing/selftests/capabilities/test_execve.c +++ b/tools/testing/selftests/capabilities/test_execve.c | |||
@@ -1,7 +1,6 @@ | |||
1 | #define _GNU_SOURCE | 1 | #define _GNU_SOURCE |
2 | 2 | ||
3 | #include <cap-ng.h> | 3 | #include <cap-ng.h> |
4 | #include <err.h> | ||
5 | #include <linux/capability.h> | 4 | #include <linux/capability.h> |
6 | #include <stdbool.h> | 5 | #include <stdbool.h> |
7 | #include <string.h> | 6 | #include <string.h> |
@@ -18,6 +17,8 @@ | |||
18 | #include <sys/prctl.h> | 17 | #include <sys/prctl.h> |
19 | #include <sys/stat.h> | 18 | #include <sys/stat.h> |
20 | 19 | ||
20 | #include "../kselftest.h" | ||
21 | |||
21 | #ifndef PR_CAP_AMBIENT | 22 | #ifndef PR_CAP_AMBIENT |
22 | #define PR_CAP_AMBIENT 47 | 23 | #define PR_CAP_AMBIENT 47 |
23 | # define PR_CAP_AMBIENT_IS_SET 1 | 24 | # define PR_CAP_AMBIENT_IS_SET 1 |
@@ -27,6 +28,7 @@ | |||
27 | #endif | 28 | #endif |
28 | 29 | ||
29 | static int nerrs; | 30 | static int nerrs; |
31 | static pid_t mpid; /* main() pid is used to avoid duplicate test counts */ | ||
30 | 32 | ||
31 | static void vmaybe_write_file(bool enoent_ok, char *filename, char *fmt, va_list ap) | 33 | static void vmaybe_write_file(bool enoent_ok, char *filename, char *fmt, va_list ap) |
32 | { | 34 | { |
@@ -36,29 +38,32 @@ static void vmaybe_write_file(bool enoent_ok, char *filename, char *fmt, va_list | |||
36 | int buf_len; | 38 | int buf_len; |
37 | 39 | ||
38 | buf_len = vsnprintf(buf, sizeof(buf), fmt, ap); | 40 | buf_len = vsnprintf(buf, sizeof(buf), fmt, ap); |
39 | if (buf_len < 0) { | 41 | if (buf_len < 0) |
40 | err(1, "vsnprintf failed"); | 42 | ksft_exit_fail_msg("vsnprintf failed - %s\n", strerror(errno)); |
41 | } | 43 | |
42 | if (buf_len >= sizeof(buf)) { | 44 | if (buf_len >= sizeof(buf)) |
43 | errx(1, "vsnprintf output truncated"); | 45 | ksft_exit_fail_msg("vsnprintf output truncated\n"); |
44 | } | 46 | |
45 | 47 | ||
46 | fd = open(filename, O_WRONLY); | 48 | fd = open(filename, O_WRONLY); |
47 | if (fd < 0) { | 49 | if (fd < 0) { |
48 | if ((errno == ENOENT) && enoent_ok) | 50 | if ((errno == ENOENT) && enoent_ok) |
49 | return; | 51 | return; |
50 | err(1, "open of %s failed", filename); | 52 | ksft_exit_fail_msg("open of %s failed - %s\n", |
53 | filename, strerror(errno)); | ||
51 | } | 54 | } |
52 | written = write(fd, buf, buf_len); | 55 | written = write(fd, buf, buf_len); |
53 | if (written != buf_len) { | 56 | if (written != buf_len) { |
54 | if (written >= 0) { | 57 | if (written >= 0) { |
55 | errx(1, "short write to %s", filename); | 58 | ksft_exit_fail_msg("short write to %s\n", filename); |
56 | } else { | 59 | } else { |
57 | err(1, "write to %s failed", filename); | 60 | ksft_exit_fail_msg("write to %s failed - %s\n", |
61 | filename, strerror(errno)); | ||
58 | } | 62 | } |
59 | } | 63 | } |
60 | if (close(fd) != 0) { | 64 | if (close(fd) != 0) { |
61 | err(1, "close of %s failed", filename); | 65 | ksft_exit_fail_msg("close of %s failed - %s\n", |
66 | filename, strerror(errno)); | ||
62 | } | 67 | } |
63 | } | 68 | } |
64 | 69 | ||
@@ -95,11 +100,12 @@ static bool create_and_enter_ns(uid_t inner_uid) | |||
95 | */ | 100 | */ |
96 | 101 | ||
97 | if (unshare(CLONE_NEWNS) == 0) { | 102 | if (unshare(CLONE_NEWNS) == 0) { |
98 | printf("[NOTE]\tUsing global UIDs for tests\n"); | 103 | ksft_print_msg("[NOTE]\tUsing global UIDs for tests\n"); |
99 | if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) | 104 | if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) |
100 | err(1, "PR_SET_KEEPCAPS"); | 105 | ksft_exit_fail_msg("PR_SET_KEEPCAPS - %s\n", |
106 | strerror(errno)); | ||
101 | if (setresuid(inner_uid, inner_uid, -1) != 0) | 107 | if (setresuid(inner_uid, inner_uid, -1) != 0) |
102 | err(1, "setresuid"); | 108 | ksft_exit_fail_msg("setresuid - %s\n", strerror(errno)); |
103 | 109 | ||
104 | // Re-enable effective caps | 110 | // Re-enable effective caps |
105 | capng_get_caps_process(); | 111 | capng_get_caps_process(); |
@@ -107,22 +113,24 @@ static bool create_and_enter_ns(uid_t inner_uid) | |||
107 | if (capng_have_capability(CAPNG_PERMITTED, i)) | 113 | if (capng_have_capability(CAPNG_PERMITTED, i)) |
108 | capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, i); | 114 | capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, i); |
109 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) | 115 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) |
110 | err(1, "capng_apply"); | 116 | ksft_exit_fail_msg( |
117 | "capng_apply - %s\n", strerror(errno)); | ||
111 | 118 | ||
112 | have_outer_privilege = true; | 119 | have_outer_privilege = true; |
113 | } else if (unshare(CLONE_NEWUSER | CLONE_NEWNS) == 0) { | 120 | } else if (unshare(CLONE_NEWUSER | CLONE_NEWNS) == 0) { |
114 | printf("[NOTE]\tUsing a user namespace for tests\n"); | 121 | ksft_print_msg("[NOTE]\tUsing a user namespace for tests\n"); |
115 | maybe_write_file("/proc/self/setgroups", "deny"); | 122 | maybe_write_file("/proc/self/setgroups", "deny"); |
116 | write_file("/proc/self/uid_map", "%d %d 1", inner_uid, outer_uid); | 123 | write_file("/proc/self/uid_map", "%d %d 1", inner_uid, outer_uid); |
117 | write_file("/proc/self/gid_map", "0 %d 1", outer_gid); | 124 | write_file("/proc/self/gid_map", "0 %d 1", outer_gid); |
118 | 125 | ||
119 | have_outer_privilege = false; | 126 | have_outer_privilege = false; |
120 | } else { | 127 | } else { |
121 | errx(1, "must be root or be able to create a userns"); | 128 | ksft_exit_skip("must be root or be able to create a userns\n"); |
122 | } | 129 | } |
123 | 130 | ||
124 | if (mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0) | 131 | if (mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0) |
125 | err(1, "remount everything private"); | 132 | ksft_exit_fail_msg("remount everything private - %s\n", |
133 | strerror(errno)); | ||
126 | 134 | ||
127 | return have_outer_privilege; | 135 | return have_outer_privilege; |
128 | } | 136 | } |
@@ -131,20 +139,22 @@ static void chdir_to_tmpfs(void) | |||
131 | { | 139 | { |
132 | char cwd[PATH_MAX]; | 140 | char cwd[PATH_MAX]; |
133 | if (getcwd(cwd, sizeof(cwd)) != cwd) | 141 | if (getcwd(cwd, sizeof(cwd)) != cwd) |
134 | err(1, "getcwd"); | 142 | ksft_exit_fail_msg("getcwd - %s\n", strerror(errno)); |
135 | 143 | ||
136 | if (mount("private_tmp", ".", "tmpfs", 0, "mode=0777") != 0) | 144 | if (mount("private_tmp", ".", "tmpfs", 0, "mode=0777") != 0) |
137 | err(1, "mount private tmpfs"); | 145 | ksft_exit_fail_msg("mount private tmpfs - %s\n", |
146 | strerror(errno)); | ||
138 | 147 | ||
139 | if (chdir(cwd) != 0) | 148 | if (chdir(cwd) != 0) |
140 | err(1, "chdir to private tmpfs"); | 149 | ksft_exit_fail_msg("chdir to private tmpfs - %s\n", |
150 | strerror(errno)); | ||
141 | } | 151 | } |
142 | 152 | ||
143 | static void copy_fromat_to(int fromfd, const char *fromname, const char *toname) | 153 | static void copy_fromat_to(int fromfd, const char *fromname, const char *toname) |
144 | { | 154 | { |
145 | int from = openat(fromfd, fromname, O_RDONLY); | 155 | int from = openat(fromfd, fromname, O_RDONLY); |
146 | if (from == -1) | 156 | if (from == -1) |
147 | err(1, "open copy source"); | 157 | ksft_exit_fail_msg("open copy source - %s\n", strerror(errno)); |
148 | 158 | ||
149 | int to = open(toname, O_CREAT | O_WRONLY | O_EXCL, 0700); | 159 | int to = open(toname, O_CREAT | O_WRONLY | O_EXCL, 0700); |
150 | 160 | ||
@@ -154,10 +164,11 @@ static void copy_fromat_to(int fromfd, const char *fromname, const char *toname) | |||
154 | if (sz == 0) | 164 | if (sz == 0) |
155 | break; | 165 | break; |
156 | if (sz < 0) | 166 | if (sz < 0) |
157 | err(1, "read"); | 167 | ksft_exit_fail_msg("read - %s\n", strerror(errno)); |
158 | 168 | ||
159 | if (write(to, buf, sz) != sz) | 169 | if (write(to, buf, sz) != sz) |
160 | err(1, "write"); /* no short writes on tmpfs */ | 170 | /* no short writes on tmpfs */ |
171 | ksft_exit_fail_msg("write - %s\n", strerror(errno)); | ||
161 | } | 172 | } |
162 | 173 | ||
163 | close(from); | 174 | close(from); |
@@ -174,18 +185,20 @@ static bool fork_wait(void) | |||
174 | int status; | 185 | int status; |
175 | if (waitpid(child, &status, 0) != child || | 186 | if (waitpid(child, &status, 0) != child || |
176 | !WIFEXITED(status)) { | 187 | !WIFEXITED(status)) { |
177 | printf("[FAIL]\tChild died\n"); | 188 | ksft_print_msg("Child died\n"); |
178 | nerrs++; | 189 | nerrs++; |
179 | } else if (WEXITSTATUS(status) != 0) { | 190 | } else if (WEXITSTATUS(status) != 0) { |
180 | printf("[FAIL]\tChild failed\n"); | 191 | ksft_print_msg("Child failed\n"); |
181 | nerrs++; | 192 | nerrs++; |
182 | } else { | 193 | } else { |
183 | printf("[OK]\tChild succeeded\n"); | 194 | /* don't print this message for mpid */ |
195 | if (getpid() != mpid) | ||
196 | ksft_test_result_pass("Passed\n"); | ||
184 | } | 197 | } |
185 | |||
186 | return false; | 198 | return false; |
187 | } else { | 199 | } else { |
188 | err(1, "fork"); | 200 | ksft_exit_fail_msg("fork - %s\n", strerror(errno)); |
201 | return false; | ||
189 | } | 202 | } |
190 | } | 203 | } |
191 | 204 | ||
@@ -195,7 +208,7 @@ static void exec_other_validate_cap(const char *name, | |||
195 | execl(name, name, (eff ? "1" : "0"), | 208 | execl(name, name, (eff ? "1" : "0"), |
196 | (perm ? "1" : "0"), (inh ? "1" : "0"), (ambient ? "1" : "0"), | 209 | (perm ? "1" : "0"), (inh ? "1" : "0"), (ambient ? "1" : "0"), |
197 | NULL); | 210 | NULL); |
198 | err(1, "execl"); | 211 | ksft_exit_fail_msg("execl - %s\n", strerror(errno)); |
199 | } | 212 | } |
200 | 213 | ||
201 | static void exec_validate_cap(bool eff, bool perm, bool inh, bool ambient) | 214 | static void exec_validate_cap(bool eff, bool perm, bool inh, bool ambient) |
@@ -209,7 +222,8 @@ static int do_tests(int uid, const char *our_path) | |||
209 | 222 | ||
210 | int ourpath_fd = open(our_path, O_RDONLY | O_DIRECTORY); | 223 | int ourpath_fd = open(our_path, O_RDONLY | O_DIRECTORY); |
211 | if (ourpath_fd == -1) | 224 | if (ourpath_fd == -1) |
212 | err(1, "open '%s'", our_path); | 225 | ksft_exit_fail_msg("open '%s' - %s\n", |
226 | our_path, strerror(errno)); | ||
213 | 227 | ||
214 | chdir_to_tmpfs(); | 228 | chdir_to_tmpfs(); |
215 | 229 | ||
@@ -221,30 +235,30 @@ static int do_tests(int uid, const char *our_path) | |||
221 | copy_fromat_to(ourpath_fd, "validate_cap", | 235 | copy_fromat_to(ourpath_fd, "validate_cap", |
222 | "validate_cap_suidroot"); | 236 | "validate_cap_suidroot"); |
223 | if (chown("validate_cap_suidroot", 0, -1) != 0) | 237 | if (chown("validate_cap_suidroot", 0, -1) != 0) |
224 | err(1, "chown"); | 238 | ksft_exit_fail_msg("chown - %s\n", strerror(errno)); |
225 | if (chmod("validate_cap_suidroot", S_ISUID | 0700) != 0) | 239 | if (chmod("validate_cap_suidroot", S_ISUID | 0700) != 0) |
226 | err(1, "chmod"); | 240 | ksft_exit_fail_msg("chmod - %s\n", strerror(errno)); |
227 | 241 | ||
228 | copy_fromat_to(ourpath_fd, "validate_cap", | 242 | copy_fromat_to(ourpath_fd, "validate_cap", |
229 | "validate_cap_suidnonroot"); | 243 | "validate_cap_suidnonroot"); |
230 | if (chown("validate_cap_suidnonroot", uid + 1, -1) != 0) | 244 | if (chown("validate_cap_suidnonroot", uid + 1, -1) != 0) |
231 | err(1, "chown"); | 245 | ksft_exit_fail_msg("chown - %s\n", strerror(errno)); |
232 | if (chmod("validate_cap_suidnonroot", S_ISUID | 0700) != 0) | 246 | if (chmod("validate_cap_suidnonroot", S_ISUID | 0700) != 0) |
233 | err(1, "chmod"); | 247 | ksft_exit_fail_msg("chmod - %s\n", strerror(errno)); |
234 | 248 | ||
235 | copy_fromat_to(ourpath_fd, "validate_cap", | 249 | copy_fromat_to(ourpath_fd, "validate_cap", |
236 | "validate_cap_sgidroot"); | 250 | "validate_cap_sgidroot"); |
237 | if (chown("validate_cap_sgidroot", -1, 0) != 0) | 251 | if (chown("validate_cap_sgidroot", -1, 0) != 0) |
238 | err(1, "chown"); | 252 | ksft_exit_fail_msg("chown - %s\n", strerror(errno)); |
239 | if (chmod("validate_cap_sgidroot", S_ISGID | 0710) != 0) | 253 | if (chmod("validate_cap_sgidroot", S_ISGID | 0710) != 0) |
240 | err(1, "chmod"); | 254 | ksft_exit_fail_msg("chmod - %s\n", strerror(errno)); |
241 | 255 | ||
242 | copy_fromat_to(ourpath_fd, "validate_cap", | 256 | copy_fromat_to(ourpath_fd, "validate_cap", |
243 | "validate_cap_sgidnonroot"); | 257 | "validate_cap_sgidnonroot"); |
244 | if (chown("validate_cap_sgidnonroot", -1, gid + 1) != 0) | 258 | if (chown("validate_cap_sgidnonroot", -1, gid + 1) != 0) |
245 | err(1, "chown"); | 259 | ksft_exit_fail_msg("chown - %s\n", strerror(errno)); |
246 | if (chmod("validate_cap_sgidnonroot", S_ISGID | 0710) != 0) | 260 | if (chmod("validate_cap_sgidnonroot", S_ISGID | 0710) != 0) |
247 | err(1, "chmod"); | 261 | ksft_exit_fail_msg("chmod - %s\n", strerror(errno)); |
248 | } | 262 | } |
249 | 263 | ||
250 | capng_get_caps_process(); | 264 | capng_get_caps_process(); |
@@ -252,147 +266,162 @@ static int do_tests(int uid, const char *our_path) | |||
252 | /* Make sure that i starts out clear */ | 266 | /* Make sure that i starts out clear */ |
253 | capng_update(CAPNG_DROP, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); | 267 | capng_update(CAPNG_DROP, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); |
254 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) | 268 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) |
255 | err(1, "capng_apply"); | 269 | ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno)); |
256 | 270 | ||
257 | if (uid == 0) { | 271 | if (uid == 0) { |
258 | printf("[RUN]\tRoot => ep\n"); | 272 | ksft_print_msg("[RUN]\tRoot => ep\n"); |
259 | if (fork_wait()) | 273 | if (fork_wait()) |
260 | exec_validate_cap(true, true, false, false); | 274 | exec_validate_cap(true, true, false, false); |
261 | } else { | 275 | } else { |
262 | printf("[RUN]\tNon-root => no caps\n"); | 276 | ksft_print_msg("[RUN]\tNon-root => no caps\n"); |
263 | if (fork_wait()) | 277 | if (fork_wait()) |
264 | exec_validate_cap(false, false, false, false); | 278 | exec_validate_cap(false, false, false, false); |
265 | } | 279 | } |
266 | 280 | ||
267 | printf("[OK]\tCheck cap_ambient manipulation rules\n"); | 281 | ksft_print_msg("Check cap_ambient manipulation rules\n"); |
268 | 282 | ||
269 | /* We should not be able to add ambient caps yet. */ | 283 | /* We should not be able to add ambient caps yet. */ |
270 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != -1 || errno != EPERM) { | 284 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != -1 || errno != EPERM) { |
271 | if (errno == EINVAL) | 285 | if (errno == EINVAL) |
272 | printf("[FAIL]\tPR_CAP_AMBIENT_RAISE isn't supported\n"); | 286 | ksft_test_result_fail( |
287 | "PR_CAP_AMBIENT_RAISE isn't supported\n"); | ||
273 | else | 288 | else |
274 | printf("[FAIL]\tPR_CAP_AMBIENT_RAISE should have failed eith EPERM on a non-inheritable cap\n"); | 289 | ksft_test_result_fail( |
290 | "PR_CAP_AMBIENT_RAISE should have failed eith EPERM on a non-inheritable cap\n"); | ||
275 | return 1; | 291 | return 1; |
276 | } | 292 | } |
277 | printf("[OK]\tPR_CAP_AMBIENT_RAISE failed on non-inheritable cap\n"); | 293 | ksft_test_result_pass( |
294 | "PR_CAP_AMBIENT_RAISE failed on non-inheritable cap\n"); | ||
278 | 295 | ||
279 | capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_RAW); | 296 | capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_RAW); |
280 | capng_update(CAPNG_DROP, CAPNG_PERMITTED, CAP_NET_RAW); | 297 | capng_update(CAPNG_DROP, CAPNG_PERMITTED, CAP_NET_RAW); |
281 | capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_NET_RAW); | 298 | capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_NET_RAW); |
282 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) | 299 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) |
283 | err(1, "capng_apply"); | 300 | ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno)); |
284 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_RAW, 0, 0, 0) != -1 || errno != EPERM) { | 301 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_RAW, 0, 0, 0) != -1 || errno != EPERM) { |
285 | printf("[FAIL]\tPR_CAP_AMBIENT_RAISE should have failed on a non-permitted cap\n"); | 302 | ksft_test_result_fail( |
303 | "PR_CAP_AMBIENT_RAISE should have failed on a non-permitted cap\n"); | ||
286 | return 1; | 304 | return 1; |
287 | } | 305 | } |
288 | printf("[OK]\tPR_CAP_AMBIENT_RAISE failed on non-permitted cap\n"); | 306 | ksft_test_result_pass( |
307 | "PR_CAP_AMBIENT_RAISE failed on non-permitted cap\n"); | ||
289 | 308 | ||
290 | capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); | 309 | capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); |
291 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) | 310 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) |
292 | err(1, "capng_apply"); | 311 | ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno)); |
293 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) { | 312 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) { |
294 | printf("[FAIL]\tPR_CAP_AMBIENT_RAISE should have succeeded\n"); | 313 | ksft_test_result_fail( |
314 | "PR_CAP_AMBIENT_RAISE should have succeeded\n"); | ||
295 | return 1; | 315 | return 1; |
296 | } | 316 | } |
297 | printf("[OK]\tPR_CAP_AMBIENT_RAISE worked\n"); | 317 | ksft_test_result_pass("PR_CAP_AMBIENT_RAISE worked\n"); |
298 | 318 | ||
299 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 1) { | 319 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 1) { |
300 | printf("[FAIL]\tPR_CAP_AMBIENT_IS_SET is broken\n"); | 320 | ksft_test_result_fail("PR_CAP_AMBIENT_IS_SET is broken\n"); |
301 | return 1; | 321 | return 1; |
302 | } | 322 | } |
303 | 323 | ||
304 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0, 0) != 0) | 324 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0, 0) != 0) |
305 | err(1, "PR_CAP_AMBIENT_CLEAR_ALL"); | 325 | ksft_exit_fail_msg("PR_CAP_AMBIENT_CLEAR_ALL - %s\n", |
326 | strerror(errno)); | ||
306 | 327 | ||
307 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) { | 328 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) { |
308 | printf("[FAIL]\tPR_CAP_AMBIENT_CLEAR_ALL didn't work\n"); | 329 | ksft_test_result_fail( |
330 | "PR_CAP_AMBIENT_CLEAR_ALL didn't work\n"); | ||
309 | return 1; | 331 | return 1; |
310 | } | 332 | } |
311 | 333 | ||
312 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) | 334 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) |
313 | err(1, "PR_CAP_AMBIENT_RAISE"); | 335 | ksft_exit_fail_msg("PR_CAP_AMBIENT_RAISE - %s\n", |
336 | strerror(errno)); | ||
314 | 337 | ||
315 | capng_update(CAPNG_DROP, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); | 338 | capng_update(CAPNG_DROP, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); |
316 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) | 339 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) |
317 | err(1, "capng_apply"); | 340 | ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno)); |
318 | 341 | ||
319 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) { | 342 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) { |
320 | printf("[FAIL]\tDropping I should have dropped A\n"); | 343 | ksft_test_result_fail("Dropping I should have dropped A\n"); |
321 | return 1; | 344 | return 1; |
322 | } | 345 | } |
323 | 346 | ||
324 | printf("[OK]\tBasic manipulation appears to work\n"); | 347 | ksft_test_result_pass("Basic manipulation appears to work\n"); |
325 | 348 | ||
326 | capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); | 349 | capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); |
327 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) | 350 | if (capng_apply(CAPNG_SELECT_CAPS) != 0) |
328 | err(1, "capng_apply"); | 351 | ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno)); |
329 | if (uid == 0) { | 352 | if (uid == 0) { |
330 | printf("[RUN]\tRoot +i => eip\n"); | 353 | ksft_print_msg("[RUN]\tRoot +i => eip\n"); |
331 | if (fork_wait()) | 354 | if (fork_wait()) |
332 | exec_validate_cap(true, true, true, false); | 355 | exec_validate_cap(true, true, true, false); |
333 | } else { | 356 | } else { |
334 | printf("[RUN]\tNon-root +i => i\n"); | 357 | ksft_print_msg("[RUN]\tNon-root +i => i\n"); |
335 | if (fork_wait()) | 358 | if (fork_wait()) |
336 | exec_validate_cap(false, false, true, false); | 359 | exec_validate_cap(false, false, true, false); |
337 | } | 360 | } |
338 | 361 | ||
339 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) | 362 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) |
340 | err(1, "PR_CAP_AMBIENT_RAISE"); | 363 | ksft_exit_fail_msg("PR_CAP_AMBIENT_RAISE - %s\n", |
364 | strerror(errno)); | ||
341 | 365 | ||
342 | printf("[RUN]\tUID %d +ia => eipa\n", uid); | 366 | ksft_print_msg("[RUN]\tUID %d +ia => eipa\n", uid); |
343 | if (fork_wait()) | 367 | if (fork_wait()) |
344 | exec_validate_cap(true, true, true, true); | 368 | exec_validate_cap(true, true, true, true); |
345 | 369 | ||
346 | /* The remaining tests need real privilege */ | 370 | /* The remaining tests need real privilege */ |
347 | 371 | ||
348 | if (!have_outer_privilege) { | 372 | if (!have_outer_privilege) { |
349 | printf("[SKIP]\tSUID/SGID tests (needs privilege)\n"); | 373 | ksft_test_result_skip("SUID/SGID tests (needs privilege)\n"); |
350 | goto done; | 374 | goto done; |
351 | } | 375 | } |
352 | 376 | ||
353 | if (uid == 0) { | 377 | if (uid == 0) { |
354 | printf("[RUN]\tRoot +ia, suidroot => eipa\n"); | 378 | ksft_print_msg("[RUN]\tRoot +ia, suidroot => eipa\n"); |
355 | if (fork_wait()) | 379 | if (fork_wait()) |
356 | exec_other_validate_cap("./validate_cap_suidroot", | 380 | exec_other_validate_cap("./validate_cap_suidroot", |
357 | true, true, true, true); | 381 | true, true, true, true); |
358 | 382 | ||
359 | printf("[RUN]\tRoot +ia, suidnonroot => ip\n"); | 383 | ksft_print_msg("[RUN]\tRoot +ia, suidnonroot => ip\n"); |
360 | if (fork_wait()) | 384 | if (fork_wait()) |
361 | exec_other_validate_cap("./validate_cap_suidnonroot", | 385 | exec_other_validate_cap("./validate_cap_suidnonroot", |
362 | false, true, true, false); | 386 | false, true, true, false); |
363 | 387 | ||
364 | printf("[RUN]\tRoot +ia, sgidroot => eipa\n"); | 388 | ksft_print_msg("[RUN]\tRoot +ia, sgidroot => eipa\n"); |
365 | if (fork_wait()) | 389 | if (fork_wait()) |
366 | exec_other_validate_cap("./validate_cap_sgidroot", | 390 | exec_other_validate_cap("./validate_cap_sgidroot", |
367 | true, true, true, true); | 391 | true, true, true, true); |
368 | 392 | ||
369 | if (fork_wait()) { | 393 | if (fork_wait()) { |
370 | printf("[RUN]\tRoot, gid != 0, +ia, sgidroot => eip\n"); | 394 | ksft_print_msg( |
395 | "[RUN]\tRoot, gid != 0, +ia, sgidroot => eip\n"); | ||
371 | if (setresgid(1, 1, 1) != 0) | 396 | if (setresgid(1, 1, 1) != 0) |
372 | err(1, "setresgid"); | 397 | ksft_exit_fail_msg("setresgid - %s\n", |
398 | strerror(errno)); | ||
373 | exec_other_validate_cap("./validate_cap_sgidroot", | 399 | exec_other_validate_cap("./validate_cap_sgidroot", |
374 | true, true, true, false); | 400 | true, true, true, false); |
375 | } | 401 | } |
376 | 402 | ||
377 | printf("[RUN]\tRoot +ia, sgidnonroot => eip\n"); | 403 | ksft_print_msg("[RUN]\tRoot +ia, sgidnonroot => eip\n"); |
378 | if (fork_wait()) | 404 | if (fork_wait()) |
379 | exec_other_validate_cap("./validate_cap_sgidnonroot", | 405 | exec_other_validate_cap("./validate_cap_sgidnonroot", |
380 | true, true, true, false); | 406 | true, true, true, false); |
381 | } else { | 407 | } else { |
382 | printf("[RUN]\tNon-root +ia, sgidnonroot => i\n"); | 408 | ksft_print_msg("[RUN]\tNon-root +ia, sgidnonroot => i\n"); |
383 | exec_other_validate_cap("./validate_cap_sgidnonroot", | 409 | if (fork_wait()) |
410 | exec_other_validate_cap("./validate_cap_sgidnonroot", | ||
384 | false, false, true, false); | 411 | false, false, true, false); |
385 | 412 | ||
386 | if (fork_wait()) { | 413 | if (fork_wait()) { |
387 | printf("[RUN]\tNon-root +ia, sgidroot => i\n"); | 414 | ksft_print_msg("[RUN]\tNon-root +ia, sgidroot => i\n"); |
388 | if (setresgid(1, 1, 1) != 0) | 415 | if (setresgid(1, 1, 1) != 0) |
389 | err(1, "setresgid"); | 416 | ksft_exit_fail_msg("setresgid - %s\n", |
417 | strerror(errno)); | ||
390 | exec_other_validate_cap("./validate_cap_sgidroot", | 418 | exec_other_validate_cap("./validate_cap_sgidroot", |
391 | false, false, true, false); | 419 | false, false, true, false); |
392 | } | 420 | } |
393 | } | 421 | } |
394 | 422 | ||
395 | done: | 423 | done: |
424 | ksft_print_cnts(); | ||
396 | return nerrs ? 1 : 0; | 425 | return nerrs ? 1 : 0; |
397 | } | 426 | } |
398 | 427 | ||
@@ -400,23 +429,29 @@ int main(int argc, char **argv) | |||
400 | { | 429 | { |
401 | char *tmp1, *tmp2, *our_path; | 430 | char *tmp1, *tmp2, *our_path; |
402 | 431 | ||
432 | ksft_print_header(); | ||
433 | |||
403 | /* Find our path */ | 434 | /* Find our path */ |
404 | tmp1 = strdup(argv[0]); | 435 | tmp1 = strdup(argv[0]); |
405 | if (!tmp1) | 436 | if (!tmp1) |
406 | err(1, "strdup"); | 437 | ksft_exit_fail_msg("strdup - %s\n", strerror(errno)); |
407 | tmp2 = dirname(tmp1); | 438 | tmp2 = dirname(tmp1); |
408 | our_path = strdup(tmp2); | 439 | our_path = strdup(tmp2); |
409 | if (!our_path) | 440 | if (!our_path) |
410 | err(1, "strdup"); | 441 | ksft_exit_fail_msg("strdup - %s\n", strerror(errno)); |
411 | free(tmp1); | 442 | free(tmp1); |
412 | 443 | ||
444 | mpid = getpid(); | ||
445 | |||
413 | if (fork_wait()) { | 446 | if (fork_wait()) { |
414 | printf("[RUN]\t+++ Tests with uid == 0 +++\n"); | 447 | ksft_print_msg("[RUN]\t+++ Tests with uid == 0 +++\n"); |
415 | return do_tests(0, our_path); | 448 | return do_tests(0, our_path); |
416 | } | 449 | } |
417 | 450 | ||
451 | ksft_print_msg("==================================================\n"); | ||
452 | |||
418 | if (fork_wait()) { | 453 | if (fork_wait()) { |
419 | printf("[RUN]\t+++ Tests with uid != 0 +++\n"); | 454 | ksft_print_msg("[RUN]\t+++ Tests with uid != 0 +++\n"); |
420 | return do_tests(1, our_path); | 455 | return do_tests(1, our_path); |
421 | } | 456 | } |
422 | 457 | ||
diff --git a/tools/testing/selftests/capabilities/validate_cap.c b/tools/testing/selftests/capabilities/validate_cap.c index dd3c45f7b23c..694cd73d4493 100644 --- a/tools/testing/selftests/capabilities/validate_cap.c +++ b/tools/testing/selftests/capabilities/validate_cap.c | |||
@@ -1,5 +1,4 @@ | |||
1 | #include <cap-ng.h> | 1 | #include <cap-ng.h> |
2 | #include <err.h> | ||
3 | #include <linux/capability.h> | 2 | #include <linux/capability.h> |
4 | #include <stdbool.h> | 3 | #include <stdbool.h> |
5 | #include <string.h> | 4 | #include <string.h> |
@@ -7,6 +6,8 @@ | |||
7 | #include <sys/prctl.h> | 6 | #include <sys/prctl.h> |
8 | #include <sys/auxv.h> | 7 | #include <sys/auxv.h> |
9 | 8 | ||
9 | #include "../kselftest.h" | ||
10 | |||
10 | #ifndef PR_CAP_AMBIENT | 11 | #ifndef PR_CAP_AMBIENT |
11 | #define PR_CAP_AMBIENT 47 | 12 | #define PR_CAP_AMBIENT 47 |
12 | # define PR_CAP_AMBIENT_IS_SET 1 | 13 | # define PR_CAP_AMBIENT_IS_SET 1 |
@@ -25,8 +26,10 @@ static bool bool_arg(char **argv, int i) | |||
25 | return false; | 26 | return false; |
26 | else if (!strcmp(argv[i], "1")) | 27 | else if (!strcmp(argv[i], "1")) |
27 | return true; | 28 | return true; |
28 | else | 29 | else { |
29 | errx(1, "wrong argv[%d]", i); | 30 | ksft_exit_fail_msg("wrong argv[%d]\n", i); |
31 | return false; | ||
32 | } | ||
30 | } | 33 | } |
31 | 34 | ||
32 | int main(int argc, char **argv) | 35 | int main(int argc, char **argv) |
@@ -39,7 +42,7 @@ int main(int argc, char **argv) | |||
39 | */ | 42 | */ |
40 | 43 | ||
41 | if (argc != 5) | 44 | if (argc != 5) |
42 | errx(1, "wrong argc"); | 45 | ksft_exit_fail_msg("wrong argc\n"); |
43 | 46 | ||
44 | #ifdef HAVE_GETAUXVAL | 47 | #ifdef HAVE_GETAUXVAL |
45 | if (getauxval(AT_SECURE)) | 48 | if (getauxval(AT_SECURE)) |
@@ -51,23 +54,26 @@ int main(int argc, char **argv) | |||
51 | capng_get_caps_process(); | 54 | capng_get_caps_process(); |
52 | 55 | ||
53 | if (capng_have_capability(CAPNG_EFFECTIVE, CAP_NET_BIND_SERVICE) != bool_arg(argv, 1)) { | 56 | if (capng_have_capability(CAPNG_EFFECTIVE, CAP_NET_BIND_SERVICE) != bool_arg(argv, 1)) { |
54 | printf("[FAIL]\tWrong effective state%s\n", atsec); | 57 | ksft_print_msg("Wrong effective state%s\n", atsec); |
55 | return 1; | 58 | return 1; |
56 | } | 59 | } |
60 | |||
57 | if (capng_have_capability(CAPNG_PERMITTED, CAP_NET_BIND_SERVICE) != bool_arg(argv, 2)) { | 61 | if (capng_have_capability(CAPNG_PERMITTED, CAP_NET_BIND_SERVICE) != bool_arg(argv, 2)) { |
58 | printf("[FAIL]\tWrong permitted state%s\n", atsec); | 62 | ksft_print_msg("Wrong permitted state%s\n", atsec); |
59 | return 1; | 63 | return 1; |
60 | } | 64 | } |
65 | |||
61 | if (capng_have_capability(CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE) != bool_arg(argv, 3)) { | 66 | if (capng_have_capability(CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE) != bool_arg(argv, 3)) { |
62 | printf("[FAIL]\tWrong inheritable state%s\n", atsec); | 67 | ksft_print_msg("Wrong inheritable state%s\n", atsec); |
63 | return 1; | 68 | return 1; |
64 | } | 69 | } |
65 | 70 | ||
66 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != bool_arg(argv, 4)) { | 71 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != bool_arg(argv, 4)) { |
67 | printf("[FAIL]\tWrong ambient state%s\n", atsec); | 72 | ksft_print_msg("Wrong ambient state%s\n", atsec); |
68 | return 1; | 73 | return 1; |
69 | } | 74 | } |
70 | 75 | ||
71 | printf("[OK]\tCapabilities after execve were correct\n"); | 76 | ksft_print_msg("%s: Capabilities after execve were correct\n", |
77 | "validate_cap:"); | ||
72 | return 0; | 78 | return 0; |
73 | } | 79 | } |
diff --git a/tools/testing/selftests/cpu-hotplug/cpu-on-off-test.sh b/tools/testing/selftests/cpu-hotplug/cpu-on-off-test.sh index 98b1d6565f2c..b18b253d7bfb 100755 --- a/tools/testing/selftests/cpu-hotplug/cpu-on-off-test.sh +++ b/tools/testing/selftests/cpu-hotplug/cpu-on-off-test.sh | |||
@@ -28,6 +28,12 @@ prerequisite() | |||
28 | echo "CPU online/offline summary:" | 28 | echo "CPU online/offline summary:" |
29 | online_cpus=`cat $SYSFS/devices/system/cpu/online` | 29 | online_cpus=`cat $SYSFS/devices/system/cpu/online` |
30 | online_max=${online_cpus##*-} | 30 | online_max=${online_cpus##*-} |
31 | |||
32 | if [[ "$online_cpus" = "$online_max" ]]; then | ||
33 | echo "$msg: since there is only one cpu: $online_cpus" | ||
34 | exit 0 | ||
35 | fi | ||
36 | |||
31 | echo -e "\t Cpus in online state: $online_cpus" | 37 | echo -e "\t Cpus in online state: $online_cpus" |
32 | 38 | ||
33 | offline_cpus=`cat $SYSFS/devices/system/cpu/offline` | 39 | offline_cpus=`cat $SYSFS/devices/system/cpu/offline` |
@@ -89,8 +95,10 @@ online_cpu_expect_success() | |||
89 | 95 | ||
90 | if ! online_cpu $cpu; then | 96 | if ! online_cpu $cpu; then |
91 | echo $FUNCNAME $cpu: unexpected fail >&2 | 97 | echo $FUNCNAME $cpu: unexpected fail >&2 |
98 | exit 1 | ||
92 | elif ! cpu_is_online $cpu; then | 99 | elif ! cpu_is_online $cpu; then |
93 | echo $FUNCNAME $cpu: unexpected offline >&2 | 100 | echo $FUNCNAME $cpu: unexpected offline >&2 |
101 | exit 1 | ||
94 | fi | 102 | fi |
95 | } | 103 | } |
96 | 104 | ||
@@ -100,8 +108,10 @@ online_cpu_expect_fail() | |||
100 | 108 | ||
101 | if online_cpu $cpu 2> /dev/null; then | 109 | if online_cpu $cpu 2> /dev/null; then |
102 | echo $FUNCNAME $cpu: unexpected success >&2 | 110 | echo $FUNCNAME $cpu: unexpected success >&2 |
111 | exit 1 | ||
103 | elif ! cpu_is_offline $cpu; then | 112 | elif ! cpu_is_offline $cpu; then |
104 | echo $FUNCNAME $cpu: unexpected online >&2 | 113 | echo $FUNCNAME $cpu: unexpected online >&2 |
114 | exit 1 | ||
105 | fi | 115 | fi |
106 | } | 116 | } |
107 | 117 | ||
@@ -111,8 +121,10 @@ offline_cpu_expect_success() | |||
111 | 121 | ||
112 | if ! offline_cpu $cpu; then | 122 | if ! offline_cpu $cpu; then |
113 | echo $FUNCNAME $cpu: unexpected fail >&2 | 123 | echo $FUNCNAME $cpu: unexpected fail >&2 |
124 | exit 1 | ||
114 | elif ! cpu_is_offline $cpu; then | 125 | elif ! cpu_is_offline $cpu; then |
115 | echo $FUNCNAME $cpu: unexpected offline >&2 | 126 | echo $FUNCNAME $cpu: unexpected offline >&2 |
127 | exit 1 | ||
116 | fi | 128 | fi |
117 | } | 129 | } |
118 | 130 | ||
@@ -122,8 +134,10 @@ offline_cpu_expect_fail() | |||
122 | 134 | ||
123 | if offline_cpu $cpu 2> /dev/null; then | 135 | if offline_cpu $cpu 2> /dev/null; then |
124 | echo $FUNCNAME $cpu: unexpected success >&2 | 136 | echo $FUNCNAME $cpu: unexpected success >&2 |
137 | exit 1 | ||
125 | elif ! cpu_is_online $cpu; then | 138 | elif ! cpu_is_online $cpu; then |
126 | echo $FUNCNAME $cpu: unexpected offline >&2 | 139 | echo $FUNCNAME $cpu: unexpected offline >&2 |
140 | exit 1 | ||
127 | fi | 141 | fi |
128 | } | 142 | } |
129 | 143 | ||
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest index 14a03ea1e21d..abc706cf7702 100755 --- a/tools/testing/selftests/ftrace/ftracetest +++ b/tools/testing/selftests/ftrace/ftracetest | |||
@@ -8,15 +8,18 @@ | |||
8 | # Released under the terms of the GPL v2. | 8 | # Released under the terms of the GPL v2. |
9 | 9 | ||
10 | usage() { # errno [message] | 10 | usage() { # errno [message] |
11 | [ "$2" ] && echo $2 | 11 | [ ! -z "$2" ] && echo $2 |
12 | echo "Usage: ftracetest [options] [testcase(s)] [testcase-directory(s)]" | 12 | echo "Usage: ftracetest [options] [testcase(s)] [testcase-directory(s)]" |
13 | echo " Options:" | 13 | echo " Options:" |
14 | echo " -h|--help Show help message" | 14 | echo " -h|--help Show help message" |
15 | echo " -k|--keep Keep passed test logs" | 15 | echo " -k|--keep Keep passed test logs" |
16 | echo " -v|--verbose Increase verbosity of test messages" | 16 | echo " -v|--verbose Increase verbosity of test messages" |
17 | echo " -vv Alias of -v -v (Show all results in stdout)" | 17 | echo " -vv Alias of -v -v (Show all results in stdout)" |
18 | echo " -vvv Alias of -v -v -v (Show all commands immediately)" | ||
19 | echo " --fail-unsupported Treat UNSUPPORTED as a failure" | ||
18 | echo " -d|--debug Debug mode (trace all shell commands)" | 20 | echo " -d|--debug Debug mode (trace all shell commands)" |
19 | echo " -l|--logdir <dir> Save logs on the <dir>" | 21 | echo " -l|--logdir <dir> Save logs on the <dir>" |
22 | echo " If <dir> is -, all logs output in console only" | ||
20 | exit $1 | 23 | exit $1 |
21 | } | 24 | } |
22 | 25 | ||
@@ -47,7 +50,7 @@ parse_opts() { # opts | |||
47 | local OPT_TEST_CASES= | 50 | local OPT_TEST_CASES= |
48 | local OPT_TEST_DIR= | 51 | local OPT_TEST_DIR= |
49 | 52 | ||
50 | while [ "$1" ]; do | 53 | while [ ! -z "$1" ]; do |
51 | case "$1" in | 54 | case "$1" in |
52 | --help|-h) | 55 | --help|-h) |
53 | usage 0 | 56 | usage 0 |
@@ -56,15 +59,20 @@ parse_opts() { # opts | |||
56 | KEEP_LOG=1 | 59 | KEEP_LOG=1 |
57 | shift 1 | 60 | shift 1 |
58 | ;; | 61 | ;; |
59 | --verbose|-v|-vv) | 62 | --verbose|-v|-vv|-vvv) |
60 | VERBOSE=$((VERBOSE + 1)) | 63 | VERBOSE=$((VERBOSE + 1)) |
61 | [ $1 = '-vv' ] && VERBOSE=$((VERBOSE + 1)) | 64 | [ $1 = '-vv' ] && VERBOSE=$((VERBOSE + 1)) |
65 | [ $1 = '-vvv' ] && VERBOSE=$((VERBOSE + 2)) | ||
62 | shift 1 | 66 | shift 1 |
63 | ;; | 67 | ;; |
64 | --debug|-d) | 68 | --debug|-d) |
65 | DEBUG=1 | 69 | DEBUG=1 |
66 | shift 1 | 70 | shift 1 |
67 | ;; | 71 | ;; |
72 | --fail-unsupported) | ||
73 | UNSUPPORTED_RESULT=1 | ||
74 | shift 1 | ||
75 | ;; | ||
68 | --logdir|-l) | 76 | --logdir|-l) |
69 | LOG_DIR=$2 | 77 | LOG_DIR=$2 |
70 | shift 2 | 78 | shift 2 |
@@ -88,7 +96,7 @@ parse_opts() { # opts | |||
88 | ;; | 96 | ;; |
89 | esac | 97 | esac |
90 | done | 98 | done |
91 | if [ "$OPT_TEST_CASES" ]; then | 99 | if [ ! -z "$OPT_TEST_CASES" ]; then |
92 | TEST_CASES=$OPT_TEST_CASES | 100 | TEST_CASES=$OPT_TEST_CASES |
93 | fi | 101 | fi |
94 | } | 102 | } |
@@ -108,6 +116,7 @@ LOG_DIR=$TOP_DIR/logs/`date +%Y%m%d-%H%M%S`/ | |||
108 | KEEP_LOG=0 | 116 | KEEP_LOG=0 |
109 | DEBUG=0 | 117 | DEBUG=0 |
110 | VERBOSE=0 | 118 | VERBOSE=0 |
119 | UNSUPPORTED_RESULT=0 | ||
111 | # Parse command-line options | 120 | # Parse command-line options |
112 | parse_opts $* | 121 | parse_opts $* |
113 | 122 | ||
@@ -119,14 +128,20 @@ if [ -z "$TRACING_DIR" -o ! -d "$TRACING_DIR" ]; then | |||
119 | fi | 128 | fi |
120 | 129 | ||
121 | # Preparing logs | 130 | # Preparing logs |
122 | LOG_FILE=$LOG_DIR/ftracetest.log | 131 | if [ "x$LOG_DIR" = "x-" ]; then |
123 | mkdir -p $LOG_DIR || errexit "Failed to make a log directory: $LOG_DIR" | 132 | LOG_FILE= |
124 | date > $LOG_FILE | 133 | date |
134 | else | ||
135 | LOG_FILE=$LOG_DIR/ftracetest.log | ||
136 | mkdir -p $LOG_DIR || errexit "Failed to make a log directory: $LOG_DIR" | ||
137 | date > $LOG_FILE | ||
138 | fi | ||
139 | |||
125 | prlog() { # messages | 140 | prlog() { # messages |
126 | echo "$@" | tee -a $LOG_FILE | 141 | [ -z "$LOG_FILE" ] && echo "$@" || echo "$@" | tee -a $LOG_FILE |
127 | } | 142 | } |
128 | catlog() { #file | 143 | catlog() { #file |
129 | cat $1 | tee -a $LOG_FILE | 144 | [ -z "$LOG_FILE" ] && cat $1 || cat $1 | tee -a $LOG_FILE |
130 | } | 145 | } |
131 | prlog "=== Ftrace unit tests ===" | 146 | prlog "=== Ftrace unit tests ===" |
132 | 147 | ||
@@ -187,7 +202,7 @@ eval_result() { # sigval | |||
187 | $UNSUPPORTED) | 202 | $UNSUPPORTED) |
188 | prlog " [UNSUPPORTED]" | 203 | prlog " [UNSUPPORTED]" |
189 | UNSUPPORTED_CASES="$UNSUPPORTED_CASES $CASENO" | 204 | UNSUPPORTED_CASES="$UNSUPPORTED_CASES $CASENO" |
190 | return 1 # this is not a bug, but the result should be reported. | 205 | return $UNSUPPORTED_RESULT # depends on use case |
191 | ;; | 206 | ;; |
192 | $XFAIL) | 207 | $XFAIL) |
193 | prlog " [XFAIL]" | 208 | prlog " [XFAIL]" |
@@ -247,12 +262,20 @@ __run_test() { # testfile | |||
247 | # Run one test case | 262 | # Run one test case |
248 | run_test() { # testfile | 263 | run_test() { # testfile |
249 | local testname=`basename $1` | 264 | local testname=`basename $1` |
250 | local testlog=`mktemp $LOG_DIR/${testname}-log.XXXXXX` | 265 | if [ ! -z "$LOG_FILE" ] ; then |
266 | local testlog=`mktemp $LOG_DIR/${testname}-log.XXXXXX` | ||
267 | else | ||
268 | local testlog=/proc/self/fd/1 | ||
269 | fi | ||
251 | export TMPDIR=`mktemp -d /tmp/ftracetest-dir.XXXXXX` | 270 | export TMPDIR=`mktemp -d /tmp/ftracetest-dir.XXXXXX` |
252 | testcase $1 | 271 | testcase $1 |
253 | echo "execute$INSTANCE: "$1 > $testlog | 272 | echo "execute$INSTANCE: "$1 > $testlog |
254 | SIG_RESULT=0 | 273 | SIG_RESULT=0 |
255 | if [ $VERBOSE -ge 2 ]; then | 274 | if [ -z "$LOG_FILE" ]; then |
275 | __run_test $1 2>&1 | ||
276 | elif [ $VERBOSE -ge 3 ]; then | ||
277 | __run_test $1 | tee -a $testlog 2>&1 | ||
278 | elif [ $VERBOSE -eq 2 ]; then | ||
256 | __run_test $1 2>> $testlog | tee -a $testlog | 279 | __run_test $1 2>> $testlog | tee -a $testlog |
257 | else | 280 | else |
258 | __run_test $1 >> $testlog 2>&1 | 281 | __run_test $1 >> $testlog 2>&1 |
@@ -260,9 +283,9 @@ run_test() { # testfile | |||
260 | eval_result $SIG_RESULT | 283 | eval_result $SIG_RESULT |
261 | if [ $? -eq 0 ]; then | 284 | if [ $? -eq 0 ]; then |
262 | # Remove test log if the test was done as it was expected. | 285 | # Remove test log if the test was done as it was expected. |
263 | [ $KEEP_LOG -eq 0 ] && rm $testlog | 286 | [ $KEEP_LOG -eq 0 -a ! -z "$LOG_FILE" ] && rm $testlog |
264 | else | 287 | else |
265 | [ $VERBOSE -ge 1 ] && catlog $testlog | 288 | [ $VERBOSE -eq 1 -o $VERBOSE -eq 2 ] && catlog $testlog |
266 | TOTAL_RESULT=1 | 289 | TOTAL_RESULT=1 |
267 | fi | 290 | fi |
268 | rm -rf $TMPDIR | 291 | rm -rf $TMPDIR |
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc index 2a1cb9908746..a4fd4c851a5b 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc | |||
@@ -1,6 +1,8 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # description: Register/unregister many kprobe events | 2 | # description: Register/unregister many kprobe events |
3 | 3 | ||
4 | [ -f kprobe_events ] || exit_unsupported # this is configurable | ||
5 | |||
4 | # ftrace fentry skip size depends on the machine architecture. | 6 | # ftrace fentry skip size depends on the machine architecture. |
5 | # Currently HAVE_KPROBES_ON_FTRACE defined on x86 and powerpc64le | 7 | # Currently HAVE_KPROBES_ON_FTRACE defined on x86 and powerpc64le |
6 | case `uname -m` in | 8 | case `uname -m` in |
diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile index 7c647f619d63..f0c0369ccb79 100644 --- a/tools/testing/selftests/futex/Makefile +++ b/tools/testing/selftests/futex/Makefile | |||
@@ -7,14 +7,17 @@ TEST_PROGS := run.sh | |||
7 | include ../lib.mk | 7 | include ../lib.mk |
8 | 8 | ||
9 | all: | 9 | all: |
10 | for DIR in $(SUBDIRS); do \ | 10 | @for DIR in $(SUBDIRS); do \ |
11 | BUILD_TARGET=$(OUTPUT)/$$DIR; \ | 11 | BUILD_TARGET=$(OUTPUT)/$$DIR; \ |
12 | mkdir $$BUILD_TARGET -p; \ | 12 | mkdir $$BUILD_TARGET -p; \ |
13 | make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ | 13 | make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ |
14 | if [ -e $$DIR/$(TEST_PROGS) ]; then | ||
15 | rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/; | ||
16 | fi | ||
14 | done | 17 | done |
15 | 18 | ||
16 | override define RUN_TESTS | 19 | override define RUN_TESTS |
17 | $(OUTPUT)/run.sh | 20 | @cd $(OUTPUT); ./run.sh |
18 | endef | 21 | endef |
19 | 22 | ||
20 | override define INSTALL_RULE | 23 | override define INSTALL_RULE |
@@ -33,7 +36,7 @@ override define EMIT_TESTS | |||
33 | endef | 36 | endef |
34 | 37 | ||
35 | override define CLEAN | 38 | override define CLEAN |
36 | for DIR in $(SUBDIRS); do \ | 39 | @for DIR in $(SUBDIRS); do \ |
37 | BUILD_TARGET=$(OUTPUT)/$$DIR; \ | 40 | BUILD_TARGET=$(OUTPUT)/$$DIR; \ |
38 | mkdir $$BUILD_TARGET -p; \ | 41 | mkdir $$BUILD_TARGET -p; \ |
39 | make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ | 42 | make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ |
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi.c b/tools/testing/selftests/futex/functional/futex_requeue_pi.c index d24ab7421e73..54cd5c414e82 100644 --- a/tools/testing/selftests/futex/functional/futex_requeue_pi.c +++ b/tools/testing/selftests/futex/functional/futex_requeue_pi.c | |||
@@ -394,9 +394,11 @@ int main(int argc, char *argv[]) | |||
394 | } | 394 | } |
395 | } | 395 | } |
396 | 396 | ||
397 | printf("%s: Test requeue functionality\n", basename(argv[0])); | 397 | ksft_print_header(); |
398 | printf("\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n", | 398 | ksft_print_msg("%s: Test requeue functionality\n", basename(argv[0])); |
399 | broadcast, locked, owner, timeout_ns); | 399 | ksft_print_msg( |
400 | "\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n", | ||
401 | broadcast, locked, owner, timeout_ns); | ||
400 | 402 | ||
401 | /* | 403 | /* |
402 | * FIXME: unit_test is obsolete now that we parse options and the | 404 | * FIXME: unit_test is obsolete now that we parse options and the |
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c index e0a798ad0d21..08187a16507f 100644 --- a/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c +++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c | |||
@@ -78,7 +78,8 @@ int main(int argc, char *argv[]) | |||
78 | } | 78 | } |
79 | } | 79 | } |
80 | 80 | ||
81 | printf("%s: Detect mismatched requeue_pi operations\n", | 81 | ksft_print_header(); |
82 | ksft_print_msg("%s: Detect mismatched requeue_pi operations\n", | ||
82 | basename(argv[0])); | 83 | basename(argv[0])); |
83 | 84 | ||
84 | if (pthread_create(&child, NULL, blocking_child, NULL)) { | 85 | if (pthread_create(&child, NULL, blocking_child, NULL)) { |
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c index 982f83577501..f0542a344d95 100644 --- a/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c +++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c | |||
@@ -143,9 +143,10 @@ int main(int argc, char *argv[]) | |||
143 | } | 143 | } |
144 | } | 144 | } |
145 | 145 | ||
146 | printf("%s: Test signal handling during requeue_pi\n", | 146 | ksft_print_header(); |
147 | ksft_print_msg("%s: Test signal handling during requeue_pi\n", | ||
147 | basename(argv[0])); | 148 | basename(argv[0])); |
148 | printf("\tArguments: <none>\n"); | 149 | ksft_print_msg("\tArguments: <none>\n"); |
149 | 150 | ||
150 | sa.sa_handler = handle_signal; | 151 | sa.sa_handler = handle_signal; |
151 | sigemptyset(&sa.sa_mask); | 152 | sigemptyset(&sa.sa_mask); |
diff --git a/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c b/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c index bdc48dc047e5..6216de828093 100644 --- a/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c +++ b/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c | |||
@@ -97,8 +97,10 @@ int main(int argc, char **argv) | |||
97 | } | 97 | } |
98 | } | 98 | } |
99 | 99 | ||
100 | printf("%s: Test the futex value of private file mappings in FUTEX_WAIT\n", | 100 | ksft_print_header(); |
101 | basename(argv[0])); | 101 | ksft_print_msg( |
102 | "%s: Test the futex value of private file mappings in FUTEX_WAIT\n", | ||
103 | basename(argv[0])); | ||
102 | 104 | ||
103 | ret = pthread_create(&thr, NULL, thr_futex_wait, NULL); | 105 | ret = pthread_create(&thr, NULL, thr_futex_wait, NULL); |
104 | if (ret < 0) { | 106 | if (ret < 0) { |
diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c b/tools/testing/selftests/futex/functional/futex_wait_timeout.c index 6aadd560366e..bab3dfe1787f 100644 --- a/tools/testing/selftests/futex/functional/futex_wait_timeout.c +++ b/tools/testing/selftests/futex/functional/futex_wait_timeout.c | |||
@@ -68,9 +68,10 @@ int main(int argc, char *argv[]) | |||
68 | } | 68 | } |
69 | } | 69 | } |
70 | 70 | ||
71 | printf("%s: Block on a futex and wait for timeout\n", | 71 | ksft_print_header(); |
72 | ksft_print_msg("%s: Block on a futex and wait for timeout\n", | ||
72 | basename(argv[0])); | 73 | basename(argv[0])); |
73 | printf("\tArguments: timeout=%ldns\n", timeout_ns); | 74 | ksft_print_msg("\tArguments: timeout=%ldns\n", timeout_ns); |
74 | 75 | ||
75 | /* initialize timeout */ | 76 | /* initialize timeout */ |
76 | to.tv_sec = 0; | 77 | to.tv_sec = 0; |
diff --git a/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c b/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c index d237a8b702f0..26975322545b 100644 --- a/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c +++ b/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c | |||
@@ -99,7 +99,8 @@ int main(int argc, char **argv) | |||
99 | exit(1); | 99 | exit(1); |
100 | } | 100 | } |
101 | 101 | ||
102 | printf("%s: Test the uninitialized futex value in FUTEX_WAIT\n", | 102 | ksft_print_header(); |
103 | ksft_print_msg("%s: Test the uninitialized futex value in FUTEX_WAIT\n", | ||
103 | basename(argv[0])); | 104 | basename(argv[0])); |
104 | 105 | ||
105 | 106 | ||
diff --git a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c index 9a2c56fa7305..da15a63269b4 100644 --- a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c +++ b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c | |||
@@ -64,7 +64,8 @@ int main(int argc, char *argv[]) | |||
64 | } | 64 | } |
65 | } | 65 | } |
66 | 66 | ||
67 | printf("%s: Test the unexpected futex value in FUTEX_WAIT\n", | 67 | ksft_print_header(); |
68 | ksft_print_msg("%s: Test the unexpected futex value in FUTEX_WAIT\n", | ||
68 | basename(argv[0])); | 69 | basename(argv[0])); |
69 | 70 | ||
70 | info("Calling futex_wait on f1: %u @ %p with val=%u\n", f1, &f1, f1+1); | 71 | info("Calling futex_wait on f1: %u @ %p with val=%u\n", f1, &f1, f1+1); |
diff --git a/tools/testing/selftests/futex/include/logging.h b/tools/testing/selftests/futex/include/logging.h index 4e7944984fbb..01989644e50a 100644 --- a/tools/testing/selftests/futex/include/logging.h +++ b/tools/testing/selftests/futex/include/logging.h | |||
@@ -109,22 +109,20 @@ void log_verbosity(int level) | |||
109 | */ | 109 | */ |
110 | void print_result(const char *test_name, int ret) | 110 | void print_result(const char *test_name, int ret) |
111 | { | 111 | { |
112 | const char *result = "Unknown return code"; | ||
113 | |||
114 | switch (ret) { | 112 | switch (ret) { |
115 | case RET_PASS: | 113 | case RET_PASS: |
116 | ksft_inc_pass_cnt(); | 114 | ksft_test_result_pass("%s\n", test_name); |
117 | result = PASS; | 115 | ksft_print_cnts(); |
118 | break; | 116 | return; |
119 | case RET_ERROR: | 117 | case RET_ERROR: |
120 | result = ERROR; | 118 | ksft_test_result_error("%s\n", test_name); |
121 | break; | 119 | ksft_print_cnts(); |
120 | return; | ||
122 | case RET_FAIL: | 121 | case RET_FAIL: |
123 | ksft_inc_fail_cnt(); | 122 | ksft_test_result_fail("%s\n", test_name); |
124 | result = FAIL; | 123 | ksft_print_cnts(); |
125 | break; | 124 | return; |
126 | } | 125 | } |
127 | printf("selftests: %s [%s]\n", test_name, result); | ||
128 | } | 126 | } |
129 | 127 | ||
130 | /* log level macros */ | 128 | /* log level macros */ |
diff --git a/tools/testing/selftests/intel_pstate/Makefile b/tools/testing/selftests/intel_pstate/Makefile index 849a90ffe8dd..a97e24edde39 100644 --- a/tools/testing/selftests/intel_pstate/Makefile +++ b/tools/testing/selftests/intel_pstate/Makefile | |||
@@ -1,7 +1,9 @@ | |||
1 | CFLAGS := $(CFLAGS) -Wall -D_GNU_SOURCE | 1 | CFLAGS := $(CFLAGS) -Wall -D_GNU_SOURCE |
2 | LDLIBS := $(LDLIBS) -lm | 2 | LDLIBS := $(LDLIBS) -lm |
3 | 3 | ||
4 | ifeq (,$(filter $(ARCH),x86)) | ||
4 | TEST_GEN_FILES := msr aperf | 5 | TEST_GEN_FILES := msr aperf |
6 | endif | ||
5 | 7 | ||
6 | TEST_PROGS := run.sh | 8 | TEST_PROGS := run.sh |
7 | 9 | ||
diff --git a/tools/testing/selftests/intel_pstate/run.sh b/tools/testing/selftests/intel_pstate/run.sh index 7868c106b8b1..d3ab48f91cd6 100755 --- a/tools/testing/selftests/intel_pstate/run.sh +++ b/tools/testing/selftests/intel_pstate/run.sh | |||
@@ -29,13 +29,12 @@ | |||
29 | 29 | ||
30 | EVALUATE_ONLY=0 | 30 | EVALUATE_ONLY=0 |
31 | 31 | ||
32 | max_cpus=$(($(nproc)-1)) | 32 | if ! uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ | grep -q x86; then |
33 | echo "$0 # Skipped: Test can only run on x86 architectures." | ||
34 | exit 0 | ||
35 | fi | ||
33 | 36 | ||
34 | # compile programs | 37 | max_cpus=$(($(nproc)-1)) |
35 | gcc aperf.c -Wall -D_GNU_SOURCE -o aperf -lm | ||
36 | [ $? -ne 0 ] && echo "Problem compiling aperf.c." && exit 1 | ||
37 | gcc -o msr msr.c -lm | ||
38 | [ $? -ne 0 ] && echo "Problem compiling msr.c." && exit 1 | ||
39 | 38 | ||
40 | function run_test () { | 39 | function run_test () { |
41 | 40 | ||
diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c index a5a4da856dfe..73684c4a1ed6 100644 --- a/tools/testing/selftests/kcmp/kcmp_test.c +++ b/tools/testing/selftests/kcmp/kcmp_test.c | |||
@@ -8,7 +8,6 @@ | |||
8 | #include <errno.h> | 8 | #include <errno.h> |
9 | #include <string.h> | 9 | #include <string.h> |
10 | #include <fcntl.h> | 10 | #include <fcntl.h> |
11 | |||
12 | #include <linux/unistd.h> | 11 | #include <linux/unistd.h> |
13 | #include <linux/kcmp.h> | 12 | #include <linux/kcmp.h> |
14 | 13 | ||
@@ -16,20 +15,28 @@ | |||
16 | #include <sys/types.h> | 15 | #include <sys/types.h> |
17 | #include <sys/stat.h> | 16 | #include <sys/stat.h> |
18 | #include <sys/wait.h> | 17 | #include <sys/wait.h> |
18 | #include <sys/epoll.h> | ||
19 | 19 | ||
20 | #include "../kselftest.h" | 20 | #include "../kselftest.h" |
21 | 21 | ||
22 | static long sys_kcmp(int pid1, int pid2, int type, int fd1, int fd2) | 22 | static long sys_kcmp(int pid1, int pid2, int type, unsigned long fd1, unsigned long fd2) |
23 | { | 23 | { |
24 | return syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2); | 24 | return syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2); |
25 | } | 25 | } |
26 | 26 | ||
27 | static const unsigned int duped_num = 64; | ||
28 | |||
27 | int main(int argc, char **argv) | 29 | int main(int argc, char **argv) |
28 | { | 30 | { |
29 | const char kpath[] = "kcmp-test-file"; | 31 | const char kpath[] = "kcmp-test-file"; |
32 | struct kcmp_epoll_slot epoll_slot; | ||
33 | struct epoll_event ev; | ||
30 | int pid1, pid2; | 34 | int pid1, pid2; |
35 | int pipefd[2]; | ||
31 | int fd1, fd2; | 36 | int fd1, fd2; |
37 | int epollfd; | ||
32 | int status; | 38 | int status; |
39 | int fddup; | ||
33 | 40 | ||
34 | fd1 = open(kpath, O_RDWR | O_CREAT | O_TRUNC, 0644); | 41 | fd1 = open(kpath, O_RDWR | O_CREAT | O_TRUNC, 0644); |
35 | pid1 = getpid(); | 42 | pid1 = getpid(); |
@@ -39,6 +46,37 @@ int main(int argc, char **argv) | |||
39 | ksft_exit_fail(); | 46 | ksft_exit_fail(); |
40 | } | 47 | } |
41 | 48 | ||
49 | if (pipe(pipefd)) { | ||
50 | perror("Can't create pipe"); | ||
51 | ksft_exit_fail(); | ||
52 | } | ||
53 | |||
54 | epollfd = epoll_create1(0); | ||
55 | if (epollfd < 0) { | ||
56 | perror("epoll_create1 failed"); | ||
57 | ksft_exit_fail(); | ||
58 | } | ||
59 | |||
60 | memset(&ev, 0xff, sizeof(ev)); | ||
61 | ev.events = EPOLLIN | EPOLLOUT; | ||
62 | |||
63 | if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd[0], &ev)) { | ||
64 | perror("epoll_ctl failed"); | ||
65 | ksft_exit_fail(); | ||
66 | } | ||
67 | |||
68 | fddup = dup2(pipefd[1], duped_num); | ||
69 | if (fddup < 0) { | ||
70 | perror("dup2 failed"); | ||
71 | ksft_exit_fail(); | ||
72 | } | ||
73 | |||
74 | if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fddup, &ev)) { | ||
75 | perror("epoll_ctl failed"); | ||
76 | ksft_exit_fail(); | ||
77 | } | ||
78 | close(fddup); | ||
79 | |||
42 | pid2 = fork(); | 80 | pid2 = fork(); |
43 | if (pid2 < 0) { | 81 | if (pid2 < 0) { |
44 | perror("fork failed"); | 82 | perror("fork failed"); |
@@ -95,6 +133,24 @@ int main(int argc, char **argv) | |||
95 | ksft_inc_pass_cnt(); | 133 | ksft_inc_pass_cnt(); |
96 | } | 134 | } |
97 | 135 | ||
136 | /* Compare epoll target */ | ||
137 | epoll_slot = (struct kcmp_epoll_slot) { | ||
138 | .efd = epollfd, | ||
139 | .tfd = duped_num, | ||
140 | .toff = 0, | ||
141 | }; | ||
142 | ret = sys_kcmp(pid1, pid1, KCMP_EPOLL_TFD, pipefd[1], | ||
143 | (unsigned long)(void *)&epoll_slot); | ||
144 | if (ret) { | ||
145 | printf("FAIL: 0 expected but %d returned (%s)\n", | ||
146 | ret, strerror(errno)); | ||
147 | ksft_inc_fail_cnt(); | ||
148 | ret = -1; | ||
149 | } else { | ||
150 | printf("PASS: 0 returned as expected\n"); | ||
151 | ksft_inc_pass_cnt(); | ||
152 | } | ||
153 | |||
98 | ksft_print_cnts(); | 154 | ksft_print_cnts(); |
99 | 155 | ||
100 | if (ret) | 156 | if (ret) |
diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h index 08e90c2cc5cb..1ae565ed9bf0 100644 --- a/tools/testing/selftests/kselftest.h +++ b/tools/testing/selftests/kselftest.h | |||
@@ -19,7 +19,8 @@ | |||
19 | #define KSFT_FAIL 1 | 19 | #define KSFT_FAIL 1 |
20 | #define KSFT_XFAIL 2 | 20 | #define KSFT_XFAIL 2 |
21 | #define KSFT_XPASS 3 | 21 | #define KSFT_XPASS 3 |
22 | #define KSFT_SKIP 4 | 22 | /* Treat skip as pass */ |
23 | #define KSFT_SKIP KSFT_PASS | ||
23 | 24 | ||
24 | /* counters */ | 25 | /* counters */ |
25 | struct ksft_count { | 26 | struct ksft_count { |
@@ -28,6 +29,7 @@ struct ksft_count { | |||
28 | unsigned int ksft_xfail; | 29 | unsigned int ksft_xfail; |
29 | unsigned int ksft_xpass; | 30 | unsigned int ksft_xpass; |
30 | unsigned int ksft_xskip; | 31 | unsigned int ksft_xskip; |
32 | unsigned int ksft_error; | ||
31 | }; | 33 | }; |
32 | 34 | ||
33 | static struct ksft_count ksft_cnt; | 35 | static struct ksft_count ksft_cnt; |
@@ -36,7 +38,7 @@ static inline int ksft_test_num(void) | |||
36 | { | 38 | { |
37 | return ksft_cnt.ksft_pass + ksft_cnt.ksft_fail + | 39 | return ksft_cnt.ksft_pass + ksft_cnt.ksft_fail + |
38 | ksft_cnt.ksft_xfail + ksft_cnt.ksft_xpass + | 40 | ksft_cnt.ksft_xfail + ksft_cnt.ksft_xpass + |
39 | ksft_cnt.ksft_xskip; | 41 | ksft_cnt.ksft_xskip + ksft_cnt.ksft_error; |
40 | } | 42 | } |
41 | 43 | ||
42 | static inline void ksft_inc_pass_cnt(void) { ksft_cnt.ksft_pass++; } | 44 | static inline void ksft_inc_pass_cnt(void) { ksft_cnt.ksft_pass++; } |
@@ -44,6 +46,14 @@ static inline void ksft_inc_fail_cnt(void) { ksft_cnt.ksft_fail++; } | |||
44 | static inline void ksft_inc_xfail_cnt(void) { ksft_cnt.ksft_xfail++; } | 46 | static inline void ksft_inc_xfail_cnt(void) { ksft_cnt.ksft_xfail++; } |
45 | static inline void ksft_inc_xpass_cnt(void) { ksft_cnt.ksft_xpass++; } | 47 | static inline void ksft_inc_xpass_cnt(void) { ksft_cnt.ksft_xpass++; } |
46 | static inline void ksft_inc_xskip_cnt(void) { ksft_cnt.ksft_xskip++; } | 48 | static inline void ksft_inc_xskip_cnt(void) { ksft_cnt.ksft_xskip++; } |
49 | static inline void ksft_inc_error_cnt(void) { ksft_cnt.ksft_error++; } | ||
50 | |||
51 | static inline int ksft_get_pass_cnt(void) { return ksft_cnt.ksft_pass; } | ||
52 | static inline int ksft_get_fail_cnt(void) { return ksft_cnt.ksft_fail; } | ||
53 | static inline int ksft_get_xfail_cnt(void) { return ksft_cnt.ksft_xfail; } | ||
54 | static inline int ksft_get_xpass_cnt(void) { return ksft_cnt.ksft_xpass; } | ||
55 | static inline int ksft_get_xskip_cnt(void) { return ksft_cnt.ksft_xskip; } | ||
56 | static inline int ksft_get_error_cnt(void) { return ksft_cnt.ksft_error; } | ||
47 | 57 | ||
48 | static inline void ksft_print_header(void) | 58 | static inline void ksft_print_header(void) |
49 | { | 59 | { |
@@ -52,6 +62,10 @@ static inline void ksft_print_header(void) | |||
52 | 62 | ||
53 | static inline void ksft_print_cnts(void) | 63 | static inline void ksft_print_cnts(void) |
54 | { | 64 | { |
65 | printf("Pass %d Fail %d Xfail %d Xpass %d Skip %d Error %d\n", | ||
66 | ksft_cnt.ksft_pass, ksft_cnt.ksft_fail, | ||
67 | ksft_cnt.ksft_xfail, ksft_cnt.ksft_xpass, | ||
68 | ksft_cnt.ksft_xskip, ksft_cnt.ksft_error); | ||
55 | printf("1..%d\n", ksft_test_num()); | 69 | printf("1..%d\n", ksft_test_num()); |
56 | } | 70 | } |
57 | 71 | ||
@@ -101,6 +115,18 @@ static inline void ksft_test_result_skip(const char *msg, ...) | |||
101 | va_end(args); | 115 | va_end(args); |
102 | } | 116 | } |
103 | 117 | ||
118 | static inline void ksft_test_result_error(const char *msg, ...) | ||
119 | { | ||
120 | va_list args; | ||
121 | |||
122 | ksft_cnt.ksft_error++; | ||
123 | |||
124 | va_start(args, msg); | ||
125 | printf("not ok %d # error ", ksft_test_num()); | ||
126 | vprintf(msg, args); | ||
127 | va_end(args); | ||
128 | } | ||
129 | |||
104 | static inline int ksft_exit_pass(void) | 130 | static inline int ksft_exit_pass(void) |
105 | { | 131 | { |
106 | ksft_print_cnts(); | 132 | ksft_print_cnts(); |
diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index c56f72e07cd7..e81bd28bdd89 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h | |||
@@ -51,6 +51,9 @@ | |||
51 | #define __KSELFTEST_HARNESS_H | 51 | #define __KSELFTEST_HARNESS_H |
52 | 52 | ||
53 | #define _GNU_SOURCE | 53 | #define _GNU_SOURCE |
54 | #include <asm/types.h> | ||
55 | #include <errno.h> | ||
56 | #include <stdbool.h> | ||
54 | #include <stdint.h> | 57 | #include <stdint.h> |
55 | #include <stdio.h> | 58 | #include <stdio.h> |
56 | #include <stdlib.h> | 59 | #include <stdlib.h> |
@@ -84,6 +87,14 @@ | |||
84 | * E.g., #define TH_LOG_ENABLED 1 | 87 | * E.g., #define TH_LOG_ENABLED 1 |
85 | * | 88 | * |
86 | * If no definition is provided, logging is enabled by default. | 89 | * If no definition is provided, logging is enabled by default. |
90 | * | ||
91 | * If there is no way to print an error message for the process running the | ||
92 | * test (e.g. not allowed to write to stderr), it is still possible to get the | ||
93 | * ASSERT_* number for which the test failed. This behavior can be enabled by | ||
94 | * writing `_metadata->no_print = true;` before the check sequence that is | ||
95 | * unable to print. When an error occur, instead of printing an error message | ||
96 | * and calling `abort(3)`, the test process call `_exit(2)` with the assert | ||
97 | * number as argument, which is then printed by the parent process. | ||
87 | */ | 98 | */ |
88 | #define TH_LOG(fmt, ...) do { \ | 99 | #define TH_LOG(fmt, ...) do { \ |
89 | if (TH_LOG_ENABLED) \ | 100 | if (TH_LOG_ENABLED) \ |
@@ -555,12 +566,18 @@ | |||
555 | * return while still providing an optional block to the API consumer. | 566 | * return while still providing an optional block to the API consumer. |
556 | */ | 567 | */ |
557 | #define OPTIONAL_HANDLER(_assert) \ | 568 | #define OPTIONAL_HANDLER(_assert) \ |
558 | for (; _metadata->trigger; _metadata->trigger = __bail(_assert)) | 569 | for (; _metadata->trigger; _metadata->trigger = \ |
570 | __bail(_assert, _metadata->no_print, _metadata->step)) | ||
571 | |||
572 | #define __INC_STEP(_metadata) \ | ||
573 | if (_metadata->passed && _metadata->step < 255) \ | ||
574 | _metadata->step++; | ||
559 | 575 | ||
560 | #define __EXPECT(_expected, _seen, _t, _assert) do { \ | 576 | #define __EXPECT(_expected, _seen, _t, _assert) do { \ |
561 | /* Avoid multiple evaluation of the cases */ \ | 577 | /* Avoid multiple evaluation of the cases */ \ |
562 | __typeof__(_expected) __exp = (_expected); \ | 578 | __typeof__(_expected) __exp = (_expected); \ |
563 | __typeof__(_seen) __seen = (_seen); \ | 579 | __typeof__(_seen) __seen = (_seen); \ |
580 | if (_assert) __INC_STEP(_metadata); \ | ||
564 | if (!(__exp _t __seen)) { \ | 581 | if (!(__exp _t __seen)) { \ |
565 | unsigned long long __exp_print = (uintptr_t)__exp; \ | 582 | unsigned long long __exp_print = (uintptr_t)__exp; \ |
566 | unsigned long long __seen_print = (uintptr_t)__seen; \ | 583 | unsigned long long __seen_print = (uintptr_t)__seen; \ |
@@ -576,6 +593,7 @@ | |||
576 | #define __EXPECT_STR(_expected, _seen, _t, _assert) do { \ | 593 | #define __EXPECT_STR(_expected, _seen, _t, _assert) do { \ |
577 | const char *__exp = (_expected); \ | 594 | const char *__exp = (_expected); \ |
578 | const char *__seen = (_seen); \ | 595 | const char *__seen = (_seen); \ |
596 | if (_assert) __INC_STEP(_metadata); \ | ||
579 | if (!(strcmp(__exp, __seen) _t 0)) { \ | 597 | if (!(strcmp(__exp, __seen) _t 0)) { \ |
580 | __TH_LOG("Expected '%s' %s '%s'.", __exp, #_t, __seen); \ | 598 | __TH_LOG("Expected '%s' %s '%s'.", __exp, #_t, __seen); \ |
581 | _metadata->passed = 0; \ | 599 | _metadata->passed = 0; \ |
@@ -590,6 +608,8 @@ struct __test_metadata { | |||
590 | int termsig; | 608 | int termsig; |
591 | int passed; | 609 | int passed; |
592 | int trigger; /* extra handler after the evaluation */ | 610 | int trigger; /* extra handler after the evaluation */ |
611 | __u8 step; | ||
612 | bool no_print; /* manual trigger when TH_LOG_STREAM is not available */ | ||
593 | struct __test_metadata *prev, *next; | 613 | struct __test_metadata *prev, *next; |
594 | }; | 614 | }; |
595 | 615 | ||
@@ -634,10 +654,13 @@ static inline void __register_test(struct __test_metadata *t) | |||
634 | } | 654 | } |
635 | } | 655 | } |
636 | 656 | ||
637 | static inline int __bail(int for_realz) | 657 | static inline int __bail(int for_realz, bool no_print, __u8 step) |
638 | { | 658 | { |
639 | if (for_realz) | 659 | if (for_realz) { |
660 | if (no_print) | ||
661 | _exit(step); | ||
640 | abort(); | 662 | abort(); |
663 | } | ||
641 | return 0; | 664 | return 0; |
642 | } | 665 | } |
643 | 666 | ||
@@ -655,18 +678,24 @@ void __run_test(struct __test_metadata *t) | |||
655 | t->passed = 0; | 678 | t->passed = 0; |
656 | } else if (child_pid == 0) { | 679 | } else if (child_pid == 0) { |
657 | t->fn(t); | 680 | t->fn(t); |
658 | _exit(t->passed); | 681 | /* return the step that failed or 0 */ |
682 | _exit(t->passed ? 0 : t->step); | ||
659 | } else { | 683 | } else { |
660 | /* TODO(wad) add timeout support. */ | 684 | /* TODO(wad) add timeout support. */ |
661 | waitpid(child_pid, &status, 0); | 685 | waitpid(child_pid, &status, 0); |
662 | if (WIFEXITED(status)) { | 686 | if (WIFEXITED(status)) { |
663 | t->passed = t->termsig == -1 ? WEXITSTATUS(status) : 0; | 687 | t->passed = t->termsig == -1 ? !WEXITSTATUS(status) : 0; |
664 | if (t->termsig != -1) { | 688 | if (t->termsig != -1) { |
665 | fprintf(TH_LOG_STREAM, | 689 | fprintf(TH_LOG_STREAM, |
666 | "%s: Test exited normally " | 690 | "%s: Test exited normally " |
667 | "instead of by signal (code: %d)\n", | 691 | "instead of by signal (code: %d)\n", |
668 | t->name, | 692 | t->name, |
669 | WEXITSTATUS(status)); | 693 | WEXITSTATUS(status)); |
694 | } else if (!t->passed) { | ||
695 | fprintf(TH_LOG_STREAM, | ||
696 | "%s: Test failed at step #%d\n", | ||
697 | t->name, | ||
698 | WEXITSTATUS(status)); | ||
670 | } | 699 | } |
671 | } else if (WIFSIGNALED(status)) { | 700 | } else if (WIFSIGNALED(status)) { |
672 | t->passed = 0; | 701 | t->passed = 0; |
diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk index 959273c3a52e..f65886af7c0c 100644 --- a/tools/testing/selftests/lib.mk +++ b/tools/testing/selftests/lib.mk | |||
@@ -6,20 +6,49 @@ ifeq (0,$(MAKELEVEL)) | |||
6 | OUTPUT := $(shell pwd) | 6 | OUTPUT := $(shell pwd) |
7 | endif | 7 | endif |
8 | 8 | ||
9 | # The following are built by lib.mk common compile rules. | ||
10 | # TEST_CUSTOM_PROGS should be used by tests that require | ||
11 | # custom build rule and prevent common build rule use. | ||
12 | # TEST_PROGS are for test shell scripts. | ||
13 | # TEST_CUSTOM_PROGS and TEST_PROGS will be run by common run_tests | ||
14 | # and install targets. Common clean doesn't touch them. | ||
9 | TEST_GEN_PROGS := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS)) | 15 | TEST_GEN_PROGS := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS)) |
16 | TEST_GEN_PROGS_EXTENDED := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS_EXTENDED)) | ||
10 | TEST_GEN_FILES := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_FILES)) | 17 | TEST_GEN_FILES := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_FILES)) |
11 | 18 | ||
12 | all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) | 19 | all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) |
13 | 20 | ||
21 | .ONESHELL: | ||
14 | define RUN_TESTS | 22 | define RUN_TESTS |
15 | @for TEST in $(TEST_GEN_PROGS) $(TEST_PROGS); do \ | 23 | @test_num=`echo 0`; |
24 | @echo "TAP version 13"; | ||
25 | @for TEST in $(1); do \ | ||
16 | BASENAME_TEST=`basename $$TEST`; \ | 26 | BASENAME_TEST=`basename $$TEST`; \ |
17 | cd `dirname $$TEST`; (./$$BASENAME_TEST && echo "selftests: $$BASENAME_TEST [PASS]") || echo "selftests: $$BASENAME_TEST [FAIL]"; cd -;\ | 27 | test_num=`echo $$test_num+1 | bc`; \ |
28 | echo "selftests: $$BASENAME_TEST"; \ | ||
29 | echo "========================================"; \ | ||
30 | if [ ! -x $$TEST ]; then \ | ||
31 | echo "selftests: Warning: file $$BASENAME_TEST is not executable, correct this.";\ | ||
32 | echo "not ok 1..$$test_num selftests: $$BASENAME_TEST [FAIL]"; \ | ||
33 | else \ | ||
34 | cd `dirname $$TEST` > /dev/null; (./$$BASENAME_TEST > /tmp/$$BASENAME_TEST 2>&1 && echo "ok 1..$$test_num selftests: $$BASENAME_TEST [PASS]") || echo "not ok 1..$$test_num selftests: $$BASENAME_TEST [FAIL]"; cd - > /dev/null;\ | ||
35 | fi; \ | ||
18 | done; | 36 | done; |
19 | endef | 37 | endef |
20 | 38 | ||
21 | run_tests: all | 39 | run_tests: all |
22 | $(RUN_TESTS) | 40 | ifneq ($(KBUILD_SRC),) |
41 | @if [ "X$(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES)" != "X" ]; then | ||
42 | @rsync -aq $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(OUTPUT) | ||
43 | fi | ||
44 | @if [ "X$(TEST_PROGS)" != "X" ]; then | ||
45 | $(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(OUTPUT)/$(TEST_PROGS)) | ||
46 | else | ||
47 | $(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS)) | ||
48 | fi | ||
49 | else | ||
50 | $(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS)) | ||
51 | endif | ||
23 | 52 | ||
24 | define INSTALL_RULE | 53 | define INSTALL_RULE |
25 | @if [ "X$(TEST_PROGS)$(TEST_PROGS_EXTENDED)$(TEST_FILES)" != "X" ]; then \ | 54 | @if [ "X$(TEST_PROGS)$(TEST_PROGS_EXTENDED)$(TEST_FILES)" != "X" ]; then \ |
@@ -27,10 +56,10 @@ define INSTALL_RULE | |||
27 | echo "rsync -a $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(INSTALL_PATH)/"; \ | 56 | echo "rsync -a $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(INSTALL_PATH)/"; \ |
28 | rsync -a $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(INSTALL_PATH)/; \ | 57 | rsync -a $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(INSTALL_PATH)/; \ |
29 | fi | 58 | fi |
30 | @if [ "X$(TEST_GEN_PROGS)$(TEST_GEN_PROGS_EXTENDED)$(TEST_GEN_FILES)" != "X" ]; then \ | 59 | @if [ "X$(TEST_GEN_PROGS)$(TEST_CUSTOM_PROGS)$(TEST_GEN_PROGS_EXTENDED)$(TEST_GEN_FILES)" != "X" ]; then \ |
31 | mkdir -p ${INSTALL_PATH}; \ | 60 | mkdir -p ${INSTALL_PATH}; \ |
32 | echo "rsync -a $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(INSTALL_PATH)/"; \ | 61 | echo "rsync -a $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(INSTALL_PATH)/"; \ |
33 | rsync -a $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(INSTALL_PATH)/; \ | 62 | rsync -a $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(INSTALL_PATH)/; \ |
34 | fi | 63 | fi |
35 | endef | 64 | endef |
36 | 65 | ||
@@ -42,15 +71,20 @@ else | |||
42 | endif | 71 | endif |
43 | 72 | ||
44 | define EMIT_TESTS | 73 | define EMIT_TESTS |
45 | @for TEST in $(TEST_GEN_PROGS) $(TEST_PROGS); do \ | 74 | @for TEST in $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS); do \ |
46 | BASENAME_TEST=`basename $$TEST`; \ | 75 | BASENAME_TEST=`basename $$TEST`; \ |
47 | echo "(./$$BASENAME_TEST && echo \"selftests: $$BASENAME_TEST [PASS]\") || echo \"selftests: $$BASENAME_TEST [FAIL]\""; \ | 76 | echo "(./$$BASENAME_TEST > /tmp/$$BASENAME_TEST 2>&1 && echo \"selftests: $$BASENAME_TEST [PASS]\") || echo \"selftests: $$BASENAME_TEST [FAIL]\""; \ |
48 | done; | 77 | done; |
49 | endef | 78 | endef |
50 | 79 | ||
51 | emit_tests: | 80 | emit_tests: |
52 | $(EMIT_TESTS) | 81 | $(EMIT_TESTS) |
53 | 82 | ||
83 | # define if isn't already. It is undefined in make O= case. | ||
84 | ifeq ($(RM),) | ||
85 | RM := rm -f | ||
86 | endif | ||
87 | |||
54 | define CLEAN | 88 | define CLEAN |
55 | $(RM) -r $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(EXTRA_CLEAN) | 89 | $(RM) -r $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(EXTRA_CLEAN) |
56 | endef | 90 | endef |
@@ -58,6 +92,15 @@ endef | |||
58 | clean: | 92 | clean: |
59 | $(CLEAN) | 93 | $(CLEAN) |
60 | 94 | ||
95 | # When make O= with kselftest target from main level | ||
96 | # the following aren't defined. | ||
97 | # | ||
98 | ifneq ($(KBUILD_SRC),) | ||
99 | LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) | ||
100 | COMPILE.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c | ||
101 | LINK.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) | ||
102 | endif | ||
103 | |||
61 | $(OUTPUT)/%:%.c | 104 | $(OUTPUT)/%:%.c |
62 | $(LINK.c) $^ $(LDLIBS) -o $@ | 105 | $(LINK.c) $^ $(LDLIBS) -o $@ |
63 | 106 | ||
diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile index ad8a0897e47f..bc9d02d615da 100644 --- a/tools/testing/selftests/memfd/Makefile +++ b/tools/testing/selftests/memfd/Makefile | |||
@@ -3,7 +3,7 @@ CFLAGS += -I../../../../include/uapi/ | |||
3 | CFLAGS += -I../../../../include/ | 3 | CFLAGS += -I../../../../include/ |
4 | CFLAGS += -I../../../../usr/include/ | 4 | CFLAGS += -I../../../../usr/include/ |
5 | 5 | ||
6 | TEST_PROGS := run_fuse_test.sh | 6 | TEST_PROGS := run_tests.sh |
7 | TEST_GEN_FILES := memfd_test fuse_mnt fuse_test | 7 | TEST_GEN_FILES := memfd_test fuse_mnt fuse_test |
8 | 8 | ||
9 | fuse_mnt.o: CFLAGS += $(shell pkg-config fuse --cflags) | 9 | fuse_mnt.o: CFLAGS += $(shell pkg-config fuse --cflags) |
diff --git a/tools/testing/selftests/memfd/fuse_test.c b/tools/testing/selftests/memfd/fuse_test.c index 67908b18f035..7f3617274bf5 100644 --- a/tools/testing/selftests/memfd/fuse_test.c +++ b/tools/testing/selftests/memfd/fuse_test.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <unistd.h> | 33 | #include <unistd.h> |
34 | 34 | ||
35 | #define MFD_DEF_SIZE 8192 | 35 | #define MFD_DEF_SIZE 8192 |
36 | #define STACK_SIZE 65535 | 36 | #define STACK_SIZE 65536 |
37 | 37 | ||
38 | static int sys_memfd_create(const char *name, | 38 | static int sys_memfd_create(const char *name, |
39 | unsigned int flags) | 39 | unsigned int flags) |
diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c index 26546892cd54..f94c6d1fb46f 100644 --- a/tools/testing/selftests/memfd/memfd_test.c +++ b/tools/testing/selftests/memfd/memfd_test.c | |||
@@ -18,12 +18,48 @@ | |||
18 | #include <sys/wait.h> | 18 | #include <sys/wait.h> |
19 | #include <unistd.h> | 19 | #include <unistd.h> |
20 | 20 | ||
21 | #define MEMFD_STR "memfd:" | ||
22 | #define SHARED_FT_STR "(shared file-table)" | ||
23 | |||
21 | #define MFD_DEF_SIZE 8192 | 24 | #define MFD_DEF_SIZE 8192 |
22 | #define STACK_SIZE 65536 | 25 | #define STACK_SIZE 65536 |
23 | 26 | ||
27 | /* | ||
28 | * Default is not to test hugetlbfs | ||
29 | */ | ||
30 | static int hugetlbfs_test; | ||
31 | static size_t mfd_def_size = MFD_DEF_SIZE; | ||
32 | |||
33 | /* | ||
34 | * Copied from mlock2-tests.c | ||
35 | */ | ||
36 | static unsigned long default_huge_page_size(void) | ||
37 | { | ||
38 | unsigned long hps = 0; | ||
39 | char *line = NULL; | ||
40 | size_t linelen = 0; | ||
41 | FILE *f = fopen("/proc/meminfo", "r"); | ||
42 | |||
43 | if (!f) | ||
44 | return 0; | ||
45 | while (getline(&line, &linelen, f) > 0) { | ||
46 | if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) { | ||
47 | hps <<= 10; | ||
48 | break; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | free(line); | ||
53 | fclose(f); | ||
54 | return hps; | ||
55 | } | ||
56 | |||
24 | static int sys_memfd_create(const char *name, | 57 | static int sys_memfd_create(const char *name, |
25 | unsigned int flags) | 58 | unsigned int flags) |
26 | { | 59 | { |
60 | if (hugetlbfs_test) | ||
61 | flags |= MFD_HUGETLB; | ||
62 | |||
27 | return syscall(__NR_memfd_create, name, flags); | 63 | return syscall(__NR_memfd_create, name, flags); |
28 | } | 64 | } |
29 | 65 | ||
@@ -150,7 +186,7 @@ static void *mfd_assert_mmap_shared(int fd) | |||
150 | void *p; | 186 | void *p; |
151 | 187 | ||
152 | p = mmap(NULL, | 188 | p = mmap(NULL, |
153 | MFD_DEF_SIZE, | 189 | mfd_def_size, |
154 | PROT_READ | PROT_WRITE, | 190 | PROT_READ | PROT_WRITE, |
155 | MAP_SHARED, | 191 | MAP_SHARED, |
156 | fd, | 192 | fd, |
@@ -168,7 +204,7 @@ static void *mfd_assert_mmap_private(int fd) | |||
168 | void *p; | 204 | void *p; |
169 | 205 | ||
170 | p = mmap(NULL, | 206 | p = mmap(NULL, |
171 | MFD_DEF_SIZE, | 207 | mfd_def_size, |
172 | PROT_READ, | 208 | PROT_READ, |
173 | MAP_PRIVATE, | 209 | MAP_PRIVATE, |
174 | fd, | 210 | fd, |
@@ -223,7 +259,7 @@ static void mfd_assert_read(int fd) | |||
223 | 259 | ||
224 | /* verify PROT_READ *is* allowed */ | 260 | /* verify PROT_READ *is* allowed */ |
225 | p = mmap(NULL, | 261 | p = mmap(NULL, |
226 | MFD_DEF_SIZE, | 262 | mfd_def_size, |
227 | PROT_READ, | 263 | PROT_READ, |
228 | MAP_PRIVATE, | 264 | MAP_PRIVATE, |
229 | fd, | 265 | fd, |
@@ -232,11 +268,11 @@ static void mfd_assert_read(int fd) | |||
232 | printf("mmap() failed: %m\n"); | 268 | printf("mmap() failed: %m\n"); |
233 | abort(); | 269 | abort(); |
234 | } | 270 | } |
235 | munmap(p, MFD_DEF_SIZE); | 271 | munmap(p, mfd_def_size); |
236 | 272 | ||
237 | /* verify MAP_PRIVATE is *always* allowed (even writable) */ | 273 | /* verify MAP_PRIVATE is *always* allowed (even writable) */ |
238 | p = mmap(NULL, | 274 | p = mmap(NULL, |
239 | MFD_DEF_SIZE, | 275 | mfd_def_size, |
240 | PROT_READ | PROT_WRITE, | 276 | PROT_READ | PROT_WRITE, |
241 | MAP_PRIVATE, | 277 | MAP_PRIVATE, |
242 | fd, | 278 | fd, |
@@ -245,7 +281,7 @@ static void mfd_assert_read(int fd) | |||
245 | printf("mmap() failed: %m\n"); | 281 | printf("mmap() failed: %m\n"); |
246 | abort(); | 282 | abort(); |
247 | } | 283 | } |
248 | munmap(p, MFD_DEF_SIZE); | 284 | munmap(p, mfd_def_size); |
249 | } | 285 | } |
250 | 286 | ||
251 | static void mfd_assert_write(int fd) | 287 | static void mfd_assert_write(int fd) |
@@ -254,16 +290,22 @@ static void mfd_assert_write(int fd) | |||
254 | void *p; | 290 | void *p; |
255 | int r; | 291 | int r; |
256 | 292 | ||
257 | /* verify write() succeeds */ | 293 | /* |
258 | l = write(fd, "\0\0\0\0", 4); | 294 | * huegtlbfs does not support write, but we want to |
259 | if (l != 4) { | 295 | * verify everything else here. |
260 | printf("write() failed: %m\n"); | 296 | */ |
261 | abort(); | 297 | if (!hugetlbfs_test) { |
298 | /* verify write() succeeds */ | ||
299 | l = write(fd, "\0\0\0\0", 4); | ||
300 | if (l != 4) { | ||
301 | printf("write() failed: %m\n"); | ||
302 | abort(); | ||
303 | } | ||
262 | } | 304 | } |
263 | 305 | ||
264 | /* verify PROT_READ | PROT_WRITE is allowed */ | 306 | /* verify PROT_READ | PROT_WRITE is allowed */ |
265 | p = mmap(NULL, | 307 | p = mmap(NULL, |
266 | MFD_DEF_SIZE, | 308 | mfd_def_size, |
267 | PROT_READ | PROT_WRITE, | 309 | PROT_READ | PROT_WRITE, |
268 | MAP_SHARED, | 310 | MAP_SHARED, |
269 | fd, | 311 | fd, |
@@ -273,11 +315,11 @@ static void mfd_assert_write(int fd) | |||
273 | abort(); | 315 | abort(); |
274 | } | 316 | } |
275 | *(char *)p = 0; | 317 | *(char *)p = 0; |
276 | munmap(p, MFD_DEF_SIZE); | 318 | munmap(p, mfd_def_size); |
277 | 319 | ||
278 | /* verify PROT_WRITE is allowed */ | 320 | /* verify PROT_WRITE is allowed */ |
279 | p = mmap(NULL, | 321 | p = mmap(NULL, |
280 | MFD_DEF_SIZE, | 322 | mfd_def_size, |
281 | PROT_WRITE, | 323 | PROT_WRITE, |
282 | MAP_SHARED, | 324 | MAP_SHARED, |
283 | fd, | 325 | fd, |
@@ -287,12 +329,12 @@ static void mfd_assert_write(int fd) | |||
287 | abort(); | 329 | abort(); |
288 | } | 330 | } |
289 | *(char *)p = 0; | 331 | *(char *)p = 0; |
290 | munmap(p, MFD_DEF_SIZE); | 332 | munmap(p, mfd_def_size); |
291 | 333 | ||
292 | /* verify PROT_READ with MAP_SHARED is allowed and a following | 334 | /* verify PROT_READ with MAP_SHARED is allowed and a following |
293 | * mprotect(PROT_WRITE) allows writing */ | 335 | * mprotect(PROT_WRITE) allows writing */ |
294 | p = mmap(NULL, | 336 | p = mmap(NULL, |
295 | MFD_DEF_SIZE, | 337 | mfd_def_size, |
296 | PROT_READ, | 338 | PROT_READ, |
297 | MAP_SHARED, | 339 | MAP_SHARED, |
298 | fd, | 340 | fd, |
@@ -302,20 +344,20 @@ static void mfd_assert_write(int fd) | |||
302 | abort(); | 344 | abort(); |
303 | } | 345 | } |
304 | 346 | ||
305 | r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE); | 347 | r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE); |
306 | if (r < 0) { | 348 | if (r < 0) { |
307 | printf("mprotect() failed: %m\n"); | 349 | printf("mprotect() failed: %m\n"); |
308 | abort(); | 350 | abort(); |
309 | } | 351 | } |
310 | 352 | ||
311 | *(char *)p = 0; | 353 | *(char *)p = 0; |
312 | munmap(p, MFD_DEF_SIZE); | 354 | munmap(p, mfd_def_size); |
313 | 355 | ||
314 | /* verify PUNCH_HOLE works */ | 356 | /* verify PUNCH_HOLE works */ |
315 | r = fallocate(fd, | 357 | r = fallocate(fd, |
316 | FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, | 358 | FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, |
317 | 0, | 359 | 0, |
318 | MFD_DEF_SIZE); | 360 | mfd_def_size); |
319 | if (r < 0) { | 361 | if (r < 0) { |
320 | printf("fallocate(PUNCH_HOLE) failed: %m\n"); | 362 | printf("fallocate(PUNCH_HOLE) failed: %m\n"); |
321 | abort(); | 363 | abort(); |
@@ -337,7 +379,7 @@ static void mfd_fail_write(int fd) | |||
337 | 379 | ||
338 | /* verify PROT_READ | PROT_WRITE is not allowed */ | 380 | /* verify PROT_READ | PROT_WRITE is not allowed */ |
339 | p = mmap(NULL, | 381 | p = mmap(NULL, |
340 | MFD_DEF_SIZE, | 382 | mfd_def_size, |
341 | PROT_READ | PROT_WRITE, | 383 | PROT_READ | PROT_WRITE, |
342 | MAP_SHARED, | 384 | MAP_SHARED, |
343 | fd, | 385 | fd, |
@@ -349,7 +391,7 @@ static void mfd_fail_write(int fd) | |||
349 | 391 | ||
350 | /* verify PROT_WRITE is not allowed */ | 392 | /* verify PROT_WRITE is not allowed */ |
351 | p = mmap(NULL, | 393 | p = mmap(NULL, |
352 | MFD_DEF_SIZE, | 394 | mfd_def_size, |
353 | PROT_WRITE, | 395 | PROT_WRITE, |
354 | MAP_SHARED, | 396 | MAP_SHARED, |
355 | fd, | 397 | fd, |
@@ -362,13 +404,13 @@ static void mfd_fail_write(int fd) | |||
362 | /* Verify PROT_READ with MAP_SHARED with a following mprotect is not | 404 | /* Verify PROT_READ with MAP_SHARED with a following mprotect is not |
363 | * allowed. Note that for r/w the kernel already prevents the mmap. */ | 405 | * allowed. Note that for r/w the kernel already prevents the mmap. */ |
364 | p = mmap(NULL, | 406 | p = mmap(NULL, |
365 | MFD_DEF_SIZE, | 407 | mfd_def_size, |
366 | PROT_READ, | 408 | PROT_READ, |
367 | MAP_SHARED, | 409 | MAP_SHARED, |
368 | fd, | 410 | fd, |
369 | 0); | 411 | 0); |
370 | if (p != MAP_FAILED) { | 412 | if (p != MAP_FAILED) { |
371 | r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE); | 413 | r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE); |
372 | if (r >= 0) { | 414 | if (r >= 0) { |
373 | printf("mmap()+mprotect() didn't fail as expected\n"); | 415 | printf("mmap()+mprotect() didn't fail as expected\n"); |
374 | abort(); | 416 | abort(); |
@@ -379,7 +421,7 @@ static void mfd_fail_write(int fd) | |||
379 | r = fallocate(fd, | 421 | r = fallocate(fd, |
380 | FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, | 422 | FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, |
381 | 0, | 423 | 0, |
382 | MFD_DEF_SIZE); | 424 | mfd_def_size); |
383 | if (r >= 0) { | 425 | if (r >= 0) { |
384 | printf("fallocate(PUNCH_HOLE) didn't fail as expected\n"); | 426 | printf("fallocate(PUNCH_HOLE) didn't fail as expected\n"); |
385 | abort(); | 427 | abort(); |
@@ -390,13 +432,13 @@ static void mfd_assert_shrink(int fd) | |||
390 | { | 432 | { |
391 | int r, fd2; | 433 | int r, fd2; |
392 | 434 | ||
393 | r = ftruncate(fd, MFD_DEF_SIZE / 2); | 435 | r = ftruncate(fd, mfd_def_size / 2); |
394 | if (r < 0) { | 436 | if (r < 0) { |
395 | printf("ftruncate(SHRINK) failed: %m\n"); | 437 | printf("ftruncate(SHRINK) failed: %m\n"); |
396 | abort(); | 438 | abort(); |
397 | } | 439 | } |
398 | 440 | ||
399 | mfd_assert_size(fd, MFD_DEF_SIZE / 2); | 441 | mfd_assert_size(fd, mfd_def_size / 2); |
400 | 442 | ||
401 | fd2 = mfd_assert_open(fd, | 443 | fd2 = mfd_assert_open(fd, |
402 | O_RDWR | O_CREAT | O_TRUNC, | 444 | O_RDWR | O_CREAT | O_TRUNC, |
@@ -410,7 +452,7 @@ static void mfd_fail_shrink(int fd) | |||
410 | { | 452 | { |
411 | int r; | 453 | int r; |
412 | 454 | ||
413 | r = ftruncate(fd, MFD_DEF_SIZE / 2); | 455 | r = ftruncate(fd, mfd_def_size / 2); |
414 | if (r >= 0) { | 456 | if (r >= 0) { |
415 | printf("ftruncate(SHRINK) didn't fail as expected\n"); | 457 | printf("ftruncate(SHRINK) didn't fail as expected\n"); |
416 | abort(); | 458 | abort(); |
@@ -425,31 +467,31 @@ static void mfd_assert_grow(int fd) | |||
425 | { | 467 | { |
426 | int r; | 468 | int r; |
427 | 469 | ||
428 | r = ftruncate(fd, MFD_DEF_SIZE * 2); | 470 | r = ftruncate(fd, mfd_def_size * 2); |
429 | if (r < 0) { | 471 | if (r < 0) { |
430 | printf("ftruncate(GROW) failed: %m\n"); | 472 | printf("ftruncate(GROW) failed: %m\n"); |
431 | abort(); | 473 | abort(); |
432 | } | 474 | } |
433 | 475 | ||
434 | mfd_assert_size(fd, MFD_DEF_SIZE * 2); | 476 | mfd_assert_size(fd, mfd_def_size * 2); |
435 | 477 | ||
436 | r = fallocate(fd, | 478 | r = fallocate(fd, |
437 | 0, | 479 | 0, |
438 | 0, | 480 | 0, |
439 | MFD_DEF_SIZE * 4); | 481 | mfd_def_size * 4); |
440 | if (r < 0) { | 482 | if (r < 0) { |
441 | printf("fallocate(ALLOC) failed: %m\n"); | 483 | printf("fallocate(ALLOC) failed: %m\n"); |
442 | abort(); | 484 | abort(); |
443 | } | 485 | } |
444 | 486 | ||
445 | mfd_assert_size(fd, MFD_DEF_SIZE * 4); | 487 | mfd_assert_size(fd, mfd_def_size * 4); |
446 | } | 488 | } |
447 | 489 | ||
448 | static void mfd_fail_grow(int fd) | 490 | static void mfd_fail_grow(int fd) |
449 | { | 491 | { |
450 | int r; | 492 | int r; |
451 | 493 | ||
452 | r = ftruncate(fd, MFD_DEF_SIZE * 2); | 494 | r = ftruncate(fd, mfd_def_size * 2); |
453 | if (r >= 0) { | 495 | if (r >= 0) { |
454 | printf("ftruncate(GROW) didn't fail as expected\n"); | 496 | printf("ftruncate(GROW) didn't fail as expected\n"); |
455 | abort(); | 497 | abort(); |
@@ -458,7 +500,7 @@ static void mfd_fail_grow(int fd) | |||
458 | r = fallocate(fd, | 500 | r = fallocate(fd, |
459 | 0, | 501 | 0, |
460 | 0, | 502 | 0, |
461 | MFD_DEF_SIZE * 4); | 503 | mfd_def_size * 4); |
462 | if (r >= 0) { | 504 | if (r >= 0) { |
463 | printf("fallocate(ALLOC) didn't fail as expected\n"); | 505 | printf("fallocate(ALLOC) didn't fail as expected\n"); |
464 | abort(); | 506 | abort(); |
@@ -467,25 +509,37 @@ static void mfd_fail_grow(int fd) | |||
467 | 509 | ||
468 | static void mfd_assert_grow_write(int fd) | 510 | static void mfd_assert_grow_write(int fd) |
469 | { | 511 | { |
470 | static char buf[MFD_DEF_SIZE * 8]; | 512 | static char *buf; |
471 | ssize_t l; | 513 | ssize_t l; |
472 | 514 | ||
473 | l = pwrite(fd, buf, sizeof(buf), 0); | 515 | buf = malloc(mfd_def_size * 8); |
474 | if (l != sizeof(buf)) { | 516 | if (!buf) { |
517 | printf("malloc(%d) failed: %m\n", mfd_def_size * 8); | ||
518 | abort(); | ||
519 | } | ||
520 | |||
521 | l = pwrite(fd, buf, mfd_def_size * 8, 0); | ||
522 | if (l != (mfd_def_size * 8)) { | ||
475 | printf("pwrite() failed: %m\n"); | 523 | printf("pwrite() failed: %m\n"); |
476 | abort(); | 524 | abort(); |
477 | } | 525 | } |
478 | 526 | ||
479 | mfd_assert_size(fd, MFD_DEF_SIZE * 8); | 527 | mfd_assert_size(fd, mfd_def_size * 8); |
480 | } | 528 | } |
481 | 529 | ||
482 | static void mfd_fail_grow_write(int fd) | 530 | static void mfd_fail_grow_write(int fd) |
483 | { | 531 | { |
484 | static char buf[MFD_DEF_SIZE * 8]; | 532 | static char *buf; |
485 | ssize_t l; | 533 | ssize_t l; |
486 | 534 | ||
487 | l = pwrite(fd, buf, sizeof(buf), 0); | 535 | buf = malloc(mfd_def_size * 8); |
488 | if (l == sizeof(buf)) { | 536 | if (!buf) { |
537 | printf("malloc(%d) failed: %m\n", mfd_def_size * 8); | ||
538 | abort(); | ||
539 | } | ||
540 | |||
541 | l = pwrite(fd, buf, mfd_def_size * 8, 0); | ||
542 | if (l == (mfd_def_size * 8)) { | ||
489 | printf("pwrite() didn't fail as expected\n"); | 543 | printf("pwrite() didn't fail as expected\n"); |
490 | abort(); | 544 | abort(); |
491 | } | 545 | } |
@@ -543,6 +597,8 @@ static void test_create(void) | |||
543 | char buf[2048]; | 597 | char buf[2048]; |
544 | int fd; | 598 | int fd; |
545 | 599 | ||
600 | printf("%s CREATE\n", MEMFD_STR); | ||
601 | |||
546 | /* test NULL name */ | 602 | /* test NULL name */ |
547 | mfd_fail_new(NULL, 0); | 603 | mfd_fail_new(NULL, 0); |
548 | 604 | ||
@@ -570,13 +626,18 @@ static void test_create(void) | |||
570 | fd = mfd_assert_new("", 0, MFD_CLOEXEC); | 626 | fd = mfd_assert_new("", 0, MFD_CLOEXEC); |
571 | close(fd); | 627 | close(fd); |
572 | 628 | ||
573 | /* verify MFD_ALLOW_SEALING is allowed */ | 629 | if (!hugetlbfs_test) { |
574 | fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING); | 630 | /* verify MFD_ALLOW_SEALING is allowed */ |
575 | close(fd); | 631 | fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING); |
576 | 632 | close(fd); | |
577 | /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */ | 633 | |
578 | fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC); | 634 | /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */ |
579 | close(fd); | 635 | fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC); |
636 | close(fd); | ||
637 | } else { | ||
638 | /* sealing is not supported on hugetlbfs */ | ||
639 | mfd_fail_new("", MFD_ALLOW_SEALING); | ||
640 | } | ||
580 | } | 641 | } |
581 | 642 | ||
582 | /* | 643 | /* |
@@ -587,8 +648,14 @@ static void test_basic(void) | |||
587 | { | 648 | { |
588 | int fd; | 649 | int fd; |
589 | 650 | ||
651 | /* hugetlbfs does not contain sealing support */ | ||
652 | if (hugetlbfs_test) | ||
653 | return; | ||
654 | |||
655 | printf("%s BASIC\n", MEMFD_STR); | ||
656 | |||
590 | fd = mfd_assert_new("kern_memfd_basic", | 657 | fd = mfd_assert_new("kern_memfd_basic", |
591 | MFD_DEF_SIZE, | 658 | mfd_def_size, |
592 | MFD_CLOEXEC | MFD_ALLOW_SEALING); | 659 | MFD_CLOEXEC | MFD_ALLOW_SEALING); |
593 | 660 | ||
594 | /* add basic seals */ | 661 | /* add basic seals */ |
@@ -619,7 +686,7 @@ static void test_basic(void) | |||
619 | 686 | ||
620 | /* verify sealing does not work without MFD_ALLOW_SEALING */ | 687 | /* verify sealing does not work without MFD_ALLOW_SEALING */ |
621 | fd = mfd_assert_new("kern_memfd_basic", | 688 | fd = mfd_assert_new("kern_memfd_basic", |
622 | MFD_DEF_SIZE, | 689 | mfd_def_size, |
623 | MFD_CLOEXEC); | 690 | MFD_CLOEXEC); |
624 | mfd_assert_has_seals(fd, F_SEAL_SEAL); | 691 | mfd_assert_has_seals(fd, F_SEAL_SEAL); |
625 | mfd_fail_add_seals(fd, F_SEAL_SHRINK | | 692 | mfd_fail_add_seals(fd, F_SEAL_SHRINK | |
@@ -630,6 +697,28 @@ static void test_basic(void) | |||
630 | } | 697 | } |
631 | 698 | ||
632 | /* | 699 | /* |
700 | * hugetlbfs doesn't support seals or write, so just verify grow and shrink | ||
701 | * on a hugetlbfs file created via memfd_create. | ||
702 | */ | ||
703 | static void test_hugetlbfs_grow_shrink(void) | ||
704 | { | ||
705 | int fd; | ||
706 | |||
707 | printf("%s HUGETLBFS-GROW-SHRINK\n", MEMFD_STR); | ||
708 | |||
709 | fd = mfd_assert_new("kern_memfd_seal_write", | ||
710 | mfd_def_size, | ||
711 | MFD_CLOEXEC); | ||
712 | |||
713 | mfd_assert_read(fd); | ||
714 | mfd_assert_write(fd); | ||
715 | mfd_assert_shrink(fd); | ||
716 | mfd_assert_grow(fd); | ||
717 | |||
718 | close(fd); | ||
719 | } | ||
720 | |||
721 | /* | ||
633 | * Test SEAL_WRITE | 722 | * Test SEAL_WRITE |
634 | * Test whether SEAL_WRITE actually prevents modifications. | 723 | * Test whether SEAL_WRITE actually prevents modifications. |
635 | */ | 724 | */ |
@@ -637,8 +726,17 @@ static void test_seal_write(void) | |||
637 | { | 726 | { |
638 | int fd; | 727 | int fd; |
639 | 728 | ||
729 | /* | ||
730 | * hugetlbfs does not contain sealing or write support. Just test | ||
731 | * basic grow and shrink via test_hugetlbfs_grow_shrink. | ||
732 | */ | ||
733 | if (hugetlbfs_test) | ||
734 | return test_hugetlbfs_grow_shrink(); | ||
735 | |||
736 | printf("%s SEAL-WRITE\n", MEMFD_STR); | ||
737 | |||
640 | fd = mfd_assert_new("kern_memfd_seal_write", | 738 | fd = mfd_assert_new("kern_memfd_seal_write", |
641 | MFD_DEF_SIZE, | 739 | mfd_def_size, |
642 | MFD_CLOEXEC | MFD_ALLOW_SEALING); | 740 | MFD_CLOEXEC | MFD_ALLOW_SEALING); |
643 | mfd_assert_has_seals(fd, 0); | 741 | mfd_assert_has_seals(fd, 0); |
644 | mfd_assert_add_seals(fd, F_SEAL_WRITE); | 742 | mfd_assert_add_seals(fd, F_SEAL_WRITE); |
@@ -661,8 +759,14 @@ static void test_seal_shrink(void) | |||
661 | { | 759 | { |
662 | int fd; | 760 | int fd; |
663 | 761 | ||
762 | /* hugetlbfs does not contain sealing support */ | ||
763 | if (hugetlbfs_test) | ||
764 | return; | ||
765 | |||
766 | printf("%s SEAL-SHRINK\n", MEMFD_STR); | ||
767 | |||
664 | fd = mfd_assert_new("kern_memfd_seal_shrink", | 768 | fd = mfd_assert_new("kern_memfd_seal_shrink", |
665 | MFD_DEF_SIZE, | 769 | mfd_def_size, |
666 | MFD_CLOEXEC | MFD_ALLOW_SEALING); | 770 | MFD_CLOEXEC | MFD_ALLOW_SEALING); |
667 | mfd_assert_has_seals(fd, 0); | 771 | mfd_assert_has_seals(fd, 0); |
668 | mfd_assert_add_seals(fd, F_SEAL_SHRINK); | 772 | mfd_assert_add_seals(fd, F_SEAL_SHRINK); |
@@ -685,8 +789,14 @@ static void test_seal_grow(void) | |||
685 | { | 789 | { |
686 | int fd; | 790 | int fd; |
687 | 791 | ||
792 | /* hugetlbfs does not contain sealing support */ | ||
793 | if (hugetlbfs_test) | ||
794 | return; | ||
795 | |||
796 | printf("%s SEAL-GROW\n", MEMFD_STR); | ||
797 | |||
688 | fd = mfd_assert_new("kern_memfd_seal_grow", | 798 | fd = mfd_assert_new("kern_memfd_seal_grow", |
689 | MFD_DEF_SIZE, | 799 | mfd_def_size, |
690 | MFD_CLOEXEC | MFD_ALLOW_SEALING); | 800 | MFD_CLOEXEC | MFD_ALLOW_SEALING); |
691 | mfd_assert_has_seals(fd, 0); | 801 | mfd_assert_has_seals(fd, 0); |
692 | mfd_assert_add_seals(fd, F_SEAL_GROW); | 802 | mfd_assert_add_seals(fd, F_SEAL_GROW); |
@@ -709,8 +819,14 @@ static void test_seal_resize(void) | |||
709 | { | 819 | { |
710 | int fd; | 820 | int fd; |
711 | 821 | ||
822 | /* hugetlbfs does not contain sealing support */ | ||
823 | if (hugetlbfs_test) | ||
824 | return; | ||
825 | |||
826 | printf("%s SEAL-RESIZE\n", MEMFD_STR); | ||
827 | |||
712 | fd = mfd_assert_new("kern_memfd_seal_resize", | 828 | fd = mfd_assert_new("kern_memfd_seal_resize", |
713 | MFD_DEF_SIZE, | 829 | mfd_def_size, |
714 | MFD_CLOEXEC | MFD_ALLOW_SEALING); | 830 | MFD_CLOEXEC | MFD_ALLOW_SEALING); |
715 | mfd_assert_has_seals(fd, 0); | 831 | mfd_assert_has_seals(fd, 0); |
716 | mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW); | 832 | mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW); |
@@ -726,15 +842,52 @@ static void test_seal_resize(void) | |||
726 | } | 842 | } |
727 | 843 | ||
728 | /* | 844 | /* |
845 | * hugetlbfs does not support seals. Basic test to dup the memfd created | ||
846 | * fd and perform some basic operations on it. | ||
847 | */ | ||
848 | static void hugetlbfs_dup(char *b_suffix) | ||
849 | { | ||
850 | int fd, fd2; | ||
851 | |||
852 | printf("%s HUGETLBFS-DUP %s\n", MEMFD_STR, b_suffix); | ||
853 | |||
854 | fd = mfd_assert_new("kern_memfd_share_dup", | ||
855 | mfd_def_size, | ||
856 | MFD_CLOEXEC); | ||
857 | |||
858 | fd2 = mfd_assert_dup(fd); | ||
859 | |||
860 | mfd_assert_read(fd); | ||
861 | mfd_assert_write(fd); | ||
862 | |||
863 | mfd_assert_shrink(fd2); | ||
864 | mfd_assert_grow(fd2); | ||
865 | |||
866 | close(fd2); | ||
867 | close(fd); | ||
868 | } | ||
869 | |||
870 | /* | ||
729 | * Test sharing via dup() | 871 | * Test sharing via dup() |
730 | * Test that seals are shared between dupped FDs and they're all equal. | 872 | * Test that seals are shared between dupped FDs and they're all equal. |
731 | */ | 873 | */ |
732 | static void test_share_dup(void) | 874 | static void test_share_dup(char *banner, char *b_suffix) |
733 | { | 875 | { |
734 | int fd, fd2; | 876 | int fd, fd2; |
735 | 877 | ||
878 | /* | ||
879 | * hugetlbfs does not contain sealing support. Perform some | ||
880 | * basic testing on dup'ed fd instead via hugetlbfs_dup. | ||
881 | */ | ||
882 | if (hugetlbfs_test) { | ||
883 | hugetlbfs_dup(b_suffix); | ||
884 | return; | ||
885 | } | ||
886 | |||
887 | printf("%s %s %s\n", MEMFD_STR, banner, b_suffix); | ||
888 | |||
736 | fd = mfd_assert_new("kern_memfd_share_dup", | 889 | fd = mfd_assert_new("kern_memfd_share_dup", |
737 | MFD_DEF_SIZE, | 890 | mfd_def_size, |
738 | MFD_CLOEXEC | MFD_ALLOW_SEALING); | 891 | MFD_CLOEXEC | MFD_ALLOW_SEALING); |
739 | mfd_assert_has_seals(fd, 0); | 892 | mfd_assert_has_seals(fd, 0); |
740 | 893 | ||
@@ -768,13 +921,19 @@ static void test_share_dup(void) | |||
768 | * Test sealing with active mmap()s | 921 | * Test sealing with active mmap()s |
769 | * Modifying seals is only allowed if no other mmap() refs exist. | 922 | * Modifying seals is only allowed if no other mmap() refs exist. |
770 | */ | 923 | */ |
771 | static void test_share_mmap(void) | 924 | static void test_share_mmap(char *banner, char *b_suffix) |
772 | { | 925 | { |
773 | int fd; | 926 | int fd; |
774 | void *p; | 927 | void *p; |
775 | 928 | ||
929 | /* hugetlbfs does not contain sealing support */ | ||
930 | if (hugetlbfs_test) | ||
931 | return; | ||
932 | |||
933 | printf("%s %s %s\n", MEMFD_STR, banner, b_suffix); | ||
934 | |||
776 | fd = mfd_assert_new("kern_memfd_share_mmap", | 935 | fd = mfd_assert_new("kern_memfd_share_mmap", |
777 | MFD_DEF_SIZE, | 936 | mfd_def_size, |
778 | MFD_CLOEXEC | MFD_ALLOW_SEALING); | 937 | MFD_CLOEXEC | MFD_ALLOW_SEALING); |
779 | mfd_assert_has_seals(fd, 0); | 938 | mfd_assert_has_seals(fd, 0); |
780 | 939 | ||
@@ -784,14 +943,40 @@ static void test_share_mmap(void) | |||
784 | mfd_assert_has_seals(fd, 0); | 943 | mfd_assert_has_seals(fd, 0); |
785 | mfd_assert_add_seals(fd, F_SEAL_SHRINK); | 944 | mfd_assert_add_seals(fd, F_SEAL_SHRINK); |
786 | mfd_assert_has_seals(fd, F_SEAL_SHRINK); | 945 | mfd_assert_has_seals(fd, F_SEAL_SHRINK); |
787 | munmap(p, MFD_DEF_SIZE); | 946 | munmap(p, mfd_def_size); |
788 | 947 | ||
789 | /* readable ref allows sealing */ | 948 | /* readable ref allows sealing */ |
790 | p = mfd_assert_mmap_private(fd); | 949 | p = mfd_assert_mmap_private(fd); |
791 | mfd_assert_add_seals(fd, F_SEAL_WRITE); | 950 | mfd_assert_add_seals(fd, F_SEAL_WRITE); |
792 | mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); | 951 | mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); |
793 | munmap(p, MFD_DEF_SIZE); | 952 | munmap(p, mfd_def_size); |
953 | |||
954 | close(fd); | ||
955 | } | ||
956 | |||
957 | /* | ||
958 | * Basic test to make sure we can open the hugetlbfs fd via /proc and | ||
959 | * perform some simple operations on it. | ||
960 | */ | ||
961 | static void hugetlbfs_proc_open(char *b_suffix) | ||
962 | { | ||
963 | int fd, fd2; | ||
964 | |||
965 | printf("%s HUGETLBFS-PROC-OPEN %s\n", MEMFD_STR, b_suffix); | ||
794 | 966 | ||
967 | fd = mfd_assert_new("kern_memfd_share_open", | ||
968 | mfd_def_size, | ||
969 | MFD_CLOEXEC); | ||
970 | |||
971 | fd2 = mfd_assert_open(fd, O_RDWR, 0); | ||
972 | |||
973 | mfd_assert_read(fd); | ||
974 | mfd_assert_write(fd); | ||
975 | |||
976 | mfd_assert_shrink(fd2); | ||
977 | mfd_assert_grow(fd2); | ||
978 | |||
979 | close(fd2); | ||
795 | close(fd); | 980 | close(fd); |
796 | } | 981 | } |
797 | 982 | ||
@@ -801,12 +986,23 @@ static void test_share_mmap(void) | |||
801 | * This is *not* like dup(), but like a real separate open(). Make sure the | 986 | * This is *not* like dup(), but like a real separate open(). Make sure the |
802 | * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR. | 987 | * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR. |
803 | */ | 988 | */ |
804 | static void test_share_open(void) | 989 | static void test_share_open(char *banner, char *b_suffix) |
805 | { | 990 | { |
806 | int fd, fd2; | 991 | int fd, fd2; |
807 | 992 | ||
993 | /* | ||
994 | * hugetlbfs does not contain sealing support. So test basic | ||
995 | * functionality of using /proc fd via hugetlbfs_proc_open | ||
996 | */ | ||
997 | if (hugetlbfs_test) { | ||
998 | hugetlbfs_proc_open(b_suffix); | ||
999 | return; | ||
1000 | } | ||
1001 | |||
1002 | printf("%s %s %s\n", MEMFD_STR, banner, b_suffix); | ||
1003 | |||
808 | fd = mfd_assert_new("kern_memfd_share_open", | 1004 | fd = mfd_assert_new("kern_memfd_share_open", |
809 | MFD_DEF_SIZE, | 1005 | mfd_def_size, |
810 | MFD_CLOEXEC | MFD_ALLOW_SEALING); | 1006 | MFD_CLOEXEC | MFD_ALLOW_SEALING); |
811 | mfd_assert_has_seals(fd, 0); | 1007 | mfd_assert_has_seals(fd, 0); |
812 | 1008 | ||
@@ -841,13 +1037,19 @@ static void test_share_open(void) | |||
841 | * Test sharing via fork() | 1037 | * Test sharing via fork() |
842 | * Test whether seal-modifications work as expected with forked childs. | 1038 | * Test whether seal-modifications work as expected with forked childs. |
843 | */ | 1039 | */ |
844 | static void test_share_fork(void) | 1040 | static void test_share_fork(char *banner, char *b_suffix) |
845 | { | 1041 | { |
846 | int fd; | 1042 | int fd; |
847 | pid_t pid; | 1043 | pid_t pid; |
848 | 1044 | ||
1045 | /* hugetlbfs does not contain sealing support */ | ||
1046 | if (hugetlbfs_test) | ||
1047 | return; | ||
1048 | |||
1049 | printf("%s %s %s\n", MEMFD_STR, banner, b_suffix); | ||
1050 | |||
849 | fd = mfd_assert_new("kern_memfd_share_fork", | 1051 | fd = mfd_assert_new("kern_memfd_share_fork", |
850 | MFD_DEF_SIZE, | 1052 | mfd_def_size, |
851 | MFD_CLOEXEC | MFD_ALLOW_SEALING); | 1053 | MFD_CLOEXEC | MFD_ALLOW_SEALING); |
852 | mfd_assert_has_seals(fd, 0); | 1054 | mfd_assert_has_seals(fd, 0); |
853 | 1055 | ||
@@ -870,40 +1072,40 @@ int main(int argc, char **argv) | |||
870 | { | 1072 | { |
871 | pid_t pid; | 1073 | pid_t pid; |
872 | 1074 | ||
873 | printf("memfd: CREATE\n"); | 1075 | if (argc == 2) { |
1076 | if (!strcmp(argv[1], "hugetlbfs")) { | ||
1077 | unsigned long hpage_size = default_huge_page_size(); | ||
1078 | |||
1079 | if (!hpage_size) { | ||
1080 | printf("Unable to determine huge page size\n"); | ||
1081 | abort(); | ||
1082 | } | ||
1083 | |||
1084 | hugetlbfs_test = 1; | ||
1085 | mfd_def_size = hpage_size * 2; | ||
1086 | } | ||
1087 | } | ||
1088 | |||
874 | test_create(); | 1089 | test_create(); |
875 | printf("memfd: BASIC\n"); | ||
876 | test_basic(); | 1090 | test_basic(); |
877 | 1091 | ||
878 | printf("memfd: SEAL-WRITE\n"); | ||
879 | test_seal_write(); | 1092 | test_seal_write(); |
880 | printf("memfd: SEAL-SHRINK\n"); | ||
881 | test_seal_shrink(); | 1093 | test_seal_shrink(); |
882 | printf("memfd: SEAL-GROW\n"); | ||
883 | test_seal_grow(); | 1094 | test_seal_grow(); |
884 | printf("memfd: SEAL-RESIZE\n"); | ||
885 | test_seal_resize(); | 1095 | test_seal_resize(); |
886 | 1096 | ||
887 | printf("memfd: SHARE-DUP\n"); | 1097 | test_share_dup("SHARE-DUP", ""); |
888 | test_share_dup(); | 1098 | test_share_mmap("SHARE-MMAP", ""); |
889 | printf("memfd: SHARE-MMAP\n"); | 1099 | test_share_open("SHARE-OPEN", ""); |
890 | test_share_mmap(); | 1100 | test_share_fork("SHARE-FORK", ""); |
891 | printf("memfd: SHARE-OPEN\n"); | ||
892 | test_share_open(); | ||
893 | printf("memfd: SHARE-FORK\n"); | ||
894 | test_share_fork(); | ||
895 | 1101 | ||
896 | /* Run test-suite in a multi-threaded environment with a shared | 1102 | /* Run test-suite in a multi-threaded environment with a shared |
897 | * file-table. */ | 1103 | * file-table. */ |
898 | pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM); | 1104 | pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM); |
899 | printf("memfd: SHARE-DUP (shared file-table)\n"); | 1105 | test_share_dup("SHARE-DUP", SHARED_FT_STR); |
900 | test_share_dup(); | 1106 | test_share_mmap("SHARE-MMAP", SHARED_FT_STR); |
901 | printf("memfd: SHARE-MMAP (shared file-table)\n"); | 1107 | test_share_open("SHARE-OPEN", SHARED_FT_STR); |
902 | test_share_mmap(); | 1108 | test_share_fork("SHARE-FORK", SHARED_FT_STR); |
903 | printf("memfd: SHARE-OPEN (shared file-table)\n"); | ||
904 | test_share_open(); | ||
905 | printf("memfd: SHARE-FORK (shared file-table)\n"); | ||
906 | test_share_fork(); | ||
907 | join_idle_thread(pid); | 1109 | join_idle_thread(pid); |
908 | 1110 | ||
909 | printf("memfd: DONE\n"); | 1111 | printf("memfd: DONE\n"); |
diff --git a/tools/testing/selftests/memfd/run_tests.sh b/tools/testing/selftests/memfd/run_tests.sh new file mode 100755 index 000000000000..daabb350697c --- /dev/null +++ b/tools/testing/selftests/memfd/run_tests.sh | |||
@@ -0,0 +1,69 @@ | |||
1 | #!/bin/bash | ||
2 | # please run as root | ||
3 | |||
4 | # | ||
5 | # Normal tests requiring no special resources | ||
6 | # | ||
7 | ./run_fuse_test.sh | ||
8 | ./memfd_test | ||
9 | |||
10 | # | ||
11 | # To test memfd_create with hugetlbfs, there needs to be hpages_test | ||
12 | # huge pages free. Attempt to allocate enough pages to test. | ||
13 | # | ||
14 | hpages_test=8 | ||
15 | |||
16 | # | ||
17 | # Get count of free huge pages from /proc/meminfo | ||
18 | # | ||
19 | while read name size unit; do | ||
20 | if [ "$name" = "HugePages_Free:" ]; then | ||
21 | freepgs=$size | ||
22 | fi | ||
23 | done < /proc/meminfo | ||
24 | |||
25 | # | ||
26 | # If not enough free huge pages for test, attempt to increase | ||
27 | # | ||
28 | if [ -n "$freepgs" ] && [ $freepgs -lt $hpages_test ]; then | ||
29 | nr_hugepgs=`cat /proc/sys/vm/nr_hugepages` | ||
30 | hpages_needed=`expr $hpages_test - $freepgs` | ||
31 | |||
32 | echo 3 > /proc/sys/vm/drop_caches | ||
33 | echo $(( $hpages_needed + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages | ||
34 | if [ $? -ne 0 ]; then | ||
35 | echo "Please run this test as root" | ||
36 | exit 1 | ||
37 | fi | ||
38 | while read name size unit; do | ||
39 | if [ "$name" = "HugePages_Free:" ]; then | ||
40 | freepgs=$size | ||
41 | fi | ||
42 | done < /proc/meminfo | ||
43 | fi | ||
44 | |||
45 | # | ||
46 | # If still not enough huge pages available, exit. But, give back any huge | ||
47 | # pages potentially allocated above. | ||
48 | # | ||
49 | if [ $freepgs -lt $hpages_test ]; then | ||
50 | # nr_hugepgs non-zero only if we attempted to increase | ||
51 | if [ -n "$nr_hugepgs" ]; then | ||
52 | echo $nr_hugepgs > /proc/sys/vm/nr_hugepages | ||
53 | fi | ||
54 | printf "Not enough huge pages available (%d < %d)\n" \ | ||
55 | $freepgs $needpgs | ||
56 | exit 1 | ||
57 | fi | ||
58 | |||
59 | # | ||
60 | # Run the hugetlbfs test | ||
61 | # | ||
62 | ./memfd_test hugetlbfs | ||
63 | |||
64 | # | ||
65 | # Give back any huge pages allocated for the test | ||
66 | # | ||
67 | if [ -n "$nr_hugepgs" ]; then | ||
68 | echo $nr_hugepgs > /proc/sys/vm/nr_hugepages | ||
69 | fi | ||
diff --git a/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile index 79a664aeb8d7..152823b6cb21 100644 --- a/tools/testing/selftests/mqueue/Makefile +++ b/tools/testing/selftests/mqueue/Makefile | |||
@@ -5,8 +5,8 @@ TEST_GEN_PROGS := mq_open_tests mq_perf_tests | |||
5 | include ../lib.mk | 5 | include ../lib.mk |
6 | 6 | ||
7 | override define RUN_TESTS | 7 | override define RUN_TESTS |
8 | @./mq_open_tests /test1 || echo "selftests: mq_open_tests [FAIL]" | 8 | @$(OUTPUT)/mq_open_tests /test1 || echo "selftests: mq_open_tests [FAIL]" |
9 | @./mq_perf_tests || echo "selftests: mq_perf_tests [FAIL]" | 9 | @$(OUTPUT)/mq_perf_tests || echo "selftests: mq_perf_tests [FAIL]" |
10 | endef | 10 | endef |
11 | 11 | ||
12 | override define EMIT_TESTS | 12 | override define EMIT_TESTS |
diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore index afe109e5508a..c612d6e38c62 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore | |||
@@ -1,3 +1,4 @@ | |||
1 | msg_zerocopy | ||
1 | socket | 2 | socket |
2 | psock_fanout | 3 | psock_fanout |
3 | psock_tpacket | 4 | psock_tpacket |
@@ -5,3 +6,4 @@ reuseport_bpf | |||
5 | reuseport_bpf_cpu | 6 | reuseport_bpf_cpu |
6 | reuseport_bpf_numa | 7 | reuseport_bpf_numa |
7 | reuseport_dualstack | 8 | reuseport_dualstack |
9 | reuseaddr_conflict | ||
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index f6c9dbf478f8..d86bca991f45 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile | |||
@@ -3,11 +3,11 @@ | |||
3 | CFLAGS = -Wall -Wl,--no-as-needed -O2 -g | 3 | CFLAGS = -Wall -Wl,--no-as-needed -O2 -g |
4 | CFLAGS += -I../../../../usr/include/ | 4 | CFLAGS += -I../../../../usr/include/ |
5 | 5 | ||
6 | TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh | 6 | TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh |
7 | TEST_GEN_FILES = socket | 7 | TEST_GEN_FILES = socket |
8 | TEST_GEN_FILES += psock_fanout psock_tpacket | 8 | TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy |
9 | TEST_GEN_FILES += reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa | 9 | TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa |
10 | TEST_GEN_FILES += reuseport_dualstack | 10 | TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict |
11 | 11 | ||
12 | include ../lib.mk | 12 | include ../lib.mk |
13 | 13 | ||
diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c new file mode 100644 index 000000000000..3ab6ec403905 --- /dev/null +++ b/tools/testing/selftests/net/msg_zerocopy.c | |||
@@ -0,0 +1,697 @@ | |||
1 | /* Evaluate MSG_ZEROCOPY | ||
2 | * | ||
3 | * Send traffic between two processes over one of the supported | ||
4 | * protocols and modes: | ||
5 | * | ||
6 | * PF_INET/PF_INET6 | ||
7 | * - SOCK_STREAM | ||
8 | * - SOCK_DGRAM | ||
9 | * - SOCK_DGRAM with UDP_CORK | ||
10 | * - SOCK_RAW | ||
11 | * - SOCK_RAW with IP_HDRINCL | ||
12 | * | ||
13 | * PF_PACKET | ||
14 | * - SOCK_DGRAM | ||
15 | * - SOCK_RAW | ||
16 | * | ||
17 | * Start this program on two connected hosts, one in send mode and | ||
18 | * the other with option '-r' to put it in receiver mode. | ||
19 | * | ||
20 | * If zerocopy mode ('-z') is enabled, the sender will verify that | ||
21 | * the kernel queues completions on the error queue for all zerocopy | ||
22 | * transfers. | ||
23 | */ | ||
24 | |||
25 | #define _GNU_SOURCE | ||
26 | |||
27 | #include <arpa/inet.h> | ||
28 | #include <error.h> | ||
29 | #include <errno.h> | ||
30 | #include <limits.h> | ||
31 | #include <linux/errqueue.h> | ||
32 | #include <linux/if_packet.h> | ||
33 | #include <linux/ipv6.h> | ||
34 | #include <linux/socket.h> | ||
35 | #include <linux/sockios.h> | ||
36 | #include <net/ethernet.h> | ||
37 | #include <net/if.h> | ||
38 | #include <netinet/ip.h> | ||
39 | #include <netinet/ip6.h> | ||
40 | #include <netinet/tcp.h> | ||
41 | #include <netinet/udp.h> | ||
42 | #include <poll.h> | ||
43 | #include <sched.h> | ||
44 | #include <stdbool.h> | ||
45 | #include <stdio.h> | ||
46 | #include <stdint.h> | ||
47 | #include <stdlib.h> | ||
48 | #include <string.h> | ||
49 | #include <sys/ioctl.h> | ||
50 | #include <sys/socket.h> | ||
51 | #include <sys/stat.h> | ||
52 | #include <sys/time.h> | ||
53 | #include <sys/types.h> | ||
54 | #include <sys/wait.h> | ||
55 | #include <unistd.h> | ||
56 | |||
57 | #ifndef SO_EE_ORIGIN_ZEROCOPY | ||
58 | #define SO_EE_ORIGIN_ZEROCOPY 5 | ||
59 | #endif | ||
60 | |||
61 | #ifndef SO_ZEROCOPY | ||
62 | #define SO_ZEROCOPY 60 | ||
63 | #endif | ||
64 | |||
65 | #ifndef SO_EE_CODE_ZEROCOPY_COPIED | ||
66 | #define SO_EE_CODE_ZEROCOPY_COPIED 1 | ||
67 | #endif | ||
68 | |||
69 | #ifndef MSG_ZEROCOPY | ||
70 | #define MSG_ZEROCOPY 0x4000000 | ||
71 | #endif | ||
72 | |||
73 | static int cfg_cork; | ||
74 | static bool cfg_cork_mixed; | ||
75 | static int cfg_cpu = -1; /* default: pin to last cpu */ | ||
76 | static int cfg_family = PF_UNSPEC; | ||
77 | static int cfg_ifindex = 1; | ||
78 | static int cfg_payload_len; | ||
79 | static int cfg_port = 8000; | ||
80 | static bool cfg_rx; | ||
81 | static int cfg_runtime_ms = 4200; | ||
82 | static int cfg_verbose; | ||
83 | static int cfg_waittime_ms = 500; | ||
84 | static bool cfg_zerocopy; | ||
85 | |||
86 | static socklen_t cfg_alen; | ||
87 | static struct sockaddr_storage cfg_dst_addr; | ||
88 | static struct sockaddr_storage cfg_src_addr; | ||
89 | |||
90 | static char payload[IP_MAXPACKET]; | ||
91 | static long packets, bytes, completions, expected_completions; | ||
92 | static int zerocopied = -1; | ||
93 | static uint32_t next_completion; | ||
94 | |||
95 | static unsigned long gettimeofday_ms(void) | ||
96 | { | ||
97 | struct timeval tv; | ||
98 | |||
99 | gettimeofday(&tv, NULL); | ||
100 | return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); | ||
101 | } | ||
102 | |||
103 | static uint16_t get_ip_csum(const uint16_t *start, int num_words) | ||
104 | { | ||
105 | unsigned long sum = 0; | ||
106 | int i; | ||
107 | |||
108 | for (i = 0; i < num_words; i++) | ||
109 | sum += start[i]; | ||
110 | |||
111 | while (sum >> 16) | ||
112 | sum = (sum & 0xFFFF) + (sum >> 16); | ||
113 | |||
114 | return ~sum; | ||
115 | } | ||
116 | |||
117 | static int do_setcpu(int cpu) | ||
118 | { | ||
119 | cpu_set_t mask; | ||
120 | |||
121 | CPU_ZERO(&mask); | ||
122 | CPU_SET(cpu, &mask); | ||
123 | if (sched_setaffinity(0, sizeof(mask), &mask)) | ||
124 | error(1, 0, "setaffinity %d", cpu); | ||
125 | |||
126 | if (cfg_verbose) | ||
127 | fprintf(stderr, "cpu: %u\n", cpu); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static void do_setsockopt(int fd, int level, int optname, int val) | ||
133 | { | ||
134 | if (setsockopt(fd, level, optname, &val, sizeof(val))) | ||
135 | error(1, errno, "setsockopt %d.%d: %d", level, optname, val); | ||
136 | } | ||
137 | |||
138 | static int do_poll(int fd, int events) | ||
139 | { | ||
140 | struct pollfd pfd; | ||
141 | int ret; | ||
142 | |||
143 | pfd.events = events; | ||
144 | pfd.revents = 0; | ||
145 | pfd.fd = fd; | ||
146 | |||
147 | ret = poll(&pfd, 1, cfg_waittime_ms); | ||
148 | if (ret == -1) | ||
149 | error(1, errno, "poll"); | ||
150 | |||
151 | return ret && (pfd.revents & events); | ||
152 | } | ||
153 | |||
154 | static int do_accept(int fd) | ||
155 | { | ||
156 | int fda = fd; | ||
157 | |||
158 | fd = accept(fda, NULL, NULL); | ||
159 | if (fd == -1) | ||
160 | error(1, errno, "accept"); | ||
161 | if (close(fda)) | ||
162 | error(1, errno, "close listen sock"); | ||
163 | |||
164 | return fd; | ||
165 | } | ||
166 | |||
167 | static bool do_sendmsg(int fd, struct msghdr *msg, bool do_zerocopy) | ||
168 | { | ||
169 | int ret, len, i, flags; | ||
170 | |||
171 | len = 0; | ||
172 | for (i = 0; i < msg->msg_iovlen; i++) | ||
173 | len += msg->msg_iov[i].iov_len; | ||
174 | |||
175 | flags = MSG_DONTWAIT; | ||
176 | if (do_zerocopy) | ||
177 | flags |= MSG_ZEROCOPY; | ||
178 | |||
179 | ret = sendmsg(fd, msg, flags); | ||
180 | if (ret == -1 && errno == EAGAIN) | ||
181 | return false; | ||
182 | if (ret == -1) | ||
183 | error(1, errno, "send"); | ||
184 | if (cfg_verbose && ret != len) | ||
185 | fprintf(stderr, "send: ret=%u != %u\n", ret, len); | ||
186 | |||
187 | if (len) { | ||
188 | packets++; | ||
189 | bytes += ret; | ||
190 | if (do_zerocopy && ret) | ||
191 | expected_completions++; | ||
192 | } | ||
193 | |||
194 | return true; | ||
195 | } | ||
196 | |||
197 | static void do_sendmsg_corked(int fd, struct msghdr *msg) | ||
198 | { | ||
199 | bool do_zerocopy = cfg_zerocopy; | ||
200 | int i, payload_len, extra_len; | ||
201 | |||
202 | /* split up the packet. for non-multiple, make first buffer longer */ | ||
203 | payload_len = cfg_payload_len / cfg_cork; | ||
204 | extra_len = cfg_payload_len - (cfg_cork * payload_len); | ||
205 | |||
206 | do_setsockopt(fd, IPPROTO_UDP, UDP_CORK, 1); | ||
207 | |||
208 | for (i = 0; i < cfg_cork; i++) { | ||
209 | |||
210 | /* in mixed-frags mode, alternate zerocopy and copy frags | ||
211 | * start with non-zerocopy, to ensure attach later works | ||
212 | */ | ||
213 | if (cfg_cork_mixed) | ||
214 | do_zerocopy = (i & 1); | ||
215 | |||
216 | msg->msg_iov[0].iov_len = payload_len + extra_len; | ||
217 | extra_len = 0; | ||
218 | |||
219 | do_sendmsg(fd, msg, do_zerocopy); | ||
220 | } | ||
221 | |||
222 | do_setsockopt(fd, IPPROTO_UDP, UDP_CORK, 0); | ||
223 | } | ||
224 | |||
225 | static int setup_iph(struct iphdr *iph, uint16_t payload_len) | ||
226 | { | ||
227 | struct sockaddr_in *daddr = (void *) &cfg_dst_addr; | ||
228 | struct sockaddr_in *saddr = (void *) &cfg_src_addr; | ||
229 | |||
230 | memset(iph, 0, sizeof(*iph)); | ||
231 | |||
232 | iph->version = 4; | ||
233 | iph->tos = 0; | ||
234 | iph->ihl = 5; | ||
235 | iph->ttl = 2; | ||
236 | iph->saddr = saddr->sin_addr.s_addr; | ||
237 | iph->daddr = daddr->sin_addr.s_addr; | ||
238 | iph->protocol = IPPROTO_EGP; | ||
239 | iph->tot_len = htons(sizeof(*iph) + payload_len); | ||
240 | iph->check = get_ip_csum((void *) iph, iph->ihl << 1); | ||
241 | |||
242 | return sizeof(*iph); | ||
243 | } | ||
244 | |||
245 | static int setup_ip6h(struct ipv6hdr *ip6h, uint16_t payload_len) | ||
246 | { | ||
247 | struct sockaddr_in6 *daddr = (void *) &cfg_dst_addr; | ||
248 | struct sockaddr_in6 *saddr = (void *) &cfg_src_addr; | ||
249 | |||
250 | memset(ip6h, 0, sizeof(*ip6h)); | ||
251 | |||
252 | ip6h->version = 6; | ||
253 | ip6h->payload_len = htons(payload_len); | ||
254 | ip6h->nexthdr = IPPROTO_EGP; | ||
255 | ip6h->hop_limit = 2; | ||
256 | ip6h->saddr = saddr->sin6_addr; | ||
257 | ip6h->daddr = daddr->sin6_addr; | ||
258 | |||
259 | return sizeof(*ip6h); | ||
260 | } | ||
261 | |||
262 | static void setup_sockaddr(int domain, const char *str_addr, void *sockaddr) | ||
263 | { | ||
264 | struct sockaddr_in6 *addr6 = (void *) sockaddr; | ||
265 | struct sockaddr_in *addr4 = (void *) sockaddr; | ||
266 | |||
267 | switch (domain) { | ||
268 | case PF_INET: | ||
269 | addr4->sin_family = AF_INET; | ||
270 | addr4->sin_port = htons(cfg_port); | ||
271 | if (inet_pton(AF_INET, str_addr, &(addr4->sin_addr)) != 1) | ||
272 | error(1, 0, "ipv4 parse error: %s", str_addr); | ||
273 | break; | ||
274 | case PF_INET6: | ||
275 | addr6->sin6_family = AF_INET6; | ||
276 | addr6->sin6_port = htons(cfg_port); | ||
277 | if (inet_pton(AF_INET6, str_addr, &(addr6->sin6_addr)) != 1) | ||
278 | error(1, 0, "ipv6 parse error: %s", str_addr); | ||
279 | break; | ||
280 | default: | ||
281 | error(1, 0, "illegal domain"); | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static int do_setup_tx(int domain, int type, int protocol) | ||
286 | { | ||
287 | int fd; | ||
288 | |||
289 | fd = socket(domain, type, protocol); | ||
290 | if (fd == -1) | ||
291 | error(1, errno, "socket t"); | ||
292 | |||
293 | do_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, 1 << 21); | ||
294 | if (cfg_zerocopy) | ||
295 | do_setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, 1); | ||
296 | |||
297 | if (domain != PF_PACKET) | ||
298 | if (connect(fd, (void *) &cfg_dst_addr, cfg_alen)) | ||
299 | error(1, errno, "connect"); | ||
300 | |||
301 | return fd; | ||
302 | } | ||
303 | |||
304 | static bool do_recv_completion(int fd) | ||
305 | { | ||
306 | struct sock_extended_err *serr; | ||
307 | struct msghdr msg = {}; | ||
308 | struct cmsghdr *cm; | ||
309 | uint32_t hi, lo, range; | ||
310 | int ret, zerocopy; | ||
311 | char control[100]; | ||
312 | |||
313 | msg.msg_control = control; | ||
314 | msg.msg_controllen = sizeof(control); | ||
315 | |||
316 | ret = recvmsg(fd, &msg, MSG_ERRQUEUE); | ||
317 | if (ret == -1 && errno == EAGAIN) | ||
318 | return false; | ||
319 | if (ret == -1) | ||
320 | error(1, errno, "recvmsg notification"); | ||
321 | if (msg.msg_flags & MSG_CTRUNC) | ||
322 | error(1, errno, "recvmsg notification: truncated"); | ||
323 | |||
324 | cm = CMSG_FIRSTHDR(&msg); | ||
325 | if (!cm) | ||
326 | error(1, 0, "cmsg: no cmsg"); | ||
327 | if (!((cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_RECVERR) || | ||
328 | (cm->cmsg_level == SOL_IPV6 && cm->cmsg_type == IPV6_RECVERR) || | ||
329 | (cm->cmsg_level == SOL_PACKET && cm->cmsg_type == PACKET_TX_TIMESTAMP))) | ||
330 | error(1, 0, "serr: wrong type: %d.%d", | ||
331 | cm->cmsg_level, cm->cmsg_type); | ||
332 | |||
333 | serr = (void *) CMSG_DATA(cm); | ||
334 | if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) | ||
335 | error(1, 0, "serr: wrong origin: %u", serr->ee_origin); | ||
336 | if (serr->ee_errno != 0) | ||
337 | error(1, 0, "serr: wrong error code: %u", serr->ee_errno); | ||
338 | |||
339 | hi = serr->ee_data; | ||
340 | lo = serr->ee_info; | ||
341 | range = hi - lo + 1; | ||
342 | |||
343 | /* Detect notification gaps. These should not happen often, if at all. | ||
344 | * Gaps can occur due to drops, reordering and retransmissions. | ||
345 | */ | ||
346 | if (lo != next_completion) | ||
347 | fprintf(stderr, "gap: %u..%u does not append to %u\n", | ||
348 | lo, hi, next_completion); | ||
349 | next_completion = hi + 1; | ||
350 | |||
351 | zerocopy = !(serr->ee_code & SO_EE_CODE_ZEROCOPY_COPIED); | ||
352 | if (zerocopied == -1) | ||
353 | zerocopied = zerocopy; | ||
354 | else if (zerocopied != zerocopy) { | ||
355 | fprintf(stderr, "serr: inconsistent\n"); | ||
356 | zerocopied = zerocopy; | ||
357 | } | ||
358 | |||
359 | if (cfg_verbose >= 2) | ||
360 | fprintf(stderr, "completed: %u (h=%u l=%u)\n", | ||
361 | range, hi, lo); | ||
362 | |||
363 | completions += range; | ||
364 | return true; | ||
365 | } | ||
366 | |||
367 | /* Read all outstanding messages on the errqueue */ | ||
368 | static void do_recv_completions(int fd) | ||
369 | { | ||
370 | while (do_recv_completion(fd)) {} | ||
371 | } | ||
372 | |||
373 | /* Wait for all remaining completions on the errqueue */ | ||
374 | static void do_recv_remaining_completions(int fd) | ||
375 | { | ||
376 | int64_t tstop = gettimeofday_ms() + cfg_waittime_ms; | ||
377 | |||
378 | while (completions < expected_completions && | ||
379 | gettimeofday_ms() < tstop) { | ||
380 | if (do_poll(fd, POLLERR)) | ||
381 | do_recv_completions(fd); | ||
382 | } | ||
383 | |||
384 | if (completions < expected_completions) | ||
385 | fprintf(stderr, "missing notifications: %lu < %lu\n", | ||
386 | completions, expected_completions); | ||
387 | } | ||
388 | |||
389 | static void do_tx(int domain, int type, int protocol) | ||
390 | { | ||
391 | struct iovec iov[3] = { {0} }; | ||
392 | struct sockaddr_ll laddr; | ||
393 | struct msghdr msg = {0}; | ||
394 | struct ethhdr eth; | ||
395 | union { | ||
396 | struct ipv6hdr ip6h; | ||
397 | struct iphdr iph; | ||
398 | } nh; | ||
399 | uint64_t tstop; | ||
400 | int fd; | ||
401 | |||
402 | fd = do_setup_tx(domain, type, protocol); | ||
403 | |||
404 | if (domain == PF_PACKET) { | ||
405 | uint16_t proto = cfg_family == PF_INET ? ETH_P_IP : ETH_P_IPV6; | ||
406 | |||
407 | /* sock_raw passes ll header as data */ | ||
408 | if (type == SOCK_RAW) { | ||
409 | memset(eth.h_dest, 0x06, ETH_ALEN); | ||
410 | memset(eth.h_source, 0x02, ETH_ALEN); | ||
411 | eth.h_proto = htons(proto); | ||
412 | iov[0].iov_base = ð | ||
413 | iov[0].iov_len = sizeof(eth); | ||
414 | msg.msg_iovlen++; | ||
415 | } | ||
416 | |||
417 | /* both sock_raw and sock_dgram expect name */ | ||
418 | memset(&laddr, 0, sizeof(laddr)); | ||
419 | laddr.sll_family = AF_PACKET; | ||
420 | laddr.sll_ifindex = cfg_ifindex; | ||
421 | laddr.sll_protocol = htons(proto); | ||
422 | laddr.sll_halen = ETH_ALEN; | ||
423 | |||
424 | memset(laddr.sll_addr, 0x06, ETH_ALEN); | ||
425 | |||
426 | msg.msg_name = &laddr; | ||
427 | msg.msg_namelen = sizeof(laddr); | ||
428 | } | ||
429 | |||
430 | /* packet and raw sockets with hdrincl must pass network header */ | ||
431 | if (domain == PF_PACKET || protocol == IPPROTO_RAW) { | ||
432 | if (cfg_family == PF_INET) | ||
433 | iov[1].iov_len = setup_iph(&nh.iph, cfg_payload_len); | ||
434 | else | ||
435 | iov[1].iov_len = setup_ip6h(&nh.ip6h, cfg_payload_len); | ||
436 | |||
437 | iov[1].iov_base = (void *) &nh; | ||
438 | msg.msg_iovlen++; | ||
439 | } | ||
440 | |||
441 | iov[2].iov_base = payload; | ||
442 | iov[2].iov_len = cfg_payload_len; | ||
443 | msg.msg_iovlen++; | ||
444 | msg.msg_iov = &iov[3 - msg.msg_iovlen]; | ||
445 | |||
446 | tstop = gettimeofday_ms() + cfg_runtime_ms; | ||
447 | do { | ||
448 | if (cfg_cork) | ||
449 | do_sendmsg_corked(fd, &msg); | ||
450 | else | ||
451 | do_sendmsg(fd, &msg, cfg_zerocopy); | ||
452 | |||
453 | while (!do_poll(fd, POLLOUT)) { | ||
454 | if (cfg_zerocopy) | ||
455 | do_recv_completions(fd); | ||
456 | } | ||
457 | |||
458 | } while (gettimeofday_ms() < tstop); | ||
459 | |||
460 | if (cfg_zerocopy) | ||
461 | do_recv_remaining_completions(fd); | ||
462 | |||
463 | if (close(fd)) | ||
464 | error(1, errno, "close"); | ||
465 | |||
466 | fprintf(stderr, "tx=%lu (%lu MB) txc=%lu zc=%c\n", | ||
467 | packets, bytes >> 20, completions, | ||
468 | zerocopied == 1 ? 'y' : 'n'); | ||
469 | } | ||
470 | |||
471 | static int do_setup_rx(int domain, int type, int protocol) | ||
472 | { | ||
473 | int fd; | ||
474 | |||
475 | /* If tx over PF_PACKET, rx over PF_INET(6)/SOCK_RAW, | ||
476 | * to recv the only copy of the packet, not a clone | ||
477 | */ | ||
478 | if (domain == PF_PACKET) | ||
479 | error(1, 0, "Use PF_INET/SOCK_RAW to read"); | ||
480 | |||
481 | if (type == SOCK_RAW && protocol == IPPROTO_RAW) | ||
482 | error(1, 0, "IPPROTO_RAW: not supported on Rx"); | ||
483 | |||
484 | fd = socket(domain, type, protocol); | ||
485 | if (fd == -1) | ||
486 | error(1, errno, "socket r"); | ||
487 | |||
488 | do_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, 1 << 21); | ||
489 | do_setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT, 1 << 16); | ||
490 | do_setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, 1); | ||
491 | |||
492 | if (bind(fd, (void *) &cfg_dst_addr, cfg_alen)) | ||
493 | error(1, errno, "bind"); | ||
494 | |||
495 | if (type == SOCK_STREAM) { | ||
496 | if (listen(fd, 1)) | ||
497 | error(1, errno, "listen"); | ||
498 | fd = do_accept(fd); | ||
499 | } | ||
500 | |||
501 | return fd; | ||
502 | } | ||
503 | |||
504 | /* Flush all outstanding bytes for the tcp receive queue */ | ||
505 | static void do_flush_tcp(int fd) | ||
506 | { | ||
507 | int ret; | ||
508 | |||
509 | /* MSG_TRUNC flushes up to len bytes */ | ||
510 | ret = recv(fd, NULL, 1 << 21, MSG_TRUNC | MSG_DONTWAIT); | ||
511 | if (ret == -1 && errno == EAGAIN) | ||
512 | return; | ||
513 | if (ret == -1) | ||
514 | error(1, errno, "flush"); | ||
515 | if (!ret) | ||
516 | return; | ||
517 | |||
518 | packets++; | ||
519 | bytes += ret; | ||
520 | } | ||
521 | |||
522 | /* Flush all outstanding datagrams. Verify first few bytes of each. */ | ||
523 | static void do_flush_datagram(int fd, int type) | ||
524 | { | ||
525 | int ret, off = 0; | ||
526 | char buf[64]; | ||
527 | |||
528 | /* MSG_TRUNC will return full datagram length */ | ||
529 | ret = recv(fd, buf, sizeof(buf), MSG_DONTWAIT | MSG_TRUNC); | ||
530 | if (ret == -1 && errno == EAGAIN) | ||
531 | return; | ||
532 | |||
533 | /* raw ipv4 return with header, raw ipv6 without */ | ||
534 | if (cfg_family == PF_INET && type == SOCK_RAW) { | ||
535 | off += sizeof(struct iphdr); | ||
536 | ret -= sizeof(struct iphdr); | ||
537 | } | ||
538 | |||
539 | if (ret == -1) | ||
540 | error(1, errno, "recv"); | ||
541 | if (ret != cfg_payload_len) | ||
542 | error(1, 0, "recv: ret=%u != %u", ret, cfg_payload_len); | ||
543 | if (ret > sizeof(buf) - off) | ||
544 | ret = sizeof(buf) - off; | ||
545 | if (memcmp(buf + off, payload, ret)) | ||
546 | error(1, 0, "recv: data mismatch"); | ||
547 | |||
548 | packets++; | ||
549 | bytes += cfg_payload_len; | ||
550 | } | ||
551 | |||
552 | static void do_rx(int domain, int type, int protocol) | ||
553 | { | ||
554 | uint64_t tstop; | ||
555 | int fd; | ||
556 | |||
557 | fd = do_setup_rx(domain, type, protocol); | ||
558 | |||
559 | tstop = gettimeofday_ms() + cfg_runtime_ms; | ||
560 | do { | ||
561 | if (type == SOCK_STREAM) | ||
562 | do_flush_tcp(fd); | ||
563 | else | ||
564 | do_flush_datagram(fd, type); | ||
565 | |||
566 | do_poll(fd, POLLIN); | ||
567 | |||
568 | } while (gettimeofday_ms() < tstop); | ||
569 | |||
570 | if (close(fd)) | ||
571 | error(1, errno, "close"); | ||
572 | |||
573 | fprintf(stderr, "rx=%lu (%lu MB)\n", packets, bytes >> 20); | ||
574 | } | ||
575 | |||
576 | static void do_test(int domain, int type, int protocol) | ||
577 | { | ||
578 | int i; | ||
579 | |||
580 | if (cfg_cork && (domain == PF_PACKET || type != SOCK_DGRAM)) | ||
581 | error(1, 0, "can only cork udp sockets"); | ||
582 | |||
583 | do_setcpu(cfg_cpu); | ||
584 | |||
585 | for (i = 0; i < IP_MAXPACKET; i++) | ||
586 | payload[i] = 'a' + (i % 26); | ||
587 | |||
588 | if (cfg_rx) | ||
589 | do_rx(domain, type, protocol); | ||
590 | else | ||
591 | do_tx(domain, type, protocol); | ||
592 | } | ||
593 | |||
594 | static void usage(const char *filepath) | ||
595 | { | ||
596 | error(1, 0, "Usage: %s [options] <test>", filepath); | ||
597 | } | ||
598 | |||
599 | static void parse_opts(int argc, char **argv) | ||
600 | { | ||
601 | const int max_payload_len = sizeof(payload) - | ||
602 | sizeof(struct ipv6hdr) - | ||
603 | sizeof(struct tcphdr) - | ||
604 | 40 /* max tcp options */; | ||
605 | int c; | ||
606 | |||
607 | cfg_payload_len = max_payload_len; | ||
608 | |||
609 | while ((c = getopt(argc, argv, "46c:C:D:i:mp:rs:S:t:vz")) != -1) { | ||
610 | switch (c) { | ||
611 | case '4': | ||
612 | if (cfg_family != PF_UNSPEC) | ||
613 | error(1, 0, "Pass one of -4 or -6"); | ||
614 | cfg_family = PF_INET; | ||
615 | cfg_alen = sizeof(struct sockaddr_in); | ||
616 | break; | ||
617 | case '6': | ||
618 | if (cfg_family != PF_UNSPEC) | ||
619 | error(1, 0, "Pass one of -4 or -6"); | ||
620 | cfg_family = PF_INET6; | ||
621 | cfg_alen = sizeof(struct sockaddr_in6); | ||
622 | break; | ||
623 | case 'c': | ||
624 | cfg_cork = strtol(optarg, NULL, 0); | ||
625 | break; | ||
626 | case 'C': | ||
627 | cfg_cpu = strtol(optarg, NULL, 0); | ||
628 | break; | ||
629 | case 'D': | ||
630 | setup_sockaddr(cfg_family, optarg, &cfg_dst_addr); | ||
631 | break; | ||
632 | case 'i': | ||
633 | cfg_ifindex = if_nametoindex(optarg); | ||
634 | if (cfg_ifindex == 0) | ||
635 | error(1, errno, "invalid iface: %s", optarg); | ||
636 | break; | ||
637 | case 'm': | ||
638 | cfg_cork_mixed = true; | ||
639 | break; | ||
640 | case 'p': | ||
641 | cfg_port = htons(strtoul(optarg, NULL, 0)); | ||
642 | break; | ||
643 | case 'r': | ||
644 | cfg_rx = true; | ||
645 | break; | ||
646 | case 's': | ||
647 | cfg_payload_len = strtoul(optarg, NULL, 0); | ||
648 | break; | ||
649 | case 'S': | ||
650 | setup_sockaddr(cfg_family, optarg, &cfg_src_addr); | ||
651 | break; | ||
652 | case 't': | ||
653 | cfg_runtime_ms = 200 + strtoul(optarg, NULL, 10) * 1000; | ||
654 | break; | ||
655 | case 'v': | ||
656 | cfg_verbose++; | ||
657 | break; | ||
658 | case 'z': | ||
659 | cfg_zerocopy = true; | ||
660 | break; | ||
661 | } | ||
662 | } | ||
663 | |||
664 | if (cfg_payload_len > max_payload_len) | ||
665 | error(1, 0, "-s: payload exceeds max (%d)", max_payload_len); | ||
666 | if (cfg_cork_mixed && (!cfg_zerocopy || !cfg_cork)) | ||
667 | error(1, 0, "-m: cork_mixed requires corking and zerocopy"); | ||
668 | |||
669 | if (optind != argc - 1) | ||
670 | usage(argv[0]); | ||
671 | } | ||
672 | |||
673 | int main(int argc, char **argv) | ||
674 | { | ||
675 | const char *cfg_test; | ||
676 | |||
677 | parse_opts(argc, argv); | ||
678 | |||
679 | cfg_test = argv[argc - 1]; | ||
680 | |||
681 | if (!strcmp(cfg_test, "packet")) | ||
682 | do_test(PF_PACKET, SOCK_RAW, 0); | ||
683 | else if (!strcmp(cfg_test, "packet_dgram")) | ||
684 | do_test(PF_PACKET, SOCK_DGRAM, 0); | ||
685 | else if (!strcmp(cfg_test, "raw")) | ||
686 | do_test(cfg_family, SOCK_RAW, IPPROTO_EGP); | ||
687 | else if (!strcmp(cfg_test, "raw_hdrincl")) | ||
688 | do_test(cfg_family, SOCK_RAW, IPPROTO_RAW); | ||
689 | else if (!strcmp(cfg_test, "tcp")) | ||
690 | do_test(cfg_family, SOCK_STREAM, 0); | ||
691 | else if (!strcmp(cfg_test, "udp")) | ||
692 | do_test(cfg_family, SOCK_DGRAM, 0); | ||
693 | else | ||
694 | error(1, 0, "unknown cfg_test %s", cfg_test); | ||
695 | |||
696 | return 0; | ||
697 | } | ||
diff --git a/tools/testing/selftests/net/msg_zerocopy.sh b/tools/testing/selftests/net/msg_zerocopy.sh new file mode 100755 index 000000000000..d571d213418d --- /dev/null +++ b/tools/testing/selftests/net/msg_zerocopy.sh | |||
@@ -0,0 +1,112 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Send data between two processes across namespaces | ||
4 | # Run twice: once without and once with zerocopy | ||
5 | |||
6 | set -e | ||
7 | |||
8 | readonly DEV="veth0" | ||
9 | readonly DEV_MTU=65535 | ||
10 | readonly BIN="./msg_zerocopy" | ||
11 | |||
12 | readonly RAND="$(mktemp -u XXXXXX)" | ||
13 | readonly NSPREFIX="ns-${RAND}" | ||
14 | readonly NS1="${NSPREFIX}1" | ||
15 | readonly NS2="${NSPREFIX}2" | ||
16 | |||
17 | readonly SADDR4='192.168.1.1' | ||
18 | readonly DADDR4='192.168.1.2' | ||
19 | readonly SADDR6='fd::1' | ||
20 | readonly DADDR6='fd::2' | ||
21 | |||
22 | readonly path_sysctl_mem="net.core.optmem_max" | ||
23 | |||
24 | # Argument parsing | ||
25 | if [[ "$#" -lt "2" ]]; then | ||
26 | echo "Usage: $0 [4|6] [tcp|udp|raw|raw_hdrincl|packet|packet_dgram] <args>" | ||
27 | exit 1 | ||
28 | fi | ||
29 | |||
30 | readonly IP="$1" | ||
31 | shift | ||
32 | readonly TXMODE="$1" | ||
33 | shift | ||
34 | readonly EXTRA_ARGS="$@" | ||
35 | |||
36 | # Argument parsing: configure addresses | ||
37 | if [[ "${IP}" == "4" ]]; then | ||
38 | readonly SADDR="${SADDR4}" | ||
39 | readonly DADDR="${DADDR4}" | ||
40 | elif [[ "${IP}" == "6" ]]; then | ||
41 | readonly SADDR="${SADDR6}" | ||
42 | readonly DADDR="${DADDR6}" | ||
43 | else | ||
44 | echo "Invalid IP version ${IP}" | ||
45 | exit 1 | ||
46 | fi | ||
47 | |||
48 | # Argument parsing: select receive mode | ||
49 | # | ||
50 | # This differs from send mode for | ||
51 | # - packet: use raw recv, because packet receives skb clones | ||
52 | # - raw_hdrinc: use raw recv, because hdrincl is a tx-only option | ||
53 | case "${TXMODE}" in | ||
54 | 'packet' | 'packet_dgram' | 'raw_hdrincl') | ||
55 | RXMODE='raw' | ||
56 | ;; | ||
57 | *) | ||
58 | RXMODE="${TXMODE}" | ||
59 | ;; | ||
60 | esac | ||
61 | |||
62 | # Start of state changes: install cleanup handler | ||
63 | save_sysctl_mem="$(sysctl -n ${path_sysctl_mem})" | ||
64 | |||
65 | cleanup() { | ||
66 | ip netns del "${NS2}" | ||
67 | ip netns del "${NS1}" | ||
68 | sysctl -w -q "${path_sysctl_mem}=${save_sysctl_mem}" | ||
69 | } | ||
70 | |||
71 | trap cleanup EXIT | ||
72 | |||
73 | # Configure system settings | ||
74 | sysctl -w -q "${path_sysctl_mem}=1000000" | ||
75 | |||
76 | # Create virtual ethernet pair between network namespaces | ||
77 | ip netns add "${NS1}" | ||
78 | ip netns add "${NS2}" | ||
79 | |||
80 | ip link add "${DEV}" mtu "${DEV_MTU}" netns "${NS1}" type veth \ | ||
81 | peer name "${DEV}" mtu "${DEV_MTU}" netns "${NS2}" | ||
82 | |||
83 | # Bring the devices up | ||
84 | ip -netns "${NS1}" link set "${DEV}" up | ||
85 | ip -netns "${NS2}" link set "${DEV}" up | ||
86 | |||
87 | # Set fixed MAC addresses on the devices | ||
88 | ip -netns "${NS1}" link set dev "${DEV}" address 02:02:02:02:02:02 | ||
89 | ip -netns "${NS2}" link set dev "${DEV}" address 06:06:06:06:06:06 | ||
90 | |||
91 | # Add fixed IP addresses to the devices | ||
92 | ip -netns "${NS1}" addr add 192.168.1.1/24 dev "${DEV}" | ||
93 | ip -netns "${NS2}" addr add 192.168.1.2/24 dev "${DEV}" | ||
94 | ip -netns "${NS1}" addr add fd::1/64 dev "${DEV}" nodad | ||
95 | ip -netns "${NS2}" addr add fd::2/64 dev "${DEV}" nodad | ||
96 | |||
97 | # Optionally disable sg or csum offload to test edge cases | ||
98 | # ip netns exec "${NS1}" ethtool -K "${DEV}" sg off | ||
99 | |||
100 | do_test() { | ||
101 | local readonly ARGS="$1" | ||
102 | |||
103 | echo "ipv${IP} ${TXMODE} ${ARGS}" | ||
104 | ip netns exec "${NS2}" "${BIN}" "-${IP}" -i "${DEV}" -t 2 -C 2 -S "${SADDR}" -D "${DADDR}" ${ARGS} -r "${RXMODE}" & | ||
105 | sleep 0.2 | ||
106 | ip netns exec "${NS1}" "${BIN}" "-${IP}" -i "${DEV}" -t 1 -C 3 -S "${SADDR}" -D "${DADDR}" ${ARGS} "${TXMODE}" | ||
107 | wait | ||
108 | } | ||
109 | |||
110 | do_test "${EXTRA_ARGS}" | ||
111 | do_test "-z ${EXTRA_ARGS}" | ||
112 | echo ok | ||
diff --git a/tools/testing/selftests/net/netdevice.sh b/tools/testing/selftests/net/netdevice.sh index 4e00568d70c2..90cb903c3381 100755 --- a/tools/testing/selftests/net/netdevice.sh +++ b/tools/testing/selftests/net/netdevice.sh | |||
@@ -178,7 +178,7 @@ if [ "$(id -u)" -ne 0 ];then | |||
178 | exit 0 | 178 | exit 0 |
179 | fi | 179 | fi |
180 | 180 | ||
181 | ip -Version 2>/dev/null >/dev/null | 181 | ip link show 2>/dev/null >/dev/null |
182 | if [ $? -ne 0 ];then | 182 | if [ $? -ne 0 ];then |
183 | echo "SKIP: Could not run test without the ip tool" | 183 | echo "SKIP: Could not run test without the ip tool" |
184 | exit 0 | 184 | exit 0 |
diff --git a/tools/testing/selftests/net/reuseaddr_conflict.c b/tools/testing/selftests/net/reuseaddr_conflict.c new file mode 100644 index 000000000000..7c5b12664b03 --- /dev/null +++ b/tools/testing/selftests/net/reuseaddr_conflict.c | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * Test for the regression introduced by | ||
3 | * | ||
4 | * b9470c27607b ("inet: kill smallest_size and smallest_port") | ||
5 | * | ||
6 | * If we open an ipv4 socket on a port with reuseaddr we shouldn't reset the tb | ||
7 | * when we open the ipv6 conterpart, which is what was happening previously. | ||
8 | */ | ||
9 | #include <errno.h> | ||
10 | #include <error.h> | ||
11 | #include <arpa/inet.h> | ||
12 | #include <netinet/in.h> | ||
13 | #include <stdbool.h> | ||
14 | #include <stdio.h> | ||
15 | #include <sys/socket.h> | ||
16 | #include <sys/types.h> | ||
17 | #include <unistd.h> | ||
18 | |||
19 | #define PORT 9999 | ||
20 | |||
21 | int open_port(int ipv6, int any) | ||
22 | { | ||
23 | int fd = -1; | ||
24 | int reuseaddr = 1; | ||
25 | int v6only = 1; | ||
26 | int addrlen; | ||
27 | int ret = -1; | ||
28 | struct sockaddr *addr; | ||
29 | int family = ipv6 ? AF_INET6 : AF_INET; | ||
30 | |||
31 | struct sockaddr_in6 addr6 = { | ||
32 | .sin6_family = AF_INET6, | ||
33 | .sin6_port = htons(PORT), | ||
34 | .sin6_addr = in6addr_any | ||
35 | }; | ||
36 | struct sockaddr_in addr4 = { | ||
37 | .sin_family = AF_INET, | ||
38 | .sin_port = htons(PORT), | ||
39 | .sin_addr.s_addr = any ? htonl(INADDR_ANY) : inet_addr("127.0.0.1"), | ||
40 | }; | ||
41 | |||
42 | |||
43 | if (ipv6) { | ||
44 | addr = (struct sockaddr*)&addr6; | ||
45 | addrlen = sizeof(addr6); | ||
46 | } else { | ||
47 | addr = (struct sockaddr*)&addr4; | ||
48 | addrlen = sizeof(addr4); | ||
49 | } | ||
50 | |||
51 | if ((fd = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0) { | ||
52 | perror("socket"); | ||
53 | goto out; | ||
54 | } | ||
55 | |||
56 | if (ipv6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&v6only, | ||
57 | sizeof(v6only)) < 0) { | ||
58 | perror("setsockopt IPV6_V6ONLY"); | ||
59 | goto out; | ||
60 | } | ||
61 | |||
62 | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, | ||
63 | sizeof(reuseaddr)) < 0) { | ||
64 | perror("setsockopt SO_REUSEADDR"); | ||
65 | goto out; | ||
66 | } | ||
67 | |||
68 | if (bind(fd, addr, addrlen) < 0) { | ||
69 | perror("bind"); | ||
70 | goto out; | ||
71 | } | ||
72 | |||
73 | if (any) | ||
74 | return fd; | ||
75 | |||
76 | if (listen(fd, 1) < 0) { | ||
77 | perror("listen"); | ||
78 | goto out; | ||
79 | } | ||
80 | return fd; | ||
81 | out: | ||
82 | close(fd); | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | int main(void) | ||
87 | { | ||
88 | int listenfd; | ||
89 | int fd1, fd2; | ||
90 | |||
91 | fprintf(stderr, "Opening 127.0.0.1:%d\n", PORT); | ||
92 | listenfd = open_port(0, 0); | ||
93 | if (listenfd < 0) | ||
94 | error(1, errno, "Couldn't open listen socket"); | ||
95 | fprintf(stderr, "Opening INADDR_ANY:%d\n", PORT); | ||
96 | fd1 = open_port(0, 1); | ||
97 | if (fd1 >= 0) | ||
98 | error(1, 0, "Was allowed to create an ipv4 reuseport on a already bound non-reuseport socket"); | ||
99 | fprintf(stderr, "Opening in6addr_any:%d\n", PORT); | ||
100 | fd1 = open_port(1, 1); | ||
101 | if (fd1 < 0) | ||
102 | error(1, errno, "Couldn't open ipv6 reuseport"); | ||
103 | fprintf(stderr, "Opening INADDR_ANY:%d\n", PORT); | ||
104 | fd2 = open_port(0, 1); | ||
105 | if (fd2 >= 0) | ||
106 | error(1, 0, "Was allowed to create an ipv4 reuseport on a already bound non-reuseport socket"); | ||
107 | close(fd1); | ||
108 | fprintf(stderr, "Opening INADDR_ANY:%d after closing ipv6 socket\n", PORT); | ||
109 | fd1 = open_port(0, 1); | ||
110 | if (fd1 >= 0) | ||
111 | error(1, 0, "Was allowed to create an ipv4 reuseport on an already bound non-reuseport socket with no ipv6"); | ||
112 | fprintf(stderr, "Success"); | ||
113 | return 0; | ||
114 | } | ||
diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh new file mode 100755 index 000000000000..57b5ff576240 --- /dev/null +++ b/tools/testing/selftests/net/rtnetlink.sh | |||
@@ -0,0 +1,272 @@ | |||
1 | #!/bin/sh | ||
2 | # | ||
3 | # This test is for checking rtnetlink callpaths, and get as much coverage as possible. | ||
4 | # | ||
5 | # set -e | ||
6 | |||
7 | devdummy="test-dummy0" | ||
8 | ret=0 | ||
9 | |||
10 | # set global exit status, but never reset nonzero one. | ||
11 | check_err() | ||
12 | { | ||
13 | if [ $ret -eq 0 ]; then | ||
14 | ret=$1 | ||
15 | fi | ||
16 | } | ||
17 | |||
18 | kci_add_dummy() | ||
19 | { | ||
20 | ip link add name "$devdummy" type dummy | ||
21 | check_err $? | ||
22 | ip link set "$devdummy" up | ||
23 | check_err $? | ||
24 | } | ||
25 | |||
26 | kci_del_dummy() | ||
27 | { | ||
28 | ip link del dev "$devdummy" | ||
29 | check_err $? | ||
30 | } | ||
31 | |||
32 | # add a bridge with vlans on top | ||
33 | kci_test_bridge() | ||
34 | { | ||
35 | devbr="test-br0" | ||
36 | vlandev="testbr-vlan1" | ||
37 | |||
38 | ret=0 | ||
39 | ip link add name "$devbr" type bridge | ||
40 | check_err $? | ||
41 | |||
42 | ip link set dev "$devdummy" master "$devbr" | ||
43 | check_err $? | ||
44 | |||
45 | ip link set "$devbr" up | ||
46 | check_err $? | ||
47 | |||
48 | ip link add link "$devbr" name "$vlandev" type vlan id 1 | ||
49 | check_err $? | ||
50 | ip addr add dev "$vlandev" 10.200.7.23/30 | ||
51 | check_err $? | ||
52 | ip -6 addr add dev "$vlandev" dead:42::1234/64 | ||
53 | check_err $? | ||
54 | ip -d link > /dev/null | ||
55 | check_err $? | ||
56 | ip r s t all > /dev/null | ||
57 | check_err $? | ||
58 | ip -6 addr del dev "$vlandev" dead:42::1234/64 | ||
59 | check_err $? | ||
60 | |||
61 | ip link del dev "$vlandev" | ||
62 | check_err $? | ||
63 | ip link del dev "$devbr" | ||
64 | check_err $? | ||
65 | |||
66 | if [ $ret -ne 0 ];then | ||
67 | echo "FAIL: bridge setup" | ||
68 | return 1 | ||
69 | fi | ||
70 | echo "PASS: bridge setup" | ||
71 | |||
72 | } | ||
73 | |||
74 | kci_test_gre() | ||
75 | { | ||
76 | gredev=neta | ||
77 | rem=10.42.42.1 | ||
78 | loc=10.0.0.1 | ||
79 | |||
80 | ret=0 | ||
81 | ip tunnel add $gredev mode gre remote $rem local $loc ttl 1 | ||
82 | check_err $? | ||
83 | ip link set $gredev up | ||
84 | check_err $? | ||
85 | ip addr add 10.23.7.10 dev $gredev | ||
86 | check_err $? | ||
87 | ip route add 10.23.8.0/30 dev $gredev | ||
88 | check_err $? | ||
89 | ip addr add dev "$devdummy" 10.23.7.11/24 | ||
90 | check_err $? | ||
91 | ip link > /dev/null | ||
92 | check_err $? | ||
93 | ip addr > /dev/null | ||
94 | check_err $? | ||
95 | ip addr del dev "$devdummy" 10.23.7.11/24 | ||
96 | check_err $? | ||
97 | |||
98 | ip link del $gredev | ||
99 | check_err $? | ||
100 | |||
101 | if [ $ret -ne 0 ];then | ||
102 | echo "FAIL: gre tunnel endpoint" | ||
103 | return 1 | ||
104 | fi | ||
105 | echo "PASS: gre tunnel endpoint" | ||
106 | } | ||
107 | |||
108 | # tc uses rtnetlink too, for full tc testing | ||
109 | # please see tools/testing/selftests/tc-testing. | ||
110 | kci_test_tc() | ||
111 | { | ||
112 | dev=lo | ||
113 | ret=0 | ||
114 | |||
115 | tc qdisc add dev "$dev" root handle 1: htb | ||
116 | check_err $? | ||
117 | tc class add dev "$dev" parent 1: classid 1:10 htb rate 1mbit | ||
118 | check_err $? | ||
119 | tc filter add dev "$dev" parent 1:0 prio 5 handle ffe: protocol ip u32 divisor 256 | ||
120 | check_err $? | ||
121 | tc filter add dev "$dev" parent 1:0 prio 5 handle ffd: protocol ip u32 divisor 256 | ||
122 | check_err $? | ||
123 | tc filter add dev "$dev" parent 1:0 prio 5 handle ffc: protocol ip u32 divisor 256 | ||
124 | check_err $? | ||
125 | tc filter add dev "$dev" protocol ip parent 1: prio 5 handle ffe:2:3 u32 ht ffe:2: match ip src 10.0.0.3 flowid 1:10 | ||
126 | check_err $? | ||
127 | tc filter add dev "$dev" protocol ip parent 1: prio 5 handle ffe:2:2 u32 ht ffe:2: match ip src 10.0.0.2 flowid 1:10 | ||
128 | check_err $? | ||
129 | tc filter show dev "$dev" parent 1:0 > /dev/null | ||
130 | check_err $? | ||
131 | tc filter del dev "$dev" protocol ip parent 1: prio 5 handle ffe:2:3 u32 | ||
132 | check_err $? | ||
133 | tc filter show dev "$dev" parent 1:0 > /dev/null | ||
134 | check_err $? | ||
135 | tc qdisc del dev "$dev" root handle 1: htb | ||
136 | check_err $? | ||
137 | |||
138 | if [ $ret -ne 0 ];then | ||
139 | echo "FAIL: tc htb hierarchy" | ||
140 | return 1 | ||
141 | fi | ||
142 | echo "PASS: tc htb hierarchy" | ||
143 | |||
144 | } | ||
145 | |||
146 | kci_test_polrouting() | ||
147 | { | ||
148 | ret=0 | ||
149 | ip rule add fwmark 1 lookup 100 | ||
150 | check_err $? | ||
151 | ip route add local 0.0.0.0/0 dev lo table 100 | ||
152 | check_err $? | ||
153 | ip r s t all > /dev/null | ||
154 | check_err $? | ||
155 | ip rule del fwmark 1 lookup 100 | ||
156 | check_err $? | ||
157 | ip route del local 0.0.0.0/0 dev lo table 100 | ||
158 | check_err $? | ||
159 | |||
160 | if [ $ret -ne 0 ];then | ||
161 | echo "FAIL: policy route test" | ||
162 | return 1 | ||
163 | fi | ||
164 | echo "PASS: policy routing" | ||
165 | } | ||
166 | |||
167 | kci_test_route_get() | ||
168 | { | ||
169 | ret=0 | ||
170 | |||
171 | ip route get 127.0.0.1 > /dev/null | ||
172 | check_err $? | ||
173 | ip route get 127.0.0.1 dev "$devdummy" > /dev/null | ||
174 | check_err $? | ||
175 | ip route get ::1 > /dev/null | ||
176 | check_err $? | ||
177 | ip route get fe80::1 dev "$devdummy" > /dev/null | ||
178 | check_err $? | ||
179 | ip route get 127.0.0.1 from 127.0.0.1 oif lo tos 0x1 mark 0x1 > /dev/null | ||
180 | check_err $? | ||
181 | ip route get ::1 from ::1 iif lo oif lo tos 0x1 mark 0x1 > /dev/null | ||
182 | check_err $? | ||
183 | ip addr add dev "$devdummy" 10.23.7.11/24 | ||
184 | check_err $? | ||
185 | ip route get 10.23.7.11 from 10.23.7.12 iif "$devdummy" > /dev/null | ||
186 | check_err $? | ||
187 | ip addr del dev "$devdummy" 10.23.7.11/24 | ||
188 | check_err $? | ||
189 | |||
190 | if [ $ret -ne 0 ];then | ||
191 | echo "FAIL: route get" | ||
192 | return 1 | ||
193 | fi | ||
194 | |||
195 | echo "PASS: route get" | ||
196 | } | ||
197 | |||
198 | kci_test_addrlabel() | ||
199 | { | ||
200 | ret=0 | ||
201 | |||
202 | ip addrlabel add prefix dead::/64 dev lo label 1 | ||
203 | check_err $? | ||
204 | |||
205 | ip addrlabel list |grep -q "prefix dead::/64 dev lo label 1" | ||
206 | check_err $? | ||
207 | |||
208 | ip addrlabel del prefix dead::/64 dev lo label 1 2> /dev/null | ||
209 | check_err $? | ||
210 | |||
211 | ip addrlabel add prefix dead::/64 label 1 2> /dev/null | ||
212 | check_err $? | ||
213 | |||
214 | ip addrlabel del prefix dead::/64 label 1 2> /dev/null | ||
215 | check_err $? | ||
216 | |||
217 | # concurrent add/delete | ||
218 | for i in $(seq 1 1000); do | ||
219 | ip addrlabel add prefix 1c3::/64 label 12345 2>/dev/null | ||
220 | done & | ||
221 | |||
222 | for i in $(seq 1 1000); do | ||
223 | ip addrlabel del prefix 1c3::/64 label 12345 2>/dev/null | ||
224 | done | ||
225 | |||
226 | wait | ||
227 | |||
228 | ip addrlabel del prefix 1c3::/64 label 12345 2>/dev/null | ||
229 | |||
230 | if [ $ret -ne 0 ];then | ||
231 | echo "FAIL: ipv6 addrlabel" | ||
232 | return 1 | ||
233 | fi | ||
234 | |||
235 | echo "PASS: ipv6 addrlabel" | ||
236 | } | ||
237 | |||
238 | kci_test_rtnl() | ||
239 | { | ||
240 | kci_add_dummy | ||
241 | if [ $ret -ne 0 ];then | ||
242 | echo "FAIL: cannot add dummy interface" | ||
243 | return 1 | ||
244 | fi | ||
245 | |||
246 | kci_test_polrouting | ||
247 | kci_test_route_get | ||
248 | kci_test_tc | ||
249 | kci_test_gre | ||
250 | kci_test_bridge | ||
251 | kci_test_addrlabel | ||
252 | |||
253 | kci_del_dummy | ||
254 | } | ||
255 | |||
256 | #check for needed privileges | ||
257 | if [ "$(id -u)" -ne 0 ];then | ||
258 | echo "SKIP: Need root privileges" | ||
259 | exit 0 | ||
260 | fi | ||
261 | |||
262 | for x in ip tc;do | ||
263 | $x -Version 2>/dev/null >/dev/null | ||
264 | if [ $? -ne 0 ];then | ||
265 | echo "SKIP: Could not run test without the $x tool" | ||
266 | exit 0 | ||
267 | fi | ||
268 | done | ||
269 | |||
270 | kci_test_rtnl | ||
271 | |||
272 | exit $ret | ||
diff --git a/tools/testing/selftests/networking/timestamping/.gitignore b/tools/testing/selftests/networking/timestamping/.gitignore index 9e69e982fb38..d9355035e746 100644 --- a/tools/testing/selftests/networking/timestamping/.gitignore +++ b/tools/testing/selftests/networking/timestamping/.gitignore | |||
@@ -1,3 +1,4 @@ | |||
1 | timestamping | 1 | timestamping |
2 | rxtimestamp | ||
2 | txtimestamp | 3 | txtimestamp |
3 | hwtstamp_config | 4 | hwtstamp_config |
diff --git a/tools/testing/selftests/networking/timestamping/Makefile b/tools/testing/selftests/networking/timestamping/Makefile index ccbb9edbbbb9..92fb8ee917c5 100644 --- a/tools/testing/selftests/networking/timestamping/Makefile +++ b/tools/testing/selftests/networking/timestamping/Makefile | |||
@@ -1,4 +1,6 @@ | |||
1 | TEST_PROGS := hwtstamp_config timestamping txtimestamp | 1 | CFLAGS += -I../../../../../usr/include |
2 | |||
3 | TEST_PROGS := hwtstamp_config rxtimestamp timestamping txtimestamp | ||
2 | 4 | ||
3 | all: $(TEST_PROGS) | 5 | all: $(TEST_PROGS) |
4 | 6 | ||
diff --git a/tools/testing/selftests/networking/timestamping/rxtimestamp.c b/tools/testing/selftests/networking/timestamping/rxtimestamp.c new file mode 100644 index 000000000000..dd4162fc0419 --- /dev/null +++ b/tools/testing/selftests/networking/timestamping/rxtimestamp.c | |||
@@ -0,0 +1,389 @@ | |||
1 | #include <errno.h> | ||
2 | #include <error.h> | ||
3 | #include <getopt.h> | ||
4 | #include <stdbool.h> | ||
5 | #include <stdio.h> | ||
6 | #include <stdlib.h> | ||
7 | #include <string.h> | ||
8 | |||
9 | #include <sys/time.h> | ||
10 | #include <sys/socket.h> | ||
11 | #include <sys/select.h> | ||
12 | #include <sys/ioctl.h> | ||
13 | #include <arpa/inet.h> | ||
14 | #include <net/if.h> | ||
15 | |||
16 | #include <asm/types.h> | ||
17 | #include <linux/net_tstamp.h> | ||
18 | #include <linux/errqueue.h> | ||
19 | |||
20 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
21 | |||
22 | struct options { | ||
23 | int so_timestamp; | ||
24 | int so_timestampns; | ||
25 | int so_timestamping; | ||
26 | }; | ||
27 | |||
28 | struct tstamps { | ||
29 | bool tstamp; | ||
30 | bool tstampns; | ||
31 | bool swtstamp; | ||
32 | bool hwtstamp; | ||
33 | }; | ||
34 | |||
35 | struct socket_type { | ||
36 | char *friendly_name; | ||
37 | int type; | ||
38 | int protocol; | ||
39 | bool enabled; | ||
40 | }; | ||
41 | |||
42 | struct test_case { | ||
43 | struct options sockopt; | ||
44 | struct tstamps expected; | ||
45 | bool enabled; | ||
46 | }; | ||
47 | |||
48 | struct sof_flag { | ||
49 | int mask; | ||
50 | char *name; | ||
51 | }; | ||
52 | |||
53 | static struct sof_flag sof_flags[] = { | ||
54 | #define SOF_FLAG(f) { f, #f } | ||
55 | SOF_FLAG(SOF_TIMESTAMPING_SOFTWARE), | ||
56 | SOF_FLAG(SOF_TIMESTAMPING_RX_SOFTWARE), | ||
57 | SOF_FLAG(SOF_TIMESTAMPING_RX_HARDWARE), | ||
58 | }; | ||
59 | |||
60 | static struct socket_type socket_types[] = { | ||
61 | { "ip", SOCK_RAW, IPPROTO_EGP }, | ||
62 | { "udp", SOCK_DGRAM, IPPROTO_UDP }, | ||
63 | { "tcp", SOCK_STREAM, IPPROTO_TCP }, | ||
64 | }; | ||
65 | |||
66 | static struct test_case test_cases[] = { | ||
67 | { {}, {} }, | ||
68 | { | ||
69 | { so_timestamp: 1 }, | ||
70 | { tstamp: true } | ||
71 | }, | ||
72 | { | ||
73 | { so_timestampns: 1 }, | ||
74 | { tstampns: true } | ||
75 | }, | ||
76 | { | ||
77 | { so_timestamp: 1, so_timestampns: 1 }, | ||
78 | { tstampns: true } | ||
79 | }, | ||
80 | { | ||
81 | { so_timestamping: SOF_TIMESTAMPING_RX_SOFTWARE }, | ||
82 | {} | ||
83 | }, | ||
84 | { | ||
85 | /* Loopback device does not support hw timestamps. */ | ||
86 | { so_timestamping: SOF_TIMESTAMPING_RX_HARDWARE }, | ||
87 | {} | ||
88 | }, | ||
89 | { | ||
90 | { so_timestamping: SOF_TIMESTAMPING_SOFTWARE }, | ||
91 | {} | ||
92 | }, | ||
93 | { | ||
94 | { so_timestamping: SOF_TIMESTAMPING_RX_SOFTWARE | ||
95 | | SOF_TIMESTAMPING_RX_HARDWARE }, | ||
96 | {} | ||
97 | }, | ||
98 | { | ||
99 | { so_timestamping: SOF_TIMESTAMPING_SOFTWARE | ||
100 | | SOF_TIMESTAMPING_RX_SOFTWARE }, | ||
101 | { swtstamp: true } | ||
102 | }, | ||
103 | { | ||
104 | { so_timestamp: 1, so_timestamping: SOF_TIMESTAMPING_SOFTWARE | ||
105 | | SOF_TIMESTAMPING_RX_SOFTWARE }, | ||
106 | { tstamp: true, swtstamp: true } | ||
107 | }, | ||
108 | }; | ||
109 | |||
110 | static struct option long_options[] = { | ||
111 | { "list_tests", no_argument, 0, 'l' }, | ||
112 | { "test_num", required_argument, 0, 'n' }, | ||
113 | { "op_size", required_argument, 0, 's' }, | ||
114 | { "tcp", no_argument, 0, 't' }, | ||
115 | { "udp", no_argument, 0, 'u' }, | ||
116 | { "ip", no_argument, 0, 'i' }, | ||
117 | }; | ||
118 | |||
119 | static int next_port = 19999; | ||
120 | static int op_size = 10 * 1024; | ||
121 | |||
122 | void print_test_case(struct test_case *t) | ||
123 | { | ||
124 | int f = 0; | ||
125 | |||
126 | printf("sockopts {"); | ||
127 | if (t->sockopt.so_timestamp) | ||
128 | printf(" SO_TIMESTAMP "); | ||
129 | if (t->sockopt.so_timestampns) | ||
130 | printf(" SO_TIMESTAMPNS "); | ||
131 | if (t->sockopt.so_timestamping) { | ||
132 | printf(" SO_TIMESTAMPING: {"); | ||
133 | for (f = 0; f < ARRAY_SIZE(sof_flags); f++) | ||
134 | if (t->sockopt.so_timestamping & sof_flags[f].mask) | ||
135 | printf(" %s |", sof_flags[f].name); | ||
136 | printf("}"); | ||
137 | } | ||
138 | printf("} expected cmsgs: {"); | ||
139 | if (t->expected.tstamp) | ||
140 | printf(" SCM_TIMESTAMP "); | ||
141 | if (t->expected.tstampns) | ||
142 | printf(" SCM_TIMESTAMPNS "); | ||
143 | if (t->expected.swtstamp || t->expected.hwtstamp) { | ||
144 | printf(" SCM_TIMESTAMPING {"); | ||
145 | if (t->expected.swtstamp) | ||
146 | printf("0"); | ||
147 | if (t->expected.swtstamp && t->expected.hwtstamp) | ||
148 | printf(","); | ||
149 | if (t->expected.hwtstamp) | ||
150 | printf("2"); | ||
151 | printf("}"); | ||
152 | } | ||
153 | printf("}\n"); | ||
154 | } | ||
155 | |||
156 | void do_send(int src) | ||
157 | { | ||
158 | int r; | ||
159 | char *buf = malloc(op_size); | ||
160 | |||
161 | memset(buf, 'z', op_size); | ||
162 | r = write(src, buf, op_size); | ||
163 | if (r < 0) | ||
164 | error(1, errno, "Failed to sendmsg"); | ||
165 | |||
166 | free(buf); | ||
167 | } | ||
168 | |||
169 | bool do_recv(int rcv, int read_size, struct tstamps expected) | ||
170 | { | ||
171 | const int CMSG_SIZE = 1024; | ||
172 | |||
173 | struct scm_timestamping *ts; | ||
174 | struct tstamps actual = {}; | ||
175 | char cmsg_buf[CMSG_SIZE]; | ||
176 | struct iovec recv_iov; | ||
177 | struct cmsghdr *cmsg; | ||
178 | bool failed = false; | ||
179 | struct msghdr hdr; | ||
180 | int flags = 0; | ||
181 | int r; | ||
182 | |||
183 | memset(&hdr, 0, sizeof(hdr)); | ||
184 | hdr.msg_iov = &recv_iov; | ||
185 | hdr.msg_iovlen = 1; | ||
186 | recv_iov.iov_base = malloc(read_size); | ||
187 | recv_iov.iov_len = read_size; | ||
188 | |||
189 | hdr.msg_control = cmsg_buf; | ||
190 | hdr.msg_controllen = sizeof(cmsg_buf); | ||
191 | |||
192 | r = recvmsg(rcv, &hdr, flags); | ||
193 | if (r < 0) | ||
194 | error(1, errno, "Failed to recvmsg"); | ||
195 | if (r != read_size) | ||
196 | error(1, 0, "Only received %d bytes of payload.", r); | ||
197 | |||
198 | if (hdr.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) | ||
199 | error(1, 0, "Message was truncated."); | ||
200 | |||
201 | for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL; | ||
202 | cmsg = CMSG_NXTHDR(&hdr, cmsg)) { | ||
203 | if (cmsg->cmsg_level != SOL_SOCKET) | ||
204 | error(1, 0, "Unexpected cmsg_level %d", | ||
205 | cmsg->cmsg_level); | ||
206 | switch (cmsg->cmsg_type) { | ||
207 | case SCM_TIMESTAMP: | ||
208 | actual.tstamp = true; | ||
209 | break; | ||
210 | case SCM_TIMESTAMPNS: | ||
211 | actual.tstampns = true; | ||
212 | break; | ||
213 | case SCM_TIMESTAMPING: | ||
214 | ts = (struct scm_timestamping *)CMSG_DATA(cmsg); | ||
215 | actual.swtstamp = !!ts->ts[0].tv_sec; | ||
216 | if (ts->ts[1].tv_sec != 0) | ||
217 | error(0, 0, "ts[1] should not be set."); | ||
218 | actual.hwtstamp = !!ts->ts[2].tv_sec; | ||
219 | break; | ||
220 | default: | ||
221 | error(1, 0, "Unexpected cmsg_type %d", cmsg->cmsg_type); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | #define VALIDATE(field) \ | ||
226 | do { \ | ||
227 | if (expected.field != actual.field) { \ | ||
228 | if (expected.field) \ | ||
229 | error(0, 0, "Expected " #field " to be set."); \ | ||
230 | else \ | ||
231 | error(0, 0, \ | ||
232 | "Expected " #field " to not be set."); \ | ||
233 | failed = true; \ | ||
234 | } \ | ||
235 | } while (0) | ||
236 | |||
237 | VALIDATE(tstamp); | ||
238 | VALIDATE(tstampns); | ||
239 | VALIDATE(swtstamp); | ||
240 | VALIDATE(hwtstamp); | ||
241 | #undef VALIDATE | ||
242 | |||
243 | free(recv_iov.iov_base); | ||
244 | |||
245 | return failed; | ||
246 | } | ||
247 | |||
248 | void config_so_flags(int rcv, struct options o) | ||
249 | { | ||
250 | int on = 1; | ||
251 | |||
252 | if (setsockopt(rcv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) | ||
253 | error(1, errno, "Failed to enable SO_REUSEADDR"); | ||
254 | |||
255 | if (o.so_timestamp && | ||
256 | setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMP, | ||
257 | &o.so_timestamp, sizeof(o.so_timestamp)) < 0) | ||
258 | error(1, errno, "Failed to enable SO_TIMESTAMP"); | ||
259 | |||
260 | if (o.so_timestampns && | ||
261 | setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPNS, | ||
262 | &o.so_timestampns, sizeof(o.so_timestampns)) < 0) | ||
263 | error(1, errno, "Failed to enable SO_TIMESTAMPNS"); | ||
264 | |||
265 | if (o.so_timestamping && | ||
266 | setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPING, | ||
267 | &o.so_timestamping, sizeof(o.so_timestamping)) < 0) | ||
268 | error(1, errno, "Failed to set SO_TIMESTAMPING"); | ||
269 | } | ||
270 | |||
271 | bool run_test_case(struct socket_type s, struct test_case t) | ||
272 | { | ||
273 | int port = (s.type == SOCK_RAW) ? 0 : next_port++; | ||
274 | int read_size = op_size; | ||
275 | struct sockaddr_in addr; | ||
276 | bool failed = false; | ||
277 | int src, dst, rcv; | ||
278 | |||
279 | src = socket(AF_INET, s.type, s.protocol); | ||
280 | if (src < 0) | ||
281 | error(1, errno, "Failed to open src socket"); | ||
282 | |||
283 | dst = socket(AF_INET, s.type, s.protocol); | ||
284 | if (dst < 0) | ||
285 | error(1, errno, "Failed to open dst socket"); | ||
286 | |||
287 | memset(&addr, 0, sizeof(addr)); | ||
288 | addr.sin_family = AF_INET; | ||
289 | addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | ||
290 | addr.sin_port = htons(port); | ||
291 | |||
292 | if (bind(dst, (struct sockaddr *)&addr, sizeof(addr)) < 0) | ||
293 | error(1, errno, "Failed to bind to port %d", port); | ||
294 | |||
295 | if (s.type == SOCK_STREAM && (listen(dst, 1) < 0)) | ||
296 | error(1, errno, "Failed to listen"); | ||
297 | |||
298 | if (connect(src, (struct sockaddr *)&addr, sizeof(addr)) < 0) | ||
299 | error(1, errno, "Failed to connect"); | ||
300 | |||
301 | if (s.type == SOCK_STREAM) { | ||
302 | rcv = accept(dst, NULL, NULL); | ||
303 | if (rcv < 0) | ||
304 | error(1, errno, "Failed to accept"); | ||
305 | close(dst); | ||
306 | } else { | ||
307 | rcv = dst; | ||
308 | } | ||
309 | |||
310 | config_so_flags(rcv, t.sockopt); | ||
311 | usleep(20000); /* setsockopt for SO_TIMESTAMPING is asynchronous */ | ||
312 | do_send(src); | ||
313 | |||
314 | if (s.type == SOCK_RAW) | ||
315 | read_size += 20; /* for IP header */ | ||
316 | failed = do_recv(rcv, read_size, t.expected); | ||
317 | |||
318 | close(rcv); | ||
319 | close(src); | ||
320 | |||
321 | return failed; | ||
322 | } | ||
323 | |||
324 | int main(int argc, char **argv) | ||
325 | { | ||
326 | bool all_protocols = true; | ||
327 | bool all_tests = true; | ||
328 | int arg_index = 0; | ||
329 | int failures = 0; | ||
330 | int s, t; | ||
331 | char opt; | ||
332 | |||
333 | while ((opt = getopt_long(argc, argv, "", long_options, | ||
334 | &arg_index)) != -1) { | ||
335 | switch (opt) { | ||
336 | case 'l': | ||
337 | for (t = 0; t < ARRAY_SIZE(test_cases); t++) { | ||
338 | printf("%d\t", t); | ||
339 | print_test_case(&test_cases[t]); | ||
340 | } | ||
341 | return 0; | ||
342 | case 'n': | ||
343 | t = atoi(optarg); | ||
344 | if (t >= ARRAY_SIZE(test_cases)) | ||
345 | error(1, 0, "Invalid test case: %d", t); | ||
346 | all_tests = false; | ||
347 | test_cases[t].enabled = true; | ||
348 | break; | ||
349 | case 's': | ||
350 | op_size = atoi(optarg); | ||
351 | break; | ||
352 | case 't': | ||
353 | all_protocols = false; | ||
354 | socket_types[2].enabled = true; | ||
355 | break; | ||
356 | case 'u': | ||
357 | all_protocols = false; | ||
358 | socket_types[1].enabled = true; | ||
359 | break; | ||
360 | case 'i': | ||
361 | all_protocols = false; | ||
362 | socket_types[0].enabled = true; | ||
363 | break; | ||
364 | default: | ||
365 | error(1, 0, "Failed to parse parameters."); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | for (s = 0; s < ARRAY_SIZE(socket_types); s++) { | ||
370 | if (!all_protocols && !socket_types[s].enabled) | ||
371 | continue; | ||
372 | |||
373 | printf("Testing %s...\n", socket_types[s].friendly_name); | ||
374 | for (t = 0; t < ARRAY_SIZE(test_cases); t++) { | ||
375 | if (!all_tests && !test_cases[t].enabled) | ||
376 | continue; | ||
377 | |||
378 | printf("Starting testcase %d...\n", t); | ||
379 | if (run_test_case(socket_types[s], test_cases[t])) { | ||
380 | failures++; | ||
381 | printf("FAILURE in test case "); | ||
382 | print_test_case(&test_cases[t]); | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | if (!failures) | ||
387 | printf("PASSED.\n"); | ||
388 | return failures; | ||
389 | } | ||
diff --git a/tools/testing/selftests/nsfs/config b/tools/testing/selftests/nsfs/config new file mode 100644 index 000000000000..598d0a225fc9 --- /dev/null +++ b/tools/testing/selftests/nsfs/config | |||
@@ -0,0 +1,3 @@ | |||
1 | CONFIG_USER_NS=y | ||
2 | CONFIG_UTS_NS=y | ||
3 | CONFIG_PID_NS=y | ||
diff --git a/tools/testing/selftests/powerpc/ptrace/Makefile b/tools/testing/selftests/powerpc/ptrace/Makefile index fe6bc60dfc60..8932263e5a74 100644 --- a/tools/testing/selftests/powerpc/ptrace/Makefile +++ b/tools/testing/selftests/powerpc/ptrace/Makefile | |||
@@ -6,7 +6,7 @@ include ../../lib.mk | |||
6 | 6 | ||
7 | all: $(TEST_PROGS) | 7 | all: $(TEST_PROGS) |
8 | 8 | ||
9 | CFLAGS += -m64 -I../../../../../usr/include -I../tm -mhtm | 9 | CFLAGS += -m64 -I../../../../../usr/include -I../tm -mhtm -fno-pie |
10 | 10 | ||
11 | $(TEST_PROGS): ../harness.c ../utils.c ../lib/reg.S ptrace.h | 11 | $(TEST_PROGS): ../harness.c ../utils.c ../lib/reg.S ptrace.h |
12 | 12 | ||
diff --git a/tools/testing/selftests/powerpc/switch_endian/switch_endian_test.S b/tools/testing/selftests/powerpc/switch_endian/switch_endian_test.S index ef7c971abb67..bceb53f57573 100644 --- a/tools/testing/selftests/powerpc/switch_endian/switch_endian_test.S +++ b/tools/testing/selftests/powerpc/switch_endian/switch_endian_test.S | |||
@@ -8,7 +8,7 @@ message: | |||
8 | .section ".toc" | 8 | .section ".toc" |
9 | .balign 8 | 9 | .balign 8 |
10 | pattern: | 10 | pattern: |
11 | .llong 0x5555AAAA5555AAAA | 11 | .8byte 0x5555AAAA5555AAAA |
12 | 12 | ||
13 | .text | 13 | .text |
14 | FUNC_START(_start) | 14 | FUNC_START(_start) |
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index 958c11c14acd..7bfcd454fb2a 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile | |||
@@ -15,6 +15,7 @@ $(OUTPUT)/tm-syscall: tm-syscall-asm.S | |||
15 | $(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include | 15 | $(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include |
16 | $(OUTPUT)/tm-tmspr: CFLAGS += -pthread | 16 | $(OUTPUT)/tm-tmspr: CFLAGS += -pthread |
17 | $(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64 | 17 | $(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64 |
18 | $(OUTPUT)/tm-resched-dscr: ../pmu/lib.o | ||
18 | 19 | ||
19 | SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS)) | 20 | SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS)) |
20 | $(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S | 21 | $(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S |
diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c index e79ccd6aada1..a7ac2e4c60d9 100644 --- a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c +++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | #include "utils.h" | 31 | #include "utils.h" |
32 | #include "tm.h" | 32 | #include "tm.h" |
33 | #include "../pmu/lib.h" | ||
33 | 34 | ||
34 | #define SPRN_DSCR 0x03 | 35 | #define SPRN_DSCR 0x03 |
35 | 36 | ||
@@ -75,8 +76,6 @@ int test_body(void) | |||
75 | ); | 76 | ); |
76 | assert(rv); /* make sure the transaction aborted */ | 77 | assert(rv); /* make sure the transaction aborted */ |
77 | if ((texasr >> 56) != TM_CAUSE_RESCHED) { | 78 | if ((texasr >> 56) != TM_CAUSE_RESCHED) { |
78 | putchar('.'); | ||
79 | fflush(stdout); | ||
80 | continue; | 79 | continue; |
81 | } | 80 | } |
82 | if (dscr2 != dscr1) { | 81 | if (dscr2 != dscr1) { |
@@ -89,7 +88,12 @@ int test_body(void) | |||
89 | } | 88 | } |
90 | } | 89 | } |
91 | 90 | ||
92 | int main(void) | 91 | static int tm_resched_dscr(void) |
93 | { | 92 | { |
94 | return test_harness(test_body, "tm_resched_dscr"); | 93 | return eat_cpu(test_body); |
94 | } | ||
95 | |||
96 | int main(int argc, const char *argv[]) | ||
97 | { | ||
98 | return test_harness(tm_resched_dscr, "tm_resched_dscr"); | ||
95 | } | 99 | } |
diff --git a/tools/testing/selftests/pstore/.gitignore b/tools/testing/selftests/pstore/.gitignore new file mode 100644 index 000000000000..5a4a26e5464b --- /dev/null +++ b/tools/testing/selftests/pstore/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | logs | ||
2 | *uuid | ||
diff --git a/tools/testing/selftests/ptp/Makefile b/tools/testing/selftests/ptp/Makefile index 83dd42b2129e..d4064c742c26 100644 --- a/tools/testing/selftests/ptp/Makefile +++ b/tools/testing/selftests/ptp/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | CFLAGS += -I../../../../usr/include/ | ||
1 | TEST_PROGS := testptp | 2 | TEST_PROGS := testptp |
2 | LDLIBS += -lrt | 3 | LDLIBS += -lrt |
3 | all: $(TEST_PROGS) | 4 | all: $(TEST_PROGS) |
diff --git a/tools/testing/selftests/seccomp/Makefile b/tools/testing/selftests/seccomp/Makefile index aeb0c805f3ca..553d870b4ca9 100644 --- a/tools/testing/selftests/seccomp/Makefile +++ b/tools/testing/selftests/seccomp/Makefile | |||
@@ -1,8 +1,16 @@ | |||
1 | TEST_GEN_PROGS := seccomp_bpf | 1 | all: |
2 | CFLAGS += -Wl,-no-as-needed -Wall | ||
3 | LDFLAGS += -lpthread | ||
4 | 2 | ||
5 | include ../lib.mk | 3 | include ../lib.mk |
6 | 4 | ||
7 | $(TEST_GEN_PROGS): seccomp_bpf.c ../kselftest_harness.h | 5 | .PHONY: all clean |
8 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ | 6 | |
7 | BINARIES := seccomp_bpf seccomp_benchmark | ||
8 | CFLAGS += -Wl,-no-as-needed -Wall | ||
9 | |||
10 | seccomp_bpf: seccomp_bpf.c ../kselftest_harness.h | ||
11 | $(CC) $(CFLAGS) $(LDFLAGS) -lpthread $< -o $@ | ||
12 | |||
13 | TEST_PROGS += $(BINARIES) | ||
14 | EXTRA_CLEAN := $(BINARIES) | ||
15 | |||
16 | all: $(BINARIES) | ||
diff --git a/tools/testing/selftests/seccomp/seccomp_benchmark.c b/tools/testing/selftests/seccomp/seccomp_benchmark.c new file mode 100644 index 000000000000..5838c8697ec3 --- /dev/null +++ b/tools/testing/selftests/seccomp/seccomp_benchmark.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * Strictly speaking, this is not a test. But it can report during test | ||
3 | * runs so relative performace can be measured. | ||
4 | */ | ||
5 | #define _GNU_SOURCE | ||
6 | #include <assert.h> | ||
7 | #include <stdio.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <time.h> | ||
10 | #include <unistd.h> | ||
11 | #include <linux/filter.h> | ||
12 | #include <linux/seccomp.h> | ||
13 | #include <sys/prctl.h> | ||
14 | #include <sys/syscall.h> | ||
15 | #include <sys/types.h> | ||
16 | |||
17 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) | ||
18 | |||
19 | unsigned long long timing(clockid_t clk_id, unsigned long long samples) | ||
20 | { | ||
21 | pid_t pid, ret; | ||
22 | unsigned long long i; | ||
23 | struct timespec start, finish; | ||
24 | |||
25 | pid = getpid(); | ||
26 | assert(clock_gettime(clk_id, &start) == 0); | ||
27 | for (i = 0; i < samples; i++) { | ||
28 | ret = syscall(__NR_getpid); | ||
29 | assert(pid == ret); | ||
30 | } | ||
31 | assert(clock_gettime(clk_id, &finish) == 0); | ||
32 | |||
33 | i = finish.tv_sec - start.tv_sec; | ||
34 | i *= 1000000000; | ||
35 | i += finish.tv_nsec - start.tv_nsec; | ||
36 | |||
37 | printf("%lu.%09lu - %lu.%09lu = %llu\n", | ||
38 | finish.tv_sec, finish.tv_nsec, | ||
39 | start.tv_sec, start.tv_nsec, | ||
40 | i); | ||
41 | |||
42 | return i; | ||
43 | } | ||
44 | |||
45 | unsigned long long calibrate(void) | ||
46 | { | ||
47 | unsigned long long i; | ||
48 | |||
49 | printf("Calibrating reasonable sample size...\n"); | ||
50 | |||
51 | for (i = 5; ; i++) { | ||
52 | unsigned long long samples = 1 << i; | ||
53 | |||
54 | /* Find something that takes more than 5 seconds to run. */ | ||
55 | if (timing(CLOCK_REALTIME, samples) / 1000000000ULL > 5) | ||
56 | return samples; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | int main(int argc, char *argv[]) | ||
61 | { | ||
62 | struct sock_filter filter[] = { | ||
63 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), | ||
64 | }; | ||
65 | struct sock_fprog prog = { | ||
66 | .len = (unsigned short)ARRAY_SIZE(filter), | ||
67 | .filter = filter, | ||
68 | }; | ||
69 | long ret; | ||
70 | unsigned long long samples; | ||
71 | unsigned long long native, filtered; | ||
72 | |||
73 | if (argc > 1) | ||
74 | samples = strtoull(argv[1], NULL, 0); | ||
75 | else | ||
76 | samples = calibrate(); | ||
77 | |||
78 | printf("Benchmarking %llu samples...\n", samples); | ||
79 | |||
80 | native = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; | ||
81 | printf("getpid native: %llu ns\n", native); | ||
82 | |||
83 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | ||
84 | assert(ret == 0); | ||
85 | |||
86 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); | ||
87 | assert(ret == 0); | ||
88 | |||
89 | filtered = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; | ||
90 | printf("getpid RET_ALLOW: %llu ns\n", filtered); | ||
91 | |||
92 | printf("Estimated seccomp overhead per syscall: %llu ns\n", | ||
93 | filtered - native); | ||
94 | |||
95 | if (filtered == native) | ||
96 | printf("Trying running again with more samples.\n"); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 73f5ea6778ce..24dbf634e2dd 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c | |||
@@ -6,10 +6,18 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <sys/types.h> | 8 | #include <sys/types.h> |
9 | #include <asm/siginfo.h> | 9 | |
10 | #define __have_siginfo_t 1 | 10 | /* |
11 | #define __have_sigval_t 1 | 11 | * glibc 2.26 and later have SIGSYS in siginfo_t. Before that, |
12 | #define __have_sigevent_t 1 | 12 | * we need to use the kernel's siginfo.h file and trick glibc |
13 | * into accepting it. | ||
14 | */ | ||
15 | #if !__GLIBC_PREREQ(2, 26) | ||
16 | # include <asm/siginfo.h> | ||
17 | # define __have_siginfo_t 1 | ||
18 | # define __have_sigval_t 1 | ||
19 | # define __have_sigevent_t 1 | ||
20 | #endif | ||
13 | 21 | ||
14 | #include <errno.h> | 22 | #include <errno.h> |
15 | #include <linux/filter.h> | 23 | #include <linux/filter.h> |
@@ -68,17 +76,7 @@ | |||
68 | #define SECCOMP_MODE_FILTER 2 | 76 | #define SECCOMP_MODE_FILTER 2 |
69 | #endif | 77 | #endif |
70 | 78 | ||
71 | #ifndef SECCOMP_RET_KILL | 79 | #ifndef SECCOMP_RET_ALLOW |
72 | #define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ | ||
73 | #define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ | ||
74 | #define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ | ||
75 | #define SECCOMP_RET_TRACE 0x7ff00000U /* pass to a tracer or disallow */ | ||
76 | #define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ | ||
77 | |||
78 | /* Masks for the return value sections. */ | ||
79 | #define SECCOMP_RET_ACTION 0x7fff0000U | ||
80 | #define SECCOMP_RET_DATA 0x0000ffffU | ||
81 | |||
82 | struct seccomp_data { | 80 | struct seccomp_data { |
83 | int nr; | 81 | int nr; |
84 | __u32 arch; | 82 | __u32 arch; |
@@ -87,6 +85,70 @@ struct seccomp_data { | |||
87 | }; | 85 | }; |
88 | #endif | 86 | #endif |
89 | 87 | ||
88 | #ifndef SECCOMP_RET_KILL_PROCESS | ||
89 | #define SECCOMP_RET_KILL_PROCESS 0x80000000U /* kill the process */ | ||
90 | #define SECCOMP_RET_KILL_THREAD 0x00000000U /* kill the thread */ | ||
91 | #endif | ||
92 | #ifndef SECCOMP_RET_KILL | ||
93 | #define SECCOMP_RET_KILL SECCOMP_RET_KILL_THREAD | ||
94 | #define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ | ||
95 | #define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ | ||
96 | #define SECCOMP_RET_TRACE 0x7ff00000U /* pass to a tracer or disallow */ | ||
97 | #define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ | ||
98 | #endif | ||
99 | #ifndef SECCOMP_RET_LOG | ||
100 | #define SECCOMP_RET_LOG 0x7ffc0000U /* allow after logging */ | ||
101 | #endif | ||
102 | |||
103 | #ifndef __NR_seccomp | ||
104 | # if defined(__i386__) | ||
105 | # define __NR_seccomp 354 | ||
106 | # elif defined(__x86_64__) | ||
107 | # define __NR_seccomp 317 | ||
108 | # elif defined(__arm__) | ||
109 | # define __NR_seccomp 383 | ||
110 | # elif defined(__aarch64__) | ||
111 | # define __NR_seccomp 277 | ||
112 | # elif defined(__hppa__) | ||
113 | # define __NR_seccomp 338 | ||
114 | # elif defined(__powerpc__) | ||
115 | # define __NR_seccomp 358 | ||
116 | # elif defined(__s390__) | ||
117 | # define __NR_seccomp 348 | ||
118 | # else | ||
119 | # warning "seccomp syscall number unknown for this architecture" | ||
120 | # define __NR_seccomp 0xffff | ||
121 | # endif | ||
122 | #endif | ||
123 | |||
124 | #ifndef SECCOMP_SET_MODE_STRICT | ||
125 | #define SECCOMP_SET_MODE_STRICT 0 | ||
126 | #endif | ||
127 | |||
128 | #ifndef SECCOMP_SET_MODE_FILTER | ||
129 | #define SECCOMP_SET_MODE_FILTER 1 | ||
130 | #endif | ||
131 | |||
132 | #ifndef SECCOMP_GET_ACTION_AVAIL | ||
133 | #define SECCOMP_GET_ACTION_AVAIL 2 | ||
134 | #endif | ||
135 | |||
136 | #ifndef SECCOMP_FILTER_FLAG_TSYNC | ||
137 | #define SECCOMP_FILTER_FLAG_TSYNC 1 | ||
138 | #endif | ||
139 | |||
140 | #ifndef SECCOMP_FILTER_FLAG_LOG | ||
141 | #define SECCOMP_FILTER_FLAG_LOG 2 | ||
142 | #endif | ||
143 | |||
144 | #ifndef seccomp | ||
145 | int seccomp(unsigned int op, unsigned int flags, void *args) | ||
146 | { | ||
147 | errno = 0; | ||
148 | return syscall(__NR_seccomp, op, flags, args); | ||
149 | } | ||
150 | #endif | ||
151 | |||
90 | #if __BYTE_ORDER == __LITTLE_ENDIAN | 152 | #if __BYTE_ORDER == __LITTLE_ENDIAN |
91 | #define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n])) | 153 | #define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n])) |
92 | #elif __BYTE_ORDER == __BIG_ENDIAN | 154 | #elif __BYTE_ORDER == __BIG_ENDIAN |
@@ -107,7 +169,7 @@ TEST(mode_strict_support) | |||
107 | ASSERT_EQ(0, ret) { | 169 | ASSERT_EQ(0, ret) { |
108 | TH_LOG("Kernel does not support CONFIG_SECCOMP"); | 170 | TH_LOG("Kernel does not support CONFIG_SECCOMP"); |
109 | } | 171 | } |
110 | syscall(__NR_exit, 1); | 172 | syscall(__NR_exit, 0); |
111 | } | 173 | } |
112 | 174 | ||
113 | TEST_SIGNAL(mode_strict_cannot_call_prctl, SIGKILL) | 175 | TEST_SIGNAL(mode_strict_cannot_call_prctl, SIGKILL) |
@@ -136,7 +198,7 @@ TEST(no_new_privs_support) | |||
136 | } | 198 | } |
137 | } | 199 | } |
138 | 200 | ||
139 | /* Tests kernel support by checking for a copy_from_user() fault on * NULL. */ | 201 | /* Tests kernel support by checking for a copy_from_user() fault on NULL. */ |
140 | TEST(mode_filter_support) | 202 | TEST(mode_filter_support) |
141 | { | 203 | { |
142 | long ret; | 204 | long ret; |
@@ -342,6 +404,28 @@ TEST(empty_prog) | |||
342 | EXPECT_EQ(EINVAL, errno); | 404 | EXPECT_EQ(EINVAL, errno); |
343 | } | 405 | } |
344 | 406 | ||
407 | TEST(log_all) | ||
408 | { | ||
409 | struct sock_filter filter[] = { | ||
410 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_LOG), | ||
411 | }; | ||
412 | struct sock_fprog prog = { | ||
413 | .len = (unsigned short)ARRAY_SIZE(filter), | ||
414 | .filter = filter, | ||
415 | }; | ||
416 | long ret; | ||
417 | pid_t parent = getppid(); | ||
418 | |||
419 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | ||
420 | ASSERT_EQ(0, ret); | ||
421 | |||
422 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); | ||
423 | ASSERT_EQ(0, ret); | ||
424 | |||
425 | /* getppid() should succeed and be logged (no check for logging) */ | ||
426 | EXPECT_EQ(parent, syscall(__NR_getppid)); | ||
427 | } | ||
428 | |||
345 | TEST_SIGNAL(unknown_ret_is_kill_inside, SIGSYS) | 429 | TEST_SIGNAL(unknown_ret_is_kill_inside, SIGSYS) |
346 | { | 430 | { |
347 | struct sock_filter filter[] = { | 431 | struct sock_filter filter[] = { |
@@ -520,6 +604,117 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS) | |||
520 | close(fd); | 604 | close(fd); |
521 | } | 605 | } |
522 | 606 | ||
607 | /* This is a thread task to die via seccomp filter violation. */ | ||
608 | void *kill_thread(void *data) | ||
609 | { | ||
610 | bool die = (bool)data; | ||
611 | |||
612 | if (die) { | ||
613 | prctl(PR_GET_SECCOMP, 0, 0, 0, 0); | ||
614 | return (void *)SIBLING_EXIT_FAILURE; | ||
615 | } | ||
616 | |||
617 | return (void *)SIBLING_EXIT_UNKILLED; | ||
618 | } | ||
619 | |||
620 | /* Prepare a thread that will kill itself or both of us. */ | ||
621 | void kill_thread_or_group(struct __test_metadata *_metadata, bool kill_process) | ||
622 | { | ||
623 | pthread_t thread; | ||
624 | void *status; | ||
625 | /* Kill only when calling __NR_prctl. */ | ||
626 | struct sock_filter filter_thread[] = { | ||
627 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, | ||
628 | offsetof(struct seccomp_data, nr)), | ||
629 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1), | ||
630 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_THREAD), | ||
631 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), | ||
632 | }; | ||
633 | struct sock_fprog prog_thread = { | ||
634 | .len = (unsigned short)ARRAY_SIZE(filter_thread), | ||
635 | .filter = filter_thread, | ||
636 | }; | ||
637 | struct sock_filter filter_process[] = { | ||
638 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, | ||
639 | offsetof(struct seccomp_data, nr)), | ||
640 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1), | ||
641 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_PROCESS), | ||
642 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), | ||
643 | }; | ||
644 | struct sock_fprog prog_process = { | ||
645 | .len = (unsigned short)ARRAY_SIZE(filter_process), | ||
646 | .filter = filter_process, | ||
647 | }; | ||
648 | |||
649 | ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
650 | TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); | ||
651 | } | ||
652 | |||
653 | ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, | ||
654 | kill_process ? &prog_process : &prog_thread)); | ||
655 | |||
656 | /* | ||
657 | * Add the KILL_THREAD rule again to make sure that the KILL_PROCESS | ||
658 | * flag cannot be downgraded by a new filter. | ||
659 | */ | ||
660 | ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog_thread)); | ||
661 | |||
662 | /* Start a thread that will exit immediately. */ | ||
663 | ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)false)); | ||
664 | ASSERT_EQ(0, pthread_join(thread, &status)); | ||
665 | ASSERT_EQ(SIBLING_EXIT_UNKILLED, (unsigned long)status); | ||
666 | |||
667 | /* Start a thread that will die immediately. */ | ||
668 | ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)true)); | ||
669 | ASSERT_EQ(0, pthread_join(thread, &status)); | ||
670 | ASSERT_NE(SIBLING_EXIT_FAILURE, (unsigned long)status); | ||
671 | |||
672 | /* | ||
673 | * If we get here, only the spawned thread died. Let the parent know | ||
674 | * the whole process didn't die (i.e. this thread, the spawner, | ||
675 | * stayed running). | ||
676 | */ | ||
677 | exit(42); | ||
678 | } | ||
679 | |||
680 | TEST(KILL_thread) | ||
681 | { | ||
682 | int status; | ||
683 | pid_t child_pid; | ||
684 | |||
685 | child_pid = fork(); | ||
686 | ASSERT_LE(0, child_pid); | ||
687 | if (child_pid == 0) { | ||
688 | kill_thread_or_group(_metadata, false); | ||
689 | _exit(38); | ||
690 | } | ||
691 | |||
692 | ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); | ||
693 | |||
694 | /* If only the thread was killed, we'll see exit 42. */ | ||
695 | ASSERT_TRUE(WIFEXITED(status)); | ||
696 | ASSERT_EQ(42, WEXITSTATUS(status)); | ||
697 | } | ||
698 | |||
699 | TEST(KILL_process) | ||
700 | { | ||
701 | int status; | ||
702 | pid_t child_pid; | ||
703 | |||
704 | child_pid = fork(); | ||
705 | ASSERT_LE(0, child_pid); | ||
706 | if (child_pid == 0) { | ||
707 | kill_thread_or_group(_metadata, true); | ||
708 | _exit(38); | ||
709 | } | ||
710 | |||
711 | ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); | ||
712 | |||
713 | /* If the entire process was killed, we'll see SIGSYS. */ | ||
714 | ASSERT_TRUE(WIFSIGNALED(status)); | ||
715 | ASSERT_EQ(SIGSYS, WTERMSIG(status)); | ||
716 | } | ||
717 | |||
523 | /* TODO(wad) add 64-bit versus 32-bit arg tests. */ | 718 | /* TODO(wad) add 64-bit versus 32-bit arg tests. */ |
524 | TEST(arg_out_of_range) | 719 | TEST(arg_out_of_range) |
525 | { | 720 | { |
@@ -541,26 +736,30 @@ TEST(arg_out_of_range) | |||
541 | EXPECT_EQ(EINVAL, errno); | 736 | EXPECT_EQ(EINVAL, errno); |
542 | } | 737 | } |
543 | 738 | ||
739 | #define ERRNO_FILTER(name, errno) \ | ||
740 | struct sock_filter _read_filter_##name[] = { \ | ||
741 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, \ | ||
742 | offsetof(struct seccomp_data, nr)), \ | ||
743 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), \ | ||
744 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | errno), \ | ||
745 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), \ | ||
746 | }; \ | ||
747 | struct sock_fprog prog_##name = { \ | ||
748 | .len = (unsigned short)ARRAY_SIZE(_read_filter_##name), \ | ||
749 | .filter = _read_filter_##name, \ | ||
750 | } | ||
751 | |||
752 | /* Make sure basic errno values are correctly passed through a filter. */ | ||
544 | TEST(ERRNO_valid) | 753 | TEST(ERRNO_valid) |
545 | { | 754 | { |
546 | struct sock_filter filter[] = { | 755 | ERRNO_FILTER(valid, E2BIG); |
547 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, | ||
548 | offsetof(struct seccomp_data, nr)), | ||
549 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), | ||
550 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | E2BIG), | ||
551 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), | ||
552 | }; | ||
553 | struct sock_fprog prog = { | ||
554 | .len = (unsigned short)ARRAY_SIZE(filter), | ||
555 | .filter = filter, | ||
556 | }; | ||
557 | long ret; | 756 | long ret; |
558 | pid_t parent = getppid(); | 757 | pid_t parent = getppid(); |
559 | 758 | ||
560 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | 759 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); |
561 | ASSERT_EQ(0, ret); | 760 | ASSERT_EQ(0, ret); |
562 | 761 | ||
563 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); | 762 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_valid); |
564 | ASSERT_EQ(0, ret); | 763 | ASSERT_EQ(0, ret); |
565 | 764 | ||
566 | EXPECT_EQ(parent, syscall(__NR_getppid)); | 765 | EXPECT_EQ(parent, syscall(__NR_getppid)); |
@@ -568,26 +767,17 @@ TEST(ERRNO_valid) | |||
568 | EXPECT_EQ(E2BIG, errno); | 767 | EXPECT_EQ(E2BIG, errno); |
569 | } | 768 | } |
570 | 769 | ||
770 | /* Make sure an errno of zero is correctly handled by the arch code. */ | ||
571 | TEST(ERRNO_zero) | 771 | TEST(ERRNO_zero) |
572 | { | 772 | { |
573 | struct sock_filter filter[] = { | 773 | ERRNO_FILTER(zero, 0); |
574 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, | ||
575 | offsetof(struct seccomp_data, nr)), | ||
576 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), | ||
577 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | 0), | ||
578 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), | ||
579 | }; | ||
580 | struct sock_fprog prog = { | ||
581 | .len = (unsigned short)ARRAY_SIZE(filter), | ||
582 | .filter = filter, | ||
583 | }; | ||
584 | long ret; | 774 | long ret; |
585 | pid_t parent = getppid(); | 775 | pid_t parent = getppid(); |
586 | 776 | ||
587 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | 777 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); |
588 | ASSERT_EQ(0, ret); | 778 | ASSERT_EQ(0, ret); |
589 | 779 | ||
590 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); | 780 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_zero); |
591 | ASSERT_EQ(0, ret); | 781 | ASSERT_EQ(0, ret); |
592 | 782 | ||
593 | EXPECT_EQ(parent, syscall(__NR_getppid)); | 783 | EXPECT_EQ(parent, syscall(__NR_getppid)); |
@@ -595,26 +785,21 @@ TEST(ERRNO_zero) | |||
595 | EXPECT_EQ(0, read(0, NULL, 0)); | 785 | EXPECT_EQ(0, read(0, NULL, 0)); |
596 | } | 786 | } |
597 | 787 | ||
788 | /* | ||
789 | * The SECCOMP_RET_DATA mask is 16 bits wide, but errno is smaller. | ||
790 | * This tests that the errno value gets capped correctly, fixed by | ||
791 | * 580c57f10768 ("seccomp: cap SECCOMP_RET_ERRNO data to MAX_ERRNO"). | ||
792 | */ | ||
598 | TEST(ERRNO_capped) | 793 | TEST(ERRNO_capped) |
599 | { | 794 | { |
600 | struct sock_filter filter[] = { | 795 | ERRNO_FILTER(capped, 4096); |
601 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, | ||
602 | offsetof(struct seccomp_data, nr)), | ||
603 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), | ||
604 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | 4096), | ||
605 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), | ||
606 | }; | ||
607 | struct sock_fprog prog = { | ||
608 | .len = (unsigned short)ARRAY_SIZE(filter), | ||
609 | .filter = filter, | ||
610 | }; | ||
611 | long ret; | 796 | long ret; |
612 | pid_t parent = getppid(); | 797 | pid_t parent = getppid(); |
613 | 798 | ||
614 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | 799 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); |
615 | ASSERT_EQ(0, ret); | 800 | ASSERT_EQ(0, ret); |
616 | 801 | ||
617 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); | 802 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_capped); |
618 | ASSERT_EQ(0, ret); | 803 | ASSERT_EQ(0, ret); |
619 | 804 | ||
620 | EXPECT_EQ(parent, syscall(__NR_getppid)); | 805 | EXPECT_EQ(parent, syscall(__NR_getppid)); |
@@ -622,6 +807,37 @@ TEST(ERRNO_capped) | |||
622 | EXPECT_EQ(4095, errno); | 807 | EXPECT_EQ(4095, errno); |
623 | } | 808 | } |
624 | 809 | ||
810 | /* | ||
811 | * Filters are processed in reverse order: last applied is executed first. | ||
812 | * Since only the SECCOMP_RET_ACTION mask is tested for return values, the | ||
813 | * SECCOMP_RET_DATA mask results will follow the most recently applied | ||
814 | * matching filter return (and not the lowest or highest value). | ||
815 | */ | ||
816 | TEST(ERRNO_order) | ||
817 | { | ||
818 | ERRNO_FILTER(first, 11); | ||
819 | ERRNO_FILTER(second, 13); | ||
820 | ERRNO_FILTER(third, 12); | ||
821 | long ret; | ||
822 | pid_t parent = getppid(); | ||
823 | |||
824 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | ||
825 | ASSERT_EQ(0, ret); | ||
826 | |||
827 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_first); | ||
828 | ASSERT_EQ(0, ret); | ||
829 | |||
830 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_second); | ||
831 | ASSERT_EQ(0, ret); | ||
832 | |||
833 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_third); | ||
834 | ASSERT_EQ(0, ret); | ||
835 | |||
836 | EXPECT_EQ(parent, syscall(__NR_getppid)); | ||
837 | EXPECT_EQ(-1, read(0, NULL, 0)); | ||
838 | EXPECT_EQ(12, errno); | ||
839 | } | ||
840 | |||
625 | FIXTURE_DATA(TRAP) { | 841 | FIXTURE_DATA(TRAP) { |
626 | struct sock_fprog prog; | 842 | struct sock_fprog prog; |
627 | }; | 843 | }; |
@@ -676,7 +892,7 @@ TEST_F_SIGNAL(TRAP, ign, SIGSYS) | |||
676 | syscall(__NR_getpid); | 892 | syscall(__NR_getpid); |
677 | } | 893 | } |
678 | 894 | ||
679 | static struct siginfo TRAP_info; | 895 | static siginfo_t TRAP_info; |
680 | static volatile int TRAP_nr; | 896 | static volatile int TRAP_nr; |
681 | static void TRAP_action(int nr, siginfo_t *info, void *void_context) | 897 | static void TRAP_action(int nr, siginfo_t *info, void *void_context) |
682 | { | 898 | { |
@@ -735,6 +951,7 @@ TEST_F(TRAP, handler) | |||
735 | 951 | ||
736 | FIXTURE_DATA(precedence) { | 952 | FIXTURE_DATA(precedence) { |
737 | struct sock_fprog allow; | 953 | struct sock_fprog allow; |
954 | struct sock_fprog log; | ||
738 | struct sock_fprog trace; | 955 | struct sock_fprog trace; |
739 | struct sock_fprog error; | 956 | struct sock_fprog error; |
740 | struct sock_fprog trap; | 957 | struct sock_fprog trap; |
@@ -746,6 +963,13 @@ FIXTURE_SETUP(precedence) | |||
746 | struct sock_filter allow_insns[] = { | 963 | struct sock_filter allow_insns[] = { |
747 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), | 964 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), |
748 | }; | 965 | }; |
966 | struct sock_filter log_insns[] = { | ||
967 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, | ||
968 | offsetof(struct seccomp_data, nr)), | ||
969 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0), | ||
970 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), | ||
971 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_LOG), | ||
972 | }; | ||
749 | struct sock_filter trace_insns[] = { | 973 | struct sock_filter trace_insns[] = { |
750 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, | 974 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, |
751 | offsetof(struct seccomp_data, nr)), | 975 | offsetof(struct seccomp_data, nr)), |
@@ -782,6 +1006,7 @@ FIXTURE_SETUP(precedence) | |||
782 | memcpy(self->_x.filter, &_x##_insns, sizeof(_x##_insns)); \ | 1006 | memcpy(self->_x.filter, &_x##_insns, sizeof(_x##_insns)); \ |
783 | self->_x.len = (unsigned short)ARRAY_SIZE(_x##_insns) | 1007 | self->_x.len = (unsigned short)ARRAY_SIZE(_x##_insns) |
784 | FILTER_ALLOC(allow); | 1008 | FILTER_ALLOC(allow); |
1009 | FILTER_ALLOC(log); | ||
785 | FILTER_ALLOC(trace); | 1010 | FILTER_ALLOC(trace); |
786 | FILTER_ALLOC(error); | 1011 | FILTER_ALLOC(error); |
787 | FILTER_ALLOC(trap); | 1012 | FILTER_ALLOC(trap); |
@@ -792,6 +1017,7 @@ FIXTURE_TEARDOWN(precedence) | |||
792 | { | 1017 | { |
793 | #define FILTER_FREE(_x) if (self->_x.filter) free(self->_x.filter) | 1018 | #define FILTER_FREE(_x) if (self->_x.filter) free(self->_x.filter) |
794 | FILTER_FREE(allow); | 1019 | FILTER_FREE(allow); |
1020 | FILTER_FREE(log); | ||
795 | FILTER_FREE(trace); | 1021 | FILTER_FREE(trace); |
796 | FILTER_FREE(error); | 1022 | FILTER_FREE(error); |
797 | FILTER_FREE(trap); | 1023 | FILTER_FREE(trap); |
@@ -809,6 +1035,8 @@ TEST_F(precedence, allow_ok) | |||
809 | 1035 | ||
810 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); | 1036 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); |
811 | ASSERT_EQ(0, ret); | 1037 | ASSERT_EQ(0, ret); |
1038 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); | ||
1039 | ASSERT_EQ(0, ret); | ||
812 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); | 1040 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); |
813 | ASSERT_EQ(0, ret); | 1041 | ASSERT_EQ(0, ret); |
814 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); | 1042 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); |
@@ -833,6 +1061,8 @@ TEST_F_SIGNAL(precedence, kill_is_highest, SIGSYS) | |||
833 | 1061 | ||
834 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); | 1062 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); |
835 | ASSERT_EQ(0, ret); | 1063 | ASSERT_EQ(0, ret); |
1064 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); | ||
1065 | ASSERT_EQ(0, ret); | ||
836 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); | 1066 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); |
837 | ASSERT_EQ(0, ret); | 1067 | ASSERT_EQ(0, ret); |
838 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); | 1068 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); |
@@ -864,6 +1094,8 @@ TEST_F_SIGNAL(precedence, kill_is_highest_in_any_order, SIGSYS) | |||
864 | ASSERT_EQ(0, ret); | 1094 | ASSERT_EQ(0, ret); |
865 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); | 1095 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); |
866 | ASSERT_EQ(0, ret); | 1096 | ASSERT_EQ(0, ret); |
1097 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); | ||
1098 | ASSERT_EQ(0, ret); | ||
867 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); | 1099 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); |
868 | ASSERT_EQ(0, ret); | 1100 | ASSERT_EQ(0, ret); |
869 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap); | 1101 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap); |
@@ -885,6 +1117,8 @@ TEST_F_SIGNAL(precedence, trap_is_second, SIGSYS) | |||
885 | 1117 | ||
886 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); | 1118 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); |
887 | ASSERT_EQ(0, ret); | 1119 | ASSERT_EQ(0, ret); |
1120 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); | ||
1121 | ASSERT_EQ(0, ret); | ||
888 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); | 1122 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); |
889 | ASSERT_EQ(0, ret); | 1123 | ASSERT_EQ(0, ret); |
890 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); | 1124 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); |
@@ -910,6 +1144,8 @@ TEST_F_SIGNAL(precedence, trap_is_second_in_any_order, SIGSYS) | |||
910 | ASSERT_EQ(0, ret); | 1144 | ASSERT_EQ(0, ret); |
911 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap); | 1145 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap); |
912 | ASSERT_EQ(0, ret); | 1146 | ASSERT_EQ(0, ret); |
1147 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); | ||
1148 | ASSERT_EQ(0, ret); | ||
913 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); | 1149 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); |
914 | ASSERT_EQ(0, ret); | 1150 | ASSERT_EQ(0, ret); |
915 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); | 1151 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); |
@@ -931,6 +1167,8 @@ TEST_F(precedence, errno_is_third) | |||
931 | 1167 | ||
932 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); | 1168 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); |
933 | ASSERT_EQ(0, ret); | 1169 | ASSERT_EQ(0, ret); |
1170 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); | ||
1171 | ASSERT_EQ(0, ret); | ||
934 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); | 1172 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); |
935 | ASSERT_EQ(0, ret); | 1173 | ASSERT_EQ(0, ret); |
936 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); | 1174 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); |
@@ -949,6 +1187,8 @@ TEST_F(precedence, errno_is_third_in_any_order) | |||
949 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | 1187 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); |
950 | ASSERT_EQ(0, ret); | 1188 | ASSERT_EQ(0, ret); |
951 | 1189 | ||
1190 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); | ||
1191 | ASSERT_EQ(0, ret); | ||
952 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); | 1192 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); |
953 | ASSERT_EQ(0, ret); | 1193 | ASSERT_EQ(0, ret); |
954 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); | 1194 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); |
@@ -971,6 +1211,8 @@ TEST_F(precedence, trace_is_fourth) | |||
971 | 1211 | ||
972 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); | 1212 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); |
973 | ASSERT_EQ(0, ret); | 1213 | ASSERT_EQ(0, ret); |
1214 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); | ||
1215 | ASSERT_EQ(0, ret); | ||
974 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); | 1216 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); |
975 | ASSERT_EQ(0, ret); | 1217 | ASSERT_EQ(0, ret); |
976 | /* Should work just fine. */ | 1218 | /* Should work just fine. */ |
@@ -992,12 +1234,54 @@ TEST_F(precedence, trace_is_fourth_in_any_order) | |||
992 | ASSERT_EQ(0, ret); | 1234 | ASSERT_EQ(0, ret); |
993 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); | 1235 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); |
994 | ASSERT_EQ(0, ret); | 1236 | ASSERT_EQ(0, ret); |
1237 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); | ||
1238 | ASSERT_EQ(0, ret); | ||
995 | /* Should work just fine. */ | 1239 | /* Should work just fine. */ |
996 | EXPECT_EQ(parent, syscall(__NR_getppid)); | 1240 | EXPECT_EQ(parent, syscall(__NR_getppid)); |
997 | /* No ptracer */ | 1241 | /* No ptracer */ |
998 | EXPECT_EQ(-1, syscall(__NR_getpid)); | 1242 | EXPECT_EQ(-1, syscall(__NR_getpid)); |
999 | } | 1243 | } |
1000 | 1244 | ||
1245 | TEST_F(precedence, log_is_fifth) | ||
1246 | { | ||
1247 | pid_t mypid, parent; | ||
1248 | long ret; | ||
1249 | |||
1250 | mypid = getpid(); | ||
1251 | parent = getppid(); | ||
1252 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | ||
1253 | ASSERT_EQ(0, ret); | ||
1254 | |||
1255 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); | ||
1256 | ASSERT_EQ(0, ret); | ||
1257 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); | ||
1258 | ASSERT_EQ(0, ret); | ||
1259 | /* Should work just fine. */ | ||
1260 | EXPECT_EQ(parent, syscall(__NR_getppid)); | ||
1261 | /* Should also work just fine */ | ||
1262 | EXPECT_EQ(mypid, syscall(__NR_getpid)); | ||
1263 | } | ||
1264 | |||
1265 | TEST_F(precedence, log_is_fifth_in_any_order) | ||
1266 | { | ||
1267 | pid_t mypid, parent; | ||
1268 | long ret; | ||
1269 | |||
1270 | mypid = getpid(); | ||
1271 | parent = getppid(); | ||
1272 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | ||
1273 | ASSERT_EQ(0, ret); | ||
1274 | |||
1275 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); | ||
1276 | ASSERT_EQ(0, ret); | ||
1277 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); | ||
1278 | ASSERT_EQ(0, ret); | ||
1279 | /* Should work just fine. */ | ||
1280 | EXPECT_EQ(parent, syscall(__NR_getppid)); | ||
1281 | /* Should also work just fine */ | ||
1282 | EXPECT_EQ(mypid, syscall(__NR_getpid)); | ||
1283 | } | ||
1284 | |||
1001 | #ifndef PTRACE_O_TRACESECCOMP | 1285 | #ifndef PTRACE_O_TRACESECCOMP |
1002 | #define PTRACE_O_TRACESECCOMP 0x00000080 | 1286 | #define PTRACE_O_TRACESECCOMP 0x00000080 |
1003 | #endif | 1287 | #endif |
@@ -1262,6 +1546,13 @@ TEST_F(TRACE_poke, getpid_runs_normally) | |||
1262 | # error "Do not know how to find your architecture's registers and syscalls" | 1546 | # error "Do not know how to find your architecture's registers and syscalls" |
1263 | #endif | 1547 | #endif |
1264 | 1548 | ||
1549 | /* When the syscall return can't be changed, stub out the tests for it. */ | ||
1550 | #ifdef SYSCALL_NUM_RET_SHARE_REG | ||
1551 | # define EXPECT_SYSCALL_RETURN(val, action) EXPECT_EQ(-1, action) | ||
1552 | #else | ||
1553 | # define EXPECT_SYSCALL_RETURN(val, action) EXPECT_EQ(val, action) | ||
1554 | #endif | ||
1555 | |||
1265 | /* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for | 1556 | /* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for |
1266 | * architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux). | 1557 | * architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux). |
1267 | */ | 1558 | */ |
@@ -1357,7 +1648,7 @@ void change_syscall(struct __test_metadata *_metadata, | |||
1357 | #ifdef SYSCALL_NUM_RET_SHARE_REG | 1648 | #ifdef SYSCALL_NUM_RET_SHARE_REG |
1358 | TH_LOG("Can't modify syscall return on this architecture"); | 1649 | TH_LOG("Can't modify syscall return on this architecture"); |
1359 | #else | 1650 | #else |
1360 | regs.SYSCALL_RET = 1; | 1651 | regs.SYSCALL_RET = EPERM; |
1361 | #endif | 1652 | #endif |
1362 | 1653 | ||
1363 | #ifdef HAVE_GETREGS | 1654 | #ifdef HAVE_GETREGS |
@@ -1426,6 +1717,8 @@ void tracer_ptrace(struct __test_metadata *_metadata, pid_t tracee, | |||
1426 | 1717 | ||
1427 | if (nr == __NR_getpid) | 1718 | if (nr == __NR_getpid) |
1428 | change_syscall(_metadata, tracee, __NR_getppid); | 1719 | change_syscall(_metadata, tracee, __NR_getppid); |
1720 | if (nr == __NR_open) | ||
1721 | change_syscall(_metadata, tracee, -1); | ||
1429 | } | 1722 | } |
1430 | 1723 | ||
1431 | FIXTURE_DATA(TRACE_syscall) { | 1724 | FIXTURE_DATA(TRACE_syscall) { |
@@ -1480,6 +1773,28 @@ FIXTURE_TEARDOWN(TRACE_syscall) | |||
1480 | free(self->prog.filter); | 1773 | free(self->prog.filter); |
1481 | } | 1774 | } |
1482 | 1775 | ||
1776 | TEST_F(TRACE_syscall, ptrace_syscall_redirected) | ||
1777 | { | ||
1778 | /* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */ | ||
1779 | teardown_trace_fixture(_metadata, self->tracer); | ||
1780 | self->tracer = setup_trace_fixture(_metadata, tracer_ptrace, NULL, | ||
1781 | true); | ||
1782 | |||
1783 | /* Tracer will redirect getpid to getppid. */ | ||
1784 | EXPECT_NE(self->mypid, syscall(__NR_getpid)); | ||
1785 | } | ||
1786 | |||
1787 | TEST_F(TRACE_syscall, ptrace_syscall_dropped) | ||
1788 | { | ||
1789 | /* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */ | ||
1790 | teardown_trace_fixture(_metadata, self->tracer); | ||
1791 | self->tracer = setup_trace_fixture(_metadata, tracer_ptrace, NULL, | ||
1792 | true); | ||
1793 | |||
1794 | /* Tracer should skip the open syscall, resulting in EPERM. */ | ||
1795 | EXPECT_SYSCALL_RETURN(EPERM, syscall(__NR_open)); | ||
1796 | } | ||
1797 | |||
1483 | TEST_F(TRACE_syscall, syscall_allowed) | 1798 | TEST_F(TRACE_syscall, syscall_allowed) |
1484 | { | 1799 | { |
1485 | long ret; | 1800 | long ret; |
@@ -1520,13 +1835,8 @@ TEST_F(TRACE_syscall, syscall_dropped) | |||
1520 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0); | 1835 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0); |
1521 | ASSERT_EQ(0, ret); | 1836 | ASSERT_EQ(0, ret); |
1522 | 1837 | ||
1523 | #ifdef SYSCALL_NUM_RET_SHARE_REG | ||
1524 | /* gettid has been skipped */ | ||
1525 | EXPECT_EQ(-1, syscall(__NR_gettid)); | ||
1526 | #else | ||
1527 | /* gettid has been skipped and an altered return value stored. */ | 1838 | /* gettid has been skipped and an altered return value stored. */ |
1528 | EXPECT_EQ(1, syscall(__NR_gettid)); | 1839 | EXPECT_SYSCALL_RETURN(EPERM, syscall(__NR_gettid)); |
1529 | #endif | ||
1530 | EXPECT_NE(self->mytid, syscall(__NR_gettid)); | 1840 | EXPECT_NE(self->mytid, syscall(__NR_gettid)); |
1531 | } | 1841 | } |
1532 | 1842 | ||
@@ -1557,6 +1867,7 @@ TEST_F(TRACE_syscall, skip_after_RET_TRACE) | |||
1557 | ASSERT_EQ(0, ret); | 1867 | ASSERT_EQ(0, ret); |
1558 | 1868 | ||
1559 | /* Tracer will redirect getpid to getppid, and we should see EPERM. */ | 1869 | /* Tracer will redirect getpid to getppid, and we should see EPERM. */ |
1870 | errno = 0; | ||
1560 | EXPECT_EQ(-1, syscall(__NR_getpid)); | 1871 | EXPECT_EQ(-1, syscall(__NR_getpid)); |
1561 | EXPECT_EQ(EPERM, errno); | 1872 | EXPECT_EQ(EPERM, errno); |
1562 | } | 1873 | } |
@@ -1654,47 +1965,6 @@ TEST_F_SIGNAL(TRACE_syscall, kill_after_ptrace, SIGSYS) | |||
1654 | EXPECT_NE(self->mypid, syscall(__NR_getpid)); | 1965 | EXPECT_NE(self->mypid, syscall(__NR_getpid)); |
1655 | } | 1966 | } |
1656 | 1967 | ||
1657 | #ifndef __NR_seccomp | ||
1658 | # if defined(__i386__) | ||
1659 | # define __NR_seccomp 354 | ||
1660 | # elif defined(__x86_64__) | ||
1661 | # define __NR_seccomp 317 | ||
1662 | # elif defined(__arm__) | ||
1663 | # define __NR_seccomp 383 | ||
1664 | # elif defined(__aarch64__) | ||
1665 | # define __NR_seccomp 277 | ||
1666 | # elif defined(__hppa__) | ||
1667 | # define __NR_seccomp 338 | ||
1668 | # elif defined(__powerpc__) | ||
1669 | # define __NR_seccomp 358 | ||
1670 | # elif defined(__s390__) | ||
1671 | # define __NR_seccomp 348 | ||
1672 | # else | ||
1673 | # warning "seccomp syscall number unknown for this architecture" | ||
1674 | # define __NR_seccomp 0xffff | ||
1675 | # endif | ||
1676 | #endif | ||
1677 | |||
1678 | #ifndef SECCOMP_SET_MODE_STRICT | ||
1679 | #define SECCOMP_SET_MODE_STRICT 0 | ||
1680 | #endif | ||
1681 | |||
1682 | #ifndef SECCOMP_SET_MODE_FILTER | ||
1683 | #define SECCOMP_SET_MODE_FILTER 1 | ||
1684 | #endif | ||
1685 | |||
1686 | #ifndef SECCOMP_FILTER_FLAG_TSYNC | ||
1687 | #define SECCOMP_FILTER_FLAG_TSYNC 1 | ||
1688 | #endif | ||
1689 | |||
1690 | #ifndef seccomp | ||
1691 | int seccomp(unsigned int op, unsigned int flags, void *args) | ||
1692 | { | ||
1693 | errno = 0; | ||
1694 | return syscall(__NR_seccomp, op, flags, args); | ||
1695 | } | ||
1696 | #endif | ||
1697 | |||
1698 | TEST(seccomp_syscall) | 1968 | TEST(seccomp_syscall) |
1699 | { | 1969 | { |
1700 | struct sock_filter filter[] = { | 1970 | struct sock_filter filter[] = { |
@@ -1783,6 +2053,67 @@ TEST(seccomp_syscall_mode_lock) | |||
1783 | } | 2053 | } |
1784 | } | 2054 | } |
1785 | 2055 | ||
2056 | /* | ||
2057 | * Test detection of known and unknown filter flags. Userspace needs to be able | ||
2058 | * to check if a filter flag is supported by the current kernel and a good way | ||
2059 | * of doing that is by attempting to enter filter mode, with the flag bit in | ||
2060 | * question set, and a NULL pointer for the _args_ parameter. EFAULT indicates | ||
2061 | * that the flag is valid and EINVAL indicates that the flag is invalid. | ||
2062 | */ | ||
2063 | TEST(detect_seccomp_filter_flags) | ||
2064 | { | ||
2065 | unsigned int flags[] = { SECCOMP_FILTER_FLAG_TSYNC, | ||
2066 | SECCOMP_FILTER_FLAG_LOG }; | ||
2067 | unsigned int flag, all_flags; | ||
2068 | int i; | ||
2069 | long ret; | ||
2070 | |||
2071 | /* Test detection of known-good filter flags */ | ||
2072 | for (i = 0, all_flags = 0; i < ARRAY_SIZE(flags); i++) { | ||
2073 | flag = flags[i]; | ||
2074 | ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); | ||
2075 | ASSERT_NE(ENOSYS, errno) { | ||
2076 | TH_LOG("Kernel does not support seccomp syscall!"); | ||
2077 | } | ||
2078 | EXPECT_EQ(-1, ret); | ||
2079 | EXPECT_EQ(EFAULT, errno) { | ||
2080 | TH_LOG("Failed to detect that a known-good filter flag (0x%X) is supported!", | ||
2081 | flag); | ||
2082 | } | ||
2083 | |||
2084 | all_flags |= flag; | ||
2085 | } | ||
2086 | |||
2087 | /* Test detection of all known-good filter flags */ | ||
2088 | ret = seccomp(SECCOMP_SET_MODE_FILTER, all_flags, NULL); | ||
2089 | EXPECT_EQ(-1, ret); | ||
2090 | EXPECT_EQ(EFAULT, errno) { | ||
2091 | TH_LOG("Failed to detect that all known-good filter flags (0x%X) are supported!", | ||
2092 | all_flags); | ||
2093 | } | ||
2094 | |||
2095 | /* Test detection of an unknown filter flag */ | ||
2096 | flag = -1; | ||
2097 | ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); | ||
2098 | EXPECT_EQ(-1, ret); | ||
2099 | EXPECT_EQ(EINVAL, errno) { | ||
2100 | TH_LOG("Failed to detect that an unknown filter flag (0x%X) is unsupported!", | ||
2101 | flag); | ||
2102 | } | ||
2103 | |||
2104 | /* | ||
2105 | * Test detection of an unknown filter flag that may simply need to be | ||
2106 | * added to this test | ||
2107 | */ | ||
2108 | flag = flags[ARRAY_SIZE(flags) - 1] << 1; | ||
2109 | ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); | ||
2110 | EXPECT_EQ(-1, ret); | ||
2111 | EXPECT_EQ(EINVAL, errno) { | ||
2112 | TH_LOG("Failed to detect that an unknown filter flag (0x%X) is unsupported! Does a new flag need to be added to this test?", | ||
2113 | flag); | ||
2114 | } | ||
2115 | } | ||
2116 | |||
1786 | TEST(TSYNC_first) | 2117 | TEST(TSYNC_first) |
1787 | { | 2118 | { |
1788 | struct sock_filter filter[] = { | 2119 | struct sock_filter filter[] = { |
@@ -2421,6 +2752,99 @@ TEST(syscall_restart) | |||
2421 | _metadata->passed = 0; | 2752 | _metadata->passed = 0; |
2422 | } | 2753 | } |
2423 | 2754 | ||
2755 | TEST_SIGNAL(filter_flag_log, SIGSYS) | ||
2756 | { | ||
2757 | struct sock_filter allow_filter[] = { | ||
2758 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), | ||
2759 | }; | ||
2760 | struct sock_filter kill_filter[] = { | ||
2761 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, | ||
2762 | offsetof(struct seccomp_data, nr)), | ||
2763 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1), | ||
2764 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), | ||
2765 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), | ||
2766 | }; | ||
2767 | struct sock_fprog allow_prog = { | ||
2768 | .len = (unsigned short)ARRAY_SIZE(allow_filter), | ||
2769 | .filter = allow_filter, | ||
2770 | }; | ||
2771 | struct sock_fprog kill_prog = { | ||
2772 | .len = (unsigned short)ARRAY_SIZE(kill_filter), | ||
2773 | .filter = kill_filter, | ||
2774 | }; | ||
2775 | long ret; | ||
2776 | pid_t parent = getppid(); | ||
2777 | |||
2778 | ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); | ||
2779 | ASSERT_EQ(0, ret); | ||
2780 | |||
2781 | /* Verify that the FILTER_FLAG_LOG flag isn't accepted in strict mode */ | ||
2782 | ret = seccomp(SECCOMP_SET_MODE_STRICT, SECCOMP_FILTER_FLAG_LOG, | ||
2783 | &allow_prog); | ||
2784 | ASSERT_NE(ENOSYS, errno) { | ||
2785 | TH_LOG("Kernel does not support seccomp syscall!"); | ||
2786 | } | ||
2787 | EXPECT_NE(0, ret) { | ||
2788 | TH_LOG("Kernel accepted FILTER_FLAG_LOG flag in strict mode!"); | ||
2789 | } | ||
2790 | EXPECT_EQ(EINVAL, errno) { | ||
2791 | TH_LOG("Kernel returned unexpected errno for FILTER_FLAG_LOG flag in strict mode!"); | ||
2792 | } | ||
2793 | |||
2794 | /* Verify that a simple, permissive filter can be added with no flags */ | ||
2795 | ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &allow_prog); | ||
2796 | EXPECT_EQ(0, ret); | ||
2797 | |||
2798 | /* See if the same filter can be added with the FILTER_FLAG_LOG flag */ | ||
2799 | ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG, | ||
2800 | &allow_prog); | ||
2801 | ASSERT_NE(EINVAL, errno) { | ||
2802 | TH_LOG("Kernel does not support the FILTER_FLAG_LOG flag!"); | ||
2803 | } | ||
2804 | EXPECT_EQ(0, ret); | ||
2805 | |||
2806 | /* Ensure that the kill filter works with the FILTER_FLAG_LOG flag */ | ||
2807 | ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG, | ||
2808 | &kill_prog); | ||
2809 | EXPECT_EQ(0, ret); | ||
2810 | |||
2811 | EXPECT_EQ(parent, syscall(__NR_getppid)); | ||
2812 | /* getpid() should never return. */ | ||
2813 | EXPECT_EQ(0, syscall(__NR_getpid)); | ||
2814 | } | ||
2815 | |||
2816 | TEST(get_action_avail) | ||
2817 | { | ||
2818 | __u32 actions[] = { SECCOMP_RET_KILL_THREAD, SECCOMP_RET_TRAP, | ||
2819 | SECCOMP_RET_ERRNO, SECCOMP_RET_TRACE, | ||
2820 | SECCOMP_RET_LOG, SECCOMP_RET_ALLOW }; | ||
2821 | __u32 unknown_action = 0x10000000U; | ||
2822 | int i; | ||
2823 | long ret; | ||
2824 | |||
2825 | ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[0]); | ||
2826 | ASSERT_NE(ENOSYS, errno) { | ||
2827 | TH_LOG("Kernel does not support seccomp syscall!"); | ||
2828 | } | ||
2829 | ASSERT_NE(EINVAL, errno) { | ||
2830 | TH_LOG("Kernel does not support SECCOMP_GET_ACTION_AVAIL operation!"); | ||
2831 | } | ||
2832 | EXPECT_EQ(ret, 0); | ||
2833 | |||
2834 | for (i = 0; i < ARRAY_SIZE(actions); i++) { | ||
2835 | ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[i]); | ||
2836 | EXPECT_EQ(ret, 0) { | ||
2837 | TH_LOG("Expected action (0x%X) not available!", | ||
2838 | actions[i]); | ||
2839 | } | ||
2840 | } | ||
2841 | |||
2842 | /* Check that an unknown action is handled properly (EOPNOTSUPP) */ | ||
2843 | ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &unknown_action); | ||
2844 | EXPECT_EQ(ret, -1); | ||
2845 | EXPECT_EQ(errno, EOPNOTSUPP); | ||
2846 | } | ||
2847 | |||
2424 | /* | 2848 | /* |
2425 | * TODO: | 2849 | * TODO: |
2426 | * - add microbenchmarks | 2850 | * - add microbenchmarks |
@@ -2429,6 +2853,8 @@ TEST(syscall_restart) | |||
2429 | * - endianness checking when appropriate | 2853 | * - endianness checking when appropriate |
2430 | * - 64-bit arg prodding | 2854 | * - 64-bit arg prodding |
2431 | * - arch value testing (x86 modes especially) | 2855 | * - arch value testing (x86 modes especially) |
2856 | * - verify that FILTER_FLAG_LOG filters generate log messages | ||
2857 | * - verify that RET_LOG generates log messages | ||
2432 | * - ... | 2858 | * - ... |
2433 | */ | 2859 | */ |
2434 | 2860 | ||
diff --git a/tools/testing/selftests/sigaltstack/sas.c b/tools/testing/selftests/sigaltstack/sas.c index ccd07343d418..97bb150837df 100644 --- a/tools/testing/selftests/sigaltstack/sas.c +++ b/tools/testing/selftests/sigaltstack/sas.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <assert.h> | 17 | #include <assert.h> |
18 | #include <errno.h> | 18 | #include <errno.h> |
19 | 19 | ||
20 | #include "../kselftest.h" | ||
21 | |||
20 | #ifndef SS_AUTODISARM | 22 | #ifndef SS_AUTODISARM |
21 | #define SS_AUTODISARM (1U << 31) | 23 | #define SS_AUTODISARM (1U << 31) |
22 | #endif | 24 | #endif |
@@ -37,12 +39,15 @@ void my_usr1(int sig, siginfo_t *si, void *u) | |||
37 | stack_t stk; | 39 | stack_t stk; |
38 | struct stk_data *p; | 40 | struct stk_data *p; |
39 | 41 | ||
42 | #if __s390x__ | ||
43 | register unsigned long sp asm("%15"); | ||
44 | #else | ||
40 | register unsigned long sp asm("sp"); | 45 | register unsigned long sp asm("sp"); |
46 | #endif | ||
41 | 47 | ||
42 | if (sp < (unsigned long)sstack || | 48 | if (sp < (unsigned long)sstack || |
43 | sp >= (unsigned long)sstack + SIGSTKSZ) { | 49 | sp >= (unsigned long)sstack + SIGSTKSZ) { |
44 | printf("[FAIL]\tSP is not on sigaltstack\n"); | 50 | ksft_exit_fail_msg("SP is not on sigaltstack\n"); |
45 | exit(EXIT_FAILURE); | ||
46 | } | 51 | } |
47 | /* put some data on stack. other sighandler will try to overwrite it */ | 52 | /* put some data on stack. other sighandler will try to overwrite it */ |
48 | aa = alloca(1024); | 53 | aa = alloca(1024); |
@@ -50,21 +55,22 @@ void my_usr1(int sig, siginfo_t *si, void *u) | |||
50 | p = (struct stk_data *)(aa + 512); | 55 | p = (struct stk_data *)(aa + 512); |
51 | strcpy(p->msg, msg); | 56 | strcpy(p->msg, msg); |
52 | p->flag = 1; | 57 | p->flag = 1; |
53 | printf("[RUN]\tsignal USR1\n"); | 58 | ksft_print_msg("[RUN]\tsignal USR1\n"); |
54 | err = sigaltstack(NULL, &stk); | 59 | err = sigaltstack(NULL, &stk); |
55 | if (err) { | 60 | if (err) { |
56 | perror("[FAIL]\tsigaltstack()"); | 61 | ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno)); |
57 | exit(EXIT_FAILURE); | 62 | exit(EXIT_FAILURE); |
58 | } | 63 | } |
59 | if (stk.ss_flags != SS_DISABLE) | 64 | if (stk.ss_flags != SS_DISABLE) |
60 | printf("[FAIL]\tss_flags=%x, should be SS_DISABLE\n", | 65 | ksft_test_result_fail("tss_flags=%x, should be SS_DISABLE\n", |
61 | stk.ss_flags); | 66 | stk.ss_flags); |
62 | else | 67 | else |
63 | printf("[OK]\tsigaltstack is disabled in sighandler\n"); | 68 | ksft_test_result_pass( |
69 | "sigaltstack is disabled in sighandler\n"); | ||
64 | swapcontext(&sc, &uc); | 70 | swapcontext(&sc, &uc); |
65 | printf("%s\n", p->msg); | 71 | ksft_print_msg("%s\n", p->msg); |
66 | if (!p->flag) { | 72 | if (!p->flag) { |
67 | printf("[RUN]\tAborting\n"); | 73 | ksft_exit_skip("[RUN]\tAborting\n"); |
68 | exit(EXIT_FAILURE); | 74 | exit(EXIT_FAILURE); |
69 | } | 75 | } |
70 | } | 76 | } |
@@ -74,13 +80,13 @@ void my_usr2(int sig, siginfo_t *si, void *u) | |||
74 | char *aa; | 80 | char *aa; |
75 | struct stk_data *p; | 81 | struct stk_data *p; |
76 | 82 | ||
77 | printf("[RUN]\tsignal USR2\n"); | 83 | ksft_print_msg("[RUN]\tsignal USR2\n"); |
78 | aa = alloca(1024); | 84 | aa = alloca(1024); |
79 | /* dont run valgrind on this */ | 85 | /* dont run valgrind on this */ |
80 | /* try to find the data stored by previous sighandler */ | 86 | /* try to find the data stored by previous sighandler */ |
81 | p = memmem(aa, 1024, msg, strlen(msg)); | 87 | p = memmem(aa, 1024, msg, strlen(msg)); |
82 | if (p) { | 88 | if (p) { |
83 | printf("[FAIL]\tsigaltstack re-used\n"); | 89 | ksft_test_result_fail("sigaltstack re-used\n"); |
84 | /* corrupt the data */ | 90 | /* corrupt the data */ |
85 | strcpy(p->msg, msg2); | 91 | strcpy(p->msg, msg2); |
86 | /* tell other sighandler that his data is corrupted */ | 92 | /* tell other sighandler that his data is corrupted */ |
@@ -90,7 +96,7 @@ void my_usr2(int sig, siginfo_t *si, void *u) | |||
90 | 96 | ||
91 | static void switch_fn(void) | 97 | static void switch_fn(void) |
92 | { | 98 | { |
93 | printf("[RUN]\tswitched to user ctx\n"); | 99 | ksft_print_msg("[RUN]\tswitched to user ctx\n"); |
94 | raise(SIGUSR2); | 100 | raise(SIGUSR2); |
95 | setcontext(&sc); | 101 | setcontext(&sc); |
96 | } | 102 | } |
@@ -101,6 +107,8 @@ int main(void) | |||
101 | stack_t stk; | 107 | stack_t stk; |
102 | int err; | 108 | int err; |
103 | 109 | ||
110 | ksft_print_header(); | ||
111 | |||
104 | sigemptyset(&act.sa_mask); | 112 | sigemptyset(&act.sa_mask); |
105 | act.sa_flags = SA_ONSTACK | SA_SIGINFO; | 113 | act.sa_flags = SA_ONSTACK | SA_SIGINFO; |
106 | act.sa_sigaction = my_usr1; | 114 | act.sa_sigaction = my_usr1; |
@@ -110,19 +118,20 @@ int main(void) | |||
110 | sstack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, | 118 | sstack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, |
111 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); | 119 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); |
112 | if (sstack == MAP_FAILED) { | 120 | if (sstack == MAP_FAILED) { |
113 | perror("mmap()"); | 121 | ksft_exit_fail_msg("mmap() - %s\n", strerror(errno)); |
114 | return EXIT_FAILURE; | 122 | return EXIT_FAILURE; |
115 | } | 123 | } |
116 | 124 | ||
117 | err = sigaltstack(NULL, &stk); | 125 | err = sigaltstack(NULL, &stk); |
118 | if (err) { | 126 | if (err) { |
119 | perror("[FAIL]\tsigaltstack()"); | 127 | ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno)); |
120 | exit(EXIT_FAILURE); | 128 | exit(EXIT_FAILURE); |
121 | } | 129 | } |
122 | if (stk.ss_flags == SS_DISABLE) { | 130 | if (stk.ss_flags == SS_DISABLE) { |
123 | printf("[OK]\tInitial sigaltstack state was SS_DISABLE\n"); | 131 | ksft_test_result_pass( |
132 | "Initial sigaltstack state was SS_DISABLE\n"); | ||
124 | } else { | 133 | } else { |
125 | printf("[FAIL]\tInitial sigaltstack state was %x; " | 134 | ksft_exit_fail_msg("Initial sigaltstack state was %x; " |
126 | "should have been SS_DISABLE\n", stk.ss_flags); | 135 | "should have been SS_DISABLE\n", stk.ss_flags); |
127 | return EXIT_FAILURE; | 136 | return EXIT_FAILURE; |
128 | } | 137 | } |
@@ -133,7 +142,8 @@ int main(void) | |||
133 | err = sigaltstack(&stk, NULL); | 142 | err = sigaltstack(&stk, NULL); |
134 | if (err) { | 143 | if (err) { |
135 | if (errno == EINVAL) { | 144 | if (errno == EINVAL) { |
136 | printf("[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n"); | 145 | ksft_exit_skip( |
146 | "[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n"); | ||
137 | /* | 147 | /* |
138 | * If test cases for the !SS_AUTODISARM variant were | 148 | * If test cases for the !SS_AUTODISARM variant were |
139 | * added, we could still run them. We don't have any | 149 | * added, we could still run them. We don't have any |
@@ -142,7 +152,9 @@ int main(void) | |||
142 | */ | 152 | */ |
143 | return 0; | 153 | return 0; |
144 | } else { | 154 | } else { |
145 | perror("[FAIL]\tsigaltstack(SS_ONSTACK | SS_AUTODISARM)"); | 155 | ksft_exit_fail_msg( |
156 | "sigaltstack(SS_ONSTACK | SS_AUTODISARM) %s\n", | ||
157 | strerror(errno)); | ||
146 | return EXIT_FAILURE; | 158 | return EXIT_FAILURE; |
147 | } | 159 | } |
148 | } | 160 | } |
@@ -150,7 +162,7 @@ int main(void) | |||
150 | ustack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, | 162 | ustack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, |
151 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); | 163 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); |
152 | if (ustack == MAP_FAILED) { | 164 | if (ustack == MAP_FAILED) { |
153 | perror("mmap()"); | 165 | ksft_exit_fail_msg("mmap() - %s\n", strerror(errno)); |
154 | return EXIT_FAILURE; | 166 | return EXIT_FAILURE; |
155 | } | 167 | } |
156 | getcontext(&uc); | 168 | getcontext(&uc); |
@@ -162,16 +174,17 @@ int main(void) | |||
162 | 174 | ||
163 | err = sigaltstack(NULL, &stk); | 175 | err = sigaltstack(NULL, &stk); |
164 | if (err) { | 176 | if (err) { |
165 | perror("[FAIL]\tsigaltstack()"); | 177 | ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno)); |
166 | exit(EXIT_FAILURE); | 178 | exit(EXIT_FAILURE); |
167 | } | 179 | } |
168 | if (stk.ss_flags != SS_AUTODISARM) { | 180 | if (stk.ss_flags != SS_AUTODISARM) { |
169 | printf("[FAIL]\tss_flags=%x, should be SS_AUTODISARM\n", | 181 | ksft_exit_fail_msg("ss_flags=%x, should be SS_AUTODISARM\n", |
170 | stk.ss_flags); | 182 | stk.ss_flags); |
171 | exit(EXIT_FAILURE); | 183 | exit(EXIT_FAILURE); |
172 | } | 184 | } |
173 | printf("[OK]\tsigaltstack is still SS_AUTODISARM after signal\n"); | 185 | ksft_test_result_pass( |
186 | "sigaltstack is still SS_AUTODISARM after signal\n"); | ||
174 | 187 | ||
175 | printf("[OK]\tTest passed\n"); | 188 | ksft_exit_pass(); |
176 | return 0; | 189 | return 0; |
177 | } | 190 | } |
diff --git a/tools/testing/selftests/splice/.gitignore b/tools/testing/selftests/splice/.gitignore new file mode 100644 index 000000000000..1e23fefd68e8 --- /dev/null +++ b/tools/testing/selftests/splice/.gitignore | |||
@@ -0,0 +1 @@ | |||
default_file_splice_read | |||
diff --git a/tools/testing/selftests/splice/Makefile b/tools/testing/selftests/splice/Makefile index 9fc78e5e5451..7e1187e007fa 100644 --- a/tools/testing/selftests/splice/Makefile +++ b/tools/testing/selftests/splice/Makefile | |||
@@ -1,7 +1,4 @@ | |||
1 | TEST_PROGS := default_file_splice_read.sh | 1 | TEST_PROGS := default_file_splice_read.sh |
2 | EXTRA := default_file_splice_read | 2 | TEST_GEN_PROGS_EXTENDED := default_file_splice_read |
3 | all: $(TEST_PROGS) $(EXTRA) | ||
4 | 3 | ||
5 | include ../lib.mk | 4 | include ../lib.mk |
6 | |||
7 | EXTRA_CLEAN := $(EXTRA) | ||
diff --git a/tools/testing/selftests/sync/Makefile b/tools/testing/selftests/sync/Makefile index 4981c6b6d050..8e04d0afcbd7 100644 --- a/tools/testing/selftests/sync/Makefile +++ b/tools/testing/selftests/sync/Makefile | |||
@@ -2,12 +2,16 @@ CFLAGS += -O2 -g -std=gnu89 -pthread -Wall -Wextra | |||
2 | CFLAGS += -I../../../../usr/include/ | 2 | CFLAGS += -I../../../../usr/include/ |
3 | LDFLAGS += -pthread | 3 | LDFLAGS += -pthread |
4 | 4 | ||
5 | TEST_PROGS = sync_test | 5 | .PHONY: all clean |
6 | |||
7 | all: $(TEST_PROGS) | ||
8 | 6 | ||
9 | include ../lib.mk | 7 | include ../lib.mk |
10 | 8 | ||
9 | # lib.mk TEST_CUSTOM_PROGS var is for custom tests that need special | ||
10 | # build rules. lib.mk will run and install them. | ||
11 | |||
12 | TEST_CUSTOM_PROGS := $(OUTPUT)/sync_test | ||
13 | all: $(TEST_CUSTOM_PROGS) | ||
14 | |||
11 | OBJS = sync_test.o sync.o | 15 | OBJS = sync_test.o sync.o |
12 | 16 | ||
13 | TESTS += sync_alloc.o | 17 | TESTS += sync_alloc.o |
@@ -18,6 +22,16 @@ TESTS += sync_stress_parallelism.o | |||
18 | TESTS += sync_stress_consumer.o | 22 | TESTS += sync_stress_consumer.o |
19 | TESTS += sync_stress_merge.o | 23 | TESTS += sync_stress_merge.o |
20 | 24 | ||
21 | sync_test: $(OBJS) $(TESTS) | 25 | OBJS := $(patsubst %,$(OUTPUT)/%,$(OBJS)) |
26 | TESTS := $(patsubst %,$(OUTPUT)/%,$(TESTS)) | ||
27 | |||
28 | $(TEST_CUSTOM_PROGS): $(TESTS) $(OBJS) | ||
29 | $(CC) -o $(TEST_CUSTOM_PROGS) $(OBJS) $(TESTS) $(CFLAGS) $(LDFLAGS) | ||
30 | |||
31 | $(OBJS): $(OUTPUT)/%.o: %.c | ||
32 | $(CC) -c $^ -o $@ | ||
33 | |||
34 | $(TESTS): $(OUTPUT)/%.o: %.c | ||
35 | $(CC) -c $^ -o $@ | ||
22 | 36 | ||
23 | EXTRA_CLEAN := sync_test $(OBJS) $(TESTS) | 37 | EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(OBJS) $(TESTS) |
diff --git a/tools/testing/selftests/sync/sync_test.c b/tools/testing/selftests/sync/sync_test.c index 62fa666e501a..7f7938263c5c 100644 --- a/tools/testing/selftests/sync/sync_test.c +++ b/tools/testing/selftests/sync/sync_test.c | |||
@@ -31,62 +31,83 @@ | |||
31 | #include <sys/types.h> | 31 | #include <sys/types.h> |
32 | #include <sys/stat.h> | 32 | #include <sys/stat.h> |
33 | #include <sys/wait.h> | 33 | #include <sys/wait.h> |
34 | #include <errno.h> | ||
35 | #include <string.h> | ||
34 | 36 | ||
37 | #include "../kselftest.h" | ||
35 | #include "synctest.h" | 38 | #include "synctest.h" |
36 | 39 | ||
37 | static int run_test(int (*test)(void), char *name) | 40 | static int run_test(int (*test)(void), char *name) |
38 | { | 41 | { |
39 | int result; | 42 | int result; |
40 | pid_t childpid; | 43 | pid_t childpid; |
44 | int ret; | ||
41 | 45 | ||
42 | fflush(stdout); | 46 | fflush(stdout); |
43 | childpid = fork(); | 47 | childpid = fork(); |
44 | 48 | ||
45 | if (childpid) { | 49 | if (childpid) { |
46 | waitpid(childpid, &result, 0); | 50 | waitpid(childpid, &result, 0); |
47 | if (WIFEXITED(result)) | 51 | if (WIFEXITED(result)) { |
48 | return WEXITSTATUS(result); | 52 | ret = WEXITSTATUS(result); |
53 | if (!ret) | ||
54 | ksft_test_result_pass("[RUN]\t%s\n", name); | ||
55 | else | ||
56 | ksft_test_result_fail("[RUN]\t%s\n", name); | ||
57 | return ret; | ||
58 | } | ||
49 | return 1; | 59 | return 1; |
50 | } | 60 | } |
51 | 61 | ||
52 | printf("[RUN]\tExecuting %s\n", name); | ||
53 | exit(test()); | 62 | exit(test()); |
54 | } | 63 | } |
55 | 64 | ||
56 | static int sync_api_supported(void) | 65 | static void sync_api_supported(void) |
57 | { | 66 | { |
58 | struct stat sbuf; | 67 | struct stat sbuf; |
68 | int ret; | ||
59 | 69 | ||
60 | return 0 == stat("/sys/kernel/debug/sync/sw_sync", &sbuf); | 70 | ret = stat("/sys/kernel/debug/sync/sw_sync", &sbuf); |
71 | if (!ret) | ||
72 | return; | ||
73 | |||
74 | if (errno == ENOENT) | ||
75 | ksft_exit_skip("Sync framework not supported by kernel\n"); | ||
76 | |||
77 | if (errno == EACCES) | ||
78 | ksft_exit_skip("Run Sync test as root.\n"); | ||
79 | |||
80 | ksft_exit_fail_msg("stat failed on /sys/kernel/debug/sync/sw_sync: %s", | ||
81 | strerror(errno)); | ||
61 | } | 82 | } |
62 | 83 | ||
63 | int main(void) | 84 | int main(void) |
64 | { | 85 | { |
65 | int err = 0; | 86 | int err; |
66 | 87 | ||
67 | if (!sync_api_supported()) { | 88 | ksft_print_header(); |
68 | printf("SKIP: Sync framework not supported by kernel\n"); | 89 | |
69 | return 0; | 90 | sync_api_supported(); |
70 | } | ||
71 | 91 | ||
72 | printf("[RUN]\tTesting sync framework\n"); | 92 | ksft_print_msg("[RUN]\tTesting sync framework\n"); |
73 | 93 | ||
74 | err += RUN_TEST(test_alloc_timeline); | 94 | RUN_TEST(test_alloc_timeline); |
75 | err += RUN_TEST(test_alloc_fence); | 95 | RUN_TEST(test_alloc_fence); |
76 | err += RUN_TEST(test_alloc_fence_negative); | 96 | RUN_TEST(test_alloc_fence_negative); |
77 | 97 | ||
78 | err += RUN_TEST(test_fence_one_timeline_wait); | 98 | RUN_TEST(test_fence_one_timeline_wait); |
79 | err += RUN_TEST(test_fence_one_timeline_merge); | 99 | RUN_TEST(test_fence_one_timeline_merge); |
80 | err += RUN_TEST(test_fence_merge_same_fence); | 100 | RUN_TEST(test_fence_merge_same_fence); |
81 | err += RUN_TEST(test_fence_multi_timeline_wait); | 101 | RUN_TEST(test_fence_multi_timeline_wait); |
82 | err += RUN_TEST(test_stress_two_threads_shared_timeline); | 102 | RUN_TEST(test_stress_two_threads_shared_timeline); |
83 | err += RUN_TEST(test_consumer_stress_multi_producer_single_consumer); | 103 | RUN_TEST(test_consumer_stress_multi_producer_single_consumer); |
84 | err += RUN_TEST(test_merge_stress_random_merge); | 104 | RUN_TEST(test_merge_stress_random_merge); |
85 | 105 | ||
106 | err = ksft_get_fail_cnt(); | ||
86 | if (err) | 107 | if (err) |
87 | printf("[FAIL]\tsync errors: %d\n", err); | 108 | ksft_exit_fail_msg("%d out of %d sync tests failed\n", |
88 | else | 109 | err, ksft_test_num()); |
89 | printf("[OK]\tsync\n"); | ||
90 | 110 | ||
91 | return !!err; | 111 | /* need this return to keep gcc happy */ |
112 | return ksft_exit_pass(); | ||
92 | } | 113 | } |
diff --git a/tools/testing/selftests/sync/synctest.h b/tools/testing/selftests/sync/synctest.h index e7d1d57dba7a..90a8e5369914 100644 --- a/tools/testing/selftests/sync/synctest.h +++ b/tools/testing/selftests/sync/synctest.h | |||
@@ -29,10 +29,11 @@ | |||
29 | #define SELFTESTS_SYNCTEST_H | 29 | #define SELFTESTS_SYNCTEST_H |
30 | 30 | ||
31 | #include <stdio.h> | 31 | #include <stdio.h> |
32 | #include "../kselftest.h" | ||
32 | 33 | ||
33 | #define ASSERT(cond, msg) do { \ | 34 | #define ASSERT(cond, msg) do { \ |
34 | if (!(cond)) { \ | 35 | if (!(cond)) { \ |
35 | printf("[ERROR]\t%s", (msg)); \ | 36 | ksft_print_msg("[ERROR]\t%s", (msg)); \ |
36 | return 1; \ | 37 | return 1; \ |
37 | } \ | 38 | } \ |
38 | } while (0) | 39 | } while (0) |
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/tests.json b/tools/testing/selftests/tc-testing/tc-tests/actions/tests.json index af519bc97a8e..6973bdc5b5bf 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/tests.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/tests.json | |||
@@ -1111,5 +1111,55 @@ | |||
1111 | "teardown": [ | 1111 | "teardown": [ |
1112 | "$TC actions flush action gact" | 1112 | "$TC actions flush action gact" |
1113 | ] | 1113 | ] |
1114 | }, | ||
1115 | { | ||
1116 | "id": "a568", | ||
1117 | "name": "Add action with ife type", | ||
1118 | "category": [ | ||
1119 | "actions", | ||
1120 | "ife" | ||
1121 | ], | ||
1122 | "setup": [ | ||
1123 | [ | ||
1124 | "$TC actions flush action ife", | ||
1125 | 0, | ||
1126 | 1, | ||
1127 | 255 | ||
1128 | ], | ||
1129 | "$TC actions add action ife encode type 0xDEAD index 1" | ||
1130 | ], | ||
1131 | "cmdUnderTest": "$TC actions get action ife index 1", | ||
1132 | "expExitCode": "0", | ||
1133 | "verifyCmd": "$TC actions get action ife index 1", | ||
1134 | "matchPattern": "type 0xDEAD", | ||
1135 | "matchCount": "1", | ||
1136 | "teardown": [ | ||
1137 | "$TC actions flush action ife" | ||
1138 | ] | ||
1139 | }, | ||
1140 | { | ||
1141 | "id": "b983", | ||
1142 | "name": "Add action without ife type", | ||
1143 | "category": [ | ||
1144 | "actions", | ||
1145 | "ife" | ||
1146 | ], | ||
1147 | "setup": [ | ||
1148 | [ | ||
1149 | "$TC actions flush action ife", | ||
1150 | 0, | ||
1151 | 1, | ||
1152 | 255 | ||
1153 | ], | ||
1154 | "$TC actions add action ife encode index 1" | ||
1155 | ], | ||
1156 | "cmdUnderTest": "$TC actions get action ife index 1", | ||
1157 | "expExitCode": "0", | ||
1158 | "verifyCmd": "$TC actions get action ife index 1", | ||
1159 | "matchPattern": "type 0xED3E", | ||
1160 | "matchCount": "1", | ||
1161 | "teardown": [ | ||
1162 | "$TC actions flush action ife" | ||
1163 | ] | ||
1114 | } | 1164 | } |
1115 | ] \ No newline at end of file | 1165 | ] \ No newline at end of file |
diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile index a9b86133b9b3..ae4593115408 100644 --- a/tools/testing/selftests/timers/Makefile +++ b/tools/testing/selftests/timers/Makefile | |||
@@ -1,5 +1,4 @@ | |||
1 | BUILD_FLAGS = -DKTEST | 1 | CFLAGS += -O3 -Wl,-no-as-needed -Wall |
2 | CFLAGS += -O3 -Wl,-no-as-needed -Wall $(BUILD_FLAGS) | ||
3 | LDFLAGS += -lrt -lpthread -lm | 2 | LDFLAGS += -lrt -lpthread -lm |
4 | 3 | ||
5 | # these are all "safe" tests that don't modify | 4 | # these are all "safe" tests that don't modify |
@@ -7,9 +6,11 @@ LDFLAGS += -lrt -lpthread -lm | |||
7 | TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \ | 6 | TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \ |
8 | inconsistency-check raw_skew threadtest rtctest | 7 | inconsistency-check raw_skew threadtest rtctest |
9 | 8 | ||
10 | TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \ | 9 | DESTRUCTIVE_TESTS = alarmtimer-suspend valid-adjtimex adjtick change_skew \ |
11 | skew_consistency clocksource-switch freq-step leap-a-day \ | 10 | skew_consistency clocksource-switch freq-step leap-a-day \ |
12 | leapcrash set-tai set-2038 set-tz rtctest_setdate | 11 | leapcrash set-tai set-2038 set-tz |
12 | |||
13 | TEST_GEN_PROGS_EXTENDED = $(DESTRUCTIVE_TESTS) rtctest_setdate | ||
13 | 14 | ||
14 | 15 | ||
15 | include ../lib.mk | 16 | include ../lib.mk |
@@ -18,16 +19,4 @@ include ../lib.mk | |||
18 | # and may modify the system time or trigger | 19 | # and may modify the system time or trigger |
19 | # other behavior like suspend | 20 | # other behavior like suspend |
20 | run_destructive_tests: run_tests | 21 | run_destructive_tests: run_tests |
21 | ./alarmtimer-suspend | 22 | $(call RUN_TESTS, $(DESTRUCTIVE_TESTS)) |
22 | ./valid-adjtimex | ||
23 | ./adjtick | ||
24 | ./change_skew | ||
25 | ./skew_consistency | ||
26 | ./clocksource-switch | ||
27 | ./freq-step | ||
28 | ./leap-a-day -s -i 10 | ||
29 | ./leapcrash | ||
30 | ./set-tz | ||
31 | ./set-tai | ||
32 | ./set-2038 | ||
33 | |||
diff --git a/tools/testing/selftests/timers/adjtick.c b/tools/testing/selftests/timers/adjtick.c index 9887fd538fec..0caca3a06bd2 100644 --- a/tools/testing/selftests/timers/adjtick.c +++ b/tools/testing/selftests/timers/adjtick.c | |||
@@ -23,18 +23,7 @@ | |||
23 | #include <sys/timex.h> | 23 | #include <sys/timex.h> |
24 | #include <time.h> | 24 | #include <time.h> |
25 | 25 | ||
26 | #ifdef KTEST | ||
27 | #include "../kselftest.h" | 26 | #include "../kselftest.h" |
28 | #else | ||
29 | static inline int ksft_exit_pass(void) | ||
30 | { | ||
31 | exit(0); | ||
32 | } | ||
33 | static inline int ksft_exit_fail(void) | ||
34 | { | ||
35 | exit(1); | ||
36 | } | ||
37 | #endif | ||
38 | 27 | ||
39 | #define CLOCK_MONOTONIC_RAW 4 | 28 | #define CLOCK_MONOTONIC_RAW 4 |
40 | 29 | ||
diff --git a/tools/testing/selftests/timers/alarmtimer-suspend.c b/tools/testing/selftests/timers/alarmtimer-suspend.c index 2b361b830395..4da09dbf83ba 100644 --- a/tools/testing/selftests/timers/alarmtimer-suspend.c +++ b/tools/testing/selftests/timers/alarmtimer-suspend.c | |||
@@ -28,18 +28,7 @@ | |||
28 | #include <signal.h> | 28 | #include <signal.h> |
29 | #include <stdlib.h> | 29 | #include <stdlib.h> |
30 | #include <pthread.h> | 30 | #include <pthread.h> |
31 | #ifdef KTEST | ||
32 | #include "../kselftest.h" | 31 | #include "../kselftest.h" |
33 | #else | ||
34 | static inline int ksft_exit_pass(void) | ||
35 | { | ||
36 | exit(0); | ||
37 | } | ||
38 | static inline int ksft_exit_fail(void) | ||
39 | { | ||
40 | exit(1); | ||
41 | } | ||
42 | #endif | ||
43 | 32 | ||
44 | #define CLOCK_REALTIME 0 | 33 | #define CLOCK_REALTIME 0 |
45 | #define CLOCK_MONOTONIC 1 | 34 | #define CLOCK_MONOTONIC 1 |
diff --git a/tools/testing/selftests/timers/change_skew.c b/tools/testing/selftests/timers/change_skew.c index cb1968977c04..c4eab7124990 100644 --- a/tools/testing/selftests/timers/change_skew.c +++ b/tools/testing/selftests/timers/change_skew.c | |||
@@ -28,18 +28,7 @@ | |||
28 | #include <sys/time.h> | 28 | #include <sys/time.h> |
29 | #include <sys/timex.h> | 29 | #include <sys/timex.h> |
30 | #include <time.h> | 30 | #include <time.h> |
31 | #ifdef KTEST | ||
32 | #include "../kselftest.h" | 31 | #include "../kselftest.h" |
33 | #else | ||
34 | static inline int ksft_exit_pass(void) | ||
35 | { | ||
36 | exit(0); | ||
37 | } | ||
38 | static inline int ksft_exit_fail(void) | ||
39 | { | ||
40 | exit(1); | ||
41 | } | ||
42 | #endif | ||
43 | 32 | ||
44 | #define NSEC_PER_SEC 1000000000LL | 33 | #define NSEC_PER_SEC 1000000000LL |
45 | 34 | ||
diff --git a/tools/testing/selftests/timers/clocksource-switch.c b/tools/testing/selftests/timers/clocksource-switch.c index 5ff165373f8b..bfc974b4572d 100644 --- a/tools/testing/selftests/timers/clocksource-switch.c +++ b/tools/testing/selftests/timers/clocksource-switch.c | |||
@@ -34,18 +34,7 @@ | |||
34 | #include <fcntl.h> | 34 | #include <fcntl.h> |
35 | #include <string.h> | 35 | #include <string.h> |
36 | #include <sys/wait.h> | 36 | #include <sys/wait.h> |
37 | #ifdef KTEST | ||
38 | #include "../kselftest.h" | 37 | #include "../kselftest.h" |
39 | #else | ||
40 | static inline int ksft_exit_pass(void) | ||
41 | { | ||
42 | exit(0); | ||
43 | } | ||
44 | static inline int ksft_exit_fail(void) | ||
45 | { | ||
46 | exit(1); | ||
47 | } | ||
48 | #endif | ||
49 | 38 | ||
50 | 39 | ||
51 | int get_clocksources(char list[][30]) | 40 | int get_clocksources(char list[][30]) |
@@ -61,7 +50,7 @@ int get_clocksources(char list[][30]) | |||
61 | 50 | ||
62 | close(fd); | 51 | close(fd); |
63 | 52 | ||
64 | for (i = 0; i < 30; i++) | 53 | for (i = 0; i < 10; i++) |
65 | list[i][0] = '\0'; | 54 | list[i][0] = '\0'; |
66 | 55 | ||
67 | head = buf; | 56 | head = buf; |
diff --git a/tools/testing/selftests/timers/inconsistency-check.c b/tools/testing/selftests/timers/inconsistency-check.c index 74c60e8759a0..022d3ffe3fbf 100644 --- a/tools/testing/selftests/timers/inconsistency-check.c +++ b/tools/testing/selftests/timers/inconsistency-check.c | |||
@@ -28,18 +28,7 @@ | |||
28 | #include <sys/timex.h> | 28 | #include <sys/timex.h> |
29 | #include <string.h> | 29 | #include <string.h> |
30 | #include <signal.h> | 30 | #include <signal.h> |
31 | #ifdef KTEST | ||
32 | #include "../kselftest.h" | 31 | #include "../kselftest.h" |
33 | #else | ||
34 | static inline int ksft_exit_pass(void) | ||
35 | { | ||
36 | exit(0); | ||
37 | } | ||
38 | static inline int ksft_exit_fail(void) | ||
39 | { | ||
40 | exit(1); | ||
41 | } | ||
42 | #endif | ||
43 | 32 | ||
44 | #define CALLS_PER_LOOP 64 | 33 | #define CALLS_PER_LOOP 64 |
45 | #define NSEC_PER_SEC 1000000000ULL | 34 | #define NSEC_PER_SEC 1000000000ULL |
diff --git a/tools/testing/selftests/timers/leap-a-day.c b/tools/testing/selftests/timers/leap-a-day.c index fb46ad6ac92c..19e46ed5dfb5 100644 --- a/tools/testing/selftests/timers/leap-a-day.c +++ b/tools/testing/selftests/timers/leap-a-day.c | |||
@@ -48,18 +48,7 @@ | |||
48 | #include <string.h> | 48 | #include <string.h> |
49 | #include <signal.h> | 49 | #include <signal.h> |
50 | #include <unistd.h> | 50 | #include <unistd.h> |
51 | #ifdef KTEST | ||
52 | #include "../kselftest.h" | 51 | #include "../kselftest.h" |
53 | #else | ||
54 | static inline int ksft_exit_pass(void) | ||
55 | { | ||
56 | exit(0); | ||
57 | } | ||
58 | static inline int ksft_exit_fail(void) | ||
59 | { | ||
60 | exit(1); | ||
61 | } | ||
62 | #endif | ||
63 | 52 | ||
64 | #define NSEC_PER_SEC 1000000000ULL | 53 | #define NSEC_PER_SEC 1000000000ULL |
65 | #define CLOCK_TAI 11 | 54 | #define CLOCK_TAI 11 |
@@ -190,18 +179,18 @@ int main(int argc, char **argv) | |||
190 | struct sigevent se; | 179 | struct sigevent se; |
191 | struct sigaction act; | 180 | struct sigaction act; |
192 | int signum = SIGRTMAX; | 181 | int signum = SIGRTMAX; |
193 | int settime = 0; | 182 | int settime = 1; |
194 | int tai_time = 0; | 183 | int tai_time = 0; |
195 | int insert = 1; | 184 | int insert = 1; |
196 | int iterations = -1; | 185 | int iterations = 10; |
197 | int opt; | 186 | int opt; |
198 | 187 | ||
199 | /* Process arguments */ | 188 | /* Process arguments */ |
200 | while ((opt = getopt(argc, argv, "sti:")) != -1) { | 189 | while ((opt = getopt(argc, argv, "sti:")) != -1) { |
201 | switch (opt) { | 190 | switch (opt) { |
202 | case 's': | 191 | case 'w': |
203 | printf("Setting time to speed up testing\n"); | 192 | printf("Only setting leap-flag, not changing time. It could take up to a day for leap to trigger.\n"); |
204 | settime = 1; | 193 | settime = 0; |
205 | break; | 194 | break; |
206 | case 'i': | 195 | case 'i': |
207 | iterations = atoi(optarg); | 196 | iterations = atoi(optarg); |
@@ -210,9 +199,10 @@ int main(int argc, char **argv) | |||
210 | tai_time = 1; | 199 | tai_time = 1; |
211 | break; | 200 | break; |
212 | default: | 201 | default: |
213 | printf("Usage: %s [-s] [-i <iterations>]\n", argv[0]); | 202 | printf("Usage: %s [-w] [-i <iterations>]\n", argv[0]); |
214 | printf(" -s: Set time to right before leap second each iteration\n"); | 203 | printf(" -w: Set flag and wait for leap second each iteration"); |
215 | printf(" -i: Number of iterations\n"); | 204 | printf(" (default sets time to right before leapsecond)\n"); |
205 | printf(" -i: Number of iterations (-1 = infinite, default is 10)\n"); | ||
216 | printf(" -t: Print TAI time\n"); | 206 | printf(" -t: Print TAI time\n"); |
217 | exit(-1); | 207 | exit(-1); |
218 | } | 208 | } |
diff --git a/tools/testing/selftests/timers/leapcrash.c b/tools/testing/selftests/timers/leapcrash.c index a1071bdbdeb7..830c462f605d 100644 --- a/tools/testing/selftests/timers/leapcrash.c +++ b/tools/testing/selftests/timers/leapcrash.c | |||
@@ -22,20 +22,7 @@ | |||
22 | #include <sys/timex.h> | 22 | #include <sys/timex.h> |
23 | #include <string.h> | 23 | #include <string.h> |
24 | #include <signal.h> | 24 | #include <signal.h> |
25 | #ifdef KTEST | ||
26 | #include "../kselftest.h" | 25 | #include "../kselftest.h" |
27 | #else | ||
28 | static inline int ksft_exit_pass(void) | ||
29 | { | ||
30 | exit(0); | ||
31 | } | ||
32 | static inline int ksft_exit_fail(void) | ||
33 | { | ||
34 | exit(1); | ||
35 | } | ||
36 | #endif | ||
37 | |||
38 | |||
39 | 26 | ||
40 | /* clear NTP time_status & time_state */ | 27 | /* clear NTP time_status & time_state */ |
41 | int clear_time_state(void) | 28 | int clear_time_state(void) |
diff --git a/tools/testing/selftests/timers/mqueue-lat.c b/tools/testing/selftests/timers/mqueue-lat.c index a2a3924d0b41..1867db5d6f5e 100644 --- a/tools/testing/selftests/timers/mqueue-lat.c +++ b/tools/testing/selftests/timers/mqueue-lat.c | |||
@@ -29,18 +29,7 @@ | |||
29 | #include <signal.h> | 29 | #include <signal.h> |
30 | #include <errno.h> | 30 | #include <errno.h> |
31 | #include <mqueue.h> | 31 | #include <mqueue.h> |
32 | #ifdef KTEST | ||
33 | #include "../kselftest.h" | 32 | #include "../kselftest.h" |
34 | #else | ||
35 | static inline int ksft_exit_pass(void) | ||
36 | { | ||
37 | exit(0); | ||
38 | } | ||
39 | static inline int ksft_exit_fail(void) | ||
40 | { | ||
41 | exit(1); | ||
42 | } | ||
43 | #endif | ||
44 | 33 | ||
45 | #define NSEC_PER_SEC 1000000000ULL | 34 | #define NSEC_PER_SEC 1000000000ULL |
46 | 35 | ||
diff --git a/tools/testing/selftests/timers/nanosleep.c b/tools/testing/selftests/timers/nanosleep.c index ff942ff7c9b3..8adb0bb51d4d 100644 --- a/tools/testing/selftests/timers/nanosleep.c +++ b/tools/testing/selftests/timers/nanosleep.c | |||
@@ -27,18 +27,7 @@ | |||
27 | #include <sys/timex.h> | 27 | #include <sys/timex.h> |
28 | #include <string.h> | 28 | #include <string.h> |
29 | #include <signal.h> | 29 | #include <signal.h> |
30 | #ifdef KTEST | ||
31 | #include "../kselftest.h" | 30 | #include "../kselftest.h" |
32 | #else | ||
33 | static inline int ksft_exit_pass(void) | ||
34 | { | ||
35 | exit(0); | ||
36 | } | ||
37 | static inline int ksft_exit_fail(void) | ||
38 | { | ||
39 | exit(1); | ||
40 | } | ||
41 | #endif | ||
42 | 31 | ||
43 | #define NSEC_PER_SEC 1000000000ULL | 32 | #define NSEC_PER_SEC 1000000000ULL |
44 | 33 | ||
diff --git a/tools/testing/selftests/timers/nsleep-lat.c b/tools/testing/selftests/timers/nsleep-lat.c index 2d7898fda0f1..c3c3dc10db17 100644 --- a/tools/testing/selftests/timers/nsleep-lat.c +++ b/tools/testing/selftests/timers/nsleep-lat.c | |||
@@ -24,18 +24,7 @@ | |||
24 | #include <sys/timex.h> | 24 | #include <sys/timex.h> |
25 | #include <string.h> | 25 | #include <string.h> |
26 | #include <signal.h> | 26 | #include <signal.h> |
27 | #ifdef KTEST | ||
28 | #include "../kselftest.h" | 27 | #include "../kselftest.h" |
29 | #else | ||
30 | static inline int ksft_exit_pass(void) | ||
31 | { | ||
32 | exit(0); | ||
33 | } | ||
34 | static inline int ksft_exit_fail(void) | ||
35 | { | ||
36 | exit(1); | ||
37 | } | ||
38 | #endif | ||
39 | 28 | ||
40 | #define NSEC_PER_SEC 1000000000ULL | 29 | #define NSEC_PER_SEC 1000000000ULL |
41 | 30 | ||
diff --git a/tools/testing/selftests/timers/raw_skew.c b/tools/testing/selftests/timers/raw_skew.c index 30906bfd9c1b..ca6cd146aafe 100644 --- a/tools/testing/selftests/timers/raw_skew.c +++ b/tools/testing/selftests/timers/raw_skew.c | |||
@@ -25,19 +25,7 @@ | |||
25 | #include <sys/time.h> | 25 | #include <sys/time.h> |
26 | #include <sys/timex.h> | 26 | #include <sys/timex.h> |
27 | #include <time.h> | 27 | #include <time.h> |
28 | #ifdef KTEST | ||
29 | #include "../kselftest.h" | 28 | #include "../kselftest.h" |
30 | #else | ||
31 | static inline int ksft_exit_pass(void) | ||
32 | { | ||
33 | exit(0); | ||
34 | } | ||
35 | static inline int ksft_exit_fail(void) | ||
36 | { | ||
37 | exit(1); | ||
38 | } | ||
39 | #endif | ||
40 | |||
41 | 29 | ||
42 | #define CLOCK_MONOTONIC_RAW 4 | 30 | #define CLOCK_MONOTONIC_RAW 4 |
43 | #define NSEC_PER_SEC 1000000000LL | 31 | #define NSEC_PER_SEC 1000000000LL |
diff --git a/tools/testing/selftests/timers/rtctest.c b/tools/testing/selftests/timers/rtctest.c index f61170f7b024..411eff625e66 100644 --- a/tools/testing/selftests/timers/rtctest.c +++ b/tools/testing/selftests/timers/rtctest.c | |||
@@ -221,6 +221,11 @@ test_READ: | |||
221 | /* Read the current alarm settings */ | 221 | /* Read the current alarm settings */ |
222 | retval = ioctl(fd, RTC_ALM_READ, &rtc_tm); | 222 | retval = ioctl(fd, RTC_ALM_READ, &rtc_tm); |
223 | if (retval == -1) { | 223 | if (retval == -1) { |
224 | if (errno == EINVAL) { | ||
225 | fprintf(stderr, | ||
226 | "\n...EINVAL reading current alarm setting.\n"); | ||
227 | goto test_PIE; | ||
228 | } | ||
224 | perror("RTC_ALM_READ ioctl"); | 229 | perror("RTC_ALM_READ ioctl"); |
225 | exit(errno); | 230 | exit(errno); |
226 | } | 231 | } |
@@ -231,7 +236,7 @@ test_READ: | |||
231 | /* Enable alarm interrupts */ | 236 | /* Enable alarm interrupts */ |
232 | retval = ioctl(fd, RTC_AIE_ON, 0); | 237 | retval = ioctl(fd, RTC_AIE_ON, 0); |
233 | if (retval == -1) { | 238 | if (retval == -1) { |
234 | if (errno == EINVAL) { | 239 | if (errno == EINVAL || errno == EIO) { |
235 | fprintf(stderr, | 240 | fprintf(stderr, |
236 | "\n...Alarm IRQs not supported.\n"); | 241 | "\n...Alarm IRQs not supported.\n"); |
237 | goto test_PIE; | 242 | goto test_PIE; |
diff --git a/tools/testing/selftests/timers/set-2038.c b/tools/testing/selftests/timers/set-2038.c index c8a7e14446b1..688cfd81b531 100644 --- a/tools/testing/selftests/timers/set-2038.c +++ b/tools/testing/selftests/timers/set-2038.c | |||
@@ -27,18 +27,7 @@ | |||
27 | #include <unistd.h> | 27 | #include <unistd.h> |
28 | #include <time.h> | 28 | #include <time.h> |
29 | #include <sys/time.h> | 29 | #include <sys/time.h> |
30 | #ifdef KTEST | ||
31 | #include "../kselftest.h" | 30 | #include "../kselftest.h" |
32 | #else | ||
33 | static inline int ksft_exit_pass(void) | ||
34 | { | ||
35 | exit(0); | ||
36 | } | ||
37 | static inline int ksft_exit_fail(void) | ||
38 | { | ||
39 | exit(1); | ||
40 | } | ||
41 | #endif | ||
42 | 31 | ||
43 | #define NSEC_PER_SEC 1000000000LL | 32 | #define NSEC_PER_SEC 1000000000LL |
44 | 33 | ||
diff --git a/tools/testing/selftests/timers/set-tai.c b/tools/testing/selftests/timers/set-tai.c index dc88dbc8831f..70fed27d8fd3 100644 --- a/tools/testing/selftests/timers/set-tai.c +++ b/tools/testing/selftests/timers/set-tai.c | |||
@@ -23,18 +23,7 @@ | |||
23 | #include <string.h> | 23 | #include <string.h> |
24 | #include <signal.h> | 24 | #include <signal.h> |
25 | #include <unistd.h> | 25 | #include <unistd.h> |
26 | #ifdef KTEST | ||
27 | #include "../kselftest.h" | 26 | #include "../kselftest.h" |
28 | #else | ||
29 | static inline int ksft_exit_pass(void) | ||
30 | { | ||
31 | exit(0); | ||
32 | } | ||
33 | static inline int ksft_exit_fail(void) | ||
34 | { | ||
35 | exit(1); | ||
36 | } | ||
37 | #endif | ||
38 | 27 | ||
39 | int set_tai(int offset) | 28 | int set_tai(int offset) |
40 | { | 29 | { |
diff --git a/tools/testing/selftests/timers/set-timer-lat.c b/tools/testing/selftests/timers/set-timer-lat.c index 15434da23b04..50da45437daa 100644 --- a/tools/testing/selftests/timers/set-timer-lat.c +++ b/tools/testing/selftests/timers/set-timer-lat.c | |||
@@ -28,18 +28,7 @@ | |||
28 | #include <signal.h> | 28 | #include <signal.h> |
29 | #include <stdlib.h> | 29 | #include <stdlib.h> |
30 | #include <pthread.h> | 30 | #include <pthread.h> |
31 | #ifdef KTEST | ||
32 | #include "../kselftest.h" | 31 | #include "../kselftest.h" |
33 | #else | ||
34 | static inline int ksft_exit_pass(void) | ||
35 | { | ||
36 | exit(0); | ||
37 | } | ||
38 | static inline int ksft_exit_fail(void) | ||
39 | { | ||
40 | exit(1); | ||
41 | } | ||
42 | #endif | ||
43 | 32 | ||
44 | #define CLOCK_REALTIME 0 | 33 | #define CLOCK_REALTIME 0 |
45 | #define CLOCK_MONOTONIC 1 | 34 | #define CLOCK_MONOTONIC 1 |
@@ -154,7 +143,8 @@ int setup_timer(int clock_id, int flags, int interval, timer_t *tm1) | |||
154 | printf("%-22s %s missing CAP_WAKE_ALARM? : [UNSUPPORTED]\n", | 143 | printf("%-22s %s missing CAP_WAKE_ALARM? : [UNSUPPORTED]\n", |
155 | clockstring(clock_id), | 144 | clockstring(clock_id), |
156 | flags ? "ABSTIME":"RELTIME"); | 145 | flags ? "ABSTIME":"RELTIME"); |
157 | return 0; | 146 | /* Indicate timer isn't set, so caller doesn't wait */ |
147 | return 1; | ||
158 | } | 148 | } |
159 | printf("%s - timer_create() failed\n", clockstring(clock_id)); | 149 | printf("%s - timer_create() failed\n", clockstring(clock_id)); |
160 | return -1; | 150 | return -1; |
@@ -224,8 +214,9 @@ int do_timer(int clock_id, int flags) | |||
224 | int err; | 214 | int err; |
225 | 215 | ||
226 | err = setup_timer(clock_id, flags, interval, &tm1); | 216 | err = setup_timer(clock_id, flags, interval, &tm1); |
217 | /* Unsupported case - return 0 to not fail the test */ | ||
227 | if (err) | 218 | if (err) |
228 | return err; | 219 | return err == 1 ? 0 : err; |
229 | 220 | ||
230 | while (alarmcount < 5) | 221 | while (alarmcount < 5) |
231 | sleep(1); | 222 | sleep(1); |
@@ -239,18 +230,17 @@ int do_timer_oneshot(int clock_id, int flags) | |||
239 | timer_t tm1; | 230 | timer_t tm1; |
240 | const int interval = 0; | 231 | const int interval = 0; |
241 | struct timeval timeout; | 232 | struct timeval timeout; |
242 | fd_set fds; | ||
243 | int err; | 233 | int err; |
244 | 234 | ||
245 | err = setup_timer(clock_id, flags, interval, &tm1); | 235 | err = setup_timer(clock_id, flags, interval, &tm1); |
236 | /* Unsupported case - return 0 to not fail the test */ | ||
246 | if (err) | 237 | if (err) |
247 | return err; | 238 | return err == 1 ? 0 : err; |
248 | 239 | ||
249 | memset(&timeout, 0, sizeof(timeout)); | 240 | memset(&timeout, 0, sizeof(timeout)); |
250 | timeout.tv_sec = 5; | 241 | timeout.tv_sec = 5; |
251 | FD_ZERO(&fds); | ||
252 | do { | 242 | do { |
253 | err = select(FD_SETSIZE, &fds, NULL, NULL, &timeout); | 243 | err = select(0, NULL, NULL, NULL, &timeout); |
254 | } while (err == -1 && errno == EINTR); | 244 | } while (err == -1 && errno == EINTR); |
255 | 245 | ||
256 | timer_delete(tm1); | 246 | timer_delete(tm1); |
diff --git a/tools/testing/selftests/timers/set-tz.c b/tools/testing/selftests/timers/set-tz.c index f4184928b16b..877fd5532fee 100644 --- a/tools/testing/selftests/timers/set-tz.c +++ b/tools/testing/selftests/timers/set-tz.c | |||
@@ -23,18 +23,7 @@ | |||
23 | #include <string.h> | 23 | #include <string.h> |
24 | #include <signal.h> | 24 | #include <signal.h> |
25 | #include <unistd.h> | 25 | #include <unistd.h> |
26 | #ifdef KTEST | ||
27 | #include "../kselftest.h" | 26 | #include "../kselftest.h" |
28 | #else | ||
29 | static inline int ksft_exit_pass(void) | ||
30 | { | ||
31 | exit(0); | ||
32 | } | ||
33 | static inline int ksft_exit_fail(void) | ||
34 | { | ||
35 | exit(1); | ||
36 | } | ||
37 | #endif | ||
38 | 27 | ||
39 | int set_tz(int min, int dst) | 28 | int set_tz(int min, int dst) |
40 | { | 29 | { |
diff --git a/tools/testing/selftests/timers/skew_consistency.c b/tools/testing/selftests/timers/skew_consistency.c index 2a996e072259..022b711c78ee 100644 --- a/tools/testing/selftests/timers/skew_consistency.c +++ b/tools/testing/selftests/timers/skew_consistency.c | |||
@@ -35,18 +35,7 @@ | |||
35 | #include <stdlib.h> | 35 | #include <stdlib.h> |
36 | #include <string.h> | 36 | #include <string.h> |
37 | #include <sys/wait.h> | 37 | #include <sys/wait.h> |
38 | #ifdef KTEST | ||
39 | #include "../kselftest.h" | 38 | #include "../kselftest.h" |
40 | #else | ||
41 | static inline int ksft_exit_pass(void) | ||
42 | { | ||
43 | exit(0); | ||
44 | } | ||
45 | static inline int ksft_exit_fail(void) | ||
46 | { | ||
47 | exit(1); | ||
48 | } | ||
49 | #endif | ||
50 | 39 | ||
51 | #define NSEC_PER_SEC 1000000000LL | 40 | #define NSEC_PER_SEC 1000000000LL |
52 | 41 | ||
diff --git a/tools/testing/selftests/timers/threadtest.c b/tools/testing/selftests/timers/threadtest.c index e632e116f05e..759c9c06f1a0 100644 --- a/tools/testing/selftests/timers/threadtest.c +++ b/tools/testing/selftests/timers/threadtest.c | |||
@@ -21,19 +21,7 @@ | |||
21 | #include <stdlib.h> | 21 | #include <stdlib.h> |
22 | #include <sys/time.h> | 22 | #include <sys/time.h> |
23 | #include <pthread.h> | 23 | #include <pthread.h> |
24 | #ifdef KTEST | ||
25 | #include "../kselftest.h" | 24 | #include "../kselftest.h" |
26 | #else | ||
27 | static inline int ksft_exit_pass(void) | ||
28 | { | ||
29 | exit(0); | ||
30 | } | ||
31 | static inline int ksft_exit_fail(void) | ||
32 | { | ||
33 | exit(1); | ||
34 | } | ||
35 | #endif | ||
36 | |||
37 | 25 | ||
38 | /* serializes shared list access */ | 26 | /* serializes shared list access */ |
39 | pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER; | 27 | pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER; |
diff --git a/tools/testing/selftests/timers/valid-adjtimex.c b/tools/testing/selftests/timers/valid-adjtimex.c index 60fe3c569bd9..d9d3ab93b31a 100644 --- a/tools/testing/selftests/timers/valid-adjtimex.c +++ b/tools/testing/selftests/timers/valid-adjtimex.c | |||
@@ -32,18 +32,7 @@ | |||
32 | #include <string.h> | 32 | #include <string.h> |
33 | #include <signal.h> | 33 | #include <signal.h> |
34 | #include <unistd.h> | 34 | #include <unistd.h> |
35 | #ifdef KTEST | ||
36 | #include "../kselftest.h" | 35 | #include "../kselftest.h" |
37 | #else | ||
38 | static inline int ksft_exit_pass(void) | ||
39 | { | ||
40 | exit(0); | ||
41 | } | ||
42 | static inline int ksft_exit_fail(void) | ||
43 | { | ||
44 | exit(1); | ||
45 | } | ||
46 | #endif | ||
47 | 36 | ||
48 | #define NSEC_PER_SEC 1000000000LL | 37 | #define NSEC_PER_SEC 1000000000LL |
49 | #define USEC_PER_SEC 1000000LL | 38 | #define USEC_PER_SEC 1000000LL |
diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c index 1eae79ae5b4e..a2c53a3d223d 100644 --- a/tools/testing/selftests/vm/userfaultfd.c +++ b/tools/testing/selftests/vm/userfaultfd.c | |||
@@ -66,6 +66,8 @@ | |||
66 | #include <sys/wait.h> | 66 | #include <sys/wait.h> |
67 | #include <pthread.h> | 67 | #include <pthread.h> |
68 | #include <linux/userfaultfd.h> | 68 | #include <linux/userfaultfd.h> |
69 | #include <setjmp.h> | ||
70 | #include <stdbool.h> | ||
69 | 71 | ||
70 | #ifdef __NR_userfaultfd | 72 | #ifdef __NR_userfaultfd |
71 | 73 | ||
@@ -82,11 +84,17 @@ static int bounces; | |||
82 | #define TEST_SHMEM 3 | 84 | #define TEST_SHMEM 3 |
83 | static int test_type; | 85 | static int test_type; |
84 | 86 | ||
87 | /* exercise the test_uffdio_*_eexist every ALARM_INTERVAL_SECS */ | ||
88 | #define ALARM_INTERVAL_SECS 10 | ||
89 | static volatile bool test_uffdio_copy_eexist = true; | ||
90 | static volatile bool test_uffdio_zeropage_eexist = true; | ||
91 | |||
92 | static bool map_shared; | ||
85 | static int huge_fd; | 93 | static int huge_fd; |
86 | static char *huge_fd_off0; | 94 | static char *huge_fd_off0; |
87 | static unsigned long long *count_verify; | 95 | static unsigned long long *count_verify; |
88 | static int uffd, uffd_flags, finished, *pipefd; | 96 | static int uffd, uffd_flags, finished, *pipefd; |
89 | static char *area_src, *area_dst; | 97 | static char *area_src, *area_src_alias, *area_dst, *area_dst_alias; |
90 | static char *zeropage; | 98 | static char *zeropage; |
91 | pthread_attr_t attr; | 99 | pthread_attr_t attr; |
92 | 100 | ||
@@ -125,6 +133,9 @@ static void anon_allocate_area(void **alloc_area) | |||
125 | } | 133 | } |
126 | } | 134 | } |
127 | 135 | ||
136 | static void noop_alias_mapping(__u64 *start, size_t len, unsigned long offset) | ||
137 | { | ||
138 | } | ||
128 | 139 | ||
129 | /* HugeTLB memory */ | 140 | /* HugeTLB memory */ |
130 | static int hugetlb_release_pages(char *rel_area) | 141 | static int hugetlb_release_pages(char *rel_area) |
@@ -145,17 +156,51 @@ static int hugetlb_release_pages(char *rel_area) | |||
145 | 156 | ||
146 | static void hugetlb_allocate_area(void **alloc_area) | 157 | static void hugetlb_allocate_area(void **alloc_area) |
147 | { | 158 | { |
159 | void *area_alias = NULL; | ||
160 | char **alloc_area_alias; | ||
148 | *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE, | 161 | *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE, |
149 | MAP_PRIVATE | MAP_HUGETLB, huge_fd, | 162 | (map_shared ? MAP_SHARED : MAP_PRIVATE) | |
150 | *alloc_area == area_src ? 0 : | 163 | MAP_HUGETLB, |
151 | nr_pages * page_size); | 164 | huge_fd, *alloc_area == area_src ? 0 : |
165 | nr_pages * page_size); | ||
152 | if (*alloc_area == MAP_FAILED) { | 166 | if (*alloc_area == MAP_FAILED) { |
153 | fprintf(stderr, "mmap of hugetlbfs file failed\n"); | 167 | fprintf(stderr, "mmap of hugetlbfs file failed\n"); |
154 | *alloc_area = NULL; | 168 | *alloc_area = NULL; |
155 | } | 169 | } |
156 | 170 | ||
157 | if (*alloc_area == area_src) | 171 | if (map_shared) { |
172 | area_alias = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE, | ||
173 | MAP_SHARED | MAP_HUGETLB, | ||
174 | huge_fd, *alloc_area == area_src ? 0 : | ||
175 | nr_pages * page_size); | ||
176 | if (area_alias == MAP_FAILED) { | ||
177 | if (munmap(*alloc_area, nr_pages * page_size) < 0) | ||
178 | perror("hugetlb munmap"), exit(1); | ||
179 | *alloc_area = NULL; | ||
180 | return; | ||
181 | } | ||
182 | } | ||
183 | if (*alloc_area == area_src) { | ||
158 | huge_fd_off0 = *alloc_area; | 184 | huge_fd_off0 = *alloc_area; |
185 | alloc_area_alias = &area_src_alias; | ||
186 | } else { | ||
187 | alloc_area_alias = &area_dst_alias; | ||
188 | } | ||
189 | if (area_alias) | ||
190 | *alloc_area_alias = area_alias; | ||
191 | } | ||
192 | |||
193 | static void hugetlb_alias_mapping(__u64 *start, size_t len, unsigned long offset) | ||
194 | { | ||
195 | if (!map_shared) | ||
196 | return; | ||
197 | /* | ||
198 | * We can't zap just the pagetable with hugetlbfs because | ||
199 | * MADV_DONTEED won't work. So exercise -EEXIST on a alias | ||
200 | * mapping where the pagetables are not established initially, | ||
201 | * this way we'll exercise the -EEXEC at the fs level. | ||
202 | */ | ||
203 | *start = (unsigned long) area_dst_alias + offset; | ||
159 | } | 204 | } |
160 | 205 | ||
161 | /* Shared memory */ | 206 | /* Shared memory */ |
@@ -185,6 +230,7 @@ struct uffd_test_ops { | |||
185 | unsigned long expected_ioctls; | 230 | unsigned long expected_ioctls; |
186 | void (*allocate_area)(void **alloc_area); | 231 | void (*allocate_area)(void **alloc_area); |
187 | int (*release_pages)(char *rel_area); | 232 | int (*release_pages)(char *rel_area); |
233 | void (*alias_mapping)(__u64 *start, size_t len, unsigned long offset); | ||
188 | }; | 234 | }; |
189 | 235 | ||
190 | #define ANON_EXPECTED_IOCTLS ((1 << _UFFDIO_WAKE) | \ | 236 | #define ANON_EXPECTED_IOCTLS ((1 << _UFFDIO_WAKE) | \ |
@@ -195,18 +241,21 @@ static struct uffd_test_ops anon_uffd_test_ops = { | |||
195 | .expected_ioctls = ANON_EXPECTED_IOCTLS, | 241 | .expected_ioctls = ANON_EXPECTED_IOCTLS, |
196 | .allocate_area = anon_allocate_area, | 242 | .allocate_area = anon_allocate_area, |
197 | .release_pages = anon_release_pages, | 243 | .release_pages = anon_release_pages, |
244 | .alias_mapping = noop_alias_mapping, | ||
198 | }; | 245 | }; |
199 | 246 | ||
200 | static struct uffd_test_ops shmem_uffd_test_ops = { | 247 | static struct uffd_test_ops shmem_uffd_test_ops = { |
201 | .expected_ioctls = UFFD_API_RANGE_IOCTLS_BASIC, | 248 | .expected_ioctls = ANON_EXPECTED_IOCTLS, |
202 | .allocate_area = shmem_allocate_area, | 249 | .allocate_area = shmem_allocate_area, |
203 | .release_pages = shmem_release_pages, | 250 | .release_pages = shmem_release_pages, |
251 | .alias_mapping = noop_alias_mapping, | ||
204 | }; | 252 | }; |
205 | 253 | ||
206 | static struct uffd_test_ops hugetlb_uffd_test_ops = { | 254 | static struct uffd_test_ops hugetlb_uffd_test_ops = { |
207 | .expected_ioctls = UFFD_API_RANGE_IOCTLS_BASIC, | 255 | .expected_ioctls = UFFD_API_RANGE_IOCTLS_BASIC, |
208 | .allocate_area = hugetlb_allocate_area, | 256 | .allocate_area = hugetlb_allocate_area, |
209 | .release_pages = hugetlb_release_pages, | 257 | .release_pages = hugetlb_release_pages, |
258 | .alias_mapping = hugetlb_alias_mapping, | ||
210 | }; | 259 | }; |
211 | 260 | ||
212 | static struct uffd_test_ops *uffd_test_ops; | 261 | static struct uffd_test_ops *uffd_test_ops; |
@@ -331,6 +380,23 @@ static void *locking_thread(void *arg) | |||
331 | return NULL; | 380 | return NULL; |
332 | } | 381 | } |
333 | 382 | ||
383 | static void retry_copy_page(int ufd, struct uffdio_copy *uffdio_copy, | ||
384 | unsigned long offset) | ||
385 | { | ||
386 | uffd_test_ops->alias_mapping(&uffdio_copy->dst, | ||
387 | uffdio_copy->len, | ||
388 | offset); | ||
389 | if (ioctl(ufd, UFFDIO_COPY, uffdio_copy)) { | ||
390 | /* real retval in ufdio_copy.copy */ | ||
391 | if (uffdio_copy->copy != -EEXIST) | ||
392 | fprintf(stderr, "UFFDIO_COPY retry error %Ld\n", | ||
393 | uffdio_copy->copy), exit(1); | ||
394 | } else { | ||
395 | fprintf(stderr, "UFFDIO_COPY retry unexpected %Ld\n", | ||
396 | uffdio_copy->copy), exit(1); | ||
397 | } | ||
398 | } | ||
399 | |||
334 | static int copy_page(int ufd, unsigned long offset) | 400 | static int copy_page(int ufd, unsigned long offset) |
335 | { | 401 | { |
336 | struct uffdio_copy uffdio_copy; | 402 | struct uffdio_copy uffdio_copy; |
@@ -351,8 +417,13 @@ static int copy_page(int ufd, unsigned long offset) | |||
351 | } else if (uffdio_copy.copy != page_size) { | 417 | } else if (uffdio_copy.copy != page_size) { |
352 | fprintf(stderr, "UFFDIO_COPY unexpected copy %Ld\n", | 418 | fprintf(stderr, "UFFDIO_COPY unexpected copy %Ld\n", |
353 | uffdio_copy.copy), exit(1); | 419 | uffdio_copy.copy), exit(1); |
354 | } else | 420 | } else { |
421 | if (test_uffdio_copy_eexist) { | ||
422 | test_uffdio_copy_eexist = false; | ||
423 | retry_copy_page(ufd, &uffdio_copy, offset); | ||
424 | } | ||
355 | return 1; | 425 | return 1; |
426 | } | ||
356 | return 0; | 427 | return 0; |
357 | } | 428 | } |
358 | 429 | ||
@@ -408,6 +479,7 @@ static void *uffd_poll_thread(void *arg) | |||
408 | userfaults++; | 479 | userfaults++; |
409 | break; | 480 | break; |
410 | case UFFD_EVENT_FORK: | 481 | case UFFD_EVENT_FORK: |
482 | close(uffd); | ||
411 | uffd = msg.arg.fork.ufd; | 483 | uffd = msg.arg.fork.ufd; |
412 | pollfd[0].fd = uffd; | 484 | pollfd[0].fd = uffd; |
413 | break; | 485 | break; |
@@ -572,6 +644,17 @@ static int userfaultfd_open(int features) | |||
572 | return 0; | 644 | return 0; |
573 | } | 645 | } |
574 | 646 | ||
647 | sigjmp_buf jbuf, *sigbuf; | ||
648 | |||
649 | static void sighndl(int sig, siginfo_t *siginfo, void *ptr) | ||
650 | { | ||
651 | if (sig == SIGBUS) { | ||
652 | if (sigbuf) | ||
653 | siglongjmp(*sigbuf, 1); | ||
654 | abort(); | ||
655 | } | ||
656 | } | ||
657 | |||
575 | /* | 658 | /* |
576 | * For non-cooperative userfaultfd test we fork() a process that will | 659 | * For non-cooperative userfaultfd test we fork() a process that will |
577 | * generate pagefaults, will mremap the area monitored by the | 660 | * generate pagefaults, will mremap the area monitored by the |
@@ -585,19 +668,59 @@ static int userfaultfd_open(int features) | |||
585 | * The release of the pages currently generates event for shmem and | 668 | * The release of the pages currently generates event for shmem and |
586 | * anonymous memory (UFFD_EVENT_REMOVE), hence it is not checked | 669 | * anonymous memory (UFFD_EVENT_REMOVE), hence it is not checked |
587 | * for hugetlb. | 670 | * for hugetlb. |
671 | * For signal test(UFFD_FEATURE_SIGBUS), signal_test = 1, we register | ||
672 | * monitored area, generate pagefaults and test that signal is delivered. | ||
673 | * Use UFFDIO_COPY to allocate missing page and retry. For signal_test = 2 | ||
674 | * test robustness use case - we release monitored area, fork a process | ||
675 | * that will generate pagefaults and verify signal is generated. | ||
676 | * This also tests UFFD_FEATURE_EVENT_FORK event along with the signal | ||
677 | * feature. Using monitor thread, verify no userfault events are generated. | ||
588 | */ | 678 | */ |
589 | static int faulting_process(void) | 679 | static int faulting_process(int signal_test) |
590 | { | 680 | { |
591 | unsigned long nr; | 681 | unsigned long nr; |
592 | unsigned long long count; | 682 | unsigned long long count; |
593 | unsigned long split_nr_pages; | 683 | unsigned long split_nr_pages; |
684 | unsigned long lastnr; | ||
685 | struct sigaction act; | ||
686 | unsigned long signalled = 0; | ||
594 | 687 | ||
595 | if (test_type != TEST_HUGETLB) | 688 | if (test_type != TEST_HUGETLB) |
596 | split_nr_pages = (nr_pages + 1) / 2; | 689 | split_nr_pages = (nr_pages + 1) / 2; |
597 | else | 690 | else |
598 | split_nr_pages = nr_pages; | 691 | split_nr_pages = nr_pages; |
599 | 692 | ||
693 | if (signal_test) { | ||
694 | sigbuf = &jbuf; | ||
695 | memset(&act, 0, sizeof(act)); | ||
696 | act.sa_sigaction = sighndl; | ||
697 | act.sa_flags = SA_SIGINFO; | ||
698 | if (sigaction(SIGBUS, &act, 0)) { | ||
699 | perror("sigaction"); | ||
700 | return 1; | ||
701 | } | ||
702 | lastnr = (unsigned long)-1; | ||
703 | } | ||
704 | |||
600 | for (nr = 0; nr < split_nr_pages; nr++) { | 705 | for (nr = 0; nr < split_nr_pages; nr++) { |
706 | if (signal_test) { | ||
707 | if (sigsetjmp(*sigbuf, 1) != 0) { | ||
708 | if (nr == lastnr) { | ||
709 | fprintf(stderr, "Signal repeated\n"); | ||
710 | return 1; | ||
711 | } | ||
712 | |||
713 | lastnr = nr; | ||
714 | if (signal_test == 1) { | ||
715 | if (copy_page(uffd, nr * page_size)) | ||
716 | signalled++; | ||
717 | } else { | ||
718 | signalled++; | ||
719 | continue; | ||
720 | } | ||
721 | } | ||
722 | } | ||
723 | |||
601 | count = *area_count(area_dst, nr); | 724 | count = *area_count(area_dst, nr); |
602 | if (count != count_verify[nr]) { | 725 | if (count != count_verify[nr]) { |
603 | fprintf(stderr, | 726 | fprintf(stderr, |
@@ -607,6 +730,9 @@ static int faulting_process(void) | |||
607 | } | 730 | } |
608 | } | 731 | } |
609 | 732 | ||
733 | if (signal_test) | ||
734 | return signalled != split_nr_pages; | ||
735 | |||
610 | if (test_type == TEST_HUGETLB) | 736 | if (test_type == TEST_HUGETLB) |
611 | return 0; | 737 | return 0; |
612 | 738 | ||
@@ -636,6 +762,23 @@ static int faulting_process(void) | |||
636 | return 0; | 762 | return 0; |
637 | } | 763 | } |
638 | 764 | ||
765 | static void retry_uffdio_zeropage(int ufd, | ||
766 | struct uffdio_zeropage *uffdio_zeropage, | ||
767 | unsigned long offset) | ||
768 | { | ||
769 | uffd_test_ops->alias_mapping(&uffdio_zeropage->range.start, | ||
770 | uffdio_zeropage->range.len, | ||
771 | offset); | ||
772 | if (ioctl(ufd, UFFDIO_ZEROPAGE, uffdio_zeropage)) { | ||
773 | if (uffdio_zeropage->zeropage != -EEXIST) | ||
774 | fprintf(stderr, "UFFDIO_ZEROPAGE retry error %Ld\n", | ||
775 | uffdio_zeropage->zeropage), exit(1); | ||
776 | } else { | ||
777 | fprintf(stderr, "UFFDIO_ZEROPAGE retry unexpected %Ld\n", | ||
778 | uffdio_zeropage->zeropage), exit(1); | ||
779 | } | ||
780 | } | ||
781 | |||
639 | static int uffdio_zeropage(int ufd, unsigned long offset) | 782 | static int uffdio_zeropage(int ufd, unsigned long offset) |
640 | { | 783 | { |
641 | struct uffdio_zeropage uffdio_zeropage; | 784 | struct uffdio_zeropage uffdio_zeropage; |
@@ -670,8 +813,14 @@ static int uffdio_zeropage(int ufd, unsigned long offset) | |||
670 | if (uffdio_zeropage.zeropage != page_size) { | 813 | if (uffdio_zeropage.zeropage != page_size) { |
671 | fprintf(stderr, "UFFDIO_ZEROPAGE unexpected %Ld\n", | 814 | fprintf(stderr, "UFFDIO_ZEROPAGE unexpected %Ld\n", |
672 | uffdio_zeropage.zeropage), exit(1); | 815 | uffdio_zeropage.zeropage), exit(1); |
673 | } else | 816 | } else { |
817 | if (test_uffdio_zeropage_eexist) { | ||
818 | test_uffdio_zeropage_eexist = false; | ||
819 | retry_uffdio_zeropage(ufd, &uffdio_zeropage, | ||
820 | offset); | ||
821 | } | ||
674 | return 1; | 822 | return 1; |
823 | } | ||
675 | } else { | 824 | } else { |
676 | fprintf(stderr, | 825 | fprintf(stderr, |
677 | "UFFDIO_ZEROPAGE succeeded %Ld\n", | 826 | "UFFDIO_ZEROPAGE succeeded %Ld\n", |
@@ -761,7 +910,7 @@ static int userfaultfd_events_test(void) | |||
761 | perror("fork"), exit(1); | 910 | perror("fork"), exit(1); |
762 | 911 | ||
763 | if (!pid) | 912 | if (!pid) |
764 | return faulting_process(); | 913 | return faulting_process(0); |
765 | 914 | ||
766 | waitpid(pid, &err, 0); | 915 | waitpid(pid, &err, 0); |
767 | if (err) | 916 | if (err) |
@@ -778,6 +927,72 @@ static int userfaultfd_events_test(void) | |||
778 | return userfaults != nr_pages; | 927 | return userfaults != nr_pages; |
779 | } | 928 | } |
780 | 929 | ||
930 | static int userfaultfd_sig_test(void) | ||
931 | { | ||
932 | struct uffdio_register uffdio_register; | ||
933 | unsigned long expected_ioctls; | ||
934 | unsigned long userfaults; | ||
935 | pthread_t uffd_mon; | ||
936 | int err, features; | ||
937 | pid_t pid; | ||
938 | char c; | ||
939 | |||
940 | printf("testing signal delivery: "); | ||
941 | fflush(stdout); | ||
942 | |||
943 | if (uffd_test_ops->release_pages(area_dst)) | ||
944 | return 1; | ||
945 | |||
946 | features = UFFD_FEATURE_EVENT_FORK|UFFD_FEATURE_SIGBUS; | ||
947 | if (userfaultfd_open(features) < 0) | ||
948 | return 1; | ||
949 | fcntl(uffd, F_SETFL, uffd_flags | O_NONBLOCK); | ||
950 | |||
951 | uffdio_register.range.start = (unsigned long) area_dst; | ||
952 | uffdio_register.range.len = nr_pages * page_size; | ||
953 | uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; | ||
954 | if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) | ||
955 | fprintf(stderr, "register failure\n"), exit(1); | ||
956 | |||
957 | expected_ioctls = uffd_test_ops->expected_ioctls; | ||
958 | if ((uffdio_register.ioctls & expected_ioctls) != | ||
959 | expected_ioctls) | ||
960 | fprintf(stderr, | ||
961 | "unexpected missing ioctl for anon memory\n"), | ||
962 | exit(1); | ||
963 | |||
964 | if (faulting_process(1)) | ||
965 | fprintf(stderr, "faulting process failed\n"), exit(1); | ||
966 | |||
967 | if (uffd_test_ops->release_pages(area_dst)) | ||
968 | return 1; | ||
969 | |||
970 | if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, NULL)) | ||
971 | perror("uffd_poll_thread create"), exit(1); | ||
972 | |||
973 | pid = fork(); | ||
974 | if (pid < 0) | ||
975 | perror("fork"), exit(1); | ||
976 | |||
977 | if (!pid) | ||
978 | exit(faulting_process(2)); | ||
979 | |||
980 | waitpid(pid, &err, 0); | ||
981 | if (err) | ||
982 | fprintf(stderr, "faulting process failed\n"), exit(1); | ||
983 | |||
984 | if (write(pipefd[1], &c, sizeof(c)) != sizeof(c)) | ||
985 | perror("pipe write"), exit(1); | ||
986 | if (pthread_join(uffd_mon, (void **)&userfaults)) | ||
987 | return 1; | ||
988 | |||
989 | printf("done.\n"); | ||
990 | if (userfaults) | ||
991 | fprintf(stderr, "Signal test failed, userfaults: %ld\n", | ||
992 | userfaults); | ||
993 | close(uffd); | ||
994 | return userfaults != 0; | ||
995 | } | ||
781 | static int userfaultfd_stress(void) | 996 | static int userfaultfd_stress(void) |
782 | { | 997 | { |
783 | void *area; | 998 | void *area; |
@@ -879,6 +1094,15 @@ static int userfaultfd_stress(void) | |||
879 | return 1; | 1094 | return 1; |
880 | } | 1095 | } |
881 | 1096 | ||
1097 | if (area_dst_alias) { | ||
1098 | uffdio_register.range.start = (unsigned long) | ||
1099 | area_dst_alias; | ||
1100 | if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) { | ||
1101 | fprintf(stderr, "register failure alias\n"); | ||
1102 | return 1; | ||
1103 | } | ||
1104 | } | ||
1105 | |||
882 | /* | 1106 | /* |
883 | * The madvise done previously isn't enough: some | 1107 | * The madvise done previously isn't enough: some |
884 | * uffd_thread could have read userfaults (one of | 1108 | * uffd_thread could have read userfaults (one of |
@@ -912,9 +1136,17 @@ static int userfaultfd_stress(void) | |||
912 | 1136 | ||
913 | /* unregister */ | 1137 | /* unregister */ |
914 | if (ioctl(uffd, UFFDIO_UNREGISTER, &uffdio_register.range)) { | 1138 | if (ioctl(uffd, UFFDIO_UNREGISTER, &uffdio_register.range)) { |
915 | fprintf(stderr, "register failure\n"); | 1139 | fprintf(stderr, "unregister failure\n"); |
916 | return 1; | 1140 | return 1; |
917 | } | 1141 | } |
1142 | if (area_dst_alias) { | ||
1143 | uffdio_register.range.start = (unsigned long) area_dst; | ||
1144 | if (ioctl(uffd, UFFDIO_UNREGISTER, | ||
1145 | &uffdio_register.range)) { | ||
1146 | fprintf(stderr, "unregister failure alias\n"); | ||
1147 | return 1; | ||
1148 | } | ||
1149 | } | ||
918 | 1150 | ||
919 | /* verification */ | 1151 | /* verification */ |
920 | if (bounces & BOUNCE_VERIFY) { | 1152 | if (bounces & BOUNCE_VERIFY) { |
@@ -936,6 +1168,10 @@ static int userfaultfd_stress(void) | |||
936 | area_src = area_dst; | 1168 | area_src = area_dst; |
937 | area_dst = tmp_area; | 1169 | area_dst = tmp_area; |
938 | 1170 | ||
1171 | tmp_area = area_src_alias; | ||
1172 | area_src_alias = area_dst_alias; | ||
1173 | area_dst_alias = tmp_area; | ||
1174 | |||
939 | printf("userfaults:"); | 1175 | printf("userfaults:"); |
940 | for (cpu = 0; cpu < nr_cpus; cpu++) | 1176 | for (cpu = 0; cpu < nr_cpus; cpu++) |
941 | printf(" %lu", userfaults[cpu]); | 1177 | printf(" %lu", userfaults[cpu]); |
@@ -946,7 +1182,8 @@ static int userfaultfd_stress(void) | |||
946 | return err; | 1182 | return err; |
947 | 1183 | ||
948 | close(uffd); | 1184 | close(uffd); |
949 | return userfaultfd_zeropage_test() || userfaultfd_events_test(); | 1185 | return userfaultfd_zeropage_test() || userfaultfd_sig_test() |
1186 | || userfaultfd_events_test(); | ||
950 | } | 1187 | } |
951 | 1188 | ||
952 | /* | 1189 | /* |
@@ -981,7 +1218,12 @@ static void set_test_type(const char *type) | |||
981 | } else if (!strcmp(type, "hugetlb")) { | 1218 | } else if (!strcmp(type, "hugetlb")) { |
982 | test_type = TEST_HUGETLB; | 1219 | test_type = TEST_HUGETLB; |
983 | uffd_test_ops = &hugetlb_uffd_test_ops; | 1220 | uffd_test_ops = &hugetlb_uffd_test_ops; |
1221 | } else if (!strcmp(type, "hugetlb_shared")) { | ||
1222 | map_shared = true; | ||
1223 | test_type = TEST_HUGETLB; | ||
1224 | uffd_test_ops = &hugetlb_uffd_test_ops; | ||
984 | } else if (!strcmp(type, "shmem")) { | 1225 | } else if (!strcmp(type, "shmem")) { |
1226 | map_shared = true; | ||
985 | test_type = TEST_SHMEM; | 1227 | test_type = TEST_SHMEM; |
986 | uffd_test_ops = &shmem_uffd_test_ops; | 1228 | uffd_test_ops = &shmem_uffd_test_ops; |
987 | } else { | 1229 | } else { |
@@ -1001,12 +1243,25 @@ static void set_test_type(const char *type) | |||
1001 | fprintf(stderr, "Impossible to run this test\n"), exit(2); | 1243 | fprintf(stderr, "Impossible to run this test\n"), exit(2); |
1002 | } | 1244 | } |
1003 | 1245 | ||
1246 | static void sigalrm(int sig) | ||
1247 | { | ||
1248 | if (sig != SIGALRM) | ||
1249 | abort(); | ||
1250 | test_uffdio_copy_eexist = true; | ||
1251 | test_uffdio_zeropage_eexist = true; | ||
1252 | alarm(ALARM_INTERVAL_SECS); | ||
1253 | } | ||
1254 | |||
1004 | int main(int argc, char **argv) | 1255 | int main(int argc, char **argv) |
1005 | { | 1256 | { |
1006 | if (argc < 4) | 1257 | if (argc < 4) |
1007 | fprintf(stderr, "Usage: <test type> <MiB> <bounces> [hugetlbfs_file]\n"), | 1258 | fprintf(stderr, "Usage: <test type> <MiB> <bounces> [hugetlbfs_file]\n"), |
1008 | exit(1); | 1259 | exit(1); |
1009 | 1260 | ||
1261 | if (signal(SIGALRM, sigalrm) == SIG_ERR) | ||
1262 | fprintf(stderr, "failed to arm SIGALRM"), exit(1); | ||
1263 | alarm(ALARM_INTERVAL_SECS); | ||
1264 | |||
1010 | set_test_type(argv[1]); | 1265 | set_test_type(argv[1]); |
1011 | 1266 | ||
1012 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | 1267 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); |
diff --git a/tools/testing/selftests/watchdog/Makefile b/tools/testing/selftests/watchdog/Makefile index f863c664e3d1..ee068511fd0b 100644 --- a/tools/testing/selftests/watchdog/Makefile +++ b/tools/testing/selftests/watchdog/Makefile | |||
@@ -1,8 +1,3 @@ | |||
1 | TEST_PROGS := watchdog-test | 1 | TEST_GEN_PROGS := watchdog-test |
2 | |||
3 | all: $(TEST_PROGS) | ||
4 | 2 | ||
5 | include ../lib.mk | 3 | include ../lib.mk |
6 | |||
7 | clean: | ||
8 | rm -fr $(TEST_PROGS) | ||
diff --git a/tools/testing/selftests/watchdog/watchdog-test.c b/tools/testing/selftests/watchdog/watchdog-test.c index a74c9d739d07..a1391be2dc1e 100644 --- a/tools/testing/selftests/watchdog/watchdog-test.c +++ b/tools/testing/selftests/watchdog/watchdog-test.c | |||
@@ -9,12 +9,25 @@ | |||
9 | #include <unistd.h> | 9 | #include <unistd.h> |
10 | #include <fcntl.h> | 10 | #include <fcntl.h> |
11 | #include <signal.h> | 11 | #include <signal.h> |
12 | #include <getopt.h> | ||
12 | #include <sys/ioctl.h> | 13 | #include <sys/ioctl.h> |
13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
14 | #include <linux/watchdog.h> | 15 | #include <linux/watchdog.h> |
15 | 16 | ||
17 | #define DEFAULT_PING_RATE 1 | ||
18 | |||
16 | int fd; | 19 | int fd; |
17 | const char v = 'V'; | 20 | const char v = 'V'; |
21 | static const char sopts[] = "bdehp:t:"; | ||
22 | static const struct option lopts[] = { | ||
23 | {"bootstatus", no_argument, NULL, 'b'}, | ||
24 | {"disable", no_argument, NULL, 'd'}, | ||
25 | {"enable", no_argument, NULL, 'e'}, | ||
26 | {"help", no_argument, NULL, 'h'}, | ||
27 | {"pingrate", required_argument, NULL, 'p'}, | ||
28 | {"timeout", required_argument, NULL, 't'}, | ||
29 | {NULL, no_argument, NULL, 0x0} | ||
30 | }; | ||
18 | 31 | ||
19 | /* | 32 | /* |
20 | * This function simply sends an IOCTL to the driver, which in turn ticks | 33 | * This function simply sends an IOCTL to the driver, which in turn ticks |
@@ -23,12 +36,12 @@ const char v = 'V'; | |||
23 | */ | 36 | */ |
24 | static void keep_alive(void) | 37 | static void keep_alive(void) |
25 | { | 38 | { |
26 | int dummy; | 39 | int dummy; |
27 | int ret; | 40 | int ret; |
28 | 41 | ||
29 | ret = ioctl(fd, WDIOC_KEEPALIVE, &dummy); | 42 | ret = ioctl(fd, WDIOC_KEEPALIVE, &dummy); |
30 | if (!ret) | 43 | if (!ret) |
31 | printf("."); | 44 | printf("."); |
32 | } | 45 | } |
33 | 46 | ||
34 | /* | 47 | /* |
@@ -38,75 +51,110 @@ static void keep_alive(void) | |||
38 | 51 | ||
39 | static void term(int sig) | 52 | static void term(int sig) |
40 | { | 53 | { |
41 | int ret = write(fd, &v, 1); | 54 | int ret = write(fd, &v, 1); |
42 | 55 | ||
43 | close(fd); | 56 | close(fd); |
44 | if (ret < 0) | 57 | if (ret < 0) |
45 | printf("\nStopping watchdog ticks failed (%d)...\n", errno); | 58 | printf("\nStopping watchdog ticks failed (%d)...\n", errno); |
46 | else | 59 | else |
47 | printf("\nStopping watchdog ticks...\n"); | 60 | printf("\nStopping watchdog ticks...\n"); |
48 | exit(0); | 61 | exit(0); |
62 | } | ||
63 | |||
64 | static void usage(char *progname) | ||
65 | { | ||
66 | printf("Usage: %s [options]\n", progname); | ||
67 | printf(" -b, --bootstatus Get last boot status (Watchdog/POR)\n"); | ||
68 | printf(" -d, --disable Turn off the watchdog timer\n"); | ||
69 | printf(" -e, --enable Turn on the watchdog timer\n"); | ||
70 | printf(" -h, --help Print the help message\n"); | ||
71 | printf(" -p, --pingrate=P Set ping rate to P seconds (default %d)\n", DEFAULT_PING_RATE); | ||
72 | printf(" -t, --timeout=T Set timeout to T seconds\n"); | ||
73 | printf("\n"); | ||
74 | printf("Parameters are parsed left-to-right in real-time.\n"); | ||
75 | printf("Example: %s -d -t 10 -p 5 -e\n", progname); | ||
49 | } | 76 | } |
50 | 77 | ||
51 | int main(int argc, char *argv[]) | 78 | int main(int argc, char *argv[]) |
52 | { | 79 | { |
53 | int flags; | 80 | int flags; |
54 | unsigned int ping_rate = 1; | 81 | unsigned int ping_rate = DEFAULT_PING_RATE; |
55 | int ret; | 82 | int ret; |
56 | int i; | 83 | int c; |
57 | 84 | int oneshot = 0; | |
58 | setbuf(stdout, NULL); | 85 | |
59 | 86 | setbuf(stdout, NULL); | |
60 | fd = open("/dev/watchdog", O_WRONLY); | 87 | |
61 | 88 | fd = open("/dev/watchdog", O_WRONLY); | |
62 | if (fd == -1) { | 89 | |
63 | printf("Watchdog device not enabled.\n"); | 90 | if (fd == -1) { |
64 | exit(-1); | 91 | printf("Watchdog device not enabled.\n"); |
65 | } | 92 | exit(-1); |
66 | 93 | } | |
67 | for (i = 1; i < argc; i++) { | 94 | |
68 | if (!strncasecmp(argv[i], "-d", 2)) { | 95 | while ((c = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) { |
69 | flags = WDIOS_DISABLECARD; | 96 | switch (c) { |
70 | ret = ioctl(fd, WDIOC_SETOPTIONS, &flags); | 97 | case 'b': |
71 | if (!ret) | 98 | flags = 0; |
72 | printf("Watchdog card disabled.\n"); | 99 | oneshot = 1; |
73 | } else if (!strncasecmp(argv[i], "-e", 2)) { | 100 | ret = ioctl(fd, WDIOC_GETBOOTSTATUS, &flags); |
74 | flags = WDIOS_ENABLECARD; | 101 | if (!ret) |
75 | ret = ioctl(fd, WDIOC_SETOPTIONS, &flags); | 102 | printf("Last boot is caused by: %s.\n", (flags != 0) ? |
76 | if (!ret) | 103 | "Watchdog" : "Power-On-Reset"); |
77 | printf("Watchdog card enabled.\n"); | 104 | else |
78 | } else if (!strncasecmp(argv[i], "-t", 2) && argv[2]) { | 105 | printf("WDIOC_GETBOOTSTATUS errno '%s'\n", strerror(errno)); |
79 | flags = atoi(argv[i + 1]); | 106 | break; |
80 | ret = ioctl(fd, WDIOC_SETTIMEOUT, &flags); | 107 | case 'd': |
81 | if (!ret) | 108 | flags = WDIOS_DISABLECARD; |
82 | printf("Watchdog timeout set to %u seconds.\n", flags); | 109 | ret = ioctl(fd, WDIOC_SETOPTIONS, &flags); |
83 | i++; | 110 | if (!ret) |
84 | } else if (!strncasecmp(argv[i], "-p", 2) && argv[2]) { | 111 | printf("Watchdog card disabled.\n"); |
85 | ping_rate = strtoul(argv[i + 1], NULL, 0); | 112 | else |
86 | printf("Watchdog ping rate set to %u seconds.\n", ping_rate); | 113 | printf("WDIOS_DISABLECARD errno '%s'\n", strerror(errno)); |
87 | i++; | 114 | break; |
88 | } else { | 115 | case 'e': |
89 | printf("-d to disable, -e to enable, -t <n> to set " | 116 | flags = WDIOS_ENABLECARD; |
90 | "the timeout,\n-p <n> to set the ping rate, and "); | 117 | ret = ioctl(fd, WDIOC_SETOPTIONS, &flags); |
91 | printf("run by itself to tick the card.\n"); | 118 | if (!ret) |
92 | printf("Parameters are parsed left-to-right in real-time.\n"); | 119 | printf("Watchdog card enabled.\n"); |
93 | printf("Example: %s -d -t 10 -p 5 -e\n", argv[0]); | 120 | else |
94 | goto end; | 121 | printf("WDIOS_ENABLECARD errno '%s'\n", strerror(errno)); |
95 | } | 122 | break; |
96 | } | 123 | case 'p': |
97 | 124 | ping_rate = strtoul(optarg, NULL, 0); | |
98 | printf("Watchdog Ticking Away!\n"); | 125 | if (!ping_rate) |
99 | 126 | ping_rate = DEFAULT_PING_RATE; | |
100 | signal(SIGINT, term); | 127 | printf("Watchdog ping rate set to %u seconds.\n", ping_rate); |
101 | 128 | break; | |
102 | while(1) { | 129 | case 't': |
103 | keep_alive(); | 130 | flags = strtoul(optarg, NULL, 0); |
104 | sleep(ping_rate); | 131 | ret = ioctl(fd, WDIOC_SETTIMEOUT, &flags); |
105 | } | 132 | if (!ret) |
133 | printf("Watchdog timeout set to %u seconds.\n", flags); | ||
134 | else | ||
135 | printf("WDIOC_SETTIMEOUT errno '%s'\n", strerror(errno)); | ||
136 | break; | ||
137 | default: | ||
138 | usage(argv[0]); | ||
139 | goto end; | ||
140 | } | ||
141 | } | ||
142 | |||
143 | if (oneshot) | ||
144 | goto end; | ||
145 | |||
146 | printf("Watchdog Ticking Away!\n"); | ||
147 | |||
148 | signal(SIGINT, term); | ||
149 | |||
150 | while (1) { | ||
151 | keep_alive(); | ||
152 | sleep(ping_rate); | ||
153 | } | ||
106 | end: | 154 | end: |
107 | ret = write(fd, &v, 1); | 155 | ret = write(fd, &v, 1); |
108 | if (ret < 0) | 156 | if (ret < 0) |
109 | printf("Stopping watchdog ticks failed (%d)...\n", errno); | 157 | printf("Stopping watchdog ticks failed (%d)...\n", errno); |
110 | close(fd); | 158 | close(fd); |
111 | return 0; | 159 | return 0; |
112 | } | 160 | } |
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 97f187e2663f..0a74a20ca32b 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile | |||
@@ -20,7 +20,7 @@ BINARIES_64 := $(TARGETS_C_64BIT_ALL:%=%_64) | |||
20 | BINARIES_32 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_32)) | 20 | BINARIES_32 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_32)) |
21 | BINARIES_64 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_64)) | 21 | BINARIES_64 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_64)) |
22 | 22 | ||
23 | CFLAGS := -O2 -g -std=gnu99 -pthread -Wall | 23 | CFLAGS := -O2 -g -std=gnu99 -pthread -Wall -no-pie |
24 | 24 | ||
25 | UNAME_M := $(shell uname -m) | 25 | UNAME_M := $(shell uname -m) |
26 | CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32) | 26 | CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32) |
diff --git a/tools/testing/selftests/x86/mpx-mini-test.c b/tools/testing/selftests/x86/mpx-mini-test.c index a8df159a8924..ec0f6b45ce8b 100644 --- a/tools/testing/selftests/x86/mpx-mini-test.c +++ b/tools/testing/selftests/x86/mpx-mini-test.c | |||
@@ -391,8 +391,7 @@ void handler(int signum, siginfo_t *si, void *vucontext) | |||
391 | br_count++; | 391 | br_count++; |
392 | dprintf1("#BR 0x%jx (total seen: %d)\n", status, br_count); | 392 | dprintf1("#BR 0x%jx (total seen: %d)\n", status, br_count); |
393 | 393 | ||
394 | #define __SI_FAULT (3 << 16) | 394 | #define SEGV_BNDERR 3 /* failed address bound checks */ |
395 | #define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */ | ||
396 | 395 | ||
397 | dprintf2("Saw a #BR! status 0x%jx at %016lx br_reason: %jx\n", | 396 | dprintf2("Saw a #BR! status 0x%jx at %016lx br_reason: %jx\n", |
398 | status, ip, br_reason); | 397 | status, ip, br_reason); |
diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c index 3237bc010e1c..23927845518d 100644 --- a/tools/testing/selftests/x86/protection_keys.c +++ b/tools/testing/selftests/x86/protection_keys.c | |||
@@ -212,19 +212,18 @@ void dump_mem(void *dumpme, int len_bytes) | |||
212 | } | 212 | } |
213 | } | 213 | } |
214 | 214 | ||
215 | #define __SI_FAULT (3 << 16) | 215 | #define SEGV_BNDERR 3 /* failed address bound checks */ |
216 | #define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */ | 216 | #define SEGV_PKUERR 4 |
217 | #define SEGV_PKUERR (__SI_FAULT|4) | ||
218 | 217 | ||
219 | static char *si_code_str(int si_code) | 218 | static char *si_code_str(int si_code) |
220 | { | 219 | { |
221 | if (si_code & SEGV_MAPERR) | 220 | if (si_code == SEGV_MAPERR) |
222 | return "SEGV_MAPERR"; | 221 | return "SEGV_MAPERR"; |
223 | if (si_code & SEGV_ACCERR) | 222 | if (si_code == SEGV_ACCERR) |
224 | return "SEGV_ACCERR"; | 223 | return "SEGV_ACCERR"; |
225 | if (si_code & SEGV_BNDERR) | 224 | if (si_code == SEGV_BNDERR) |
226 | return "SEGV_BNDERR"; | 225 | return "SEGV_BNDERR"; |
227 | if (si_code & SEGV_PKUERR) | 226 | if (si_code == SEGV_PKUERR) |
228 | return "SEGV_PKUERR"; | 227 | return "SEGV_PKUERR"; |
229 | return "UNKNOWN"; | 228 | return "UNKNOWN"; |
230 | } | 229 | } |