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

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

Made it build on darwin - leaving a couple of things for later...

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