1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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;
}
|