Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
virt2phys.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2019 Paparazzi Team
3  *
4  * This file is part of Paparazzi.
5  *
6  * Paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * Paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, see
18  * <http://www.gnu.org/licenses/>.
19  *
20  */
21 
36 /* Will make the 64 bit interfaces available (off64_t, lseek64(), etc...). See feature_test_macros(7) */
37 #define _LARGEFILE64_SOURCE
38 
39 #include <stdio.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include "virt2phys.h"
43 
44 #define BIT(i) ((unsigned long long) 1 << i)
45 #define FILENAME_SIZE 30
46 #define PAGE_SHIFT 12
47 #define PAGE_SIZE (1<<PAGE_SHIFT)
48 #define PAGE_MASK (((unsigned long long)1<< PAGE_SHIFT) -1)
49 
50 #define PAGE_PRESENT BIT(63)
51 #define PAGE_SWAPPED BIT(62)
52 #define PAGE_PFN_MASK (((unsigned long long)1<< 55) -1)
53 
54 /*
55  * open_pagemap - open pagemap
56  * @param[in] pid: process id of program with pagemap to access
57  * @return file descriptor of pagemap, -1 if unable to open
58  */
59 static int open_pagemap(pid_t pid)
60 {
61  char filename[FILENAME_SIZE];
62 
63  if (snprintf(filename, FILENAME_SIZE, "/proc/%d/pagemap", pid) < 0) {
64  fprintf(stderr, "Cant create file name\n");
65  return -1;
66  }
67 
68  return open(filename, O_RDONLY);
69 }
70 
71 /*
72  * virt2phys - Get physical address of virtual memory
73  * @param[in] fd : file descriptor of pagemap
74  * @param[in] vaddr : virtual address
75  * @param[in] *paddr: physical address
76  * @return 0 if successful, -1 otherwise
77  */
78 static int virt2phys(int fd, unsigned long vaddr, unsigned long *paddr)
79 {
80  unsigned long long pm_info, index;
81 
82  index = (vaddr >> PAGE_SHIFT) * sizeof(unsigned long long);
83 
84  if ((off64_t)index != lseek64(fd, index, SEEK_SET)) {
85  return -1;
86  }
87 
88  /* This read can return 0 if address is not in userspace */
89  if (sizeof(unsigned long long) != read(fd, &pm_info, sizeof(unsigned long long))) {
90  return -1;
91  }
92 
93  if ((pm_info & PAGE_PRESENT) && (!(pm_info & PAGE_SWAPPED))) {
94  *paddr = ((pm_info & PAGE_PFN_MASK) << PAGE_SHIFT) + (vaddr & PAGE_MASK);
95  }
96 
97  return 0;
98 }
99 
100 /* checkcontiguity - Get information on physical memory associated with virtual address.
101  *
102  * @param[in] vaddr : the virtual address in the context of process pid
103  * @param[in] pid : a valid pid
104  * @param[in] *pmem : Valid only if fonction returns 0.
105  * pmem->paddr contains physical address of the first byte.
106  * pmem->size contains the number of contiguous bytes checked. If size is not zero, buffer is contiguous if pmem->size >= size.
107  * @param[in] size : if size>0 contiguity is checked as far as possible.
108  * : if size=0, check contiguity until at least size bytes had been checked as contiguous.
109  * @return 0 if vaddr can be converted in physical address and -1 otherwise.
110  */
111 int check_contiguity(unsigned long vaddr, pid_t pid, struct physmem *pmem, size_t size)
112 {
113  int fd;
114  unsigned long vcurrent, pcurrent = 0, pnext;
115 
116  pmem->paddr = 0;
117  pmem->size = 0;
118 
119  fd = open_pagemap(pid);
120  if (fd < 0) {
121  return -1;
122  }
123 
124  /* Get first physical address, it may not be aligned on a page */
125  if (virt2phys(fd, vaddr, &pmem->paddr)) {
126  close(fd);
127  return -1;
128  }
129 
130  pmem->size = PAGE_SIZE - (pmem->paddr & PAGE_MASK);
131  /* We aligned addresses on pages */
132  vcurrent = vaddr & ~PAGE_MASK;
133  pnext = (pmem->paddr & ~PAGE_MASK) + PAGE_SIZE;
134 
135  while (1) {
136  /* exit if we had checked the requested bytes */
137  if (size && (pmem->size >= size)) {
138  break;
139  }
140 
141  vcurrent += PAGE_SIZE;
142  if (virt2phys(fd, vcurrent, &pcurrent)) {
143  break;
144  }
145 
146  /* Test if memory is still contiguous */
147  if (pcurrent == pnext) {
148  pmem->size += PAGE_SIZE;
149  pnext += PAGE_SIZE;
150  } else {
151  break;
152  }
153  }
154  close(fd);
155 
156  return 0;
157 }
int fd
Definition: serial.c:26
#define FILENAME_SIZE
Definition: virt2phys.c:45
#define PAGE_PRESENT
Definition: virt2phys.c:50
#define PAGE_PFN_MASK
Definition: virt2phys.c:52
static int virt2phys(int fd, unsigned long vaddr, unsigned long *paddr)
Definition: virt2phys.c:78
#define PAGE_SIZE
Definition: virt2phys.c:47
#define PAGE_SHIFT
Definition: virt2phys.c:46
#define PAGE_SWAPPED
Definition: virt2phys.c:51
int check_contiguity(unsigned long vaddr, pid_t pid, struct physmem *pmem, size_t size)
Definition: virt2phys.c:111
static int open_pagemap(pid_t pid)
Definition: virt2phys.c:59
#define PAGE_MASK
Definition: virt2phys.c:48
unsigned long paddr
Definition: virt2phys.h:8
size_t size
Definition: virt2phys.h:9