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 <sys/mman.h> /* for PROT_NONE etc. */
27 #include <glib/ghash.h>
31 * captive_flProtect_to_mmap_prot:
32 * @flProtect: reactos compatible constant such as %PAGE_READWRITE.
34 * Map reactos flProtect to mprotect(2)-compatible "prot" argument.
36 * Returns: mmap(2) compatible @prot argument.
38 gint captive_flProtect_to_mmap_prot(ULONG flProtect)
40 flProtect&=~PAGE_NOCACHE; /* too low level for libcaptive */
41 flProtect&=~PAGE_SYSTEM; /* too low level for libcaptive */
42 /* FIXME: what does mean PAGE_WRITETHROUGH ? */
44 case PAGE_GUARD: return PROT_NONE;
45 case PAGE_NOACCESS: return PROT_NONE;
46 case PAGE_READONLY: return PROT_READ;
47 case PAGE_READWRITE: return PROT_READ|PROT_WRITE;
48 case PAGE_WRITECOPY: g_return_val_if_reached(PROT_NONE); /* FIXME: no multithreading supported */
49 case PAGE_EXECUTE_READ: return PROT_EXEC|PROT_READ;
50 case PAGE_EXECUTE_READWRITE: return PROT_EXEC|PROT_READ|PROT_WRITE;
51 case PAGE_EXECUTE_WRITECOPY: g_return_val_if_reached(PROT_NONE); /* FIXME: no multithreading supported */
53 g_return_val_if_reached(PROT_NONE); /* =unsupported flags */
57 static GHashTable *captive_mmap_map_hash;
59 static void captive_mmap_map_hash_init(void)
61 if (captive_mmap_map_hash)
63 captive_mmap_map_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
67 * captive_mmap_map_new:
68 * @addr: %PAGE_SIZE aligned address of memory block.
69 * %NULL value is forbidden.
70 * @len: %PAGE_SIZE aligned length of memory block.
71 * Value %0 is permitted. Value %-1 is forbidden.
72 * @mmap_prot: Protections for the memory block as specified by @prot of mprotect(2).
74 * Initialize the protection map for the specified memory block.
75 * Any existing protections in the specified block are forbidden.
77 * This function does not do any mprotect(2) style, it just stores
78 * the settings for the later %OR operations by MmSetPageProtect().
79 * Caller is responsibel to set the same protections as the given @mmap_prot.
81 * Returns: %TRUE if the protection storage was successful.
83 gboolean captive_mmap_map_new(gconstpointer addr,size_t len,int mmap_prot)
85 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);
86 g_return_val_if_fail(addr!=NULL,FALSE);
87 g_return_val_if_fail((GPOINTER_TO_UINT(addr)&(PAGE_SIZE-1))==0,FALSE);
88 g_return_val_if_fail((len&(PAGE_SIZE-1))==0,FALSE);
89 g_return_val_if_fail(mmap_prot!=-1,FALSE);
91 captive_mmap_map_hash_init();
94 g_return_val_if_fail(FALSE==g_hash_table_lookup_extended(captive_mmap_map_hash,
95 addr, /* lookup_key */
99 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: addr=%p,PAGE_SIZE=0x%X",G_STRLOC,addr,(guint)(PAGE_SIZE));
100 g_hash_table_insert(captive_mmap_map_hash,
101 (gpointer)addr, /* key */
102 GINT_TO_POINTER(mmap_prot)); /* value */
104 addr=(gconstpointer)(((const char *)addr)+PAGE_SIZE);
113 * captive_mmap_map_get:
114 * @addr: %PAGE_SIZE aligned address of memory block.
115 * %NULL value is forbidden.
117 * Query the protection settings at @addr address.
118 * The given @addr block of %PAGE_SIZE must be already initialized
119 * by captive_mmap_map_new().
121 * Returns: Protections of the page as specified by @prot of mprotect(2)
122 * if successful. Value %-1 if failed.
124 gint captive_mmap_map_get(gconstpointer addr)
129 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: addr=%p",G_STRLOC,addr);
130 g_return_val_if_fail(addr!=NULL,-1);
131 g_return_val_if_fail((GPOINTER_TO_UINT(addr)&(PAGE_SIZE-1))==0,-1);
133 captive_mmap_map_hash_init();
135 g_return_val_if_fail(TRUE==g_hash_table_lookup_extended(captive_mmap_map_hash,
136 addr, /* lookup_key */
138 &r_gpointer), /* value */
140 r=GPOINTER_TO_INT(r_gpointer);
148 * captive_mmap_map_set:
149 * @addr: %PAGE_SIZE aligned address of memory block.
150 * %NULL value is forbidden.
151 * @mmap_prot: Protections for the memory block as specified by @prot of mprotect(2).
153 * Set the protection settings at @addr address.
154 * The given @addr block of %PAGE_SIZE must be already initialized
155 * by captive_mmap_map_new().
157 * Returns: %TRUE if the protections were successfuly set.
159 gboolean captive_mmap_map_set(gconstpointer addr,int mmap_prot)
161 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: addr=%p,mmap_prot=0x%X",G_STRLOC,addr,mmap_prot);
162 g_return_val_if_fail(addr!=NULL,FALSE);
163 g_return_val_if_fail((GPOINTER_TO_UINT(addr)&(PAGE_SIZE-1))==0,FALSE);
164 g_return_val_if_fail(mmap_prot!=-1,FALSE);
166 captive_mmap_map_hash_init();
168 g_return_val_if_fail(TRUE==g_hash_table_lookup_extended(captive_mmap_map_hash,
169 addr, /* lookup_key */
174 g_hash_table_replace(captive_mmap_map_hash,
175 (gpointer)addr, /* key */
176 GINT_TO_POINTER(mmap_prot)); /* value */
183 * @Process: Attached during the execution if not %NULL. Ignored by #libcaptive.
184 * @Address: One page to modify the protecton bits of.
185 * @flProtect: Required protection flags to logically %OR to the previos ones.
187 * FIXME: Undocumented by reactos. %ORes the protection of one page located at @Address
188 * with protection flags @flProtect. Implemented by mprotect(2) by #libcaptive.
190 VOID MmSetPageProtect(PEPROCESS Process,PVOID Address,ULONG flProtect)
195 g_return_if_fail(Address!=NULL);
197 captive_mmap_map_hash_init();
199 /* 'Address' is not required to be PAGE_SIZE-aligned:
200 * reactos MmSetPageProtect() calls MmGetPageEntry(Address) with no such requirement.
201 * glib NOTE: YOU MAY NOT STORE POINTERS IN INTEGERS.
203 Address=(VOID *)(((char *)Address)-(GPOINTER_TO_UINT(Address)&(PAGE_SIZE-1)));
204 /* This may be also invalid input 'Address' */
205 g_assert(Address!=NULL);
207 /* Prepare and updated ORed 'mmap_prot' in captive_mmap_map storage */
208 mmap_prot=captive_flProtect_to_mmap_prot(flProtect);
209 mmap_prot|=captive_mmap_map_get(Address);
210 captive_mmap_map_set(Address,mmap_prot);
212 /* protect one page; reactos call cannot return error codes */
213 err=mprotect(Address,PAGE_SIZE,mmap_prot);
214 g_return_if_fail(err==0);
221 * MmGetPhysicalAddress:
222 * @vaddr: Virtual address to convert.
224 * Function converts address from the virtual address space to the physical one.
225 * As libcaptive unifies all the address spaces this function will return @vaddr directly there.
227 * Returns: Pure @vaddr extended to 64-bits of #PHYSICAL_ADDRESS (libcaptive-specific).
229 PHYSICAL_ADDRESS MmGetPhysicalAddress(PVOID vaddr)
234 g_return_val_if_fail(vaddr!=NULL,r);
236 g_assert(sizeof(vaddr)==sizeof(guint32));
237 r.QuadPart=(guint32)vaddr;