The test creates a buffer, sets it as DONTNEED via madvise, tries to trigger a purge of buffers and then accesses the buffer via a user-space mapping. This should generate a bus error, but due to a bug in the kernel driver it fails to invalidate the mapping when the buffer is purged. Signed-off-by: Neil Roberts <nroberts@xxxxxxxxxx> --- tests/meson.build | 1 + tests/panfrost_purgemap.c | 146 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 tests/panfrost_purgemap.c diff --git a/tests/meson.build b/tests/meson.build index 825e0183..af24427a 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -82,6 +82,7 @@ test_progs = [ 'panfrost_get_param', 'panfrost_gem_new', 'panfrost_prime', + 'panfrost_purgemap', 'panfrost_submit', 'prime_busy', 'prime_mmap', diff --git a/tests/panfrost_purgemap.c b/tests/panfrost_purgemap.c new file mode 100644 index 00000000..096fb95a --- /dev/null +++ b/tests/panfrost_purgemap.c @@ -0,0 +1,146 @@ +/* + * Copyright © 2021 Igalia + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "igt.h" +#include "igt_panfrost.h" +#include "igt_syncobj.h" +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <setjmp.h> +#include <signal.h> +#include "panfrost-job.h" +#include "panfrost_drm.h" + +IGT_TEST_DESCRIPTION("Checks that accessing an mmapping of a buffer that has " + "been purged causes a bus fault signal."); + +#define BUF_SIZE (32 * 1024 * 1024) + +struct buf_link { + struct panfrost_bo *bo; + struct buf_link *next; +}; + +static jmp_buf jmp; + +__noreturn static void sigtrap(int sig) +{ + siglongjmp(jmp, sig); +} + +static void +try_writing_to_mmap(uint8_t *ptr) +{ + sighandler_t old_sigsegv, old_sigbus; + + old_sigsegv = signal(SIGSEGV, sigtrap); + old_sigbus = signal(SIGBUS, sigtrap); + + switch (sigsetjmp(jmp, SIGBUS | SIGSEGV)) { + case SIGBUS: + break; + case 0: + *ptr = 0; + default: + igt_assert(!"reached"); + break; + } + + signal(SIGBUS, old_sigsegv); + signal(SIGSEGV, old_sigbus); +} + +static void +trigger_purge(int fd, struct panfrost_bo *madv_bo) +{ + struct buf_link *buf_list = NULL, *next, *buf; + bool retained; + + /* Try to trigger a purge by allocating buffers until the main + * buffer is no longer retained. This should probably be + * replaced with a more reliable way to do this such as a + * debugfs trigger. + */ + + while (true) { + /* Mark the buffer as purgeable */ + retained = igt_panfrost_bo_madvise(fd, + madv_bo, + PANFROST_MADV_DONTNEED); + igt_assert(retained); + + buf = malloc(sizeof(*buf)); + buf->bo = igt_panfrost_gem_new(fd, BUF_SIZE); + buf->next = buf_list; + buf_list = buf; + + /* Check if that caused the buffer to be purged */ + retained = igt_panfrost_bo_madvise(fd, + madv_bo, + PANFROST_MADV_WILLNEED); + + if (!retained) + break; + } + + /* Free all the temporary buffers that we created */ + for (buf = buf_list; buf; buf = next) { + next = buf->next; + igt_panfrost_free_bo(fd, buf->bo); + free(buf); + } +} + +igt_simple_main +{ + int fd; + struct panfrost_bo *bo; + + fd = drm_open_driver(DRIVER_PANFROST); + + bo = igt_panfrost_gem_new(fd, BUF_SIZE); + + igt_panfrost_bo_mmap(fd, bo); + + /* Write to the buffer to make sure the first page is + * paged in + */ + memset(bo->map, 42, 64); + + /* Try to cause the buffer to be purged */ + trigger_purge(fd, bo); + + /* Write through the mapping. This should cause a bus fault. */ + try_writing_to_mmap(bo->map); + + igt_panfrost_free_bo(fd, bo); + + close(fd); +} -- 2.29.2 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel