Reactos
1/*
2 * Win32 memory management functions
3 *
4 * Copyright 1997 Alexandre Julliard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#include <stdarg.h>
22#include <stdlib.h>
23#include <string.h>
24#include <limits.h>
25#include <sys/types.h>
26
27#include "ntstatus.h"
28#define WIN32_NO_STATUS
29#include "windef.h"
30#include "winbase.h"
31#include "winnls.h"
32#include "winternl.h"
33#include "winerror.h"
34#include "ddk/wdm.h"
35
36#include "kernelbase.h"
37#include "wine/exception.h"
38#include "wine/debug.h"
39
40WINE_DEFAULT_DEBUG_CHANNEL(heap);
41WINE_DECLARE_DEBUG_CHANNEL(virtual);
42WINE_DECLARE_DEBUG_CHANNEL(globalmem);
43
44
45
46static CROSS_PROCESS_WORK_LIST *open_cross_process_connection( HANDLE process )
47{
48#ifdef __aarch64__
49 CROSS_PROCESS_WORK_LIST *list;
50 HANDLE section;
51
52 RtlOpenCrossProcessEmulatorWorkConnection( process, §ion, (void **)&list );
53 if (section) NtClose( section );
54 return list;
55#else
56 return NULL;
57#endif
58}
59
60static void close_cross_process_connection( CROSS_PROCESS_WORK_LIST *list )
61{
62 if (list) NtUnmapViewOfSection( GetCurrentProcess(), list );
63}
64
65static void send_cross_process_notification( CROSS_PROCESS_WORK_LIST *list, UINT id,
66 const void *addr, SIZE_T size, int nb_args, ... )
67{
68#ifdef __aarch64__
69 CROSS_PROCESS_WORK_ENTRY *entry;
70 void *unused;
71 va_list args;
72 int i;
73
74 if (!list) return;
75 if ((entry = RtlWow64PopCrossProcessWorkFromFreeList( &list->free_list )))
76 {
77 entry->id = id;
78 entry->addr = (ULONG_PTR)addr;
79 entry->size = size;
80 if (nb_args)
81 {
82 va_start( args, nb_args );
83 for (i = 0; i < nb_args; i++) entry->args[i] = va_arg( args, int );
84 va_end( args );
85 }
86 RtlWow64PushCrossProcessWorkOntoWorkList( &list->work_list, entry, &unused );
87 }
88#endif
89}
90
91
92/***********************************************************************
93 * Virtual memory functions
94 ***********************************************************************/
95
96static const SIZE_T page_mask = 0xfff;
97#define ROUND_ADDR(addr) ((void *)((UINT_PTR)(addr) & ~page_mask))
98#define ROUND_SIZE(addr,size) (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)
99
100/***********************************************************************
101 * DiscardVirtualMemory (kernelbase.@)
102 */
103DWORD WINAPI DECLSPEC_HOTPATCH DiscardVirtualMemory( void *addr, SIZE_T size )
104{
105 NTSTATUS status;
106 LPVOID ret = addr;
107
108 status = NtAllocateVirtualMemory( GetCurrentProcess(), &ret, 0, &size, MEM_RESET, PAGE_NOACCESS );
109 return RtlNtStatusToDosError( status );
110}
111
112
113/***********************************************************************
114 * FlushViewOfFile (kernelbase.@)
115 */
116BOOL WINAPI DECLSPEC_HOTPATCH FlushViewOfFile( const void *base, SIZE_T size )
117{
118 NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 );
119
120 if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS;
121 return set_ntstatus( status );
122}
123
124
125/****************************************************************************
126 * FlushInstructionCache (kernelbase.@)
127 */
128BOOL WINAPI DECLSPEC_HOTPATCH FlushInstructionCache( HANDLE process, LPCVOID addr, SIZE_T size )
129{
130 CROSS_PROCESS_WORK_LIST *list;
131
132 if ((list = open_cross_process_connection( process )))
133 {
134 send_cross_process_notification( list, CrossProcessFlushCache, addr, size, 0 );
135 close_cross_process_connection( list );
136 }
137 return set_ntstatus( NtFlushInstructionCache( process, addr, size ));
138}
139
140
141/***********************************************************************
142 * GetLargePageMinimum (kernelbase.@)
143 */
144SIZE_T WINAPI GetLargePageMinimum(void)
145{
146 return 2 * 1024 * 1024;
147}
148
149
150static void fill_system_info( SYSTEM_INFO *si, const SYSTEM_BASIC_INFORMATION *basic_info,
151 const SYSTEM_CPU_INFORMATION *cpu_info )
152{
153 si->wProcessorArchitecture = cpu_info->ProcessorArchitecture;
154 si->wReserved = 0;
155 si->dwPageSize = basic_info->PageSize;
156 si->lpMinimumApplicationAddress = basic_info->LowestUserAddress;
157 si->lpMaximumApplicationAddress = basic_info->HighestUserAddress;
158 si->dwActiveProcessorMask = basic_info->ActiveProcessorsAffinityMask;
159 si->dwNumberOfProcessors = basic_info->NumberOfProcessors;
160 si->dwAllocationGranularity = basic_info->AllocationGranularity;
161 si->wProcessorLevel = cpu_info->ProcessorLevel;
162 si->wProcessorRevision = cpu_info->ProcessorRevision;
163
164 switch (cpu_info->ProcessorArchitecture)
165 {
166 case PROCESSOR_ARCHITECTURE_INTEL:
167 switch (cpu_info->ProcessorLevel)
168 {
169 case 3: si->dwProcessorType = PROCESSOR_INTEL_386; break;
170 case 4: si->dwProcessorType = PROCESSOR_INTEL_486; break;
171 case 5:
172 case 6: si->dwProcessorType = PROCESSOR_INTEL_PENTIUM; break;
173 default: si->dwProcessorType = PROCESSOR_INTEL_PENTIUM; break;
174 }
175 break;
176 case PROCESSOR_ARCHITECTURE_AMD64:
177 si->dwProcessorType = PROCESSOR_AMD_X8664;
178 break;
179 case PROCESSOR_ARCHITECTURE_ARM:
180 switch (cpu_info->ProcessorLevel)
181 {
182 case 4: si->dwProcessorType = PROCESSOR_ARM_7TDMI; break;
183 default: si->dwProcessorType = PROCESSOR_ARM920;
184 }
185 break;
186 case PROCESSOR_ARCHITECTURE_ARM64:
187 si->dwProcessorType = 0;
188 break;
189 default:
190 FIXME( "Unknown processor architecture %x\n", cpu_info->ProcessorArchitecture );
191 si->dwProcessorType = 0;
192 break;
193 }
194}
195
196
197/***********************************************************************
198 * GetNativeSystemInfo (kernelbase.@)
199 */
200void WINAPI DECLSPEC_HOTPATCH GetNativeSystemInfo( SYSTEM_INFO *si )
201{
202 SYSTEM_BASIC_INFORMATION basic_info;
203 SYSTEM_CPU_INFORMATION cpu_info;
204
205 if (is_wow64)
206 {
207 USHORT current_machine, native_machine;
208
209 RtlWow64GetProcessMachines( 0, ¤t_machine, &native_machine );
210 if (native_machine != IMAGE_FILE_MACHINE_AMD64)
211 {
212 GetSystemInfo( si );
213 si->wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
214 return;
215 }
216 }
217
218 if (!set_ntstatus( RtlGetNativeSystemInformation( SystemBasicInformation,
219 &basic_info, sizeof(basic_info), NULL )) ||
220 !set_ntstatus( RtlGetNativeSystemInformation( SystemCpuInformation,
221 &cpu_info, sizeof(cpu_info), NULL )))
222 return;
223
224 fill_system_info( si, &basic_info, &cpu_info );
225}
226
227
228/***********************************************************************
229 * GetSystemInfo (kernelbase.@)
230 */
231void WINAPI DECLSPEC_HOTPATCH GetSystemInfo( SYSTEM_INFO *si )
232{
233 SYSTEM_BASIC_INFORMATION basic_info;
234 SYSTEM_CPU_INFORMATION cpu_info;
235
236 if (!set_ntstatus( NtQuerySystemInformation( SystemBasicInformation,
237 &basic_info, sizeof(basic_info), NULL )) ||
238 !set_ntstatus( NtQuerySystemInformation( SystemCpuInformation,
239 &cpu_info, sizeof(cpu_info), NULL )))
240 return;
241
242 fill_system_info( si, &basic_info, &cpu_info );
243}
244
245
246/***********************************************************************
247 * GetSystemFileCacheSize (kernelbase.@)
248 */
249BOOL WINAPI DECLSPEC_HOTPATCH GetSystemFileCacheSize( SIZE_T *mincache, SIZE_T *maxcache, DWORD *flags )
250{
251 FIXME( "stub: %p %p %p\n", mincache, maxcache, flags );
252 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
253 return FALSE;
254}
255
256
257/***********************************************************************
258 * GetWriteWatch (kernelbase.@)
259 */
260UINT WINAPI DECLSPEC_HOTPATCH GetWriteWatch( DWORD flags, void *base, SIZE_T size, void **addresses,
261 ULONG_PTR *count, ULONG *granularity )
262{
263 if (!set_ntstatus( NtGetWriteWatch( GetCurrentProcess(), flags, base, size,
264 addresses, count, granularity )))
265 return ~0u;
266 return 0;
267}
268
269
270/***********************************************************************
271 * MapViewOfFile (kernelbase.@)
272 */
273LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFile( HANDLE mapping, DWORD access, DWORD offset_high,
274 DWORD offset_low, SIZE_T count )
275{
276 return MapViewOfFileEx( mapping, access, offset_high, offset_low, count, NULL );
277}
278
279
280/***********************************************************************
281 * MapViewOfFileEx (kernelbase.@)
282 */
283LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFileEx( HANDLE handle, DWORD access, DWORD offset_high,
284 DWORD offset_low, SIZE_T count, LPVOID addr )
285{
286 NTSTATUS status;
287 LARGE_INTEGER offset;
288 ULONG protect;
289 BOOL exec;
290
291 offset.u.LowPart = offset_low;
292 offset.u.HighPart = offset_high;
293
294 exec = access & FILE_MAP_EXECUTE;
295 access &= ~FILE_MAP_EXECUTE;
296
297 if (access == FILE_MAP_COPY)
298 protect = exec ? PAGE_EXECUTE_WRITECOPY : PAGE_WRITECOPY;
299 else if (access & FILE_MAP_WRITE)
300 protect = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
301 else if (access & FILE_MAP_READ)
302 protect = exec ? PAGE_EXECUTE_READ : PAGE_READONLY;
303 else protect = PAGE_NOACCESS;
304
305 if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, &offset,
306 &count, ViewShare, 0, protect )) < 0)
307 {
308 SetLastError( RtlNtStatusToDosError(status) );
309 addr = NULL;
310 }
311 return addr;
312}
313
314
315/***********************************************************************
316 * MapViewOfFileFromApp (kernelbase.@)
317 */
318LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFileFromApp( HANDLE handle, ULONG access, ULONG64 offset, SIZE_T size )
319{
320 return MapViewOfFile( handle, access, offset << 32, offset, size );
321}
322
323/***********************************************************************
324 * MapViewOfFile3 (kernelbase.@)
325 */
326LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFile3( HANDLE handle, HANDLE process, PVOID baseaddr, ULONG64 offset,
327 SIZE_T size, ULONG alloc_type, ULONG protection, MEM_EXTENDED_PARAMETER *params, ULONG params_count )
328{
329 LARGE_INTEGER off;
330 void *addr;
331
332 if (!process) process = GetCurrentProcess();
333
334 addr = baseaddr;
335 off.QuadPart = offset;
336 if (!set_ntstatus( NtMapViewOfSectionEx( handle, process, &addr, &off, &size, alloc_type, protection,
337 params, params_count )))
338 {
339 return NULL;
340 }
341 return addr;
342}
343
344/***********************************************************************
345 * ReadProcessMemory (kernelbase.@)
346 */
347BOOL WINAPI DECLSPEC_HOTPATCH ReadProcessMemory( HANDLE process, const void *addr, void *buffer,
348 SIZE_T size, SIZE_T *bytes_read )
349{
350 return set_ntstatus( NtReadVirtualMemory( process, addr, buffer, size, bytes_read ));
351}
352
353
354/***********************************************************************
355 * ResetWriteWatch (kernelbase.@)
356 */
357UINT WINAPI DECLSPEC_HOTPATCH ResetWriteWatch( void *base, SIZE_T size )
358{
359 if (!set_ntstatus( NtResetWriteWatch( GetCurrentProcess(), base, size )))
360 return ~0u;
361 return 0;
362}
363
364
365/***********************************************************************
366 * SetSystemFileCacheSize (kernelbase.@)
367 */
368BOOL WINAPI DECLSPEC_HOTPATCH SetSystemFileCacheSize( SIZE_T mincache, SIZE_T maxcache, DWORD flags )
369{
370 FIXME( "stub: %Id %Id %ld\n", mincache, maxcache, flags );
371 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
372 return FALSE;
373}
374
375
376/***********************************************************************
377 * UnmapViewOfFile (kernelbase.@)
378 */
379BOOL WINAPI DECLSPEC_HOTPATCH UnmapViewOfFile( const void *addr )
380{
381 if (GetVersion() & 0x80000000)
382 {
383 MEMORY_BASIC_INFORMATION info;
384 if (!VirtualQuery( addr, &info, sizeof(info) ) || info.AllocationBase != addr)
385 {
386 SetLastError( ERROR_INVALID_ADDRESS );
387 return FALSE;
388 }
389 }
390 return set_ntstatus( NtUnmapViewOfSection( GetCurrentProcess(), (void *)addr ));
391}
392
393
394/***********************************************************************
395 * UnmapViewOfFile2 (kernelbase.@)
396 */
397BOOL WINAPI DECLSPEC_HOTPATCH UnmapViewOfFile2( HANDLE process, void *addr, ULONG flags )
398{
399 return set_ntstatus( NtUnmapViewOfSectionEx( process, addr, flags ));
400}
401
402
403/***********************************************************************
404 * UnmapViewOfFileEx (kernelbase.@)
405 */
406BOOL WINAPI DECLSPEC_HOTPATCH UnmapViewOfFileEx( void *addr, ULONG flags )
407{
408 return set_ntstatus( NtUnmapViewOfSectionEx( GetCurrentProcess(), addr, flags ));
409}
410
411
412/***********************************************************************
413 * VirtualAlloc (kernelbase.@)
414 */
415LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAlloc( void *addr, SIZE_T size, DWORD type, DWORD protect )
416{
417 return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect );
418}
419
420
421/***********************************************************************
422 * VirtualAllocEx (kernelbase.@)
423 */
424LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAllocEx( HANDLE process, void *addr, SIZE_T size,
425 DWORD type, DWORD protect )
426{
427 LPVOID ret = addr;
428
429 if (!set_ntstatus( NtAllocateVirtualMemory( process, &ret, 0, &size, type, protect ))) return NULL;
430 return ret;
431}
432
433
434/***********************************************************************
435 * VirtualAlloc2 (kernelbase.@)
436 */
437LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAlloc2( HANDLE process, void *addr, SIZE_T size,
438 DWORD type, DWORD protect,
439 MEM_EXTENDED_PARAMETER *parameters, ULONG count )
440{
441 LPVOID ret = addr;
442
443 if (!process) process = GetCurrentProcess();
444 if (!set_ntstatus( NtAllocateVirtualMemoryEx( process, &ret, &size, type, protect, parameters, count )))
445 return NULL;
446 return ret;
447}
448
449static BOOL is_exec_prot( DWORD protect )
450{
451 return protect == PAGE_EXECUTE || protect == PAGE_EXECUTE_READ || protect == PAGE_EXECUTE_READWRITE
452 || protect == PAGE_EXECUTE_WRITECOPY;
453}
454
455/***********************************************************************
456 * VirtualAlloc2FromApp (kernelbase.@)
457 */
458LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAlloc2FromApp( HANDLE process, void *addr, SIZE_T size,
459 DWORD type, DWORD protect, MEM_EXTENDED_PARAMETER *parameters, ULONG count )
460{
461 LPVOID ret = addr;
462
463 TRACE_(virtual)( "addr %p, size %p, type %#lx, protect %#lx, params %p, count %lu.\n", addr, (void *)size, type, protect,
464 parameters, count );
465
466 if (is_exec_prot( protect ))
467 {
468 SetLastError( ERROR_INVALID_PARAMETER );
469 return NULL;
470 }
471
472 if (!process) process = GetCurrentProcess();
473 if (!set_ntstatus( NtAllocateVirtualMemoryEx( process, &ret, &size, type, protect, parameters, count )))
474 return NULL;
475 return ret;
476}
477
478
479/***********************************************************************
480 * VirtualAllocFromApp (kernelbase.@)
481 */
482LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAllocFromApp( void *addr, SIZE_T size,
483 DWORD type, DWORD protect )
484{
485 LPVOID ret = addr;
486
487 TRACE_(virtual)( "addr %p, size %p, type %#lx, protect %#lx.\n", addr, (void *)size, type, protect );
488
489 if (is_exec_prot( protect ))
490 {
491 SetLastError( ERROR_INVALID_PARAMETER );
492 return NULL;
493 }
494
495 if (!set_ntstatus( NtAllocateVirtualMemory( GetCurrentProcess(), &ret, 0, &size, type, protect ))) return NULL;
496 return ret;
497}
498
499
500/***********************************************************************
501 * PrefetchVirtualMemory (kernelbase.@)
502 */
503BOOL WINAPI DECLSPEC_HOTPATCH PrefetchVirtualMemory( HANDLE process, ULONG_PTR count,
504 WIN32_MEMORY_RANGE_ENTRY *addresses, ULONG flags )
505{
506 return set_ntstatus( NtSetInformationVirtualMemory( process, VmPrefetchInformation,
507 count, (PMEMORY_RANGE_ENTRY)addresses,
508 &flags, sizeof(flags) ));
509}
510
511
512/***********************************************************************
513 * VirtualFree (kernelbase.@)
514 */
515BOOL WINAPI DECLSPEC_HOTPATCH VirtualFree( void *addr, SIZE_T size, DWORD type )
516{
517 return VirtualFreeEx( GetCurrentProcess(), addr, size, type );
518}
519
520
521/***********************************************************************
522 * VirtualFreeEx (kernelbase.@)
523 */
524BOOL WINAPI DECLSPEC_HOTPATCH VirtualFreeEx( HANDLE process, void *addr, SIZE_T size, DWORD type )
525{
526 if (type == MEM_RELEASE && size)
527 {
528 WARN( "Trying to release memory with specified size.\n" );
529 SetLastError( ERROR_INVALID_PARAMETER );
530 return FALSE;
531 }
532 return set_ntstatus( NtFreeVirtualMemory( process, &addr, &size, type ));
533}
534
535
536/***********************************************************************
537 * VirtualLock (kernelbase.@)
538 */
539BOOL WINAPI DECLSPEC_HOTPATCH VirtualLock( void *addr, SIZE_T size )
540{
541 return set_ntstatus( NtLockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 ));
542}
543
544
545/***********************************************************************
546 * VirtualProtect (kernelbase.@)
547 */
548BOOL WINAPI DECLSPEC_HOTPATCH VirtualProtect( void *addr, SIZE_T size, DWORD new_prot, DWORD *old_prot )
549{
550 return VirtualProtectEx( GetCurrentProcess(), addr, size, new_prot, old_prot );
551}
552
553
554/***********************************************************************
555 * VirtualProtectEx (kernelbase.@)
556 */
557BOOL WINAPI DECLSPEC_HOTPATCH VirtualProtectEx( HANDLE process, void *addr, SIZE_T size,
558 DWORD new_prot, DWORD *old_prot )
559{
560 DWORD prot;
561
562 /* Win9x allows passing NULL as old_prot while this fails on NT */
563 if (!old_prot && (GetVersion() & 0x80000000)) old_prot = &prot;
564 return set_ntstatus( NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot ));
565}
566
567
568/***********************************************************************
569 * VirtualQuery (kernelbase.@)
570 */
571SIZE_T WINAPI DECLSPEC_HOTPATCH VirtualQuery( LPCVOID addr, PMEMORY_BASIC_INFORMATION info, SIZE_T len )
572{
573 return VirtualQueryEx( GetCurrentProcess(), addr, info, len );
574}
575
576
577/***********************************************************************
578 * VirtualQueryEx (kernelbase.@)
579 */
580SIZE_T WINAPI DECLSPEC_HOTPATCH VirtualQueryEx( HANDLE process, LPCVOID addr,
581 PMEMORY_BASIC_INFORMATION info, SIZE_T len )
582{
583 SIZE_T ret;
584
585 if (!set_ntstatus( NtQueryVirtualMemory( process, addr, MemoryBasicInformation, info, len, &ret )))
586 return 0;
587 return ret;
588}
589
590
591/***********************************************************************
592 * VirtualUnlock (kernelbase.@)
593 */
594BOOL WINAPI DECLSPEC_HOTPATCH VirtualUnlock( void *addr, SIZE_T size )
595{
596 return set_ntstatus( NtUnlockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 ));
597}
598
599
600/***********************************************************************
601 * WriteProcessMemory (kernelbase.@)
602 */
603BOOL WINAPI DECLSPEC_HOTPATCH WriteProcessMemory( HANDLE process, void *addr, const void *buffer,
604 SIZE_T size, SIZE_T *bytes_written )
605{
606 CROSS_PROCESS_WORK_LIST *list = open_cross_process_connection( process );
607 DWORD old_prot, prot = PAGE_TARGETS_NO_UPDATE | PAGE_ENCLAVE_NO_CHANGE;
608 MEMORY_BASIC_INFORMATION info;
609 void *base_addr;
610 SIZE_T region_size;
611 NTSTATUS status, status2;
612
613 if (!VirtualQueryEx( process, addr, &info, sizeof(info) ))
614 {
615 close_cross_process_connection( list );
616 return FALSE;
617 }
618
619 switch (info.Protect & ~(PAGE_GUARD | PAGE_NOCACHE))
620 {
621 case PAGE_READWRITE:
622 case PAGE_WRITECOPY:
623 case PAGE_EXECUTE_READWRITE:
624 case PAGE_EXECUTE_WRITECOPY:
625 /* already writable */
626 if ((status = NtWriteVirtualMemory( process, addr, buffer, size, bytes_written ))) break;
627 send_cross_process_notification( list, CrossProcessFlushCache, addr, size, 0 );
628 NtFlushInstructionCache( process, addr, size );
629 break;
630
631 case PAGE_EXECUTE:
632 case PAGE_EXECUTE_READ:
633 /* make it writable */
634 base_addr = ROUND_ADDR( addr );
635 region_size = ROUND_SIZE( addr, size );
636 region_size = min( region_size, (char *)info.BaseAddress + info.RegionSize - (char *)base_addr );
637 prot |= (info.Type == MEM_PRIVATE) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_WRITECOPY;
638
639 send_cross_process_notification( list, CrossProcessPreVirtualProtect,
640 base_addr, region_size, 1, prot );
641 status = NtProtectVirtualMemory( process, &base_addr, ®ion_size, prot, &old_prot );
642 send_cross_process_notification( list, CrossProcessPostVirtualProtect,
643 base_addr, region_size, 2, prot, status );
644 if (status) break;
645
646 status = NtWriteVirtualMemory( process, addr, buffer, size, bytes_written );
647 if (!status)
648 {
649 send_cross_process_notification( list, CrossProcessFlushCache, addr, size, 0 );
650 NtFlushInstructionCache( process, addr, size );
651 }
652
653 prot = PAGE_TARGETS_NO_UPDATE | PAGE_ENCLAVE_NO_CHANGE | old_prot;
654 send_cross_process_notification( list, CrossProcessPreVirtualProtect,
655 base_addr, region_size, 1, prot );
656 status2 = NtProtectVirtualMemory( process, &base_addr, ®ion_size, prot, &old_prot );
657 send_cross_process_notification( list, CrossProcessPostVirtualProtect,
658 base_addr, region_size, 2, prot, status2 );
659 break;
660
661 default:
662 /* not writable */
663 status = STATUS_ACCESS_VIOLATION;
664 break;
665 }
666
667 close_cross_process_connection( list );
668 return set_ntstatus( status );
669}
670
671
672/* IsBadStringPtrA replacement for kernelbase, to catch exception in debug traces. */
673BOOL WINAPI IsBadStringPtrA( LPCSTR str, UINT_PTR max )
674{
675 if (!str) return TRUE;
676 __TRY
677 {
678 volatile const char *p = str;
679 while (p != str + max) if (!*p++) break;
680 }
681 __EXCEPT_PAGE_FAULT
682 {
683 return TRUE;
684 }
685 __ENDTRY
686 return FALSE;
687}
688
689
690/* IsBadStringPtrW replacement for kernelbase, to catch exception in debug traces. */
691BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT_PTR max )
692{
693 if (!str) return TRUE;
694 __TRY
695 {
696 volatile const WCHAR *p = str;
697 while (p != str + max) if (!*p++) break;
698 }
699 __EXCEPT_PAGE_FAULT
700 {
701 return TRUE;
702 }
703 __ENDTRY
704 return FALSE;
705}
706
707
708/***********************************************************************
709 * Heap functions
710 ***********************************************************************/
711
712
713/***********************************************************************
714 * HeapCompact (kernelbase.@)
715 */
716SIZE_T WINAPI DECLSPEC_HOTPATCH HeapCompact( HANDLE heap, DWORD flags )
717{
718 return RtlCompactHeap( heap, flags );
719}
720
721
722/***********************************************************************
723 * HeapCreate (kernelbase.@)
724 */
725HANDLE WINAPI DECLSPEC_HOTPATCH HeapCreate( DWORD flags, SIZE_T init_size, SIZE_T max_size )
726{
727 HANDLE ret = RtlCreateHeap( flags, NULL, max_size, init_size, NULL, NULL );
728 if (!ret) SetLastError( ERROR_NOT_ENOUGH_MEMORY );
729 return ret;
730}
731
732
733/***********************************************************************
734 * HeapDestroy (kernelbase.@)
735 */
736BOOL WINAPI DECLSPEC_HOTPATCH HeapDestroy( HANDLE heap )
737{
738 if (!RtlDestroyHeap( heap )) return TRUE;
739 SetLastError( ERROR_INVALID_HANDLE );
740 return FALSE;
741}
742
743
744/***********************************************************************
745 * HeapLock (kernelbase.@)
746 */
747BOOL WINAPI DECLSPEC_HOTPATCH HeapLock( HANDLE heap )
748{
749 return RtlLockHeap( heap );
750}
751
752
753/***********************************************************************
754 * HeapQueryInformation (kernelbase.@)
755 */
756BOOL WINAPI HeapQueryInformation( HANDLE heap, HEAP_INFORMATION_CLASS info_class,
757 PVOID info, SIZE_T size, PSIZE_T size_out )
758{
759 return set_ntstatus( RtlQueryHeapInformation( heap, info_class, info, size, size_out ));
760}
761
762
763/***********************************************************************
764 * HeapSetInformation (kernelbase.@)
765 */
766BOOL WINAPI HeapSetInformation( HANDLE heap, HEAP_INFORMATION_CLASS infoclass, PVOID info, SIZE_T size )
767{
768 return set_ntstatus( RtlSetHeapInformation( heap, infoclass, info, size ));
769}
770
771
772/***********************************************************************
773 * HeapUnlock (kernelbase.@)
774 */
775BOOL WINAPI HeapUnlock( HANDLE heap )
776{
777 return RtlUnlockHeap( heap );
778}
779
780
781/***********************************************************************
782 * HeapValidate (kernelbase.@)
783 */
784BOOL WINAPI DECLSPEC_HOTPATCH HeapValidate( HANDLE heap, DWORD flags, LPCVOID ptr )
785{
786 return RtlValidateHeap( heap, flags, ptr );
787}
788
789
790/* undocumented RtlWalkHeap structure */
791
792struct rtl_heap_entry
793{
794 LPVOID lpData;
795 SIZE_T cbData; /* differs from PROCESS_HEAP_ENTRY */
796 BYTE cbOverhead;
797 BYTE iRegionIndex;
798 WORD wFlags; /* value differs from PROCESS_HEAP_ENTRY */
799 union {
800 struct {
801 HANDLE hMem;
802 DWORD dwReserved[3];
803 } Block;
804 struct {
805 DWORD dwCommittedSize;
806 DWORD dwUnCommittedSize;
807 LPVOID lpFirstBlock;
808 LPVOID lpLastBlock;
809 } Region;
810 };
811};
812
813/* rtl_heap_entry flags, names made up */
814
815#define RTL_HEAP_ENTRY_BUSY 0x0001
816#define RTL_HEAP_ENTRY_REGION 0x0002
817#define RTL_HEAP_ENTRY_BLOCK 0x0010
818#define RTL_HEAP_ENTRY_UNCOMMITTED 0x1000
819#define RTL_HEAP_ENTRY_COMMITTED 0x4000
820#define RTL_HEAP_ENTRY_LFH 0x8000
821
822
823/***********************************************************************
824 * HeapWalk (kernelbase.@)
825 */
826BOOL WINAPI DECLSPEC_HOTPATCH HeapWalk( HANDLE heap, PROCESS_HEAP_ENTRY *entry )
827{
828 struct rtl_heap_entry rtl_entry = {0};
829 NTSTATUS status;
830
831 if (!entry) return set_ntstatus( STATUS_INVALID_PARAMETER );
832
833 rtl_entry.lpData = entry->lpData;
834 rtl_entry.cbData = entry->cbData;
835 rtl_entry.cbOverhead = entry->cbOverhead;
836 rtl_entry.iRegionIndex = entry->iRegionIndex;
837
838 if (entry->wFlags & PROCESS_HEAP_ENTRY_BUSY)
839 rtl_entry.wFlags |= RTL_HEAP_ENTRY_BUSY;
840 if (entry->wFlags & PROCESS_HEAP_REGION)
841 rtl_entry.wFlags |= RTL_HEAP_ENTRY_REGION;
842 if (entry->wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE)
843 rtl_entry.wFlags |= RTL_HEAP_ENTRY_UNCOMMITTED;
844 memcpy( &rtl_entry.Region, &entry->Region, sizeof(entry->Region) );
845
846 if (!(status = RtlWalkHeap( heap, &rtl_entry )))
847 {
848 entry->lpData = rtl_entry.lpData;
849 entry->cbData = rtl_entry.cbData;
850 entry->cbOverhead = rtl_entry.cbOverhead;
851 entry->iRegionIndex = rtl_entry.iRegionIndex;
852
853 if (rtl_entry.wFlags & RTL_HEAP_ENTRY_BUSY)
854 entry->wFlags = PROCESS_HEAP_ENTRY_BUSY;
855 else if (rtl_entry.wFlags & RTL_HEAP_ENTRY_REGION)
856 entry->wFlags = PROCESS_HEAP_REGION;
857 else if (rtl_entry.wFlags & RTL_HEAP_ENTRY_UNCOMMITTED)
858 entry->wFlags = PROCESS_HEAP_UNCOMMITTED_RANGE;
859 else
860 entry->wFlags = 0;
861
862 memcpy( &entry->Region, &rtl_entry.Region, sizeof(entry->Region) );
863 }
864
865 return set_ntstatus( status );
866}
867
868
869/***********************************************************************
870 * Global/local heap functions
871 ***********************************************************************/
872
873/* some undocumented flags (names are made up) */
874#define HEAP_ADD_USER_INFO 0x00000100
875
876/* not compatible with windows */
877struct kernelbase_global_data
878{
879 struct mem_entry *mem_entries;
880 struct mem_entry *mem_entries_end;
881};
882
883#define MEM_FLAG_USED 1
884#define MEM_FLAG_MOVEABLE 2
885#define MEM_FLAG_DISCARDABLE 4
886#define MEM_FLAG_DISCARDED 8
887#define MEM_FLAG_DDESHARE 0x8000
888
889struct mem_entry
890{
891 union
892 {
893 struct
894 {
895 WORD flags;
896 BYTE lock;
897 };
898 void *next_free;
899 };
900 void *ptr;
901};
902
903C_ASSERT(sizeof(struct mem_entry) == 2 * sizeof(void *));
904
905#define MAX_MEM_HANDLES 0x10000
906static struct mem_entry *next_free_mem;
907static struct kernelbase_global_data global_data = {0};
908
909static inline struct mem_entry *unsafe_mem_from_HLOCAL( HLOCAL handle )
910{
911 struct mem_entry *mem = CONTAINING_RECORD( *(volatile HANDLE *)&handle, struct mem_entry, ptr );
912 struct kernelbase_global_data *data = &global_data;
913 if (((UINT_PTR)handle & ((sizeof(void *) << 1) - 1)) != sizeof(void *)) return NULL;
914 if (mem < data->mem_entries || mem >= data->mem_entries_end) return NULL;
915 if (!(mem->flags & MEM_FLAG_USED)) return NULL;
916 return mem;
917}
918
919static inline HLOCAL HLOCAL_from_mem( struct mem_entry *mem )
920{
921 if (!mem) return 0;
922 return &mem->ptr;
923}
924
925static inline void *unsafe_ptr_from_HLOCAL( HLOCAL handle )
926{
927 if (((UINT_PTR)handle & ((sizeof(void *) << 1) - 1))) return NULL;
928 return handle;
929}
930
931void init_global_data(void)
932{
933 global_data.mem_entries = VirtualAlloc( NULL, MAX_MEM_HANDLES * sizeof(struct mem_entry), MEM_COMMIT, PAGE_READWRITE );
934 if (!(next_free_mem = global_data.mem_entries)) ERR( "Failed to allocate kernelbase global handle table\n" );
935 global_data.mem_entries_end = global_data.mem_entries + MAX_MEM_HANDLES;
936}
937
938/***********************************************************************
939 * KernelBaseGetGlobalData (kernelbase.@)
940 */
941void *WINAPI KernelBaseGetGlobalData(void)
942{
943 WARN_(globalmem)( "semi-stub!\n" );
944 return &global_data;
945}
946
947
948/***********************************************************************
949 * GlobalAlloc (kernelbase.@)
950 */
951HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalAlloc( UINT flags, SIZE_T size )
952{
953 struct mem_entry *mem;
954 HGLOBAL handle;
955
956 /* LocalAlloc allows a 0-size fixed block, but GlobalAlloc doesn't */
957 if (!(flags & GMEM_MOVEABLE) && !size) size = 1;
958
959 handle = LocalAlloc( flags, size );
960
961 if ((mem = unsafe_mem_from_HLOCAL( handle )) && (flags & GMEM_DDESHARE))
962 mem->flags |= MEM_FLAG_DDESHARE;
963
964 return handle;
965}
966
967
968/***********************************************************************
969 * GlobalFree (kernelbase.@)
970 */
971HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalFree( HLOCAL handle )
972{
973 return LocalFree( handle );
974}
975
976
977/***********************************************************************
978 * LocalAlloc (kernelbase.@)
979 */
980HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size )
981{
982 DWORD heap_flags = 0x200 | HEAP_ADD_USER_INFO;
983 HANDLE heap = GetProcessHeap();
984 struct mem_entry *mem;
985 HLOCAL handle;
986 void *ptr;
987
988 TRACE_(globalmem)( "flags %#x, size %#Ix\n", flags, size );
989
990 if (flags & LMEM_ZEROINIT) heap_flags |= HEAP_ZERO_MEMORY;
991
992 if (!(flags & LMEM_MOVEABLE)) /* pointer */
993 {
994 ptr = HeapAlloc( heap, heap_flags, size );
995 if (ptr) RtlSetUserValueHeap( heap, heap_flags, ptr, ptr );
996 TRACE_(globalmem)( "return %p\n", ptr );
997 return ptr;
998 }
999
1000 RtlLockHeap( heap );
1001 if ((mem = next_free_mem) < global_data.mem_entries || mem >= global_data.mem_entries_end)
1002 mem = NULL;
1003 else
1004 {
1005 if (!mem->next_free) next_free_mem++;
1006 else next_free_mem = mem->next_free;
1007 mem->next_free = NULL;
1008 }
1009 RtlUnlockHeap( heap );
1010
1011 if (!mem) goto failed;
1012 handle = HLOCAL_from_mem( mem );
1013
1014 mem->flags = MEM_FLAG_USED | MEM_FLAG_MOVEABLE;
1015 if (flags & LMEM_DISCARDABLE) mem->flags |= MEM_FLAG_DISCARDABLE;
1016 mem->lock = 0;
1017 mem->ptr = NULL;
1018
1019 if (!size) mem->flags |= MEM_FLAG_DISCARDED;
1020 else
1021 {
1022 if (!(ptr = HeapAlloc( heap, heap_flags, size ))) goto failed;
1023 RtlSetUserValueHeap( heap, heap_flags, ptr, handle );
1024 mem->ptr = ptr;
1025 }
1026
1027 TRACE_(globalmem)( "return handle %p, ptr %p\n", handle, mem->ptr );
1028 return handle;
1029
1030failed:
1031 if (mem) LocalFree( *(volatile HANDLE *)&handle );
1032 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1033 return 0;
1034}
1035
1036
1037/***********************************************************************
1038 * LocalFree (kernelbase.@)
1039 */
1040HLOCAL WINAPI DECLSPEC_HOTPATCH LocalFree( HLOCAL handle )
1041{
1042 HANDLE heap = GetProcessHeap();
1043 struct mem_entry *mem;
1044 HLOCAL ret = handle;
1045 void *ptr;
1046
1047 TRACE_(globalmem)( "handle %p\n", handle );
1048
1049 RtlLockHeap( heap );
1050 if ((ptr = unsafe_ptr_from_HLOCAL( handle )) &&
1051 HeapValidate( heap, HEAP_NO_SERIALIZE, ptr ))
1052 {
1053 if (HeapFree( heap, HEAP_NO_SERIALIZE, ptr )) ret = 0;
1054 }
1055 else if ((mem = unsafe_mem_from_HLOCAL( handle )))
1056 {
1057 if (HeapFree( heap, HEAP_NO_SERIALIZE, mem->ptr )) ret = 0;
1058 mem->ptr = NULL;
1059 mem->next_free = next_free_mem;
1060 next_free_mem = mem;
1061 }
1062 RtlUnlockHeap( heap );
1063
1064 if (ret)
1065 {
1066 WARN_(globalmem)( "invalid handle %p\n", handle );
1067 SetLastError( ERROR_INVALID_HANDLE );
1068 }
1069 return ret;
1070}
1071
1072
1073/***********************************************************************
1074 * LocalLock (kernelbase.@)
1075 */
1076LPVOID WINAPI DECLSPEC_HOTPATCH LocalLock( HLOCAL handle )
1077{
1078 HANDLE heap = GetProcessHeap();
1079 struct mem_entry *mem;
1080 void *ret = NULL;
1081
1082 TRACE_(globalmem)( "handle %p\n", handle );
1083
1084 if (!handle) return NULL;
1085 if ((ret = unsafe_ptr_from_HLOCAL( handle )))
1086 {
1087 __TRY
1088 {
1089 volatile char *p = ret;
1090 *p |= 0;
1091 }
1092 __EXCEPT_PAGE_FAULT
1093 {
1094 return NULL;
1095 }
1096 __ENDTRY
1097 return ret;
1098 }
1099
1100 RtlLockHeap( heap );
1101 if ((mem = unsafe_mem_from_HLOCAL( handle )))
1102 {
1103 if (!(ret = mem->ptr)) SetLastError( ERROR_DISCARDED );
1104 else if (!++mem->lock) mem->lock--;
1105 }
1106 else
1107 {
1108 WARN_(globalmem)( "invalid handle %p\n", handle );
1109 SetLastError( ERROR_INVALID_HANDLE );
1110 }
1111 RtlUnlockHeap( heap );
1112
1113 return ret;
1114}
1115
1116
1117/***********************************************************************
1118 * LocalReAlloc (kernelbase.@)
1119 */
1120HLOCAL WINAPI DECLSPEC_HOTPATCH LocalReAlloc( HLOCAL handle, SIZE_T size, UINT flags )
1121{
1122 DWORD heap_flags = 0x200 | HEAP_ADD_USER_INFO | HEAP_NO_SERIALIZE;
1123 HANDLE heap = GetProcessHeap();
1124 struct mem_entry *mem;
1125 HLOCAL ret = 0;
1126 void *ptr;
1127
1128 TRACE_(globalmem)( "handle %p, size %#Ix, flags %#x\n", handle, size, flags );
1129
1130 if (flags & LMEM_ZEROINIT) heap_flags |= HEAP_ZERO_MEMORY;
1131
1132 RtlLockHeap( heap );
1133 if ((ptr = unsafe_ptr_from_HLOCAL( handle )) &&
1134 HeapValidate( heap, HEAP_NO_SERIALIZE, ptr ))
1135 {
1136 if (flags & LMEM_MODIFY) ret = handle;
1137 else if (flags & LMEM_DISCARDABLE) SetLastError( ERROR_INVALID_PARAMETER );
1138 else
1139 {
1140 if (!(flags & LMEM_MOVEABLE)) heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY;
1141 ret = HeapReAlloc( heap, heap_flags, ptr, size );
1142 if (ret) RtlSetUserValueHeap( heap, heap_flags, ret, ret );
1143 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1144 }
1145 }
1146 else if ((mem = unsafe_mem_from_HLOCAL( handle )))
1147 {
1148 if (flags & LMEM_MODIFY)
1149 {
1150 if (flags & LMEM_DISCARDABLE) mem->flags |= MEM_FLAG_DISCARDABLE;
1151 ret = handle;
1152 }
1153 else if (flags & LMEM_DISCARDABLE) SetLastError( ERROR_INVALID_PARAMETER );
1154 else
1155 {
1156 if (size)
1157 {
1158 if (mem->lock && !(flags & LMEM_MOVEABLE)) heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY;
1159 if (!mem->ptr) ptr = HeapAlloc( heap, heap_flags, size );
1160 else ptr = HeapReAlloc( heap, heap_flags, mem->ptr, size );
1161
1162 if (!ptr) SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1163 else
1164 {
1165 RtlSetUserValueHeap( heap, heap_flags, ptr, handle );
1166 mem->flags &= ~MEM_FLAG_DISCARDED;
1167 mem->ptr = ptr;
1168 ret = handle;
1169 }
1170 }
1171 else if ((flags & LMEM_MOVEABLE) && !mem->lock)
1172 {
1173 HeapFree( heap, heap_flags, mem->ptr );
1174 mem->flags |= MEM_FLAG_DISCARDED;
1175 mem->ptr = NULL;
1176 ret = handle;
1177 }
1178 else SetLastError( ERROR_INVALID_PARAMETER );
1179 }
1180 }
1181 else SetLastError( ERROR_INVALID_HANDLE );
1182 RtlUnlockHeap( heap );
1183
1184 return ret;
1185}
1186
1187
1188/***********************************************************************
1189 * LocalUnlock (kernelbase.@)
1190 */
1191BOOL WINAPI DECLSPEC_HOTPATCH LocalUnlock( HLOCAL handle )
1192{
1193 HANDLE heap = GetProcessHeap();
1194 struct mem_entry *mem;
1195 BOOL ret = FALSE;
1196
1197 TRACE_(globalmem)( "handle %p\n", handle );
1198
1199 if (unsafe_ptr_from_HLOCAL( handle ))
1200 {
1201 SetLastError( ERROR_NOT_LOCKED );
1202 return FALSE;
1203 }
1204
1205 RtlLockHeap( heap );
1206 if ((mem = unsafe_mem_from_HLOCAL( handle )))
1207 {
1208 if (mem->lock)
1209 {
1210 ret = (--mem->lock != 0);
1211 if (!ret) SetLastError( NO_ERROR );
1212 }
1213 else
1214 {
1215 WARN_(globalmem)( "handle %p not locked\n", handle );
1216 SetLastError( ERROR_NOT_LOCKED );
1217 }
1218 }
1219 else
1220 {
1221 WARN_(globalmem)( "invalid handle %p\n", handle );
1222 SetLastError( ERROR_INVALID_HANDLE );
1223 }
1224 RtlUnlockHeap( heap );
1225
1226 return ret;
1227}
1228
1229
1230/***********************************************************************
1231 * Memory resource functions
1232 ***********************************************************************/
1233
1234
1235/***********************************************************************
1236 * CreateMemoryResourceNotification (kernelbase.@)
1237 */
1238HANDLE WINAPI DECLSPEC_HOTPATCH CreateMemoryResourceNotification( MEMORY_RESOURCE_NOTIFICATION_TYPE type )
1239{
1240 HANDLE ret;
1241 UNICODE_STRING nameW;
1242 OBJECT_ATTRIBUTES attr;
1243
1244 switch (type)
1245 {
1246 case LowMemoryResourceNotification:
1247 RtlInitUnicodeString( &nameW, L"\\KernelObjects\\LowMemoryCondition" );
1248 break;
1249 case HighMemoryResourceNotification:
1250 RtlInitUnicodeString( &nameW, L"\\KernelObjects\\HighMemoryCondition" );
1251 break;
1252 default:
1253 SetLastError( ERROR_INVALID_PARAMETER );
1254 return 0;
1255 }
1256
1257 InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
1258 if (!set_ntstatus( NtOpenEvent( &ret, EVENT_ALL_ACCESS, &attr ))) return 0;
1259 return ret;
1260}
1261
1262/***********************************************************************
1263 * QueryMemoryResourceNotification (kernelbase.@)
1264 */
1265BOOL WINAPI DECLSPEC_HOTPATCH QueryMemoryResourceNotification( HANDLE handle, BOOL *state )
1266{
1267 switch (WaitForSingleObject( handle, 0 ))
1268 {
1269 case WAIT_OBJECT_0:
1270 *state = TRUE;
1271 return TRUE;
1272 case WAIT_TIMEOUT:
1273 *state = FALSE;
1274 return TRUE;
1275 }
1276 SetLastError( ERROR_INVALID_PARAMETER );
1277 return FALSE;
1278}
1279
1280
1281/***********************************************************************
1282 * Physical memory functions
1283 ***********************************************************************/
1284
1285
1286/***********************************************************************
1287 * AllocateUserPhysicalPages (kernelbase.@)
1288 */
1289BOOL WINAPI DECLSPEC_HOTPATCH AllocateUserPhysicalPages( HANDLE process, ULONG_PTR *pages,
1290 ULONG_PTR *userarray )
1291{
1292 FIXME( "stub: %p %p %p\n", process, pages, userarray );
1293 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1294 return FALSE;
1295}
1296
1297
1298/***********************************************************************
1299 * FreeUserPhysicalPages (kernelbase.@)
1300 */
1301BOOL WINAPI DECLSPEC_HOTPATCH FreeUserPhysicalPages( HANDLE process, ULONG_PTR *pages,
1302 ULONG_PTR *userarray )
1303{
1304 FIXME( "stub: %p %p %p\n", process, pages, userarray );
1305 *pages = 0;
1306 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1307 return FALSE;
1308}
1309
1310
1311/***********************************************************************
1312 * GetPhysicallyInstalledSystemMemory (kernelbase.@)
1313 */
1314BOOL WINAPI DECLSPEC_HOTPATCH GetPhysicallyInstalledSystemMemory( ULONGLONG *memory )
1315{
1316 MEMORYSTATUSEX status;
1317
1318 if (!memory)
1319 {
1320 SetLastError( ERROR_INVALID_PARAMETER );
1321 return FALSE;
1322 }
1323 status.dwLength = sizeof(status);
1324 GlobalMemoryStatusEx( &status );
1325 *memory = status.ullTotalPhys / 1024;
1326 return TRUE;
1327}
1328
1329
1330/***********************************************************************
1331 * GlobalMemoryStatusEx (kernelbase.@)
1332 */
1333BOOL WINAPI DECLSPEC_HOTPATCH GlobalMemoryStatusEx( MEMORYSTATUSEX *status )
1334{
1335 static MEMORYSTATUSEX cached_status;
1336 static DWORD last_check;
1337 SYSTEM_BASIC_INFORMATION basic_info;
1338 SYSTEM_PERFORMANCE_INFORMATION perf_info;
1339 VM_COUNTERS_EX vmc;
1340
1341 if (status->dwLength != sizeof(*status))
1342 {
1343 SetLastError( ERROR_INVALID_PARAMETER );
1344 return FALSE;
1345 }
1346 if ((NtGetTickCount() - last_check) < 1000)
1347 {
1348 *status = cached_status;
1349 return TRUE;
1350 }
1351 last_check = NtGetTickCount();
1352
1353 if (!set_ntstatus( NtQuerySystemInformation( SystemBasicInformation,
1354 &basic_info, sizeof(basic_info), NULL )) ||
1355 !set_ntstatus( NtQuerySystemInformation( SystemPerformanceInformation,
1356 &perf_info, sizeof(perf_info), NULL)) ||
1357 !set_ntstatus( NtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters,
1358 &vmc, sizeof(vmc), NULL )))
1359 return FALSE;
1360
1361 status->dwMemoryLoad = 0;
1362 status->ullTotalPhys = basic_info.MmNumberOfPhysicalPages;
1363 status->ullAvailPhys = perf_info.AvailablePages;
1364 status->ullTotalPageFile = perf_info.TotalCommitLimit;
1365 status->ullAvailPageFile = status->ullTotalPageFile - perf_info.TotalCommittedPages;
1366 status->ullTotalVirtual = (ULONG_PTR)basic_info.HighestUserAddress - (ULONG_PTR)basic_info.LowestUserAddress + 1;
1367 status->ullAvailVirtual = status->ullTotalVirtual - (ULONGLONG)vmc.WorkingSetSize /* approximate */;
1368 status->ullAvailExtendedVirtual = 0;
1369
1370 status->ullTotalPhys *= basic_info.PageSize;
1371 status->ullAvailPhys *= basic_info.PageSize;
1372 status->ullTotalPageFile *= basic_info.PageSize;
1373 status->ullAvailPageFile *= basic_info.PageSize;
1374
1375 if (status->ullTotalPhys)
1376 status->dwMemoryLoad = (status->ullTotalPhys - status->ullAvailPhys) / (status->ullTotalPhys / 100);
1377
1378 TRACE_(virtual)( "MemoryLoad %lu, TotalPhys %I64u, AvailPhys %I64u, TotalPageFile %I64u, "
1379 "AvailPageFile %I64u, TotalVirtual %I64u, AvailVirtual %I64u\n",
1380 status->dwMemoryLoad, status->ullTotalPhys, status->ullAvailPhys, status->ullTotalPageFile,
1381 status->ullAvailPageFile, status->ullTotalVirtual, status->ullAvailVirtual );
1382
1383 cached_status = *status;
1384 return TRUE;
1385}
1386
1387
1388/***********************************************************************
1389 * MapUserPhysicalPages (kernelbase.@)
1390 */
1391BOOL WINAPI DECLSPEC_HOTPATCH MapUserPhysicalPages( void *addr, ULONG_PTR page_count, ULONG_PTR *pages )
1392{
1393 FIXME( "stub: %p %Iu %p\n", addr, page_count, pages );
1394 *pages = 0;
1395 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1396 return FALSE;
1397}
1398
1399
1400/***********************************************************************
1401 * NUMA functions
1402 ***********************************************************************/
1403
1404
1405/***********************************************************************
1406 * AllocateUserPhysicalPagesNuma (kernelbase.@)
1407 */
1408BOOL WINAPI DECLSPEC_HOTPATCH AllocateUserPhysicalPagesNuma( HANDLE process, ULONG_PTR *pages,
1409 ULONG_PTR *userarray, DWORD node )
1410{
1411 if (node) FIXME( "Ignoring preferred node %lu\n", node );
1412 return AllocateUserPhysicalPages( process, pages, userarray );
1413}
1414
1415
1416/***********************************************************************
1417 * CreateFileMappingNumaW (kernelbase.@)
1418 */
1419HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileMappingNumaW( HANDLE file, LPSECURITY_ATTRIBUTES sa,
1420 DWORD protect, DWORD size_high, DWORD size_low,
1421 LPCWSTR name, DWORD node )
1422{
1423 if (node) FIXME( "Ignoring preferred node %lu\n", node );
1424 return CreateFileMappingW( file, sa, protect, size_high, size_low, name );
1425}
1426
1427
1428/***********************************************************************
1429 * GetLogicalProcessorInformation (kernelbase.@)
1430 */
1431BOOL WINAPI DECLSPEC_HOTPATCH GetLogicalProcessorInformation( SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buffer,
1432 DWORD *len )
1433{
1434 NTSTATUS status;
1435
1436 if (!len)
1437 {
1438 SetLastError( ERROR_INVALID_PARAMETER );
1439 return FALSE;
1440 }
1441 status = NtQuerySystemInformation( SystemLogicalProcessorInformation, buffer, *len, len );
1442 if (status == STATUS_INFO_LENGTH_MISMATCH) status = STATUS_BUFFER_TOO_SMALL;
1443 return set_ntstatus( status );
1444}
1445
1446
1447/***********************************************************************
1448 * GetLogicalProcessorInformationEx (kernelbase.@)
1449 */
1450BOOL WINAPI DECLSPEC_HOTPATCH GetLogicalProcessorInformationEx( LOGICAL_PROCESSOR_RELATIONSHIP relationship,
1451 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, DWORD *len )
1452{
1453 NTSTATUS status;
1454
1455 if (!len)
1456 {
1457 SetLastError( ERROR_INVALID_PARAMETER );
1458 return FALSE;
1459 }
1460 status = NtQuerySystemInformationEx( SystemLogicalProcessorInformationEx, &relationship,
1461 sizeof(relationship), buffer, *len, len );
1462 if (status == STATUS_INFO_LENGTH_MISMATCH) status = STATUS_BUFFER_TOO_SMALL;
1463 return set_ntstatus( status );
1464}
1465
1466
1467/***********************************************************************
1468 * GetSystemCpuSetInformation (kernelbase.@)
1469 */
1470BOOL WINAPI GetSystemCpuSetInformation(SYSTEM_CPU_SET_INFORMATION *info, ULONG buffer_length, ULONG *return_length,
1471 HANDLE process, ULONG flags)
1472{
1473 if (flags)
1474 FIXME("Unsupported flags %#lx.\n", flags);
1475
1476 *return_length = 0;
1477
1478 return set_ntstatus( NtQuerySystemInformationEx( SystemCpuSetInformation, &process, sizeof(process), info,
1479 buffer_length, return_length ));
1480}
1481
1482
1483/***********************************************************************
1484 * SetThreadSelectedCpuSets (kernelbase.@)
1485 */
1486BOOL WINAPI SetThreadSelectedCpuSets(HANDLE thread, const ULONG *cpu_set_ids, ULONG count)
1487{
1488 FIXME( "thread %p, cpu_set_ids %p, count %lu stub.\n", thread, cpu_set_ids, count );
1489
1490 return TRUE;
1491}
1492
1493
1494/***********************************************************************
1495 * SetProcessDefaultCpuSets (kernelbase.@)
1496 */
1497BOOL WINAPI SetProcessDefaultCpuSets(HANDLE process, const ULONG *cpu_set_ids, ULONG count)
1498{
1499 FIXME( "process %p, cpu_set_ids %p, count %lu stub.\n", process, cpu_set_ids, count );
1500
1501 return TRUE;
1502}
1503
1504
1505/**********************************************************************
1506 * GetNumaHighestNodeNumber (kernelbase.@)
1507 */
1508BOOL WINAPI DECLSPEC_HOTPATCH GetNumaHighestNodeNumber( ULONG *node )
1509{
1510 FIXME( "semi-stub: %p\n", node );
1511 *node = 0;
1512 return TRUE;
1513}
1514
1515
1516/**********************************************************************
1517 * GetNumaNodeProcessorMaskEx (kernelbase.@)
1518 */
1519BOOL WINAPI DECLSPEC_HOTPATCH GetNumaNodeProcessorMaskEx( USHORT node, GROUP_AFFINITY *mask )
1520{
1521 FIXME( "stub: %hu %p\n", node, mask );
1522 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1523 return FALSE;
1524}
1525
1526
1527/***********************************************************************
1528 * GetNumaProximityNodeEx (kernelbase.@)
1529 */
1530BOOL WINAPI DECLSPEC_HOTPATCH GetNumaProximityNodeEx( ULONG proximity_id, USHORT *node )
1531{
1532 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1533 return FALSE;
1534}
1535
1536
1537/***********************************************************************
1538 * MapViewOfFileExNuma (kernelbase.@)
1539 */
1540LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFileExNuma( HANDLE handle, DWORD access, DWORD offset_high,
1541 DWORD offset_low, SIZE_T count, LPVOID addr,
1542 DWORD node )
1543{
1544 if (node) FIXME( "Ignoring preferred node %lu\n", node );
1545 return MapViewOfFileEx( handle, access, offset_high, offset_low, count, addr );
1546}
1547
1548
1549/***********************************************************************
1550 * VirtualAllocExNuma (kernelbase.@)
1551 */
1552LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAllocExNuma( HANDLE process, void *addr, SIZE_T size,
1553 DWORD type, DWORD protect, DWORD node )
1554{
1555 if (node) FIXME( "Ignoring preferred node %lu\n", node );
1556 return VirtualAllocEx( process, addr, size, type, protect );
1557}
1558
1559
1560/***********************************************************************
1561 * QueryVirtualMemoryInformation (kernelbase.@)
1562 */
1563BOOL WINAPI DECLSPEC_HOTPATCH QueryVirtualMemoryInformation( HANDLE process, const void *addr,
1564 WIN32_MEMORY_INFORMATION_CLASS info_class, void *info, SIZE_T size, SIZE_T *ret_size)
1565{
1566 switch (info_class)
1567 {
1568 case MemoryRegionInfo:
1569 return set_ntstatus( NtQueryVirtualMemory( process, addr, MemoryRegionInformation, info, size, ret_size ));
1570 default:
1571 FIXME("Unsupported info class %u.\n", info_class);
1572 return FALSE;
1573 }
1574}
1575
1576
1577/***********************************************************************
1578 * CPU functions
1579 ***********************************************************************/
1580
1581
1582/***********************************************************************
1583 * InitializeContext2 (kernelbase.@)
1584 */
1585BOOL WINAPI InitializeContext2( void *buffer, DWORD context_flags, CONTEXT **context, DWORD *length,
1586 ULONG64 compaction_mask )
1587{
1588 ULONG orig_length;
1589 NTSTATUS status;
1590
1591 TRACE( "buffer %p, context_flags %#lx, context %p, ret_length %p, compaction_mask %s.\n",
1592 buffer, context_flags, context, length, wine_dbgstr_longlong(compaction_mask) );
1593
1594 orig_length = *length;
1595
1596 if ((status = RtlGetExtendedContextLength2( context_flags, length, compaction_mask )))
1597 {
1598 if (status == STATUS_NOT_SUPPORTED && context_flags & 0x40)
1599 {
1600 context_flags &= ~0x40;
1601 status = RtlGetExtendedContextLength2( context_flags, length, compaction_mask );
1602 }
1603
1604 if (status)
1605 return set_ntstatus( status );
1606 }
1607
1608 if (!buffer || orig_length < *length)
1609 {
1610 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1611 return FALSE;
1612 }
1613
1614 if ((status = RtlInitializeExtendedContext2( buffer, context_flags, (CONTEXT_EX **)context, compaction_mask )))
1615 return set_ntstatus( status );
1616
1617 *context = (CONTEXT *)((BYTE *)*context + (*(CONTEXT_EX **)context)->Legacy.Offset);
1618
1619 return TRUE;
1620}
1621
1622/***********************************************************************
1623 * InitializeContext (kernelbase.@)
1624 */
1625BOOL WINAPI InitializeContext( void *buffer, DWORD context_flags, CONTEXT **context, DWORD *length )
1626{
1627 return InitializeContext2( buffer, context_flags, context, length, ~(ULONG64)0 );
1628}
1629
1630/***********************************************************************
1631 * CopyContext (kernelbase.@)
1632 */
1633BOOL WINAPI CopyContext( CONTEXT *dst, DWORD context_flags, CONTEXT *src )
1634{
1635 return set_ntstatus( RtlCopyContext( dst, context_flags, src ));
1636}
1637
1638
1639#if defined(__x86_64__)
1640
1641/***********************************************************************
1642 * GetEnabledXStateFeatures (kernelbase.@)
1643 */
1644DWORD64 WINAPI GetEnabledXStateFeatures(void)
1645{
1646 TRACE( "\n" );
1647 return RtlGetEnabledExtendedFeatures( ~(ULONG64)0 );
1648}
1649
1650/***********************************************************************
1651 * LocateXStateFeature (kernelbase.@)
1652 */
1653void * WINAPI LocateXStateFeature( CONTEXT *context, DWORD feature_id, DWORD *length )
1654{
1655 if (!(context->ContextFlags & CONTEXT_AMD64))
1656 return NULL;
1657
1658 if (feature_id >= 2)
1659 return ((context->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
1660 ? RtlLocateExtendedFeature( (CONTEXT_EX *)(context + 1), feature_id, length ) : NULL;
1661
1662 if (feature_id == 1)
1663 {
1664 if (length)
1665 *length = sizeof(M128A) * 16;
1666
1667 return &context->FltSave.XmmRegisters;
1668 }
1669
1670 if (length)
1671 *length = offsetof(XSAVE_FORMAT, XmmRegisters);
1672
1673 return &context->FltSave;
1674}
1675
1676/***********************************************************************
1677 * SetXStateFeaturesMask (kernelbase.@)
1678 */
1679BOOL WINAPI SetXStateFeaturesMask( CONTEXT *context, DWORD64 feature_mask )
1680{
1681 if (!(context->ContextFlags & CONTEXT_AMD64))
1682 return FALSE;
1683
1684 if (feature_mask & 0x3)
1685 context->ContextFlags |= CONTEXT_FLOATING_POINT;
1686
1687 if ((context->ContextFlags & CONTEXT_XSTATE) != CONTEXT_XSTATE)
1688 return !(feature_mask & ~(DWORD64)3);
1689
1690 RtlSetExtendedFeaturesMask( (CONTEXT_EX *)(context + 1), feature_mask );
1691 return TRUE;
1692}
1693
1694/***********************************************************************
1695 * GetXStateFeaturesMask (kernelbase.@)
1696 */
1697BOOL WINAPI GetXStateFeaturesMask( CONTEXT *context, DWORD64 *feature_mask )
1698{
1699 if (!(context->ContextFlags & CONTEXT_AMD64))
1700 return FALSE;
1701
1702 *feature_mask = (context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT
1703 ? 3 : 0;
1704
1705 if ((context->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
1706 *feature_mask |= RtlGetExtendedFeaturesMask( (CONTEXT_EX *)(context + 1) );
1707
1708 return TRUE;
1709}
1710
1711#elif defined(__i386__)
1712
1713/***********************************************************************
1714 * GetEnabledXStateFeatures (kernelbase.@)
1715 */
1716DWORD64 WINAPI GetEnabledXStateFeatures(void)
1717{
1718 TRACE( "\n" );
1719 return RtlGetEnabledExtendedFeatures( ~(ULONG64)0 );
1720}
1721
1722/***********************************************************************
1723 * LocateXStateFeature (kernelbase.@)
1724 */
1725void * WINAPI LocateXStateFeature( CONTEXT *context, DWORD feature_id, DWORD *length )
1726{
1727 if (!(context->ContextFlags & CONTEXT_i386))
1728 return NULL;
1729
1730 if (feature_id >= 2)
1731 return ((context->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
1732 ? RtlLocateExtendedFeature( (CONTEXT_EX *)(context + 1), feature_id, length ) : NULL;
1733
1734 if (feature_id == 1)
1735 {
1736 if (length)
1737 *length = sizeof(M128A) * 8;
1738
1739 return (BYTE *)&context->ExtendedRegisters + offsetof(XSAVE_FORMAT, XmmRegisters);
1740 }
1741
1742 if (length)
1743 *length = offsetof(XSAVE_FORMAT, XmmRegisters);
1744
1745 return &context->ExtendedRegisters;
1746}
1747
1748/***********************************************************************
1749 * SetXStateFeaturesMask (kernelbase.@)
1750 */
1751BOOL WINAPI SetXStateFeaturesMask( CONTEXT *context, DWORD64 feature_mask )
1752{
1753 if (!(context->ContextFlags & CONTEXT_i386))
1754 return FALSE;
1755
1756 if (feature_mask & 0x3)
1757 context->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
1758
1759 if ((context->ContextFlags & CONTEXT_XSTATE) != CONTEXT_XSTATE)
1760 return !(feature_mask & ~(DWORD64)3);
1761
1762 RtlSetExtendedFeaturesMask( (CONTEXT_EX *)(context + 1), feature_mask );
1763 return TRUE;
1764}
1765
1766/***********************************************************************
1767 * GetXStateFeaturesMask (kernelbase.@)
1768 */
1769BOOL WINAPI GetXStateFeaturesMask( CONTEXT *context, DWORD64 *feature_mask )
1770{
1771 if (!(context->ContextFlags & CONTEXT_i386))
1772 return FALSE;
1773
1774 *feature_mask = (context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS
1775 ? 3 : 0;
1776
1777 if ((context->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
1778 *feature_mask |= RtlGetExtendedFeaturesMask( (CONTEXT_EX *)(context + 1) );
1779
1780 return TRUE;
1781}
1782#endif
1783
1784/***********************************************************************
1785 * Firmware functions
1786 ***********************************************************************/
1787
1788static UINT get_firmware_table( DWORD provider, SYSTEM_FIRMWARE_TABLE_ACTION action, DWORD id,
1789 void *buffer, DWORD size )
1790{
1791 SYSTEM_FIRMWARE_TABLE_INFORMATION *info;
1792 ULONG buffer_size = offsetof( SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer ) + size;
1793 NTSTATUS status;
1794
1795 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, buffer_size )))
1796 {
1797 SetLastError( ERROR_OUTOFMEMORY );
1798 return 0;
1799 }
1800
1801 info->ProviderSignature = provider;
1802 info->Action = action;
1803 info->TableID = id;
1804
1805 status = NtQuerySystemInformation( SystemFirmwareTableInformation, info, buffer_size, &buffer_size );
1806 set_ntstatus(status);
1807 buffer_size -= offsetof( SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer );
1808 if (buffer_size <= size) memcpy( buffer, info->TableBuffer, buffer_size );
1809
1810 HeapFree( GetProcessHeap(), 0, info );
1811 return NT_SUCCESS(status) || status == STATUS_BUFFER_TOO_SMALL ? buffer_size : 0;
1812}
1813
1814/***********************************************************************
1815 * EnumSystemFirmwareTables (kernelbase.@)
1816 */
1817UINT WINAPI EnumSystemFirmwareTables( DWORD provider, void *buffer, DWORD size )
1818{
1819 TRACE( "(0x%08lx, %p, %ld)\n", provider, buffer, size );
1820
1821 return get_firmware_table( provider, SystemFirmwareTable_Enumerate, 0, buffer, size );
1822}
1823
1824/***********************************************************************
1825 * GetSystemFirmwareTable (kernelbase.@)
1826 */
1827UINT WINAPI GetSystemFirmwareTable( DWORD provider, DWORD id, void *buffer, DWORD size )
1828{
1829 TRACE( "(0x%08lx, 0x%08lx, %p, %ld)\n", provider, id, buffer, size );
1830
1831 return get_firmware_table( provider, SystemFirmwareTable_Get, id, buffer, size );
1832}