/* $Id$ * reactos spinlock emulation of libcaptive * Copyright (C) 2002 Jan Kratochvil * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; exactly version 2 of June 1991 is required * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "captive/mm.h" /* self */ #include "reactos/internal/mm.h" /* self */ #include "reactos/ntos/types.h" /* for PVOID etc. */ #include #include /* for PROT_NONE etc. */ #include /** * captive_flProtect_to_mmap_prot: * @flProtect: reactos compatible constant such as %PAGE_READWRITE. * * Map reactos flProtect to mprotect(2)-compatible "prot" argument. * * Returns: mmap(2) compatible @prot argument. */ gint captive_flProtect_to_mmap_prot(ULONG flProtect) { flProtect&=~PAGE_NOCACHE; /* too low level for libcaptive */ flProtect&=~PAGE_SYSTEM; /* too low level for libcaptive */ /* FIXME: what does mean PAGE_WRITETHROUGH ? */ switch (flProtect) { case PAGE_GUARD: return PROT_NONE; case PAGE_NOACCESS: return PROT_NONE; case PAGE_READONLY: return PROT_READ; case PAGE_READWRITE: return PROT_READ|PROT_WRITE; case PAGE_WRITECOPY: g_return_val_if_reached(PROT_NONE); /* FIXME: no multithreading supported */ case PAGE_EXECUTE_READ: return PROT_EXEC|PROT_READ; case PAGE_EXECUTE_READWRITE: return PROT_EXEC|PROT_READ|PROT_WRITE; case PAGE_EXECUTE_WRITECOPY: g_return_val_if_reached(PROT_NONE); /* FIXME: no multithreading supported */ } g_return_val_if_reached(PROT_NONE); /* =unsupported flags */ } static GHashTable *captive_mmap_map_hash; static void captive_mmap_map_hash_init(void) { if (captive_mmap_map_hash) return; captive_mmap_map_hash=g_hash_table_new(g_direct_hash,g_direct_equal); } /** * captive_mmap_map_new: * @addr: %PAGE_SIZE aligned address of memory block. * %NULL value is forbidden. * @len: %PAGE_SIZE aligned length of memory block. * Value %0 is permitted. Value %-1 is forbidden. * @mmap_prot: Protections for the memory block as specified by @prot of mprotect(2). * * Initialize the protection map for the specified memory block. * Any existing protections in the specified block are forbidden. * * This function does not do any mprotect(2) style, it just stores * the settings for the later %OR operations by MmSetPageProtect(). * Caller is responsibel to set the same protections as the given @mmap_prot. * * Returns: %TRUE if the protection storage was successful. */ gboolean captive_mmap_map_new(gconstpointer addr,size_t len,int mmap_prot) { g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: addr=%p,len=%lu,mmap_prot=0x%X",G_STRLOC,addr,(gulong)len,mmap_prot); g_return_val_if_fail(addr!=NULL,FALSE); g_return_val_if_fail((GPOINTER_TO_UINT(addr)&(PAGE_SIZE-1))==0,FALSE); g_return_val_if_fail((len&(PAGE_SIZE-1))==0,FALSE); g_return_val_if_fail(mmap_prot!=-1,FALSE); captive_mmap_map_hash_init(); while (len) { g_return_val_if_fail(FALSE==g_hash_table_lookup_extended(captive_mmap_map_hash, addr, /* lookup_key */ NULL, /* orig_key */ NULL), /* value */ FALSE); g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: addr=%p,PAGE_SIZE=0x%X",G_STRLOC,addr,(guint)(PAGE_SIZE)); g_hash_table_insert(captive_mmap_map_hash, (gpointer)addr, /* key */ GINT_TO_POINTER(mmap_prot)); /* value */ addr=(gconstpointer)(((const char *)addr)+PAGE_SIZE); len-=PAGE_SIZE; } return TRUE; } /** * captive_mmap_map_get: * @addr: %PAGE_SIZE aligned address of memory block. * %NULL value is forbidden. * * Query the protection settings at @addr address. * The given @addr block of %PAGE_SIZE must be already initialized * by captive_mmap_map_new(). * * Returns: Protections of the page as specified by @prot of mprotect(2) * if successful. Value %-1 if failed. */ gint captive_mmap_map_get(gconstpointer addr) { gpointer r_gpointer; gint r; g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: addr=%p",G_STRLOC,addr); g_return_val_if_fail(addr!=NULL,-1); g_return_val_if_fail((GPOINTER_TO_UINT(addr)&(PAGE_SIZE-1))==0,-1); captive_mmap_map_hash_init(); g_return_val_if_fail(TRUE==g_hash_table_lookup_extended(captive_mmap_map_hash, addr, /* lookup_key */ NULL, /* orig_key */ &r_gpointer), /* value */ -1); r=GPOINTER_TO_INT(r_gpointer); g_assert(r!=-1); return r; } /** * captive_mmap_map_set: * @addr: %PAGE_SIZE aligned address of memory block. * %NULL value is forbidden. * @mmap_prot: Protections for the memory block as specified by @prot of mprotect(2). * * Set the protection settings at @addr address. * The given @addr block of %PAGE_SIZE must be already initialized * by captive_mmap_map_new(). * * Returns: %TRUE if the protections were successfuly set. */ gboolean captive_mmap_map_set(gconstpointer addr,int mmap_prot) { g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: addr=%p,mmap_prot=0x%X",G_STRLOC,addr,mmap_prot); g_return_val_if_fail(addr!=NULL,FALSE); g_return_val_if_fail((GPOINTER_TO_UINT(addr)&(PAGE_SIZE-1))==0,FALSE); g_return_val_if_fail(mmap_prot!=-1,FALSE); captive_mmap_map_hash_init(); g_return_val_if_fail(TRUE==g_hash_table_lookup_extended(captive_mmap_map_hash, addr, /* lookup_key */ NULL, /* orig_key */ NULL), /* value */ FALSE); g_hash_table_replace(captive_mmap_map_hash, (gpointer)addr, /* key */ GINT_TO_POINTER(mmap_prot)); /* value */ return TRUE; } /** * MmSetPageProtect: * @Process: Attached during the execution if not %NULL. Ignored by #libcaptive. * @Address: One page to modify the protecton bits of. * @flProtect: Required protection flags to logically %OR to the previos ones. * * FIXME: Undocumented by reactos. %ORes the protection of one page located at @Address * with protection flags @flProtect. Implemented by mprotect(2) by #libcaptive. */ VOID MmSetPageProtect(PEPROCESS Process,PVOID Address,ULONG flProtect) { gint mmap_prot; int err; g_return_if_fail(Address!=NULL); captive_mmap_map_hash_init(); /* 'Address' is not required to be PAGE_SIZE-aligned: * reactos MmSetPageProtect() calls MmGetPageEntry(Address) with no such requirement. * glib NOTE: YOU MAY NOT STORE POINTERS IN INTEGERS. */ Address=(VOID *)(((char *)Address)-(GPOINTER_TO_UINT(Address)&(PAGE_SIZE-1))); /* This may be also invalid input 'Address' */ g_assert(Address!=NULL); /* Prepare and updated ORed 'mmap_prot' in captive_mmap_map storage */ mmap_prot=captive_flProtect_to_mmap_prot(flProtect); mmap_prot|=captive_mmap_map_get(Address); captive_mmap_map_set(Address,mmap_prot); /* protect one page; reactos call cannot return error codes */ err=mprotect(Address,PAGE_SIZE,mmap_prot); g_return_if_fail(err==0); /* success */ } /** * MmGetPhysicalAddress: * @vaddr: Virtual address to convert. * * Function converts address from the virtual address space to the physical one. * As libcaptive unifies all the address spaces this function will return @vaddr directly there. * * Returns: Pure @vaddr extended to 64-bits of #PHYSICAL_ADDRESS (libcaptive-specific). */ PHYSICAL_ADDRESS MmGetPhysicalAddress(PVOID vaddr) { PHYSICAL_ADDRESS r; r.QuadPart=0; g_return_val_if_fail(vaddr!=NULL,r); g_assert(sizeof(vaddr)==sizeof(guint32)); r.QuadPart=(guint32)vaddr; return r; }