925c44ca463a88b080ce35f4048bab547f52f13b
[akaros.git] / user / electric-fence / page.c
1 /* For email below, drop spaces and <spam-buster> tag.
2  * MODIFIED:  March 20, 2014 (jric<spam-buster> @ <spam-buster> chegg DOT com)
3 */
4 #include "efence.h"
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <sys/mman.h>
9 #include <stdio.h>
10 #include <errno.h>
11 #include <string.h>
12
13 /*
14  * Lots of systems are missing the definition of PROT_NONE.
15  */
16 #ifndef PROT_NONE
17 #define PROT_NONE       0
18 #endif
19
20 /*
21  * 386 BSD has MAP_ANON instead of MAP_ANONYMOUS.
22  */
23 #if ( !defined(MAP_ANONYMOUS) && defined(MAP_ANON) )
24 #define MAP_ANONYMOUS   MAP_ANON
25 #endif
26
27 /*
28  * For some reason, I can't find mprotect() in any of the headers on
29  * IRIX or SunOS 4.1.2
30  */
31 /* extern C_LINKAGE int mprotect(void * addr, size_t len, int prot); */
32
33 static caddr_t  startAddr = (caddr_t) 0;
34
35 #if ( !defined(sgi) && !defined(_AIX) && __DARWIN_C_LEVEL < __DARWIN_C_FULL )
36 extern int      sys_nerr;
37 /*extern char * sys_errlist[];*/
38 #endif
39
40 static const char *
41 stringErrorReport(void)
42 {
43 #if ( defined(sgi) )
44         return strerror(oserror());
45 #elif ( defined(_AIX) )
46         return strerror(errno);
47 #else
48         if ( errno > 0 && errno < sys_nerr )
49                 return sys_errlist[errno];
50         else
51                 return "Unknown error.\n";
52 #endif
53 }
54
55 /*
56  * Create memory.
57  */
58 #if defined(MAP_ANONYMOUS)
59 void *
60 Page_Create(size_t size)
61 {
62         caddr_t         allocation;
63
64         /*
65          * In this version, "startAddr" is a _hint_, not a demand.
66          * When the memory I map here is contiguous with other
67          * mappings, the allocator can coalesce the memory from two
68          * or more mappings into one large contiguous chunk, and thus
69          * might be able to find a fit that would not otherwise have
70          * been possible. I could _force_ it to be contiguous by using
71          * the MMAP_FIXED flag, but I don't want to stomp on memory mappings
72          * generated by other software, etc.
73          */
74         allocation = (caddr_t) mmap(
75          startAddr
76         ,size
77         ,PROT_READ|PROT_WRITE
78         ,MAP_PRIVATE|MAP_ANONYMOUS
79         ,-1
80         ,0);
81
82 #ifndef __hpux
83         /*
84          * Set the "address hint" for the next mmap() so that it will abut
85          * the mapping we just created.
86          *
87          * HP/UX 9.01 has a kernel bug that makes mmap() fail sometimes
88          * when given a non-zero address hint, so we'll leave the hint set
89          * to zero on that system. HP recently told me this is now fixed.
90          * Someone please tell me when it is probable to assume that most
91          * of those systems that were running 9.01 have been upgraded.
92          */
93         startAddr = allocation + size;
94 #endif
95
96         if ( allocation == (caddr_t)-1 )
97                 EF_Exit("mmap() failed: %s", stringErrorReport());
98
99         return (void *)allocation;
100 }
101 #else
102 void *
103 Page_Create(size_t size)
104 {
105         static int      devZeroFd = -1;
106         caddr_t         allocation;
107
108         if ( devZeroFd == -1 ) {
109                 devZeroFd = open("/dev/zero", O_RDWR);
110                 if ( devZeroFd < 0 )
111                         EF_Exit(
112                          "open() on /dev/zero failed: %s"
113                         ,stringErrorReport());
114         }
115
116         /*
117          * In this version, "startAddr" is a _hint_, not a demand.
118          * When the memory I map here is contiguous with other
119          * mappings, the allocator can coalesce the memory from two
120          * or more mappings into one large contiguous chunk, and thus
121          * might be able to find a fit that would not otherwise have
122          * been possible. I could _force_ it to be contiguous by using
123          * the MMAP_FIXED flag, but I don't want to stomp on memory mappings
124          * generated by other software, etc.
125          */
126         allocation = (caddr_t) mmap(
127          startAddr
128         ,size
129         ,PROT_READ|PROT_WRITE
130         ,MAP_PRIVATE
131         ,devZeroFd
132         ,0);
133
134         startAddr = allocation + size;
135
136         if ( allocation == (caddr_t)-1 )
137                 EF_Exit("mmap() failed: %s", stringErrorReport());
138
139         return (void *)allocation;
140 }
141 #endif
142
143 static void
144 mprotectFailed(void)
145 {
146         EF_Exit("mprotect() failed: %s", stringErrorReport());
147 }
148
149 void
150 Page_AllowAccess(void * address, size_t size)
151 {
152         if ( mprotect((caddr_t)address, size, PROT_READ|PROT_WRITE) < 0 )
153                 mprotectFailed();
154 }
155
156 void
157 Page_DenyAccess(void * address, size_t size)
158 {
159         if ( mprotect((caddr_t)address, size, PROT_NONE) < 0 )
160                 mprotectFailed();
161 }
162
163 void
164 Page_Delete(void * address, size_t size)
165 {
166         Page_DenyAccess(address, size);
167 }
168
169 #if defined(_SC_PAGESIZE)
170 size_t
171 Page_Size(void)
172 {
173         return (size_t)sysconf(_SC_PAGESIZE);
174 }
175 #elif defined(_SC_PAGE_SIZE)
176 size_t
177 Page_Size(void)
178 {
179         return (size_t)sysconf(_SC_PAGE_SIZE);
180 }
181 #else
182 /* extern int   getpagesize(); */
183 size_t
184 Page_Size(void)
185 {
186         return getpagesize();
187 }
188 #endif