VirtualBox

source: kStuff/trunk/kHlp/Generic/kHlpPage.c@ 83

Last change on this file since 83 was 29, checked in by bird, 16 years ago

Finally got around execute the switch to the MIT license.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 10.2 KB
Line 
1/* $Id: kHlpPage.c 29 2009-07-01 20:30:29Z bird $ */
2/** @file
3 * kHlp - Generic Page Memory Functions.
4 */
5
6/*
7 * Copyright (c) 2006-2007 Knut St. Osmundsen <[email protected]>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <k/kHlpAlloc.h>
35#include <k/kHlpAssert.h>
36
37#if K_OS == K_OS_DARWIN \
38 || K_OS == K_OS_FREEBSD \
39 || K_OS == K_OS_LINUX \
40 || K_OS == K_OS_NETBSD \
41 || K_OS == K_OS_OPENBSD \
42 || K_OS == K_OS_SOLARIS
43# include <k/kHlpSys.h>
44# include <sys/mman.h>
45
46#elif K_OS == K_OS_OS2
47# define INCL_BASE
48# define INCL_ERRORS
49# include <os2.h>
50
51#elif K_OS == K_OS_WINDOWS
52# include <Windows.h>
53
54#else
55# error "port me"
56#endif
57
58
59/*******************************************************************************
60* Global Variables *
61*******************************************************************************/
62#if K_OS == K_OS_DARWIN \
63 || K_OS == K_OS_FREEBSD \
64 || K_OS == K_OS_LINUX \
65 || K_OS == K_OS_NETBSD \
66 || K_OS == K_OS_OPENBSD \
67 || K_OS == K_OS_SOLARIS
68/* nothing */
69#elif K_OS == K_OS_OS2
70/** The base of the loader stub object. <kLdr Hack>
71 * The OS/2 exe stub consists of a single data object. When allocating memory
72 * for an executable, we'll have to reuse this. */
73static void *g_pvStub = NULL;
74/** The size of the stub object - 0 if no stub. <kLdr Hack> */
75static KSIZE g_cbStub = 0;
76
77#elif K_OS == K_OS_WINDOWS
78/** The system info. */
79static SYSTEM_INFO g_SystemInfo;
80#else
81# error "port me"
82#endif
83
84
85
86#if K_OS == K_OS_DARWIN \
87 || K_OS == K_OS_FREEBSD \
88 || K_OS == K_OS_LINUX \
89 || K_OS == K_OS_NETBSD \
90 || K_OS == K_OS_OPENBSD \
91 || K_OS == K_OS_SOLARIS
92static int kHlpPageProtToNative(KPROT enmProt)
93{
94 switch (enmProt)
95 {
96 case KPROT_NOACCESS: return PROT_NONE;
97 case KPROT_READONLY: return PROT_READ;
98 case KPROT_READWRITE: return PROT_READ | PROT_WRITE;
99 case KPROT_EXECUTE: return PROT_EXEC;
100 case KPROT_EXECUTE_READ: return PROT_EXEC | PROT_READ;
101 case KPROT_EXECUTE_READWRITE: return PROT_EXEC | PROT_READ | PROT_WRITE;
102 default:
103 kHlpAssert(0);
104 return ~0U;
105 }
106}
107
108#elif K_OS == K_OS_OS2
109static ULONG kHlpPageProtToNative(KPROT enmProt)
110{
111 switch (enmProt)
112 {
113 case KPROT_NOACCESS: return PAG_EXECUTE | PAG_READ | PAG_WRITE;
114 case KPROT_READONLY: return PAG_COMMIT | PAG_READ;
115 case KPROT_READWRITE: return PAG_COMMIT | PAG_READ | PAG_WRITE;
116 case KPROT_EXECUTE: return PAG_COMMIT | PAG_EXECUTE;
117 case KPROT_EXECUTE_READ: return PAG_COMMIT | PAG_EXECUTE | PAG_READ;
118 case KPROT_EXECUTE_READWRITE: return PAG_COMMIT | PAG_EXECUTE | PAG_READ | PAG_WRITE;
119 default:
120 kHlpAssert(0);
121 return ~0U;
122 }
123}
124#elif K_OS == K_OS_WINDOWS
125static DWORD kHlpPageProtToNative(KPROT enmProt)
126{
127 switch (enmProt)
128 {
129 case KPROT_NOACCESS: return PAGE_NOACCESS;
130 case KPROT_READONLY: return PAGE_READONLY;
131 case KPROT_READWRITE: return PAGE_READWRITE;
132 case KPROT_EXECUTE: return PAGE_EXECUTE;
133 case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ;
134 case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE;
135 default:
136 kHlpAssert(0);
137 return ~0U;
138 }
139}
140#endif
141
142
143
144/**
145 * Allocate a chunk of memory with page granularity.
146 *
147 * @returns 0 on success, non-zero OS status code on failure.
148 * @param ppv Where to store the address of the allocated memory.
149 * If fFixed is set, *ppv will on entry contain the desired address (page aligned).
150 * @param cb Number of bytes. Page aligned.
151 * @param enmProt The new protection. Copy-on-write is invalid.
152 */
153KHLP_DECL(int) kHlpPageAlloc(void **ppv, KSIZE cb, KPROT enmProt, KBOOL fFixed)
154{
155#if K_OS == K_OS_DARWIN \
156 || K_OS == K_OS_FREEBSD \
157 || K_OS == K_OS_LINUX \
158 || K_OS == K_OS_NETBSD \
159 || K_OS == K_OS_OPENBSD \
160 || K_OS == K_OS_SOLARIS
161 void *pv;
162
163 pv = kHlpSys_mmap(fFixed ? *ppv : NULL, cb, kHlpPageProtToNative(enmProt),
164 fFixed ? MAP_FIXED | MAP_ANON: MAP_ANON, -1, 0);
165 if ((KIPTR)pv < 256)
166 {
167 kHlpAssert(0);
168 return (int)(KIPTR)pv; /** @todo convert errno to kErrors */
169 }
170 *ppv = pv;
171 return 0;
172
173#elif K_OS == K_OS_OS2
174 APIRET rc;
175 ULONG fFlags = kHlpPageProtToNative(enmProt);
176
177 if (!fFixed)
178 {
179 /* simple */
180 rc = DosAllocMem(ppv, cb, fFlags | OBJ_ANY);
181 if (rc == ERROR_INVALID_PARAMETER)
182 rc = DosAllocMem(ppv, cb, fFlags);
183 }
184 else
185 {
186 /* not so simple. */
187 /** @todo I've got code for this in libc somewhere. */
188 rc = -1;
189 }
190 if (!rc)
191 return 0;
192 kHlpAssert(0);
193 return rc;
194
195#elif K_OS == K_OS_WINDOWS
196 /* (We don't have to care about the stub here, because the stub will be unmapped before we get here.) */
197 int rc;
198 DWORD fProt = kHlpPageProtToNative(enmProt);
199
200 if (!g_SystemInfo.dwPageSize)
201 GetSystemInfo(&g_SystemInfo);
202
203 *ppv = VirtualAlloc(fFixed ? *ppv : NULL, cb, MEM_COMMIT, fProt);
204 if (*ppv != NULL)
205 return 0;
206 rc = GetLastError();
207 kHlpAssert(0);
208 return rc;
209
210#else
211# error "port me"
212#endif
213}
214
215
216/**
217 * Change the protection of one or more pages in an allocation.
218 *
219 * (This will of course only work correctly on memory allocated by kHlpPageAlloc().)
220 *
221 * @returns 0 on success, non-zero OS status code on failure.
222 * @param pv First page. Page aligned.
223 * @param cb Number of bytes. Page aligned.
224 * @param enmProt The new protection. Copy-on-write is invalid.
225 */
226KHLP_DECL(int) kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt)
227{
228#if K_OS == K_OS_DARWIN \
229 || K_OS == K_OS_FREEBSD \
230 || K_OS == K_OS_LINUX \
231 || K_OS == K_OS_NETBSD \
232 || K_OS == K_OS_OPENBSD \
233 || K_OS == K_OS_SOLARIS
234 int rc;
235
236 rc = kHlpSys_mprotect(pv, cb, kHlpPageProtToNative(enmProt));
237 if (!rc)
238 return 0;
239 /** @todo convert errno -> kErrors */
240 kHlpAssert(0);
241 return rc;
242
243#elif K_OS == K_OS_OS2
244 APIRET rc;
245 ULONG fFlags = kHlpPageProtToNative(enmProt);
246
247 /*
248 * The non-stub pages.
249 */
250 rc = DosSetMem(pv, cb, fFlags);
251 if (rc && fFlags != PAG_DECOMMIT)
252 rc = DosSetMem(pv, cb, fFlags | PAG_COMMIT);
253 if (rc)
254 {
255 /* Try page by page. */
256 while (cb > 0)
257 {
258 rc = DosSetMem(pv, 0x1000, fFlags);
259 if (rc && fFlags != PAG_DECOMMIT)
260 rc = DosSetMem(pv, 0x1000, fFlags | PAG_COMMIT);
261 if (rc)
262 return rc;
263 pv = (void *)((KUPTR)pv + 0x1000);
264 cb -= 0x1000;
265 }
266 }
267 kHlpAssert(!rc);
268 return rc;
269
270#elif K_OS == K_OS_WINDOWS
271 DWORD fOldProt = 0;
272 DWORD fProt = kHlpPageProtToNative(enmProt);
273 int rc = 0;
274
275 if (!VirtualProtect(pv, cb, fProt, &fOldProt))
276 {
277 rc = GetLastError();
278 kHlpAssert(0);
279 }
280 return rc;
281#else
282# error "port me"
283#endif
284}
285
286
287/**
288 * Free memory allocated by kHlpPageAlloc().
289 *
290 * @returns 0 on success, non-zero OS status code on failure.
291 * @param pv The address returned by kHlpPageAlloc().
292 * @param cb The byte count requested from kHlpPageAlloc().
293 */
294KHLP_DECL(int) kHlpPageFree(void *pv, KSIZE cb)
295{
296#if K_OS == K_OS_DARWIN \
297 || K_OS == K_OS_FREEBSD \
298 || K_OS == K_OS_LINUX \
299 || K_OS == K_OS_NETBSD \
300 || K_OS == K_OS_OPENBSD \
301 || K_OS == K_OS_SOLARIS
302 int rc;
303
304 rc = kHlpSys_munmap(pv, cb);
305 if (!rc)
306 return 0;
307 /** @todo convert errno -> kErrors */
308 return rc;
309
310#elif K_OS == K_OS_OS2
311 APIRET rc;
312
313 /*
314 * Deal with any portion overlapping with the stub.
315 */
316 KUPTR offStub = (KUPTR)pv - (KUPTR)g_pvStub;
317 if (offStub < g_cbStub)
318 {
319 /* decommit the pages in the stub. */
320 KSIZE cbStub = K_MIN(g_cbStub - offStub, cb);
321 rc = DosSetMem(pv, cbStub, PAG_DECOMMIT);
322 if (rc)
323 {
324 /* Page by page, ignoring errors after the first success. */
325 while (cbStub > 0)
326 {
327 if (!DosSetMem(pv, 0x1000, PAG_DECOMMIT))
328 rc = 0;
329 pv = (void *)((KUPTR)pv + 0x1000);
330 cbStub -= 0x1000;
331 cb -= 0x1000;
332 }
333 if (rc)
334 {
335 kHlpAssert(!rc);
336 return rc;
337 }
338 }
339 else
340 {
341 cb -= cbStub;
342 if (!cb)
343 return 0;
344 pv = (void *)((KUPTR)pv + cbStub);
345 }
346 }
347
348 /*
349 * Free the object.
350 */
351 rc = DosFreeMem(pv);
352 kHlpAssert(!rc);
353 return rc;
354
355#elif K_OS == K_OS_WINDOWS
356 /*
357 * Free the object.
358 */
359 int rc = 0;
360 if (!VirtualFree(pv, 0 /*cb*/, MEM_RELEASE))
361 {
362 rc = GetLastError();
363 kHlpAssert(0);
364 }
365 return rc;
366
367#else
368# error "port me"
369#endif
370}
371
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette