ntdll: Implement NtCreateDebugObject().
[wine.git] / dlls / kernelbase / memory.c
blob2bfd3893e8e756b55114fe7cce59730a70a2961c
1 /*
2 * Win32 memory management functions
4 * Copyright 1997 Alexandre Julliard
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.
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.
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
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <limits.h>
25 #include <sys/types.h>
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "winternl.h"
35 #include "winerror.h"
36 #include "ddk/wdm.h"
38 #include "kernelbase.h"
39 #include "wine/exception.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(heap);
43 WINE_DECLARE_DEBUG_CHANNEL(virtual);
46 /***********************************************************************
47 * Virtual memory functions
48 ***********************************************************************/
51 /***********************************************************************
52 * FlushViewOfFile (kernelbase.@)
54 BOOL WINAPI DECLSPEC_HOTPATCH FlushViewOfFile( const void *base, SIZE_T size )
56 NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 );
58 if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS;
59 return set_ntstatus( status );
63 /***********************************************************************
64 * GetLargePageMinimum (kernelbase.@)
66 SIZE_T WINAPI GetLargePageMinimum(void)
68 return 2 * 1024 * 1024;
72 /***********************************************************************
73 * GetNativeSystemInfo (kernelbase.@)
75 void WINAPI DECLSPEC_HOTPATCH GetNativeSystemInfo( SYSTEM_INFO *si )
77 GetSystemInfo( si );
78 if (!is_wow64) return;
79 switch (si->u.s.wProcessorArchitecture)
81 case PROCESSOR_ARCHITECTURE_INTEL:
82 si->u.s.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
83 si->dwProcessorType = PROCESSOR_AMD_X8664;
84 break;
85 default:
86 FIXME( "Add the proper information for %d in wow64 mode\n", si->u.s.wProcessorArchitecture );
91 /***********************************************************************
92 * GetSystemInfo (kernelbase.@)
94 void WINAPI DECLSPEC_HOTPATCH GetSystemInfo( SYSTEM_INFO *si )
96 SYSTEM_BASIC_INFORMATION basic_info;
97 SYSTEM_CPU_INFORMATION cpu_info;
99 if (!set_ntstatus( NtQuerySystemInformation( SystemBasicInformation,
100 &basic_info, sizeof(basic_info), NULL )) ||
101 !set_ntstatus( NtQuerySystemInformation( SystemCpuInformation,
102 &cpu_info, sizeof(cpu_info), NULL )))
103 return;
105 si->u.s.wProcessorArchitecture = cpu_info.Architecture;
106 si->u.s.wReserved = 0;
107 si->dwPageSize = basic_info.PageSize;
108 si->lpMinimumApplicationAddress = basic_info.LowestUserAddress;
109 si->lpMaximumApplicationAddress = basic_info.HighestUserAddress;
110 si->dwActiveProcessorMask = basic_info.ActiveProcessorsAffinityMask;
111 si->dwNumberOfProcessors = basic_info.NumberOfProcessors;
112 si->dwAllocationGranularity = basic_info.AllocationGranularity;
113 si->wProcessorLevel = cpu_info.Level;
114 si->wProcessorRevision = cpu_info.Revision;
116 switch (cpu_info.Architecture)
118 case PROCESSOR_ARCHITECTURE_INTEL:
119 switch (cpu_info.Level)
121 case 3: si->dwProcessorType = PROCESSOR_INTEL_386; break;
122 case 4: si->dwProcessorType = PROCESSOR_INTEL_486; break;
123 case 5:
124 case 6: si->dwProcessorType = PROCESSOR_INTEL_PENTIUM; break;
125 default: si->dwProcessorType = PROCESSOR_INTEL_PENTIUM; break;
127 break;
128 case PROCESSOR_ARCHITECTURE_PPC:
129 switch (cpu_info.Level)
131 case 1: si->dwProcessorType = PROCESSOR_PPC_601; break;
132 case 3:
133 case 6: si->dwProcessorType = PROCESSOR_PPC_603; break;
134 case 4: si->dwProcessorType = PROCESSOR_PPC_604; break;
135 case 9: si->dwProcessorType = PROCESSOR_PPC_604; break;
136 case 20: si->dwProcessorType = PROCESSOR_PPC_620; break;
137 default: si->dwProcessorType = 0;
139 break;
140 case PROCESSOR_ARCHITECTURE_AMD64:
141 si->dwProcessorType = PROCESSOR_AMD_X8664;
142 break;
143 case PROCESSOR_ARCHITECTURE_ARM:
144 switch (cpu_info.Level)
146 case 4: si->dwProcessorType = PROCESSOR_ARM_7TDMI; break;
147 default: si->dwProcessorType = PROCESSOR_ARM920;
149 break;
150 case PROCESSOR_ARCHITECTURE_ARM64:
151 si->dwProcessorType = 0;
152 break;
153 default:
154 FIXME( "Unknown processor architecture %x\n", cpu_info.Architecture );
155 si->dwProcessorType = 0;
156 break;
161 /***********************************************************************
162 * GetSystemFileCacheSize (kernelbase.@)
164 BOOL WINAPI DECLSPEC_HOTPATCH GetSystemFileCacheSize( SIZE_T *mincache, SIZE_T *maxcache, DWORD *flags )
166 FIXME( "stub: %p %p %p\n", mincache, maxcache, flags );
167 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
168 return FALSE;
172 /***********************************************************************
173 * GetWriteWatch (kernelbase.@)
175 UINT WINAPI DECLSPEC_HOTPATCH GetWriteWatch( DWORD flags, void *base, SIZE_T size, void **addresses,
176 ULONG_PTR *count, ULONG *granularity )
178 if (!set_ntstatus( NtGetWriteWatch( GetCurrentProcess(), flags, base, size,
179 addresses, count, granularity )))
180 return ~0u;
181 return 0;
185 /***********************************************************************
186 * MapViewOfFile (kernelbase.@)
188 LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFile( HANDLE mapping, DWORD access, DWORD offset_high,
189 DWORD offset_low, SIZE_T count )
191 return MapViewOfFileEx( mapping, access, offset_high, offset_low, count, NULL );
195 /***********************************************************************
196 * MapViewOfFileEx (kernelbase.@)
198 LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFileEx( HANDLE handle, DWORD access, DWORD offset_high,
199 DWORD offset_low, SIZE_T count, LPVOID addr )
201 NTSTATUS status;
202 LARGE_INTEGER offset;
203 ULONG protect;
204 BOOL exec;
206 offset.u.LowPart = offset_low;
207 offset.u.HighPart = offset_high;
209 exec = access & FILE_MAP_EXECUTE;
210 access &= ~FILE_MAP_EXECUTE;
212 if (access == FILE_MAP_COPY)
213 protect = exec ? PAGE_EXECUTE_WRITECOPY : PAGE_WRITECOPY;
214 else if (access & FILE_MAP_WRITE)
215 protect = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
216 else if (access & FILE_MAP_READ)
217 protect = exec ? PAGE_EXECUTE_READ : PAGE_READONLY;
218 else protect = PAGE_NOACCESS;
220 if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, &offset,
221 &count, ViewShare, 0, protect )) < 0)
223 SetLastError( RtlNtStatusToDosError(status) );
224 addr = NULL;
226 return addr;
230 /***********************************************************************
231 * ReadProcessMemory (kernelbase.@)
233 BOOL WINAPI DECLSPEC_HOTPATCH ReadProcessMemory( HANDLE process, const void *addr, void *buffer,
234 SIZE_T size, SIZE_T *bytes_read )
236 return set_ntstatus( NtReadVirtualMemory( process, addr, buffer, size, bytes_read ));
240 /***********************************************************************
241 * ResetWriteWatch (kernelbase.@)
243 UINT WINAPI DECLSPEC_HOTPATCH ResetWriteWatch( void *base, SIZE_T size )
245 if (!set_ntstatus( NtResetWriteWatch( GetCurrentProcess(), base, size )))
246 return ~0u;
247 return 0;
251 /***********************************************************************
252 * SetSystemFileCacheSize (kernelbase.@)
254 BOOL WINAPI DECLSPEC_HOTPATCH SetSystemFileCacheSize( SIZE_T mincache, SIZE_T maxcache, DWORD flags )
256 FIXME( "stub: %ld %ld %d\n", mincache, maxcache, flags );
257 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
258 return FALSE;
262 /***********************************************************************
263 * UnmapViewOfFile (kernelbase.@)
265 BOOL WINAPI DECLSPEC_HOTPATCH UnmapViewOfFile( const void *addr )
267 if (GetVersion() & 0x80000000)
269 MEMORY_BASIC_INFORMATION info;
270 if (!VirtualQuery( addr, &info, sizeof(info) ) || info.AllocationBase != addr)
272 SetLastError( ERROR_INVALID_ADDRESS );
273 return FALSE;
276 return set_ntstatus( NtUnmapViewOfSection( GetCurrentProcess(), (void *)addr ));
280 /***********************************************************************
281 * VirtualAlloc (kernelbase.@)
283 LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAlloc( void *addr, SIZE_T size, DWORD type, DWORD protect )
285 return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect );
289 /***********************************************************************
290 * VirtualAllocEx (kernelbase.@)
292 LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAllocEx( HANDLE process, void *addr, SIZE_T size,
293 DWORD type, DWORD protect )
295 LPVOID ret = addr;
297 if (!set_ntstatus( NtAllocateVirtualMemory( process, &ret, 0, &size, type, protect ))) return NULL;
298 return ret;
302 /***********************************************************************
303 * VirtualAlloc2 (kernelbase.@)
305 LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAlloc2( HANDLE process, void *addr, SIZE_T size,
306 DWORD type, DWORD protect,
307 MEM_EXTENDED_PARAMETER *parameters, ULONG count )
309 LPVOID ret = addr;
311 if (!set_ntstatus( NtAllocateVirtualMemoryEx( process, &ret, &size, type, protect, parameters, count )))
312 return NULL;
313 return ret;
317 /***********************************************************************
318 * VirtualFree (kernelbase.@)
320 BOOL WINAPI DECLSPEC_HOTPATCH VirtualFree( void *addr, SIZE_T size, DWORD type )
322 return VirtualFreeEx( GetCurrentProcess(), addr, size, type );
326 /***********************************************************************
327 * VirtualFreeEx (kernelbase.@)
329 BOOL WINAPI DECLSPEC_HOTPATCH VirtualFreeEx( HANDLE process, void *addr, SIZE_T size, DWORD type )
331 return set_ntstatus( NtFreeVirtualMemory( process, &addr, &size, type ));
335 /***********************************************************************
336 * VirtualLock (kernelbase.@)
338 BOOL WINAPI DECLSPEC_HOTPATCH VirtualLock( void *addr, SIZE_T size )
340 return set_ntstatus( NtLockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 ));
344 /***********************************************************************
345 * VirtualProtect (kernelbase.@)
347 BOOL WINAPI DECLSPEC_HOTPATCH VirtualProtect( void *addr, SIZE_T size, DWORD new_prot, DWORD *old_prot )
349 return VirtualProtectEx( GetCurrentProcess(), addr, size, new_prot, old_prot );
353 /***********************************************************************
354 * VirtualProtectEx (kernelbase.@)
356 BOOL WINAPI DECLSPEC_HOTPATCH VirtualProtectEx( HANDLE process, void *addr, SIZE_T size,
357 DWORD new_prot, DWORD *old_prot )
359 DWORD prot;
361 /* Win9x allows passing NULL as old_prot while this fails on NT */
362 if (!old_prot && (GetVersion() & 0x80000000)) old_prot = &prot;
363 return set_ntstatus( NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot ));
367 /***********************************************************************
368 * VirtualQuery (kernelbase.@)
370 SIZE_T WINAPI DECLSPEC_HOTPATCH VirtualQuery( LPCVOID addr, PMEMORY_BASIC_INFORMATION info, SIZE_T len )
372 return VirtualQueryEx( GetCurrentProcess(), addr, info, len );
376 /***********************************************************************
377 * VirtualQueryEx (kernelbase.@)
379 SIZE_T WINAPI DECLSPEC_HOTPATCH VirtualQueryEx( HANDLE process, LPCVOID addr,
380 PMEMORY_BASIC_INFORMATION info, SIZE_T len )
382 SIZE_T ret;
384 if (!set_ntstatus( NtQueryVirtualMemory( process, addr, MemoryBasicInformation, info, len, &ret )))
385 return 0;
386 return ret;
390 /***********************************************************************
391 * VirtualUnlock (kernelbase.@)
393 BOOL WINAPI DECLSPEC_HOTPATCH VirtualUnlock( void *addr, SIZE_T size )
395 return set_ntstatus( NtUnlockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 ));
399 /***********************************************************************
400 * WriteProcessMemory (kernelbase.@)
402 BOOL WINAPI DECLSPEC_HOTPATCH WriteProcessMemory( HANDLE process, void *addr, const void *buffer,
403 SIZE_T size, SIZE_T *bytes_written )
405 return set_ntstatus( NtWriteVirtualMemory( process, addr, buffer, size, bytes_written ));
409 /* IsBadStringPtrA replacement for kernelbase, to catch exception in debug traces. */
410 BOOL WINAPI IsBadStringPtrA( LPCSTR str, UINT_PTR max )
412 if (!str) return TRUE;
413 __TRY
415 volatile const char *p = str;
416 while (p != str + max) if (!*p++) break;
418 __EXCEPT_PAGE_FAULT
420 return TRUE;
422 __ENDTRY
423 return FALSE;
427 /* IsBadStringPtrW replacement for kernelbase, to catch exception in debug traces. */
428 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT_PTR max )
430 if (!str) return TRUE;
431 __TRY
433 volatile const WCHAR *p = str;
434 while (p != str + max) if (!*p++) break;
436 __EXCEPT_PAGE_FAULT
438 return TRUE;
440 __ENDTRY
441 return FALSE;
445 /***********************************************************************
446 * Heap functions
447 ***********************************************************************/
450 /***********************************************************************
451 * HeapCompact (kernelbase.@)
453 SIZE_T WINAPI DECLSPEC_HOTPATCH HeapCompact( HANDLE heap, DWORD flags )
455 return RtlCompactHeap( heap, flags );
459 /***********************************************************************
460 * HeapCreate (kernelbase.@)
462 HANDLE WINAPI DECLSPEC_HOTPATCH HeapCreate( DWORD flags, SIZE_T init_size, SIZE_T max_size )
464 HANDLE ret = RtlCreateHeap( flags, NULL, max_size, init_size, NULL, NULL );
465 if (!ret) SetLastError( ERROR_NOT_ENOUGH_MEMORY );
466 return ret;
470 /***********************************************************************
471 * HeapDestroy (kernelbase.@)
473 BOOL WINAPI DECLSPEC_HOTPATCH HeapDestroy( HANDLE heap )
475 if (!RtlDestroyHeap( heap )) return TRUE;
476 SetLastError( ERROR_INVALID_HANDLE );
477 return FALSE;
481 /***********************************************************************
482 * HeapLock (kernelbase.@)
484 BOOL WINAPI DECLSPEC_HOTPATCH HeapLock( HANDLE heap )
486 return RtlLockHeap( heap );
490 /***********************************************************************
491 * HeapQueryInformation (kernelbase.@)
493 BOOL WINAPI HeapQueryInformation( HANDLE heap, HEAP_INFORMATION_CLASS info_class,
494 PVOID info, SIZE_T size, PSIZE_T size_out )
496 return set_ntstatus( RtlQueryHeapInformation( heap, info_class, info, size, size_out ));
500 /***********************************************************************
501 * HeapSetInformation (kernelbase.@)
503 BOOL WINAPI HeapSetInformation( HANDLE heap, HEAP_INFORMATION_CLASS infoclass, PVOID info, SIZE_T size )
505 return set_ntstatus( RtlSetHeapInformation( heap, infoclass, info, size ));
509 /***********************************************************************
510 * HeapUnlock (kernelbase.@)
512 BOOL WINAPI HeapUnlock( HANDLE heap )
514 return RtlUnlockHeap( heap );
518 /***********************************************************************
519 * HeapValidate (kernelbase.@)
521 BOOL WINAPI DECLSPEC_HOTPATCH HeapValidate( HANDLE heap, DWORD flags, LPCVOID ptr )
523 return RtlValidateHeap( heap, flags, ptr );
527 /***********************************************************************
528 * HeapWalk (kernelbase.@)
530 BOOL WINAPI DECLSPEC_HOTPATCH HeapWalk( HANDLE heap, PROCESS_HEAP_ENTRY *entry )
532 return set_ntstatus( RtlWalkHeap( heap, entry ));
536 /***********************************************************************
537 * Global/local heap functions
538 ***********************************************************************/
540 #include "pshpack1.h"
542 struct local_header
544 WORD magic;
545 void *ptr;
546 BYTE flags;
547 BYTE lock;
550 #include "poppack.h"
552 #define MAGIC_LOCAL_USED 0x5342
553 /* align the storage needed for the HLOCAL on an 8-byte boundary thus
554 * LocalAlloc/LocalReAlloc'ing with LMEM_MOVEABLE of memory with
555 * size = 8*k, where k=1,2,3,... allocs exactly the given size.
556 * The Minolta DiMAGE Image Viewer heavily relies on this, corrupting
557 * the output jpeg's > 1 MB if not */
558 #define HLOCAL_STORAGE (sizeof(HLOCAL) * 2)
560 static inline struct local_header *get_header( HLOCAL hmem )
562 return (struct local_header *)((char *)hmem - 2);
565 static inline HLOCAL get_handle( struct local_header *header )
567 return &header->ptr;
570 static inline BOOL is_pointer( HLOCAL hmem )
572 return !((ULONG_PTR)hmem & 2);
575 /***********************************************************************
576 * GlobalAlloc (kernelbase.@)
578 HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalAlloc( UINT flags, SIZE_T size )
580 /* mask out obsolete flags */
581 flags &= ~(GMEM_NOCOMPACT | GMEM_NOT_BANKED | GMEM_NOTIFY);
583 /* LocalAlloc allows a 0-size fixed block, but GlobalAlloc doesn't */
584 if (!(flags & GMEM_MOVEABLE) && !size) size = 1;
586 return LocalAlloc( flags, size );
590 /***********************************************************************
591 * GlobalFree (kernelbase.@)
593 HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalFree( HLOCAL hmem )
595 return LocalFree( hmem );
599 /***********************************************************************
600 * LocalAlloc (kernelbase.@)
602 HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size )
604 struct local_header *header;
605 DWORD heap_flags = 0;
606 void *ptr;
608 if (flags & LMEM_ZEROINIT) heap_flags = HEAP_ZERO_MEMORY;
610 if (!(flags & LMEM_MOVEABLE)) /* pointer */
612 ptr = HeapAlloc( GetProcessHeap(), heap_flags, size );
613 TRACE( "(flags=%04x) returning %p\n", flags, ptr );
614 return ptr;
617 if (size > INT_MAX - HLOCAL_STORAGE)
619 SetLastError( ERROR_OUTOFMEMORY );
620 return 0;
622 if (!(header = HeapAlloc( GetProcessHeap(), 0, sizeof(*header) ))) return 0;
624 header->magic = MAGIC_LOCAL_USED;
625 header->flags = flags >> 8;
626 header->lock = 0;
628 if (size)
630 if (!(ptr = HeapAlloc(GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE )))
632 HeapFree( GetProcessHeap(), 0, header );
633 return 0;
635 *(HLOCAL *)ptr = get_handle( header );
636 header->ptr = (char *)ptr + HLOCAL_STORAGE;
638 else header->ptr = NULL;
640 TRACE( "(flags=%04x) returning handle %p pointer %p\n",
641 flags, get_handle( header ), header->ptr );
642 return get_handle( header );
646 /***********************************************************************
647 * LocalFree (kernelbase.@)
649 HLOCAL WINAPI DECLSPEC_HOTPATCH LocalFree( HLOCAL hmem )
651 struct local_header *header;
652 HLOCAL ret;
654 RtlLockHeap( GetProcessHeap() );
655 __TRY
657 ret = 0;
658 if (is_pointer(hmem)) /* POINTER */
660 if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, hmem ))
662 SetLastError( ERROR_INVALID_HANDLE );
663 ret = hmem;
666 else /* HANDLE */
668 header = get_header( hmem );
669 if (header->magic == MAGIC_LOCAL_USED)
671 header->magic = 0xdead;
672 if (header->ptr)
674 if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE,
675 (char *)header->ptr - HLOCAL_STORAGE ))
676 ret = hmem;
678 if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, header )) ret = hmem;
680 else
682 WARN( "invalid handle %p (magic: 0x%04x)\n", hmem, header->magic );
683 SetLastError( ERROR_INVALID_HANDLE );
684 ret = hmem;
688 __EXCEPT_PAGE_FAULT
690 WARN( "invalid handle %p\n", hmem );
691 SetLastError( ERROR_INVALID_HANDLE );
692 ret = hmem;
694 __ENDTRY
695 RtlUnlockHeap( GetProcessHeap() );
696 return ret;
700 /***********************************************************************
701 * LocalLock (kernelbase.@)
703 LPVOID WINAPI DECLSPEC_HOTPATCH LocalLock( HLOCAL hmem )
705 void *ret = NULL;
707 if (is_pointer( hmem ))
709 __TRY
711 volatile char *p = hmem;
712 *p |= 0;
714 __EXCEPT_PAGE_FAULT
716 return NULL;
718 __ENDTRY
719 return hmem;
722 RtlLockHeap( GetProcessHeap() );
723 __TRY
725 struct local_header *header = get_header( hmem );
726 if (header->magic == MAGIC_LOCAL_USED)
728 ret = header->ptr;
729 if (!header->ptr) SetLastError( ERROR_DISCARDED );
730 else if (header->lock < LMEM_LOCKCOUNT) header->lock++;
732 else
734 WARN( "invalid handle %p (magic: 0x%04x)\n", hmem, header->magic );
735 SetLastError( ERROR_INVALID_HANDLE );
738 __EXCEPT_PAGE_FAULT
740 WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem);
741 SetLastError( ERROR_INVALID_HANDLE );
743 __ENDTRY
744 RtlUnlockHeap( GetProcessHeap() );
745 return ret;
749 /***********************************************************************
750 * LocalReAlloc (kernelbase.@)
752 HLOCAL WINAPI DECLSPEC_HOTPATCH LocalReAlloc( HLOCAL hmem, SIZE_T size, UINT flags )
754 struct local_header *header;
755 void *ptr;
756 HLOCAL ret = 0;
757 DWORD heap_flags = (flags & LMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0;
759 RtlLockHeap( GetProcessHeap() );
760 if (flags & LMEM_MODIFY) /* modify flags */
762 if (is_pointer( hmem ) && (flags & LMEM_MOVEABLE))
764 /* make a fixed block moveable
765 * actually only NT is able to do this. But it's soo simple
767 if (hmem == 0)
769 WARN( "null handle\n");
770 SetLastError( ERROR_NOACCESS );
772 else
774 size = RtlSizeHeap( GetProcessHeap(), 0, hmem );
775 ret = LocalAlloc( flags, size );
776 ptr = LocalLock( ret );
777 memcpy( ptr, hmem, size );
778 LocalUnlock( ret );
779 LocalFree( hmem );
782 else if (!is_pointer( hmem ) && (flags & LMEM_DISCARDABLE))
784 /* change the flags to make our block "discardable" */
785 header = get_header( hmem );
786 header->flags |= LMEM_DISCARDABLE >> 8;
787 ret = hmem;
789 else SetLastError( ERROR_INVALID_PARAMETER );
791 else
793 if (is_pointer( hmem ))
795 /* reallocate fixed memory */
796 if (!(flags & LMEM_MOVEABLE)) heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY;
797 ret = HeapReAlloc( GetProcessHeap(), heap_flags, hmem, size );
799 else
801 /* reallocate a moveable block */
802 header = get_header( hmem );
803 if (size != 0)
805 if (size <= INT_MAX - HLOCAL_STORAGE)
807 if (header->ptr)
809 if ((ptr = HeapReAlloc( GetProcessHeap(), heap_flags,
810 (char *)header->ptr - HLOCAL_STORAGE,
811 size + HLOCAL_STORAGE )))
813 header->ptr = (char *)ptr + HLOCAL_STORAGE;
814 ret = hmem;
817 else
819 if ((ptr = HeapAlloc( GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE )))
821 *(HLOCAL *)ptr = hmem;
822 header->ptr = (char *)ptr + HLOCAL_STORAGE;
823 ret = hmem;
827 else SetLastError( ERROR_OUTOFMEMORY );
829 else
831 if (header->lock == 0)
833 if (header->ptr)
835 HeapFree( GetProcessHeap(), 0, (char *)header->ptr - HLOCAL_STORAGE );
836 header->ptr = NULL;
838 ret = hmem;
840 else WARN( "not freeing memory associated with locked handle\n" );
844 RtlUnlockHeap( GetProcessHeap() );
845 return ret;
849 /***********************************************************************
850 * LocalUnlock (kernelbase.@)
852 BOOL WINAPI DECLSPEC_HOTPATCH LocalUnlock( HLOCAL hmem )
854 BOOL ret = FALSE;
856 if (is_pointer( hmem ))
858 SetLastError( ERROR_NOT_LOCKED );
859 return FALSE;
862 RtlLockHeap( GetProcessHeap() );
863 __TRY
865 struct local_header *header = get_header( hmem );
866 if (header->magic == MAGIC_LOCAL_USED)
868 if (header->lock)
870 header->lock--;
871 ret = (header->lock != 0);
872 if (!ret) SetLastError( NO_ERROR );
874 else
876 WARN( "%p not locked\n", hmem );
877 SetLastError( ERROR_NOT_LOCKED );
880 else
882 WARN( "invalid handle %p (Magic: 0x%04x)\n", hmem, header->magic );
883 SetLastError( ERROR_INVALID_HANDLE );
886 __EXCEPT_PAGE_FAULT
888 WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem);
889 SetLastError( ERROR_INVALID_PARAMETER );
891 __ENDTRY
892 RtlUnlockHeap( GetProcessHeap() );
893 return ret;
897 /***********************************************************************
898 * Memory resource functions
899 ***********************************************************************/
902 /***********************************************************************
903 * CreateMemoryResourceNotification (kernelbase.@)
905 HANDLE WINAPI DECLSPEC_HOTPATCH CreateMemoryResourceNotification( MEMORY_RESOURCE_NOTIFICATION_TYPE type )
907 HANDLE ret;
908 UNICODE_STRING nameW;
909 OBJECT_ATTRIBUTES attr;
911 switch (type)
913 case LowMemoryResourceNotification:
914 RtlInitUnicodeString( &nameW, L"\\KernelObjects\\LowMemoryCondition" );
915 break;
916 case HighMemoryResourceNotification:
917 RtlInitUnicodeString( &nameW, L"\\KernelObjects\\HighMemoryCondition" );
918 break;
919 default:
920 SetLastError( ERROR_INVALID_PARAMETER );
921 return 0;
924 InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
925 if (!set_ntstatus( NtOpenEvent( &ret, EVENT_ALL_ACCESS, &attr ))) return 0;
926 return ret;
929 /***********************************************************************
930 * QueryMemoryResourceNotification (kernelbase.@)
932 BOOL WINAPI DECLSPEC_HOTPATCH QueryMemoryResourceNotification( HANDLE handle, BOOL *state )
934 switch (WaitForSingleObject( handle, 0 ))
936 case WAIT_OBJECT_0:
937 *state = TRUE;
938 return TRUE;
939 case WAIT_TIMEOUT:
940 *state = FALSE;
941 return TRUE;
943 SetLastError( ERROR_INVALID_PARAMETER );
944 return FALSE;
948 /***********************************************************************
949 * Physical memory functions
950 ***********************************************************************/
953 /***********************************************************************
954 * AllocateUserPhysicalPages (kernelbase.@)
956 BOOL WINAPI DECLSPEC_HOTPATCH AllocateUserPhysicalPages( HANDLE process, ULONG_PTR *pages,
957 ULONG_PTR *userarray )
959 FIXME( "stub: %p %p %p\n", process, pages, userarray );
960 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
961 return FALSE;
965 /***********************************************************************
966 * FreeUserPhysicalPages (kernelbase.@)
968 BOOL WINAPI DECLSPEC_HOTPATCH FreeUserPhysicalPages( HANDLE process, ULONG_PTR *pages,
969 ULONG_PTR *userarray )
971 FIXME( "stub: %p %p %p\n", process, pages, userarray );
972 *pages = 0;
973 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
974 return FALSE;
978 /***********************************************************************
979 * GetPhysicallyInstalledSystemMemory (kernelbase.@)
981 BOOL WINAPI DECLSPEC_HOTPATCH GetPhysicallyInstalledSystemMemory( ULONGLONG *memory )
983 MEMORYSTATUSEX status;
985 if (!memory)
987 SetLastError( ERROR_INVALID_PARAMETER );
988 return FALSE;
990 status.dwLength = sizeof(status);
991 GlobalMemoryStatusEx( &status );
992 *memory = status.ullTotalPhys / 1024;
993 return TRUE;
997 /***********************************************************************
998 * GlobalMemoryStatusEx (kernelbase.@)
1000 BOOL WINAPI DECLSPEC_HOTPATCH GlobalMemoryStatusEx( MEMORYSTATUSEX *status )
1002 static MEMORYSTATUSEX cached_status;
1003 static DWORD last_check;
1004 SYSTEM_BASIC_INFORMATION basic_info;
1005 SYSTEM_PERFORMANCE_INFORMATION perf_info;
1007 if (status->dwLength != sizeof(*status))
1009 SetLastError( ERROR_INVALID_PARAMETER );
1010 return FALSE;
1012 if ((NtGetTickCount() - last_check) < 1000)
1014 *status = cached_status;
1015 return TRUE;
1017 last_check = NtGetTickCount();
1019 if (!set_ntstatus( NtQuerySystemInformation( SystemBasicInformation,
1020 &basic_info, sizeof(basic_info), NULL )) ||
1021 !set_ntstatus( NtQuerySystemInformation( SystemPerformanceInformation,
1022 &perf_info, sizeof(perf_info), NULL)))
1023 return FALSE;
1025 status->dwMemoryLoad = 0;
1026 status->ullTotalPhys = perf_info.TotalCommitLimit;
1027 status->ullAvailPhys = perf_info.AvailablePages;
1028 status->ullTotalPageFile = perf_info.TotalCommitLimit + 1; /* Titan Quest refuses to run if TotalPageFile <= TotalPhys */
1029 status->ullAvailPageFile = status->ullTotalPageFile - perf_info.TotalCommittedPages;
1030 status->ullTotalVirtual = (ULONG_PTR)basic_info.HighestUserAddress - (ULONG_PTR)basic_info.LowestUserAddress;
1031 status->ullAvailVirtual = status->ullTotalVirtual - 64 * 1024; /* FIXME */
1032 status->ullAvailExtendedVirtual = 0;
1034 status->ullTotalPhys *= basic_info.PageSize;
1035 status->ullAvailPhys *= basic_info.PageSize;
1036 status->ullTotalPageFile *= basic_info.PageSize;
1037 status->ullAvailPageFile *= basic_info.PageSize;
1039 if (status->ullTotalPhys)
1040 status->dwMemoryLoad = (status->ullTotalPhys - status->ullAvailPhys) / (status->ullTotalPhys / 100);
1042 TRACE_(virtual)( "MemoryLoad %d, TotalPhys %s, AvailPhys %s, TotalPageFile %s,"
1043 "AvailPageFile %s, TotalVirtual %s, AvailVirtual %s\n",
1044 status->dwMemoryLoad, wine_dbgstr_longlong(status->ullTotalPhys),
1045 wine_dbgstr_longlong(status->ullAvailPhys), wine_dbgstr_longlong(status->ullTotalPageFile),
1046 wine_dbgstr_longlong(status->ullAvailPageFile), wine_dbgstr_longlong(status->ullTotalVirtual),
1047 wine_dbgstr_longlong(status->ullAvailVirtual) );
1049 cached_status = *status;
1050 return TRUE;
1054 /***********************************************************************
1055 * MapUserPhysicalPages (kernelbase.@)
1057 BOOL WINAPI DECLSPEC_HOTPATCH MapUserPhysicalPages( void *addr, ULONG_PTR page_count, ULONG_PTR *pages )
1059 FIXME( "stub: %p %lu %p\n", addr, page_count, pages );
1060 *pages = 0;
1061 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1062 return FALSE;
1066 /***********************************************************************
1067 * NUMA functions
1068 ***********************************************************************/
1071 /***********************************************************************
1072 * AllocateUserPhysicalPagesNuma (kernelbase.@)
1074 BOOL WINAPI DECLSPEC_HOTPATCH AllocateUserPhysicalPagesNuma( HANDLE process, ULONG_PTR *pages,
1075 ULONG_PTR *userarray, DWORD node )
1077 if (node) FIXME( "Ignoring preferred node %u\n", node );
1078 return AllocateUserPhysicalPages( process, pages, userarray );
1082 /***********************************************************************
1083 * CreateFileMappingNumaW (kernelbase.@)
1085 HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileMappingNumaW( HANDLE file, LPSECURITY_ATTRIBUTES sa,
1086 DWORD protect, DWORD size_high, DWORD size_low,
1087 LPCWSTR name, DWORD node )
1089 if (node) FIXME( "Ignoring preferred node %u\n", node );
1090 return CreateFileMappingW( file, sa, protect, size_high, size_low, name );
1094 /***********************************************************************
1095 * GetLogicalProcessorInformation (kernelbase.@)
1097 BOOL WINAPI DECLSPEC_HOTPATCH GetLogicalProcessorInformation( SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buffer,
1098 DWORD *len )
1100 NTSTATUS status;
1102 if (!len)
1104 SetLastError( ERROR_INVALID_PARAMETER );
1105 return FALSE;
1107 status = NtQuerySystemInformation( SystemLogicalProcessorInformation, buffer, *len, len );
1108 if (status == STATUS_INFO_LENGTH_MISMATCH) status = STATUS_BUFFER_TOO_SMALL;
1109 return set_ntstatus( status );
1113 /***********************************************************************
1114 * GetLogicalProcessorInformationEx (kernelbase.@)
1116 BOOL WINAPI DECLSPEC_HOTPATCH GetLogicalProcessorInformationEx( LOGICAL_PROCESSOR_RELATIONSHIP relationship,
1117 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, DWORD *len )
1119 NTSTATUS status;
1121 if (!len)
1123 SetLastError( ERROR_INVALID_PARAMETER );
1124 return FALSE;
1126 status = NtQuerySystemInformationEx( SystemLogicalProcessorInformationEx, &relationship,
1127 sizeof(relationship), buffer, *len, len );
1128 if (status == STATUS_INFO_LENGTH_MISMATCH) status = STATUS_BUFFER_TOO_SMALL;
1129 return set_ntstatus( status );
1133 /**********************************************************************
1134 * GetNumaHighestNodeNumber (kernelbase.@)
1136 BOOL WINAPI DECLSPEC_HOTPATCH GetNumaHighestNodeNumber( ULONG *node )
1138 FIXME( "semi-stub: %p\n", node );
1139 *node = 0;
1140 return TRUE;
1144 /**********************************************************************
1145 * GetNumaNodeProcessorMaskEx (kernelbase.@)
1147 BOOL WINAPI DECLSPEC_HOTPATCH GetNumaNodeProcessorMaskEx( USHORT node, GROUP_AFFINITY *mask )
1149 FIXME( "stub: %hu %p\n", node, mask );
1150 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1151 return FALSE;
1155 /***********************************************************************
1156 * GetNumaProximityNodeEx (kernelbase.@)
1158 BOOL WINAPI DECLSPEC_HOTPATCH GetNumaProximityNodeEx( ULONG proximity_id, USHORT *node )
1160 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1161 return FALSE;
1165 /***********************************************************************
1166 * MapViewOfFileExNuma (kernelbase.@)
1168 LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFileExNuma( HANDLE handle, DWORD access, DWORD offset_high,
1169 DWORD offset_low, SIZE_T count, LPVOID addr,
1170 DWORD node )
1172 if (node) FIXME( "Ignoring preferred node %u\n", node );
1173 return MapViewOfFileEx( handle, access, offset_high, offset_low, count, addr );
1177 /***********************************************************************
1178 * VirtualAllocExNuma (kernelbase.@)
1180 LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAllocExNuma( HANDLE process, void *addr, SIZE_T size,
1181 DWORD type, DWORD protect, DWORD node )
1183 if (node) FIXME( "Ignoring preferred node %u\n", node );
1184 return VirtualAllocEx( process, addr, size, type, protect );
1188 /***********************************************************************
1189 * CPU functions
1190 ***********************************************************************/
1193 #if defined(__i386__) || defined(__x86_64__)
1194 /***********************************************************************
1195 * GetEnabledXStateFeatures (kernelbase.@)
1197 DWORD64 WINAPI GetEnabledXStateFeatures(void)
1199 TRACE( "\n" );
1200 return RtlGetEnabledExtendedFeatures( ~(ULONG64)0 );
1204 /***********************************************************************
1205 * InitializeContext2 (kernelbase.@)
1207 BOOL WINAPI InitializeContext2( void *buffer, DWORD context_flags, CONTEXT **context, DWORD *length,
1208 ULONG64 compaction_mask )
1210 ULONG orig_length;
1211 NTSTATUS status;
1213 TRACE( "buffer %p, context_flags %#x, context %p, ret_length %p, compaction_mask %s.\n",
1214 buffer, context_flags, context, length, wine_dbgstr_longlong(compaction_mask) );
1216 orig_length = *length;
1218 if ((status = RtlGetExtendedContextLength2( context_flags, length, compaction_mask )))
1220 if (status == STATUS_NOT_SUPPORTED && context_flags & 0x40)
1222 context_flags &= ~0x40;
1223 status = RtlGetExtendedContextLength2( context_flags, length, compaction_mask );
1226 if (status)
1227 return set_ntstatus( status );
1230 if (!buffer || orig_length < *length)
1232 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1233 return FALSE;
1236 if ((status = RtlInitializeExtendedContext2( buffer, context_flags, (CONTEXT_EX **)context, compaction_mask )))
1237 return set_ntstatus( status );
1239 *context = (CONTEXT *)((BYTE *)*context + (*(CONTEXT_EX **)context)->Legacy.Offset);
1241 return TRUE;
1244 /***********************************************************************
1245 * InitializeContext (kernelbase.@)
1247 BOOL WINAPI InitializeContext( void *buffer, DWORD context_flags, CONTEXT **context, DWORD *length )
1249 return InitializeContext2( buffer, context_flags, context, length, ~(ULONG64)0 );
1252 /***********************************************************************
1253 * CopyContext (kernelbase.@)
1255 BOOL WINAPI CopyContext( CONTEXT *dst, DWORD context_flags, CONTEXT *src )
1257 DWORD context_size, arch_flag, flags_offset, dst_flags, src_flags;
1258 static const DWORD arch_mask = 0x110000;
1259 NTSTATUS status;
1260 BYTE *d, *s;
1262 TRACE("dst %p, context_flags %#x, src %p.\n", dst, context_flags, src);
1264 if (context_flags & 0x40 && !RtlGetEnabledExtendedFeatures( ~(ULONG64)0 ))
1266 SetLastError(ERROR_NOT_SUPPORTED);
1267 return FALSE;
1270 arch_flag = context_flags & arch_mask;
1272 switch (arch_flag)
1274 case 0x10000: context_size = 0x2cc; flags_offset = 0; break;
1275 case 0x100000: context_size = 0x4d0; flags_offset = 0x30; break;
1276 default:
1277 SetLastError( ERROR_INVALID_PARAMETER );
1278 return FALSE;
1281 d = (BYTE *)dst;
1282 s = (BYTE *)src;
1283 dst_flags = *(DWORD *)(d + flags_offset);
1284 src_flags = *(DWORD *)(s + flags_offset);
1286 if ((dst_flags & arch_mask) != arch_flag
1287 || (src_flags & arch_mask) != arch_flag)
1289 SetLastError( ERROR_INVALID_PARAMETER );
1290 return FALSE;
1293 context_flags &= src_flags;
1295 if (context_flags & ~dst_flags & 0x40)
1297 SetLastError(ERROR_MORE_DATA);
1298 return FALSE;
1301 if ((status = RtlCopyExtendedContext( (CONTEXT_EX *)(d + context_size), context_flags,
1302 (CONTEXT_EX *)(s + context_size) )))
1303 return set_ntstatus( status );
1305 return TRUE;
1307 #endif
1310 #if defined(__x86_64__)
1311 /***********************************************************************
1312 * LocateXStateFeature (kernelbase.@)
1314 void * WINAPI LocateXStateFeature( CONTEXT *context, DWORD feature_id, DWORD *length )
1316 if (!(context->ContextFlags & CONTEXT_AMD64))
1317 return NULL;
1319 if (feature_id >= 2)
1320 return ((context->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
1321 ? RtlLocateExtendedFeature( (CONTEXT_EX *)(context + 1), feature_id, length ) : NULL;
1323 if (feature_id == 1)
1325 if (length)
1326 *length = sizeof(M128A) * 16;
1328 return &context->u.FltSave.XmmRegisters;
1331 if (length)
1332 *length = offsetof(XSAVE_FORMAT, XmmRegisters);
1334 return &context->u.FltSave;
1337 /***********************************************************************
1338 * SetXStateFeaturesMask (kernelbase.@)
1340 BOOL WINAPI SetXStateFeaturesMask( CONTEXT *context, DWORD64 feature_mask )
1342 if (!(context->ContextFlags & CONTEXT_AMD64))
1343 return FALSE;
1345 if (feature_mask & 0x3)
1346 context->ContextFlags |= CONTEXT_FLOATING_POINT;
1348 if ((context->ContextFlags & CONTEXT_XSTATE) != CONTEXT_XSTATE)
1349 return !(feature_mask & ~(DWORD64)3);
1351 RtlSetExtendedFeaturesMask( (CONTEXT_EX *)(context + 1), feature_mask );
1352 return TRUE;
1355 /***********************************************************************
1356 * GetXStateFeaturesMask (kernelbase.@)
1358 BOOL WINAPI GetXStateFeaturesMask( CONTEXT *context, DWORD64 *feature_mask )
1360 if (!(context->ContextFlags & CONTEXT_AMD64))
1361 return FALSE;
1363 *feature_mask = (context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT
1364 ? 3 : 0;
1366 if ((context->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
1367 *feature_mask |= RtlGetExtendedFeaturesMask( (CONTEXT_EX *)(context + 1) );
1369 return TRUE;
1371 #elif defined(__i386__)
1372 /***********************************************************************
1373 * LocateXStateFeature (kernelbase.@)
1375 void * WINAPI LocateXStateFeature( CONTEXT *context, DWORD feature_id, DWORD *length )
1377 if (!(context->ContextFlags & CONTEXT_X86))
1378 return NULL;
1380 if (feature_id >= 2)
1381 return ((context->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
1382 ? RtlLocateExtendedFeature( (CONTEXT_EX *)(context + 1), feature_id, length ) : NULL;
1384 if (feature_id == 1)
1386 if (length)
1387 *length = sizeof(M128A) * 8;
1389 return (BYTE *)&context->ExtendedRegisters + offsetof(XSAVE_FORMAT, XmmRegisters);
1392 if (length)
1393 *length = offsetof(XSAVE_FORMAT, XmmRegisters);
1395 return &context->ExtendedRegisters;
1398 /***********************************************************************
1399 * SetXStateFeaturesMask (kernelbase.@)
1401 BOOL WINAPI SetXStateFeaturesMask( CONTEXT *context, DWORD64 feature_mask )
1403 if (!(context->ContextFlags & CONTEXT_X86))
1404 return FALSE;
1406 if (feature_mask & 0x3)
1407 context->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
1409 if ((context->ContextFlags & CONTEXT_XSTATE) != CONTEXT_XSTATE)
1410 return !(feature_mask & ~(DWORD64)3);
1412 RtlSetExtendedFeaturesMask( (CONTEXT_EX *)(context + 1), feature_mask );
1413 return TRUE;
1416 /***********************************************************************
1417 * GetXStateFeaturesMask (kernelbase.@)
1419 BOOL WINAPI GetXStateFeaturesMask( CONTEXT *context, DWORD64 *feature_mask )
1421 if (!(context->ContextFlags & CONTEXT_X86))
1422 return FALSE;
1424 *feature_mask = (context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS
1425 ? 3 : 0;
1427 if ((context->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
1428 *feature_mask |= RtlGetExtendedFeaturesMask( (CONTEXT_EX *)(context + 1) );
1430 return TRUE;
1432 #endif
1434 /***********************************************************************
1435 * Firmware functions
1436 ***********************************************************************/
1439 /***********************************************************************
1440 * EnumSystemFirmwareTable (kernelbase.@)
1442 UINT WINAPI EnumSystemFirmwareTables( DWORD provider, void *buffer, DWORD size )
1444 FIXME( "(0x%08x, %p, %d)\n", provider, buffer, size );
1445 return 0;
1449 /***********************************************************************
1450 * GetSystemFirmwareTable (kernelbase.@)
1452 UINT WINAPI GetSystemFirmwareTable( DWORD provider, DWORD id, void *buffer, DWORD size )
1454 SYSTEM_FIRMWARE_TABLE_INFORMATION *info;
1455 ULONG buffer_size = offsetof( SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer ) + size;
1457 TRACE( "(0x%08x, 0x%08x, %p, %d)\n", provider, id, buffer, size );
1459 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, buffer_size )))
1461 SetLastError( ERROR_OUTOFMEMORY );
1462 return 0;
1465 info->ProviderSignature = provider;
1466 info->Action = SystemFirmwareTable_Get;
1467 info->TableID = id;
1469 set_ntstatus( NtQuerySystemInformation( SystemFirmwareTableInformation,
1470 info, buffer_size, &buffer_size ));
1471 buffer_size -= offsetof( SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer );
1472 if (buffer_size <= size) memcpy( buffer, info->TableBuffer, buffer_size );
1474 HeapFree( GetProcessHeap(), 0, info );
1475 return buffer_size;