diff options
Diffstat (limited to 'tools/test')
| -rw-r--r-- | tools/test/gpage_test.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/tools/test/gpage_test.c b/tools/test/gpage_test.c new file mode 100644 index 0000000..33d0c8d --- /dev/null +++ b/tools/test/gpage_test.c @@ -0,0 +1,110 @@ +/* gpage_test.c - guest-page GPA probe for the physical-backend guest-memory path. + * + * Run as root inside the guest (plain gcc on Ubuntu 24.04, no CUDA). + * + * mmap+mlock one 4 KiB anonymous page, fill it with the 0xa5 ^ (i & 0xff) + * pattern, resolve its guest-physical address from /proc/self/pagemap and + * print + * GPAGE gpa=0x<hex> + * to stdout (flushed) so the host harness can hand the GPA to the module via + * the gsp-phys-guest-gpa debugfs file. + * + * The page is then polled every 100 ms for up to 120 s. The host-side W2G + * trigger copies the module SRC over this page, so byte 0 becomes 0x5a + * (0xa5 ^ (0 & 0xff) = 0xa5 -> 0x5a). On seeing p[0] == 0x5a print + * "GPAGE SEEN_W2G" and exit 0; on timeout print "GPAGE TIMEOUT" and exit 1. + * If the PFN cannot be resolved or is zero, print "GPAGE NO_PFN" and exit 2. + * + * Build (guest): gcc -O2 -o /tmp/gpage /tmp/gpage.c + */ +#define _GNU_SOURCE +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <sys/mman.h> +#include <time.h> +#include <unistd.h> + +#define PAGE_SIZE 4096u +#define POLL_INTERVAL_MS 100 +#define POLL_TIMEOUT_MS 120000 + +static int resolve_gpa(const void *addr, uint64_t *gpa) +{ + size_t offset = ((uintptr_t)addr / PAGE_SIZE) * sizeof(uint64_t); + uint64_t entry = 0; + ssize_t n; + int fd = open("/proc/self/pagemap", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "open pagemap: %s\n", strerror(errno)); + return -1; + } + n = pread(fd, &entry, sizeof(entry), (off_t)offset); + close(fd); + if (n != (ssize_t)sizeof(entry)) { + fprintf(stderr, "read pagemap: %s\n", n < 0 ? strerror(errno) : "short read"); + return -1; + } + if (!(entry & (1ULL << 63))) { + fprintf(stderr, "pagemap: page not present\n"); + return -1; + } + { + uint64_t pfn = entry & ((1ULL << 55) - 1); + if (pfn == 0) { + fprintf(stderr, "pagemap: pfn is zero\n"); + return -1; + } + *gpa = pfn * PAGE_SIZE; + } + return 0; +} + +int main(void) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = POLL_INTERVAL_MS * 1000000L }; + unsigned char *p; + uint64_t gpa = 0; + size_t i; + int waited = 0; + + setvbuf(stdout, NULL, _IONBF, 0); + + p = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (p == MAP_FAILED) { + printf("GPAGE MMAP_FAILED\n"); + return 2; + } + if (mlock(p, PAGE_SIZE) != 0) { + printf("GPAGE MLOCK_FAILED\n"); + return 2; + } + + for (i = 0; i < PAGE_SIZE; i++) + p[i] = (unsigned char)(0xa5 ^ (i & 0xff)); + + if (resolve_gpa(p, &gpa) != 0) { + printf("GPAGE NO_PFN\n"); + return 2; + } + + printf("GPAGE gpa=0x%llx\n", (unsigned long long)gpa); + fflush(stdout); + + while (waited < POLL_TIMEOUT_MS) { + if (*(volatile unsigned char *)p == 0x5a) { + printf("GPAGE SEEN_W2G\n"); + fflush(stdout); + return 0; + } + nanosleep(&ts, NULL); + waited += POLL_INTERVAL_MS; + } + + printf("GPAGE TIMEOUT\n"); + fflush(stdout); + return 1; +} |
