HID: sony: Remove the size check for the Dualshock 4 HID Descriptor
[cascardo/linux.git] / tools / testing / selftests / vm / mlock2-tests.c
1 #include <sys/mman.h>
2 #include <stdint.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <sys/time.h>
8 #include <sys/resource.h>
9 #include <syscall.h>
10 #include <errno.h>
11 #include <stdbool.h>
12
13 #ifndef MLOCK_ONFAULT
14 #define MLOCK_ONFAULT 1
15 #endif
16
17 #ifndef MCL_ONFAULT
18 #define MCL_ONFAULT (MCL_FUTURE << 1)
19 #endif
20
21 static int mlock2_(void *start, size_t len, int flags)
22 {
23 #ifdef __NR_mlock2
24         return syscall(__NR_mlock2, start, len, flags);
25 #else
26         errno = ENOSYS;
27         return -1;
28 #endif
29 }
30
31 struct vm_boundaries {
32         unsigned long start;
33         unsigned long end;
34 };
35
36 static int get_vm_area(unsigned long addr, struct vm_boundaries *area)
37 {
38         FILE *file;
39         int ret = 1;
40         char line[1024] = {0};
41         char *end_addr;
42         char *stop;
43         unsigned long start;
44         unsigned long end;
45
46         if (!area)
47                 return ret;
48
49         file = fopen("/proc/self/maps", "r");
50         if (!file) {
51                 perror("fopen");
52                 return ret;
53         }
54
55         memset(area, 0, sizeof(struct vm_boundaries));
56
57         while(fgets(line, 1024, file)) {
58                 end_addr = strchr(line, '-');
59                 if (!end_addr) {
60                         printf("cannot parse /proc/self/maps\n");
61                         goto out;
62                 }
63                 *end_addr = '\0';
64                 end_addr++;
65                 stop = strchr(end_addr, ' ');
66                 if (!stop) {
67                         printf("cannot parse /proc/self/maps\n");
68                         goto out;
69                 }
70                 stop = '\0';
71
72                 sscanf(line, "%lx", &start);
73                 sscanf(end_addr, "%lx", &end);
74
75                 if (start <= addr && end > addr) {
76                         area->start = start;
77                         area->end = end;
78                         ret = 0;
79                         goto out;
80                 }
81         }
82 out:
83         fclose(file);
84         return ret;
85 }
86
87 static uint64_t get_pageflags(unsigned long addr)
88 {
89         FILE *file;
90         uint64_t pfn;
91         unsigned long offset;
92
93         file = fopen("/proc/self/pagemap", "r");
94         if (!file) {
95                 perror("fopen pagemap");
96                 _exit(1);
97         }
98
99         offset = addr / getpagesize() * sizeof(pfn);
100
101         if (fseek(file, offset, SEEK_SET)) {
102                 perror("fseek pagemap");
103                 _exit(1);
104         }
105
106         if (fread(&pfn, sizeof(pfn), 1, file) != 1) {
107                 perror("fread pagemap");
108                 _exit(1);
109         }
110
111         fclose(file);
112         return pfn;
113 }
114
115 static uint64_t get_kpageflags(unsigned long pfn)
116 {
117         uint64_t flags;
118         FILE *file;
119
120         file = fopen("/proc/kpageflags", "r");
121         if (!file) {
122                 perror("fopen kpageflags");
123                 _exit(1);
124         }
125
126         if (fseek(file, pfn * sizeof(flags), SEEK_SET)) {
127                 perror("fseek kpageflags");
128                 _exit(1);
129         }
130
131         if (fread(&flags, sizeof(flags), 1, file) != 1) {
132                 perror("fread kpageflags");
133                 _exit(1);
134         }
135
136         fclose(file);
137         return flags;
138 }
139
140 static FILE *seek_to_smaps_entry(unsigned long addr)
141 {
142         FILE *file;
143         char *line = NULL;
144         size_t size = 0;
145         unsigned long start, end;
146         char perms[5];
147         unsigned long offset;
148         char dev[32];
149         unsigned long inode;
150         char path[BUFSIZ];
151
152         file = fopen("/proc/self/smaps", "r");
153         if (!file) {
154                 perror("fopen smaps");
155                 _exit(1);
156         }
157
158         while (getline(&line, &size, file) > 0) {
159                 if (sscanf(line, "%lx-%lx %s %lx %s %lu %s\n",
160                            &start, &end, perms, &offset, dev, &inode, path) < 6)
161                         goto next;
162
163                 if (start <= addr && addr < end)
164                         goto out;
165
166 next:
167                 free(line);
168                 line = NULL;
169                 size = 0;
170         }
171
172         fclose(file);
173         file = NULL;
174
175 out:
176         free(line);
177         return file;
178 }
179
180 #define VMFLAGS "VmFlags:"
181
182 static bool is_vmflag_set(unsigned long addr, const char *vmflag)
183 {
184         char *line = NULL;
185         char *flags;
186         size_t size = 0;
187         bool ret = false;
188         FILE *smaps;
189
190         smaps = seek_to_smaps_entry(addr);
191         if (!smaps) {
192                 printf("Unable to parse /proc/self/smaps\n");
193                 goto out;
194         }
195
196         while (getline(&line, &size, smaps) > 0) {
197                 if (!strstr(line, VMFLAGS)) {
198                         free(line);
199                         line = NULL;
200                         size = 0;
201                         continue;
202                 }
203
204                 flags = line + strlen(VMFLAGS);
205                 ret = (strstr(flags, vmflag) != NULL);
206                 goto out;
207         }
208
209 out:
210         free(line);
211         fclose(smaps);
212         return ret;
213 }
214
215 #define SIZE "Size:"
216 #define RSS  "Rss:"
217 #define LOCKED "lo"
218
219 static bool is_vma_lock_on_fault(unsigned long addr)
220 {
221         bool ret = false;
222         bool locked;
223         FILE *smaps = NULL;
224         unsigned long vma_size, vma_rss;
225         char *line = NULL;
226         char *value;
227         size_t size = 0;
228
229         locked = is_vmflag_set(addr, LOCKED);
230         if (!locked)
231                 goto out;
232
233         smaps = seek_to_smaps_entry(addr);
234         if (!smaps) {
235                 printf("Unable to parse /proc/self/smaps\n");
236                 goto out;
237         }
238
239         while (getline(&line, &size, smaps) > 0) {
240                 if (!strstr(line, SIZE)) {
241                         free(line);
242                         line = NULL;
243                         size = 0;
244                         continue;
245                 }
246
247                 value = line + strlen(SIZE);
248                 if (sscanf(value, "%lu kB", &vma_size) < 1) {
249                         printf("Unable to parse smaps entry for Size\n");
250                         goto out;
251                 }
252                 break;
253         }
254
255         while (getline(&line, &size, smaps) > 0) {
256                 if (!strstr(line, RSS)) {
257                         free(line);
258                         line = NULL;
259                         size = 0;
260                         continue;
261                 }
262
263                 value = line + strlen(RSS);
264                 if (sscanf(value, "%lu kB", &vma_rss) < 1) {
265                         printf("Unable to parse smaps entry for Rss\n");
266                         goto out;
267                 }
268                 break;
269         }
270
271         ret = locked && (vma_rss < vma_size);
272 out:
273         free(line);
274         if (smaps)
275                 fclose(smaps);
276         return ret;
277 }
278
279 #define PRESENT_BIT     0x8000000000000000
280 #define PFN_MASK        0x007FFFFFFFFFFFFF
281 #define UNEVICTABLE_BIT (1UL << 18)
282
283 static int lock_check(char *map)
284 {
285         unsigned long page_size = getpagesize();
286         uint64_t page1_flags, page2_flags;
287
288         page1_flags = get_pageflags((unsigned long)map);
289         page2_flags = get_pageflags((unsigned long)map + page_size);
290
291         /* Both pages should be present */
292         if (((page1_flags & PRESENT_BIT) == 0) ||
293             ((page2_flags & PRESENT_BIT) == 0)) {
294                 printf("Failed to make both pages present\n");
295                 return 1;
296         }
297
298         page1_flags = get_kpageflags(page1_flags & PFN_MASK);
299         page2_flags = get_kpageflags(page2_flags & PFN_MASK);
300
301         /* Both pages should be unevictable */
302         if (((page1_flags & UNEVICTABLE_BIT) == 0) ||
303             ((page2_flags & UNEVICTABLE_BIT) == 0)) {
304                 printf("Failed to make both pages unevictable\n");
305                 return 1;
306         }
307
308         if (!is_vmflag_set((unsigned long)map, LOCKED)) {
309                 printf("VMA flag %s is missing on page 1\n", LOCKED);
310                 return 1;
311         }
312
313         if (!is_vmflag_set((unsigned long)map + page_size, LOCKED)) {
314                 printf("VMA flag %s is missing on page 2\n", LOCKED);
315                 return 1;
316         }
317
318         return 0;
319 }
320
321 static int unlock_lock_check(char *map)
322 {
323         unsigned long page_size = getpagesize();
324         uint64_t page1_flags, page2_flags;
325
326         page1_flags = get_pageflags((unsigned long)map);
327         page2_flags = get_pageflags((unsigned long)map + page_size);
328         page1_flags = get_kpageflags(page1_flags & PFN_MASK);
329         page2_flags = get_kpageflags(page2_flags & PFN_MASK);
330
331         if ((page1_flags & UNEVICTABLE_BIT) || (page2_flags & UNEVICTABLE_BIT)) {
332                 printf("A page is still marked unevictable after unlock\n");
333                 return 1;
334         }
335
336         if (is_vmflag_set((unsigned long)map, LOCKED)) {
337                 printf("VMA flag %s is present on page 1 after unlock\n", LOCKED);
338                 return 1;
339         }
340
341         if (is_vmflag_set((unsigned long)map + page_size, LOCKED)) {
342                 printf("VMA flag %s is present on page 2 after unlock\n", LOCKED);
343                 return 1;
344         }
345
346         return 0;
347 }
348
349 static int test_mlock_lock()
350 {
351         char *map;
352         int ret = 1;
353         unsigned long page_size = getpagesize();
354
355         map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
356                    MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
357         if (map == MAP_FAILED) {
358                 perror("test_mlock_locked mmap");
359                 goto out;
360         }
361
362         if (mlock2_(map, 2 * page_size, 0)) {
363                 if (errno == ENOSYS) {
364                         printf("Cannot call new mlock family, skipping test\n");
365                         _exit(0);
366                 }
367                 perror("mlock2(0)");
368                 goto unmap;
369         }
370
371         if (lock_check(map))
372                 goto unmap;
373
374         /* Now unlock and recheck attributes */
375         if (munlock(map, 2 * page_size)) {
376                 perror("munlock()");
377                 goto unmap;
378         }
379
380         ret = unlock_lock_check(map);
381
382 unmap:
383         munmap(map, 2 * page_size);
384 out:
385         return ret;
386 }
387
388 static int onfault_check(char *map)
389 {
390         unsigned long page_size = getpagesize();
391         uint64_t page1_flags, page2_flags;
392
393         page1_flags = get_pageflags((unsigned long)map);
394         page2_flags = get_pageflags((unsigned long)map + page_size);
395
396         /* Neither page should be present */
397         if ((page1_flags & PRESENT_BIT) || (page2_flags & PRESENT_BIT)) {
398                 printf("Pages were made present by MLOCK_ONFAULT\n");
399                 return 1;
400         }
401
402         *map = 'a';
403         page1_flags = get_pageflags((unsigned long)map);
404         page2_flags = get_pageflags((unsigned long)map + page_size);
405
406         /* Only page 1 should be present */
407         if ((page1_flags & PRESENT_BIT) == 0) {
408                 printf("Page 1 is not present after fault\n");
409                 return 1;
410         } else if (page2_flags & PRESENT_BIT) {
411                 printf("Page 2 was made present\n");
412                 return 1;
413         }
414
415         page1_flags = get_kpageflags(page1_flags & PFN_MASK);
416
417         /* Page 1 should be unevictable */
418         if ((page1_flags & UNEVICTABLE_BIT) == 0) {
419                 printf("Failed to make faulted page unevictable\n");
420                 return 1;
421         }
422
423         if (!is_vma_lock_on_fault((unsigned long)map)) {
424                 printf("VMA is not marked for lock on fault\n");
425                 return 1;
426         }
427
428         if (!is_vma_lock_on_fault((unsigned long)map + page_size)) {
429                 printf("VMA is not marked for lock on fault\n");
430                 return 1;
431         }
432
433         return 0;
434 }
435
436 static int unlock_onfault_check(char *map)
437 {
438         unsigned long page_size = getpagesize();
439         uint64_t page1_flags;
440
441         page1_flags = get_pageflags((unsigned long)map);
442         page1_flags = get_kpageflags(page1_flags & PFN_MASK);
443
444         if (page1_flags & UNEVICTABLE_BIT) {
445                 printf("Page 1 is still marked unevictable after unlock\n");
446                 return 1;
447         }
448
449         if (is_vma_lock_on_fault((unsigned long)map) ||
450             is_vma_lock_on_fault((unsigned long)map + page_size)) {
451                 printf("VMA is still lock on fault after unlock\n");
452                 return 1;
453         }
454
455         return 0;
456 }
457
458 static int test_mlock_onfault()
459 {
460         char *map;
461         int ret = 1;
462         unsigned long page_size = getpagesize();
463
464         map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
465                    MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
466         if (map == MAP_FAILED) {
467                 perror("test_mlock_locked mmap");
468                 goto out;
469         }
470
471         if (mlock2_(map, 2 * page_size, MLOCK_ONFAULT)) {
472                 if (errno == ENOSYS) {
473                         printf("Cannot call new mlock family, skipping test\n");
474                         _exit(0);
475                 }
476                 perror("mlock2(MLOCK_ONFAULT)");
477                 goto unmap;
478         }
479
480         if (onfault_check(map))
481                 goto unmap;
482
483         /* Now unlock and recheck attributes */
484         if (munlock(map, 2 * page_size)) {
485                 if (errno == ENOSYS) {
486                         printf("Cannot call new mlock family, skipping test\n");
487                         _exit(0);
488                 }
489                 perror("munlock()");
490                 goto unmap;
491         }
492
493         ret = unlock_onfault_check(map);
494 unmap:
495         munmap(map, 2 * page_size);
496 out:
497         return ret;
498 }
499
500 static int test_lock_onfault_of_present()
501 {
502         char *map;
503         int ret = 1;
504         unsigned long page_size = getpagesize();
505         uint64_t page1_flags, page2_flags;
506
507         map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
508                    MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
509         if (map == MAP_FAILED) {
510                 perror("test_mlock_locked mmap");
511                 goto out;
512         }
513
514         *map = 'a';
515
516         if (mlock2_(map, 2 * page_size, MLOCK_ONFAULT)) {
517                 if (errno == ENOSYS) {
518                         printf("Cannot call new mlock family, skipping test\n");
519                         _exit(0);
520                 }
521                 perror("mlock2(MLOCK_ONFAULT)");
522                 goto unmap;
523         }
524
525         page1_flags = get_pageflags((unsigned long)map);
526         page2_flags = get_pageflags((unsigned long)map + page_size);
527         page1_flags = get_kpageflags(page1_flags & PFN_MASK);
528         page2_flags = get_kpageflags(page2_flags & PFN_MASK);
529
530         /* Page 1 should be unevictable */
531         if ((page1_flags & UNEVICTABLE_BIT) == 0) {
532                 printf("Failed to make present page unevictable\n");
533                 goto unmap;
534         }
535
536         if (!is_vma_lock_on_fault((unsigned long)map) ||
537             !is_vma_lock_on_fault((unsigned long)map + page_size)) {
538                 printf("VMA with present pages is not marked lock on fault\n");
539                 goto unmap;
540         }
541         ret = 0;
542 unmap:
543         munmap(map, 2 * page_size);
544 out:
545         return ret;
546 }
547
548 static int test_munlockall()
549 {
550         char *map;
551         int ret = 1;
552         unsigned long page_size = getpagesize();
553
554         map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
555                    MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
556
557         if (map == MAP_FAILED) {
558                 perror("test_munlockall mmap");
559                 goto out;
560         }
561
562         if (mlockall(MCL_CURRENT)) {
563                 perror("mlockall(MCL_CURRENT)");
564                 goto out;
565         }
566
567         if (lock_check(map))
568                 goto unmap;
569
570         if (munlockall()) {
571                 perror("munlockall()");
572                 goto unmap;
573         }
574
575         if (unlock_lock_check(map))
576                 goto unmap;
577
578         munmap(map, 2 * page_size);
579
580         map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
581                    MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
582
583         if (map == MAP_FAILED) {
584                 perror("test_munlockall second mmap");
585                 goto out;
586         }
587
588         if (mlockall(MCL_CURRENT | MCL_ONFAULT)) {
589                 perror("mlockall(MCL_CURRENT | MCL_ONFAULT)");
590                 goto unmap;
591         }
592
593         if (onfault_check(map))
594                 goto unmap;
595
596         if (munlockall()) {
597                 perror("munlockall()");
598                 goto unmap;
599         }
600
601         if (unlock_onfault_check(map))
602                 goto unmap;
603
604         if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
605                 perror("mlockall(MCL_CURRENT | MCL_FUTURE)");
606                 goto out;
607         }
608
609         if (lock_check(map))
610                 goto unmap;
611
612         if (munlockall()) {
613                 perror("munlockall()");
614                 goto unmap;
615         }
616
617         ret = unlock_lock_check(map);
618
619 unmap:
620         munmap(map, 2 * page_size);
621 out:
622         munlockall();
623         return ret;
624 }
625
626 static int test_vma_management(bool call_mlock)
627 {
628         int ret = 1;
629         void *map;
630         unsigned long page_size = getpagesize();
631         struct vm_boundaries page1;
632         struct vm_boundaries page2;
633         struct vm_boundaries page3;
634
635         map = mmap(NULL, 3 * page_size, PROT_READ | PROT_WRITE,
636                    MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
637         if (map == MAP_FAILED) {
638                 perror("mmap()");
639                 return ret;
640         }
641
642         if (call_mlock && mlock2_(map, 3 * page_size, MLOCK_ONFAULT)) {
643                 if (errno == ENOSYS) {
644                         printf("Cannot call new mlock family, skipping test\n");
645                         _exit(0);
646                 }
647                 perror("mlock(ONFAULT)\n");
648                 goto out;
649         }
650
651         if (get_vm_area((unsigned long)map, &page1) ||
652             get_vm_area((unsigned long)map + page_size, &page2) ||
653             get_vm_area((unsigned long)map + page_size * 2, &page3)) {
654                 printf("couldn't find mapping in /proc/self/maps\n");
655                 goto out;
656         }
657
658         /*
659          * Before we unlock a portion, we need to that all three pages are in
660          * the same VMA.  If they are not we abort this test (Note that this is
661          * not a failure)
662          */
663         if (page1.start != page2.start || page2.start != page3.start) {
664                 printf("VMAs are not merged to start, aborting test\n");
665                 ret = 0;
666                 goto out;
667         }
668
669         if (munlock(map + page_size, page_size)) {
670                 perror("munlock()");
671                 goto out;
672         }
673
674         if (get_vm_area((unsigned long)map, &page1) ||
675             get_vm_area((unsigned long)map + page_size, &page2) ||
676             get_vm_area((unsigned long)map + page_size * 2, &page3)) {
677                 printf("couldn't find mapping in /proc/self/maps\n");
678                 goto out;
679         }
680
681         /* All three VMAs should be different */
682         if (page1.start == page2.start || page2.start == page3.start) {
683                 printf("failed to split VMA for munlock\n");
684                 goto out;
685         }
686
687         /* Now unlock the first and third page and check the VMAs again */
688         if (munlock(map, page_size * 3)) {
689                 perror("munlock()");
690                 goto out;
691         }
692
693         if (get_vm_area((unsigned long)map, &page1) ||
694             get_vm_area((unsigned long)map + page_size, &page2) ||
695             get_vm_area((unsigned long)map + page_size * 2, &page3)) {
696                 printf("couldn't find mapping in /proc/self/maps\n");
697                 goto out;
698         }
699
700         /* Now all three VMAs should be the same */
701         if (page1.start != page2.start || page2.start != page3.start) {
702                 printf("failed to merge VMAs after munlock\n");
703                 goto out;
704         }
705
706         ret = 0;
707 out:
708         munmap(map, 3 * page_size);
709         return ret;
710 }
711
712 static int test_mlockall(int (test_function)(bool call_mlock))
713 {
714         int ret = 1;
715
716         if (mlockall(MCL_CURRENT | MCL_ONFAULT | MCL_FUTURE)) {
717                 perror("mlockall");
718                 return ret;
719         }
720
721         ret = test_function(false);
722         munlockall();
723         return ret;
724 }
725
726 int main(int argc, char **argv)
727 {
728         int ret = 0;
729         ret += test_mlock_lock();
730         ret += test_mlock_onfault();
731         ret += test_munlockall();
732         ret += test_lock_onfault_of_present();
733         ret += test_vma_management(true);
734         ret += test_mlockall(test_vma_management);
735         return ret;
736 }