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

Last change on this file since 3599 was 3599, checked in by bird, 18 years ago

Built on linux.

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