From 29cd838eab01ed7110f3ccb2e8c6a35c8a31dbcc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:21:29 +0200 Subject: Adding upstream version 1:0.1.9998svn3589+dfsg. Signed-off-by: Daniel Baumann --- src/lib/kStuff/kHlp/Generic/kHlpPage.c | 371 +++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpPage.c (limited to 'src/lib/kStuff/kHlp/Generic/kHlpPage.c') diff --git a/src/lib/kStuff/kHlp/Generic/kHlpPage.c b/src/lib/kStuff/kHlp/Generic/kHlpPage.c new file mode 100644 index 0000000..f915f58 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpPage.c @@ -0,0 +1,371 @@ +/* $Id: kHlpPage.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlp - Generic Page Memory Functions. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS +# include +# include + +#elif K_OS == K_OS_OS2 +# define INCL_BASE +# define INCL_ERRORS +# include + +#elif K_OS == K_OS_WINDOWS +# include + +#else +# error "port me" +#endif + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS +/* nothing */ +#elif K_OS == K_OS_OS2 +/** The base of the loader stub object. + * The OS/2 exe stub consists of a single data object. When allocating memory + * for an executable, we'll have to reuse this. */ +static void *g_pvStub = NULL; +/** The size of the stub object - 0 if no stub. */ +static KSIZE g_cbStub = 0; + +#elif K_OS == K_OS_WINDOWS +/** The system info. */ +static SYSTEM_INFO g_SystemInfo; +#else +# error "port me" +#endif + + + +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS +static int kHlpPageProtToNative(KPROT enmProt) +{ + switch (enmProt) + { + case KPROT_NOACCESS: return PROT_NONE; + case KPROT_READONLY: return PROT_READ; + case KPROT_READWRITE: return PROT_READ | PROT_WRITE; + case KPROT_EXECUTE: return PROT_EXEC; + case KPROT_EXECUTE_READ: return PROT_EXEC | PROT_READ; + case KPROT_EXECUTE_READWRITE: return PROT_EXEC | PROT_READ | PROT_WRITE; + default: + kHlpAssert(0); + return ~0U; + } +} + +#elif K_OS == K_OS_OS2 +static ULONG kHlpPageProtToNative(KPROT enmProt) +{ + switch (enmProt) + { + case KPROT_NOACCESS: return PAG_EXECUTE | PAG_READ | PAG_WRITE; + case KPROT_READONLY: return PAG_COMMIT | PAG_READ; + case KPROT_READWRITE: return PAG_COMMIT | PAG_READ | PAG_WRITE; + case KPROT_EXECUTE: return PAG_COMMIT | PAG_EXECUTE; + case KPROT_EXECUTE_READ: return PAG_COMMIT | PAG_EXECUTE | PAG_READ; + case KPROT_EXECUTE_READWRITE: return PAG_COMMIT | PAG_EXECUTE | PAG_READ | PAG_WRITE; + default: + kHlpAssert(0); + return ~0U; + } +} +#elif K_OS == K_OS_WINDOWS +static DWORD kHlpPageProtToNative(KPROT enmProt) +{ + switch (enmProt) + { + case KPROT_NOACCESS: return PAGE_NOACCESS; + case KPROT_READONLY: return PAGE_READONLY; + case KPROT_READWRITE: return PAGE_READWRITE; + case KPROT_EXECUTE: return PAGE_EXECUTE; + case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; + case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; + default: + kHlpAssert(0); + return ~0U; + } +} +#endif + + + +/** + * Allocate a chunk of memory with page granularity. + * + * @returns 0 on success, non-zero OS status code on failure. + * @param ppv Where to store the address of the allocated memory. + * If fFixed is set, *ppv will on entry contain the desired address (page aligned). + * @param cb Number of bytes. Page aligned. + * @param enmProt The new protection. Copy-on-write is invalid. + */ +KHLP_DECL(int) kHlpPageAlloc(void **ppv, KSIZE cb, KPROT enmProt, KBOOL fFixed) +{ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + void *pv; + + pv = kHlpSys_mmap(fFixed ? *ppv : NULL, cb, kHlpPageProtToNative(enmProt), + fFixed ? MAP_FIXED | MAP_ANON: MAP_ANON, -1, 0); + if ((KIPTR)pv < 256) + { + kHlpAssert(0); + return (int)(KIPTR)pv; /** @todo convert errno to kErrors */ + } + *ppv = pv; + return 0; + +#elif K_OS == K_OS_OS2 + APIRET rc; + ULONG fFlags = kHlpPageProtToNative(enmProt); + + if (!fFixed) + { + /* simple */ + rc = DosAllocMem(ppv, cb, fFlags | OBJ_ANY); + if (rc == ERROR_INVALID_PARAMETER) + rc = DosAllocMem(ppv, cb, fFlags); + } + else + { + /* not so simple. */ + /** @todo I've got code for this in libc somewhere. */ + rc = -1; + } + if (!rc) + return 0; + kHlpAssert(0); + return rc; + +#elif K_OS == K_OS_WINDOWS + /* (We don't have to care about the stub here, because the stub will be unmapped before we get here.) */ + int rc; + DWORD fProt = kHlpPageProtToNative(enmProt); + + if (!g_SystemInfo.dwPageSize) + GetSystemInfo(&g_SystemInfo); + + *ppv = VirtualAlloc(fFixed ? *ppv : NULL, cb, MEM_COMMIT, fProt); + if (*ppv != NULL) + return 0; + rc = GetLastError(); + kHlpAssert(0); + return rc; + +#else +# error "port me" +#endif +} + + +/** + * Change the protection of one or more pages in an allocation. + * + * (This will of course only work correctly on memory allocated by kHlpPageAlloc().) + * + * @returns 0 on success, non-zero OS status code on failure. + * @param pv First page. Page aligned. + * @param cb Number of bytes. Page aligned. + * @param enmProt The new protection. Copy-on-write is invalid. + */ +KHLP_DECL(int) kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt) +{ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + int rc; + + rc = kHlpSys_mprotect(pv, cb, kHlpPageProtToNative(enmProt)); + if (!rc) + return 0; + /** @todo convert errno -> kErrors */ + kHlpAssert(0); + return rc; + +#elif K_OS == K_OS_OS2 + APIRET rc; + ULONG fFlags = kHlpPageProtToNative(enmProt); + + /* + * The non-stub pages. + */ + rc = DosSetMem(pv, cb, fFlags); + if (rc && fFlags != PAG_DECOMMIT) + rc = DosSetMem(pv, cb, fFlags | PAG_COMMIT); + if (rc) + { + /* Try page by page. */ + while (cb > 0) + { + rc = DosSetMem(pv, 0x1000, fFlags); + if (rc && fFlags != PAG_DECOMMIT) + rc = DosSetMem(pv, 0x1000, fFlags | PAG_COMMIT); + if (rc) + return rc; + pv = (void *)((KUPTR)pv + 0x1000); + cb -= 0x1000; + } + } + kHlpAssert(!rc); + return rc; + +#elif K_OS == K_OS_WINDOWS + DWORD fOldProt = 0; + DWORD fProt = kHlpPageProtToNative(enmProt); + int rc = 0; + + if (!VirtualProtect(pv, cb, fProt, &fOldProt)) + { + rc = GetLastError(); + kHlpAssert(0); + } + return rc; +#else +# error "port me" +#endif +} + + +/** + * Free memory allocated by kHlpPageAlloc(). + * + * @returns 0 on success, non-zero OS status code on failure. + * @param pv The address returned by kHlpPageAlloc(). + * @param cb The byte count requested from kHlpPageAlloc(). + */ +KHLP_DECL(int) kHlpPageFree(void *pv, KSIZE cb) +{ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + int rc; + + rc = kHlpSys_munmap(pv, cb); + if (!rc) + return 0; + /** @todo convert errno -> kErrors */ + return rc; + +#elif K_OS == K_OS_OS2 + APIRET rc; + + /* + * Deal with any portion overlapping with the stub. + */ + KUPTR offStub = (KUPTR)pv - (KUPTR)g_pvStub; + if (offStub < g_cbStub) + { + /* decommit the pages in the stub. */ + KSIZE cbStub = K_MIN(g_cbStub - offStub, cb); + rc = DosSetMem(pv, cbStub, PAG_DECOMMIT); + if (rc) + { + /* Page by page, ignoring errors after the first success. */ + while (cbStub > 0) + { + if (!DosSetMem(pv, 0x1000, PAG_DECOMMIT)) + rc = 0; + pv = (void *)((KUPTR)pv + 0x1000); + cbStub -= 0x1000; + cb -= 0x1000; + } + if (rc) + { + kHlpAssert(!rc); + return rc; + } + } + else + { + cb -= cbStub; + if (!cb) + return 0; + pv = (void *)((KUPTR)pv + cbStub); + } + } + + /* + * Free the object. + */ + rc = DosFreeMem(pv); + kHlpAssert(!rc); + return rc; + +#elif K_OS == K_OS_WINDOWS + /* + * Free the object. + */ + int rc = 0; + if (!VirtualFree(pv, 0 /*cb*/, MEM_RELEASE)) + { + rc = GetLastError(); + kHlpAssert(0); + } + return rc; + +#else +# error "port me" +#endif +} + -- cgit v1.2.3