/* 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 * 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 #include #include #include #include #include #include #include #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; }