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

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

env, paths, page allocation.

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