2 * reactos spinlock emulation of libcaptive
3 * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "captive/mm.h" /* self */
23 #include "reactos/internal/mm.h" /* self */
24 #include "reactos/ntos/types.h" /* for PVOID etc. */
25 #include <glib/gmessages.h>
26 #include <limits.h> /* for PAGE_size */
27 #include <sys/mman.h> /* for PROT_NONE etc. */
28 #include <glib/ghash.h>
32 * captive_flProtect_to_mmap_prot:
33 * @flProtect: reactos compatible constant such as %PAGE_READWRITE.
35 * Map reactos flProtect to mprotect(2)-compatible "prot" argument.
37 * Returns: mmap(2) compatible @prot argument.
39 gint captive_flProtect_to_mmap_prot(ULONG flProtect)
41 flProtect&=~PAGE_NOCACHE; /* too low level for libcaptive */
42 flProtect&=~PAGE_SYSTEM; /* too low level for libcaptive */
43 /* FIXME: what does mean PAGE_WRITETHROUGH ? */
45 case PAGE_GUARD: return PROT_NONE;
46 case PAGE_NOACCESS: return PROT_NONE;
47 case PAGE_READONLY: return PROT_READ;
48 case PAGE_READWRITE: return PROT_READ|PROT_WRITE;
49 case PAGE_WRITECOPY: g_return_val_if_reached(PROT_NONE); /* FIXME: no multithreading supported */
50 case PAGE_EXECUTE_READ: return PROT_EXEC|PROT_READ;
51 case PAGE_EXECUTE_READWRITE: return PROT_EXEC|PROT_READ|PROT_WRITE;
52 case PAGE_EXECUTE_WRITECOPY: g_return_val_if_reached(PROT_NONE); /* FIXME: no multithreading supported */
54 g_return_val_if_reached(PROT_NONE); /* =unsupported flags */
58 static GHashTable *captive_mmap_map_hash;
60 static void captive_mmap_map_hash_init(void)
62 if (captive_mmap_map_hash)
64 captive_mmap_map_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
68 * captive_mmap_map_new:
69 * @addr: %PAGE_SIZE aligned address of memory block.
70 * %NULL value is forbidden.
71 * @len: %PAGE_SIZE aligned length of memory block.
72 * Value %0 is permitted. Value %-1 is forbidden.
73 * @mmap_prot: Protections for the memory block as specified by @prot of mprotect(2).
75 * Initialize the protection map for the specified memory block.
76 * Any existing protections in the specified block are forbidden.
78 * This function does not do any mprotect(2) style, it just stores
79 * the settings for the later %OR operations by MmSetPageProtect().
80 * Caller is responsibel to set the same protections as the given @mmap_prot.
82 * Returns: %TRUE if the protection storage was successful.
84 gboolean captive_mmap_map_new(gconstpointer addr,size_t len,int mmap_prot)
86 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);
87 g_return_val_if_fail(addr!=NULL,FALSE);
88 g_return_val_if_fail((GPOINTER_TO_UINT(addr)&(PAGE_SIZE-1))==0,FALSE);
89 g_return_val_if_fail((len&(PAGE_SIZE-1))==0,FALSE);
90 g_return_val_if_fail(mmap_prot!=-1,FALSE);
92 captive_mmap_map_hash_init();
95 g_return_val_if_fail(FALSE==g_hash_table_lookup_extended(captive_mmap_map_hash,
96 addr, /* lookup_key */
100 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: addr=%p,PAGE_SIZE=0x%X",G_STRLOC,addr,(guint)(PAGE_SIZE));
101 g_hash_table_insert(captive_mmap_map_hash,
102 (gpointer)addr, /* key */
103 GINT_TO_POINTER(mmap_prot)); /* value */
105 addr=(gconstpointer)(((const char *)addr)+PAGE_SIZE);
114 * captive_mmap_map_get:
115 * @addr: %PAGE_SIZE aligned address of memory block.
116 * %NULL value is forbidden.
118 * Query the protection settings at @addr address.
119 * The given @addr block of %PAGE_SIZE must be already initialized
120 * by captive_mmap_map_new().
122 * Returns: Protections of the page as specified by @prot of mprotect(2)
123 * if successful. Value %-1 if failed.
125 gint captive_mmap_map_get(gconstpointer addr)
130 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: addr=%p",G_STRLOC,addr);
131 g_return_val_if_fail(addr!=NULL,-1);
132 g_return_val_if_fail((GPOINTER_TO_UINT(addr)&(PAGE_SIZE-1))==0,-1);
134 captive_mmap_map_hash_init();
136 g_return_val_if_fail(TRUE==g_hash_table_lookup_extended(captive_mmap_map_hash,
137 addr, /* lookup_key */
139 &r_gpointer), /* value */
141 r=GPOINTER_TO_INT(r_gpointer);
149 * captive_mmap_map_set:
150 * @addr: %PAGE_SIZE aligned address of memory block.
151 * %NULL value is forbidden.
152 * @mmap_prot: Protections for the memory block as specified by @prot of mprotect(2).
154 * Set the protection settings at @addr address.
155 * The given @addr block of %PAGE_SIZE must be already initialized
156 * by captive_mmap_map_new().
158 * Returns: %TRUE if the protections were successfuly set.
160 gboolean captive_mmap_map_set(gconstpointer addr,int mmap_prot)
162 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: addr=%p,mmap_prot=0x%X",G_STRLOC,addr,mmap_prot);
163 g_return_val_if_fail(addr!=NULL,FALSE);
164 g_return_val_if_fail((GPOINTER_TO_UINT(addr)&(PAGE_SIZE-1))==0,FALSE);
165 g_return_val_if_fail(mmap_prot!=-1,FALSE);
167 captive_mmap_map_hash_init();
169 g_return_val_if_fail(TRUE==g_hash_table_lookup_extended(captive_mmap_map_hash,
170 addr, /* lookup_key */
175 g_hash_table_replace(captive_mmap_map_hash,
176 (gpointer)addr, /* key */
177 GINT_TO_POINTER(mmap_prot)); /* value */
184 * @Process: Attached during the execution if not %NULL. Ignored by #libcaptive.
185 * @Address: One page to modify the protecton bits of.
186 * @flProtect: Required protection flags to logically %OR to the previos ones.
188 * FIXME: Undocumented by reactos. %ORes the protection of one page located at @Address
189 * with protection flags @flProtect. Implemented by mprotect(2) by #libcaptive.
191 VOID MmSetPageProtect(PEPROCESS Process,PVOID Address,ULONG flProtect)
196 g_return_if_fail(Address!=NULL);
198 captive_mmap_map_hash_init();
200 /* 'Address' is not required to be PAGE_SIZE-aligned:
201 * reactos MmSetPageProtect() calls MmGetPageEntry(Address) with no such requirement.
202 * glib NOTE: YOU MAY NOT STORE POINTERS IN INTEGERS.
204 Address=(VOID *)(((char *)Address)-(GPOINTER_TO_UINT(Address)&(PAGE_SIZE-1)));
205 /* This may be also invalid input 'Address' */
206 g_assert(Address!=NULL);
208 /* Prepare and updated ORed 'mmap_prot' in captive_mmap_map storage */
209 mmap_prot=captive_flProtect_to_mmap_prot(flProtect);
210 mmap_prot|=captive_mmap_map_get(Address);
211 captive_mmap_map_set(Address,mmap_prot);
213 /* protect one page; reactos call cannot return error codes */
214 err=mprotect(Address,PAGE_SIZE,mmap_prot);
215 g_return_if_fail(err==0);