Reactos
at master 1832 lines 60 kB view raw
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, &section, (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, &current_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, &region_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, &region_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}