-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommon.h
73 lines (66 loc) · 1.99 KB
/
common.h
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
#ifndef COMMON_H
#define COMMON_H
#define _POSIX_C_SOURCE 200809L
#include <fcntl.h> // open
#include <stdint.h> // uint64_t
#include <stdlib.h> // size_t
#include <unistd.h> // pread, sysconf
#include <stdio.h> // printf
typedef struct {
uint64_t pfn : 54;
unsigned int soft_dirty : 1;
unsigned int file_page : 1;
unsigned int swapped : 1;
unsigned int present : 1;
} PagemapEntry;
//Parse the pagemap entry for the given virtual address.
//
//@param[out] entry the parsed entry
//@param[in] pagemap_fd file descriptor to an open /proc/pid/pagemap file
//@param[in] vaddr virtual address to get entry for
//@return 0 for success, 1 for failure
int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr) {
size_t nread;
ssize_t ret;
uint64_t data;
uintptr_t vpn;
vpn = vaddr / sysconf(_SC_PAGE_SIZE);
nread = 0;
while (nread < sizeof(data)) {
ret = pread(pagemap_fd, &data, sizeof(data) - nread,
vpn * sizeof(data) + nread);
nread += ret;
if (ret <= 0) {
return 1;
}
}
entry->pfn = data & (((uint64_t)1 << 54) - 1);
entry->soft_dirty = (data >> 54) & 1;
entry->file_page = (data >> 61) & 1;
entry->swapped = (data >> 62) & 1;
entry->present = (data >> 63) & 1;
return 0;
}
// Convert the given virtual address to physical using /proc/PID/pagemap.
//
// @param[out] paddr physical address
// @param[in] pid process to convert for
// @param[in] vaddr virtual address to get entry for
// @return 0 for success, 1 for failure
int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr) {
char pagemap_file[BUFSIZ];
int pagemap_fd;
snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid);
pagemap_fd = open(pagemap_file, O_RDONLY);
if (pagemap_fd < 0) {
return 1;
}
PagemapEntry entry;
if (pagemap_get_entry(&entry, pagemap_fd, vaddr)) {
return 1;
}
close(pagemap_fd);
*paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE));
return 0;
}
#endif