From 532ee4eb5993a99fc9e878bf2c976529088ebe29 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Thu, 11 Oct 2007 20:40:38 +0000 Subject: [PATCH] - Mm-rewrite: * Get rid of a hack-based heap allocation in FreeLdr, which makes real data interleaved with temporary data, all that unfreeable and unmanageable. * Introduce new APIs MmHeapAlloc / MmHeapFree to alloc/free memory from a pre-allocated heap. * Add BGET (public domain heap implementation), hook it up to the MmHeapAlloc / MmHeapFree APIs. * MmAllocateMemory still is a backward-compatibility API, will be removed soon. - Change most of allocations to the heap-based routines, add frees where necessary (I must admit Brian already used MmFreeMemory in a lot of places, so I just had to change those to the corresponding MmHeapFree API). - Remove unneeded and wrong IDT filling, which was commented out. - Temporary disable caching support, because it needs a standalone place to keep its data in. For compatibility's sake it's better to leave it when WinLdr is more mature. svn path=/branches/winldr/; revision=29518 --- arch/i386/hardware.c | 6 +- cache/blocklist.c | 8 +- freeldr_base.rbuild | 1 + fs/fat.c | 59 +- include/bget.h | 30 + include/freeldr.h | 1 + include/mm.h | 8 + mm/meminit.c | 37 + mm/mm.c | 227 ++---- reactos/binhive.c | 20 +- reactos/registry.c | 16 +- rtl/bget.c | 1593 ++++++++++++++++++++++++++++++++++++++++++ rtl/libsupp.c | 4 +- ui/ui.c | 4 +- windows/peloader.c | 12 +- windows/winldr.c | 20 +- windows/wlmemory.c | 112 +-- windows/wlregistry.c | 30 +- 18 files changed, 1835 insertions(+), 353 deletions(-) create mode 100644 include/bget.h create mode 100644 rtl/bget.c diff --git a/arch/i386/hardware.c b/arch/i386/hardware.c index 2309ec5c540..a43e17d40c8 100644 --- a/arch/i386/hardware.c +++ b/arch/i386/hardware.c @@ -581,7 +581,7 @@ DetectBiosDisks(PCONFIGURATION_COMPONENT_DATA ComponentRoot, (int)DiskCount, (DiskCount == 1) ? "": "s")); /* Create DiskController */ - DiskComponentData = (PCONFIGURATION_COMPONENT_DATA)MmAllocateMemory(sizeof(CONFIGURATION_COMPONENT_DATA)); + DiskComponentData = (PCONFIGURATION_COMPONENT_DATA)MmHeapAlloc(sizeof(CONFIGURATION_COMPONENT_DATA)); RtlZeroMemory(DiskComponentData, sizeof(CONFIGURATION_COMPONENT_DATA)); DiskComponent = &DiskComponentData->ComponentEntry; @@ -634,7 +634,7 @@ DetectBiosDisks(PCONFIGURATION_COMPONENT_DATA ComponentRoot, } /* Get harddisk Int13 geometry data */ - Int13Drives = MmAllocateMemory(sizeof(CM_INT13_DRIVE_PARAMETER) * DiskCount); + Int13Drives = MmHeapAlloc(sizeof(CM_INT13_DRIVE_PARAMETER) * DiskCount); memset(Int13Drives, 0, sizeof(CM_INT13_DRIVE_PARAMETER) * DiskCount); for (i = 0; i < DiskCount; i++) @@ -744,7 +744,7 @@ DetectBiosDisks(PCONFIGURATION_COMPONENT_DATA ComponentRoot, DeviceData = (PVOID)((ULONG_PTR)ResourceList + sizeof(CM_PARTIAL_RESOURCE_LIST)); memcpy(DeviceData, (PVOID)Int13Drives, DeviceDataSize); - MmFreeMemory(Int13Drives); + MmHeapFree(Int13Drives); /* Now fill the 2nd partial resource descriptor */ ResourceDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)((ULONG_PTR)ResourceList + diff --git a/cache/blocklist.c b/cache/blocklist.c index a7af67bf7ab..309d02287e1 100644 --- a/cache/blocklist.c +++ b/cache/blocklist.c @@ -98,7 +98,7 @@ PCACHE_BLOCK CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive, ULONG BlockNu // We will need to add the block to the // drive's list of cached blocks. So allocate // the block memory. - CacheBlock = MmAllocateMemory(sizeof(CACHE_BLOCK)); + CacheBlock = MmHeapAlloc(sizeof(CACHE_BLOCK)); if (CacheBlock == NULL) { return NULL; @@ -111,7 +111,7 @@ PCACHE_BLOCK CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive, ULONG BlockNu CacheBlock->BlockData = MmAllocateMemory(CacheDrive->BlockSize * CacheDrive->BytesPerSector); if (CacheBlock->BlockData ==NULL) { - MmFreeMemory(CacheBlock); + MmHeapFree(CacheBlock); return NULL; } @@ -119,7 +119,7 @@ PCACHE_BLOCK CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive, ULONG BlockNu if (!MachDiskReadLogicalSectors(CacheDrive->DriveNumber, (BlockNumber * CacheDrive->BlockSize), CacheDrive->BlockSize, (PVOID)DISKREADBUFFER)) { MmFreeMemory(CacheBlock->BlockData); - MmFreeMemory(CacheBlock); + MmHeapFree(CacheBlock); return NULL; } RtlCopyMemory(CacheBlock->BlockData, (PVOID)DISKREADBUFFER, CacheDrive->BlockSize * CacheDrive->BytesPerSector); @@ -177,7 +177,7 @@ BOOLEAN CacheInternalFreeBlock(PCACHE_DRIVE CacheDrive) // Free the block memory and the block structure MmFreeMemory(CacheBlockToFree->BlockData); - MmFreeMemory(CacheBlockToFree); + MmHeapFree(CacheBlockToFree); // Update the cache data CacheBlockCount--; diff --git a/freeldr_base.rbuild b/freeldr_base.rbuild index 53e3e0da268..2a7ee7fce7d 100644 --- a/freeldr_base.rbuild +++ b/freeldr_base.rbuild @@ -49,6 +49,7 @@ reactos.c + bget.c libsupp.c list.c diff --git a/fs/fat.c b/fs/fat.c index 14cf1d4ab98..bce67191977 100644 --- a/fs/fat.c +++ b/fs/fat.c @@ -51,7 +51,7 @@ BOOLEAN FatOpenVolume(ULONG DriveNumber, ULONG VolumeStartSector, ULONG Partitio // // Allocate the memory to hold the boot sector // - FatVolumeBootSector = (PFAT_BOOTSECTOR) MmAllocateMemory(512); + FatVolumeBootSector = (PFAT_BOOTSECTOR) MmHeapAlloc(512); Fat32VolumeBootSector = (PFAT32_BOOTSECTOR) FatVolumeBootSector; FatXVolumeBootSector = (PFATX_BOOTSECTOR) FatVolumeBootSector; @@ -68,7 +68,7 @@ BOOLEAN FatOpenVolume(ULONG DriveNumber, ULONG VolumeStartSector, ULONG Partitio // If this fails then abort if (!MachDiskReadLogicalSectors(DriveNumber, VolumeStartSector, 1, (PVOID)DISKREADBUFFER)) { - MmFreeMemory(FatVolumeBootSector); + MmHeapFree(FatVolumeBootSector); return FALSE; } RtlCopyMemory(FatVolumeBootSector, (PVOID)DISKREADBUFFER, 512); @@ -164,7 +164,7 @@ BOOLEAN FatOpenVolume(ULONG DriveNumber, ULONG VolumeStartSector, ULONG Partitio sprintf(ErrMsg, "Invalid boot sector magic on drive 0x%x (expected 0xaa55 found 0x%x)", DriveNumber, FatVolumeBootSector->BootSectorMagic); FileSystemError(ErrMsg); - MmFreeMemory(FatVolumeBootSector); + MmHeapFree(FatVolumeBootSector); return FALSE; } @@ -176,7 +176,7 @@ BOOLEAN FatOpenVolume(ULONG DriveNumber, ULONG VolumeStartSector, ULONG Partitio (! ISFATX(FatType) && 64 * 1024 < FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector)) { FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this."); - MmFreeMemory(FatVolumeBootSector); + MmHeapFree(FatVolumeBootSector); return FALSE; } @@ -249,8 +249,9 @@ BOOLEAN FatOpenVolume(ULONG DriveNumber, ULONG VolumeStartSector, ULONG Partitio return FALSE; } } - MmFreeMemory(FatVolumeBootSector); + MmHeapFree(FatVolumeBootSector); +#ifdef CACHE_ENABLED // // Initialize the disk cache for this drive // @@ -271,6 +272,20 @@ BOOLEAN FatOpenVolume(ULONG DriveNumber, ULONG VolumeStartSector, ULONG Partitio return FALSE; } } +#else + { + GEOMETRY DriveGeometry; + ULONG BlockSize; + + // Initialize drive by getting its geometry + if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry)) + { + return FALSE; + } + + BlockSize = MachDiskGetCacheableBlockCount(DriveNumber); + } +#endif return TRUE; } @@ -362,7 +377,7 @@ PVOID FatBufferDirectory(ULONG DirectoryStartCluster, ULONG *DirectorySize, BOOL // Attempt to allocate memory for directory buffer // DbgPrint((DPRINT_FILESYSTEM, "Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize)); - DirectoryBuffer = MmAllocateMemory(*DirectorySize); + DirectoryBuffer = MmHeapAlloc(*DirectorySize); if (DirectoryBuffer == NULL) { @@ -376,7 +391,7 @@ PVOID FatBufferDirectory(ULONG DirectoryStartCluster, ULONG *DirectorySize, BOOL { if (!FatReadVolumeSectors(FatDriveNumber, RootDirSectorStart, RootDirSectors, DirectoryBuffer)) { - MmFreeMemory(DirectoryBuffer); + MmHeapFree(DirectoryBuffer); return NULL; } } @@ -384,7 +399,7 @@ PVOID FatBufferDirectory(ULONG DirectoryStartCluster, ULONG *DirectorySize, BOOL { if (!FatReadClusterChain(DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer)) { - MmFreeMemory(DirectoryBuffer); + MmHeapFree(DirectoryBuffer); return NULL; } } @@ -727,7 +742,7 @@ BOOLEAN FatLookupFile(PCSTR FileName, PFAT_FILE_INFO FatFileInfoPointer) { if (!FatXSearchDirectoryBufferForFile(DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo)) { - MmFreeMemory(DirectoryBuffer); + MmHeapFree(DirectoryBuffer); return FALSE; } } @@ -735,12 +750,12 @@ BOOLEAN FatLookupFile(PCSTR FileName, PFAT_FILE_INFO FatFileInfoPointer) { if (!FatSearchDirectoryBufferForFile(DirectoryBuffer, DirectorySize, PathPart, &FatFileInfo)) { - MmFreeMemory(DirectoryBuffer); + MmHeapFree(DirectoryBuffer); return FALSE; } } - MmFreeMemory(DirectoryBuffer); + MmHeapFree(DirectoryBuffer); // // If we have another sub-directory to go then @@ -749,7 +764,7 @@ BOOLEAN FatLookupFile(PCSTR FileName, PFAT_FILE_INFO FatFileInfoPointer) if ((i+1) < NumberOfPathParts) { DirectoryStartCluster = FatFileInfo.FileFatChain[0]; - MmFreeMemory(FatFileInfo.FileFatChain); + MmHeapFree(FatFileInfo.FileFatChain); } } @@ -914,7 +929,7 @@ FILE* FatOpenFile(PCSTR FileName) return NULL; } - FileHandle = MmAllocateMemory(sizeof(FAT_FILE_INFO)); + FileHandle = MmHeapAlloc(sizeof(FAT_FILE_INFO)); if (FileHandle == NULL) { @@ -978,7 +993,7 @@ ULONG* FatGetClusterChainArray(ULONG StartCluster) // // Allocate array memory // - ArrayPointer = MmAllocateMemory(ArraySize); + ArrayPointer = MmHeapAlloc(ArraySize); if (ArrayPointer == NULL) { @@ -1011,7 +1026,7 @@ ULONG* FatGetClusterChainArray(ULONG StartCluster) // if (!FatGetFatEntry(StartCluster, &StartCluster)) { - MmFreeMemory(ArrayPointer); + MmHeapFree(ArrayPointer); return NULL; } } @@ -1312,5 +1327,19 @@ ULONG FatGetFilePointer(FILE *FileHandle) BOOLEAN FatReadVolumeSectors(ULONG DriveNumber, ULONG SectorNumber, ULONG SectorCount, PVOID Buffer) { +#ifdef CACHE_ENABLED return CacheReadDiskSectors(DriveNumber, SectorNumber + FatVolumeStartSector, SectorCount, Buffer); +#else + // Now try to read in the block + if (!MachDiskReadLogicalSectors(DriveNumber, SectorNumber + FatVolumeStartSector, SectorCount, (PVOID)DISKREADBUFFER)) + { + return FALSE; + } + + // Copy data to the caller + RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, SectorCount * BytesPerSector); + + // Return success + return TRUE; +#endif } diff --git a/include/bget.h b/include/bget.h new file mode 100644 index 00000000000..0c72d0e55b2 --- /dev/null +++ b/include/bget.h @@ -0,0 +1,30 @@ +/* + + Interface definitions for bget.c, the memory management package. + +*/ + +#ifndef _ +#ifdef PROTOTYPES +#define _(x) x /* If compiler knows prototypes */ +#else +#define _(x) () /* It it doesn't */ +#endif /* PROTOTYPES */ +#endif + +typedef long bufsize; +void bpool _((void *buffer, bufsize len)); +void *bget _((bufsize size)); +void *bgetz _((bufsize size)); +void *bgetr _((void *buffer, bufsize newsize)); +void brel _((void *buf)); +void bectl _((int (*compact)(bufsize sizereq, int sequence), + void *(*acquire)(bufsize size), + void (*release)(void *buf), bufsize pool_incr)); +void bstats _((bufsize *curalloc, bufsize *totfree, bufsize *maxfree, + long *nget, long *nrel)); +void bstatse _((bufsize *pool_incr, long *npool, long *npget, + long *nprel, long *ndget, long *ndrel)); +void bufdump _((void *buf)); +void bpoold _((void *pool, int dumpalloc, int dumpfree)); +int bpoolv _((void *pool)); diff --git a/include/freeldr.h b/include/freeldr.h index 57f307adfe5..bde6b09297f 100644 --- a/include/freeldr.h +++ b/include/freeldr.h @@ -74,6 +74,7 @@ #include #include #include +#include /* Needed by boot manager */ #include #include diff --git a/include/mm.h b/include/mm.h index bdc0bf9e416..a708be10b14 100644 --- a/include/mm.h +++ b/include/mm.h @@ -52,6 +52,10 @@ typedef struct // #define LOADER_HIGH_ZONE ((16*1024*1024) >> MM_PAGE_SHIFT) //16Mb page +// HEAP and STACK size +#define HEAP_PAGES 0x100//0x18 +#define STACK_PAGES 0x00 + typedef struct { TYPE_OF_MEMORY PageAllocated; // Type of allocated memory (LoaderFree if this memory is free) @@ -97,6 +101,7 @@ PPAGE_LOOKUP_TABLE_ITEM MmGetMemoryMap(ULONG *NoEntries); // Returns a pointer //BOOLEAN MmInitializeMemoryManager(ULONG LowMemoryStart, ULONG LowMemoryLength); BOOLEAN MmInitializeMemoryManager(VOID); +VOID MmInitializeHeap(PVOID PageLookupTable); PVOID MmAllocateMemory(ULONG MemorySize); PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType); VOID MmFreeMemory(PVOID MemoryPointer); @@ -106,4 +111,7 @@ VOID MmChangeAllocationPolicy(BOOLEAN PolicyAllocatePagesFromEnd); PVOID MmAllocateMemoryAtAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType); PVOID MmAllocateHighestMemoryBelowAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType); +PVOID MmHeapAlloc(ULONG MemorySize); +VOID MmHeapFree(PVOID MemoryPointer); + #endif // defined __MEMORY_H diff --git a/mm/meminit.c b/mm/meminit.c index d47ca29f4bb..c4c186315c1 100644 --- a/mm/meminit.c +++ b/mm/meminit.c @@ -44,6 +44,9 @@ ULONG TotalPagesInLookupTable = 0; ULONG FreePagesInLookupTable = 0; ULONG LastFreePageHint = 0; +extern ULONG_PTR MmHeapPointer; +extern ULONG_PTR MmHeapStart; + BOOLEAN MmInitializeMemoryManager(VOID) { BIOS_MEMORY_MAP BiosMemoryMap[32]; @@ -110,10 +113,42 @@ BOOLEAN MmInitializeMemoryManager(VOID) FreePagesInLookupTable = MmCountFreePagesInLookupTable(PageLookupTableAddress, TotalPagesInLookupTable); + MmInitializeHeap(PageLookupTableAddress); + DbgPrint((DPRINT_MEMORY, "Memory Manager initialized. %d pages available.\n", FreePagesInLookupTable)); return TRUE; } +VOID MmInitializeHeap(PVOID PageLookupTable) +{ + ULONG PagesNeeded; + ULONG HeapStart; + + // HACK: Make it so it doesn't overlap kernel space + MmMarkPagesInLookupTable(PageLookupTableAddress, 0x100, 0xFF, LoaderSystemCode); + + // Find contigious memory block for HEAP:STACK + PagesNeeded = HEAP_PAGES + STACK_PAGES; + HeapStart = MmFindAvailablePages(PageLookupTable, TotalPagesInLookupTable, PagesNeeded, FALSE); + + // Unapply the hack + MmMarkPagesInLookupTable(PageLookupTableAddress, 0x100, 0xFF, LoaderFree); + + if (HeapStart == 0) + { + UiMessageBox("Critical error: Can't allocate heap!"); + return; + } + + // Initialize BGET + bpool(HeapStart << MM_PAGE_SHIFT, PagesNeeded << MM_PAGE_SHIFT); + + // Mark those pages as used + MmMarkPagesInLookupTable(PageLookupTableAddress, HeapStart, PagesNeeded, LoaderOsloaderHeap); + + DbgPrint((DPRINT_MEMORY, "Heap initialized, base 0x%08x, pages %d\n", (HeapStart << MM_PAGE_SHIFT), PagesNeeded)); +} + #ifdef DBG PUCHAR MmGetSystemMemoryMapTypeString(ULONG Type) { @@ -295,10 +330,12 @@ VOID MmMarkPagesInLookupTable(PVOID PageLookupTable, ULONG StartPage, ULONG Page for (Index=StartPage; Index<(StartPage+PageCount); Index++) { +#if 0 if ((Index <= (StartPage + 16)) || (Index >= (StartPage+PageCount-16))) { DbgPrint((DPRINT_MEMORY, "Index = %d StartPage = %d PageCount = %d\n", Index, StartPage, PageCount)); } +#endif RealPageLookupTable[Index].PageAllocated = PageAllocated; RealPageLookupTable[Index].PageAllocationLength = (PageAllocated != LoaderFree) ? 1 : 0; } diff --git a/mm/mm.c b/mm/mm.c index ff95805fa55..1e4045b77b6 100644 --- a/mm/mm.c +++ b/mm/mm.c @@ -21,36 +21,11 @@ #include #include -ULONG AllocationCount = 0; - #ifdef DBG -VOID VerifyHeap(VOID); VOID DumpMemoryAllocMap(VOID); -VOID IncrementAllocationCount(VOID); -VOID DecrementAllocationCount(VOID); VOID MemAllocTest(VOID); #endif // DBG -/* - * Hack alert - * Normally, we allocate whole pages. This is ofcourse wastefull for small - * allocations (a few bytes). So, for small allocations (smaller than a page) - * we sub-allocate. When the first small allocation is done, a page is - * requested. We keep a pointer to that page in SubAllocationPage. The alloc - * is satisfied by returning a pointer to the beginning of the page. We also - * keep track of how many bytes are still available in the page in SubAllocationRest. - * When the next small request comes in, we try to allocate it just after the - * memory previously allocated. If it won't fit, we allocate a new page and - * the whole process starts again. - * Note that suballocations are done back-to-back, there's no bookkeeping at all. - * That also means that we cannot really free suballocations. So, when a free is - * done and it is determined that this might be a free of a sub-allocation, we - * just no-op the free. - * Perhaps we should use the heap routines from ntdll here. - */ -static PVOID SubAllocationPage = NULL; -static unsigned SubAllocationRest = 0; - BOOLEAN AllocateFromEnd = TRUE; VOID MmChangeAllocationPolicy(BOOLEAN PolicyAllocatePagesFromEnd) @@ -72,12 +47,6 @@ PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType) } MemorySize = ROUND_UP(MemorySize, 4); - if (MemorySize <= SubAllocationRest) - { - MemPointer = (PVOID)((ULONG_PTR)SubAllocationPage + MM_PAGE_SIZE - SubAllocationRest); - SubAllocationRest -= MemorySize; - return MemPointer; - } // Find out how many blocks it will take to // satisfy this allocation @@ -87,7 +56,7 @@ PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType) // then return NULL if (FreePagesInLookupTable < PagesNeeded) { - DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount)); + DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes.\n", MemorySize)); UiMessageBoxCritical("Memory allocation failed: out of memory."); return NULL; } @@ -96,7 +65,7 @@ PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType) if (FirstFreePageFromEnd == (ULONG)-1) { - DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount)); + DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes.\n", MemorySize)); UiMessageBoxCritical("Memory allocation failed: out of memory."); return NULL; } @@ -106,16 +75,8 @@ PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType) FreePagesInLookupTable -= PagesNeeded; MemPointer = (PVOID)(FirstFreePageFromEnd * MM_PAGE_SIZE); - if (MemorySize < MM_PAGE_SIZE) - { - SubAllocationPage = MemPointer; - SubAllocationRest = MM_PAGE_SIZE - MemorySize; - } - - #ifdef DBG - IncrementAllocationCount(); - DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize, PagesNeeded, FirstFreePageFromEnd, AllocationCount)); + DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d.\n", MemorySize, PagesNeeded, FirstFreePageFromEnd)); DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer)); //VerifyHeap(); #endif // DBG @@ -124,10 +85,42 @@ PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType) return MemPointer; } +PVOID MmHeapAlloc(ULONG MemorySize) +{ + PVOID Result; + LONG CurAlloc, TotalFree, MaxFree, NumberOfGets, NumberOfRels; + + if (MemorySize > MM_PAGE_SIZE) + { + DbgPrint((DPRINT_MEMORY, "Consider using other functions to allocate %d bytes of memory!\n", MemorySize)); + } + + // Get the buffer from BGET pool + Result = bget(MemorySize); + + if (Result == NULL) + { + DbgPrint((DPRINT_MEMORY, "Heap allocation for %d bytes failed\n", MemorySize)); + } + + // Gather some stats + bstats(&CurAlloc, &TotalFree, &MaxFree, &NumberOfGets, &NumberOfRels); + + DbgPrint((DPRINT_MEMORY, "Current alloced %d bytes, free %d bytes, allocs %d, frees %d\n", + CurAlloc, TotalFree, NumberOfGets, NumberOfRels)); + + return Result; +} + +VOID MmHeapFree(PVOID MemoryPointer) +{ + // Release the buffer to the pool + brel(MemoryPointer); +} PVOID MmAllocateMemory(ULONG MemorySize) { - // Allocate it as "heap" + // Temporary forwarder... return MmAllocateMemoryWithType(MemorySize, LoaderOsloaderHeap); } @@ -157,7 +150,7 @@ PVOID MmAllocateMemoryAtAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_ { DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemoryAtAddress(). " "Not enough free memory to allocate %d bytes (requesting %d pages but have only %d). " - "AllocationCount: %d\n", MemorySize, PagesNeeded, FreePagesInLookupTable, AllocationCount)); + "\n", MemorySize, PagesNeeded, FreePagesInLookupTable)); UiMessageBoxCritical("Memory allocation failed: out of memory."); return NULL; } @@ -165,8 +158,8 @@ PVOID MmAllocateMemoryAtAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_ if (MmAreMemoryPagesAvailable(PageLookupTableAddress, TotalPagesInLookupTable, DesiredAddress, PagesNeeded) == FALSE) { DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemoryAtAddress(). " - "Not enough free memory to allocate %d bytes at address %p. AllocationCount: %d\n", - MemorySize, DesiredAddress, AllocationCount)); + "Not enough free memory to allocate %d bytes at address %p.\n", + MemorySize, DesiredAddress)); // Don't tell this to user since caller should try to alloc this memory // at a different address @@ -180,8 +173,7 @@ PVOID MmAllocateMemoryAtAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_ MemPointer = (PVOID)(StartPageNumber * MM_PAGE_SIZE); #ifdef DBG - IncrementAllocationCount(); - DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize, PagesNeeded, StartPageNumber, AllocationCount)); + DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d.\n", MemorySize, PagesNeeded, StartPageNumber)); DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer)); //VerifyHeap(); #endif // DBG @@ -215,7 +207,7 @@ PVOID MmAllocateHighestMemoryBelowAddress(ULONG MemorySize, PVOID DesiredAddress // then return NULL if (FreePagesInLookupTable < PagesNeeded) { - DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount)); + DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes.\n", MemorySize)); UiMessageBoxCritical("Memory allocation failed: out of memory."); return NULL; } @@ -224,7 +216,7 @@ PVOID MmAllocateHighestMemoryBelowAddress(ULONG MemorySize, PVOID DesiredAddress if (FirstFreePageFromEnd == 0) { - DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount)); + DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes.\n", MemorySize)); UiMessageBoxCritical("Memory allocation failed: out of memory."); return NULL; } @@ -235,8 +227,7 @@ PVOID MmAllocateHighestMemoryBelowAddress(ULONG MemorySize, PVOID DesiredAddress MemPointer = (PVOID)(FirstFreePageFromEnd * MM_PAGE_SIZE); #ifdef DBG - IncrementAllocationCount(); - DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize, PagesNeeded, FirstFreePageFromEnd, AllocationCount)); + DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d.\n", MemorySize, PagesNeeded, FirstFreePageFromEnd)); DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer)); //VerifyHeap(); #endif // DBG @@ -247,129 +238,9 @@ PVOID MmAllocateHighestMemoryBelowAddress(ULONG MemorySize, PVOID DesiredAddress VOID MmFreeMemory(PVOID MemoryPointer) { - ULONG PageNumber; - ULONG PageCount; - ULONG Idx; - PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress; - -#ifdef DBG - - // Make sure we didn't get a bogus pointer - if (MemoryPointer >= (PVOID)(TotalPagesInLookupTable * MM_PAGE_SIZE)) - { - BugCheck((DPRINT_MEMORY, "Bogus memory pointer (0x%x) passed to MmFreeMemory()\n", MemoryPointer)); - } -#endif // DBG - - // Find out the page number of the first - // page of memory they allocated - PageNumber = MmGetPageNumberFromAddress(MemoryPointer); - PageCount = RealPageLookupTable[PageNumber].PageAllocationLength; - -#ifdef DBG - // Make sure we didn't get a bogus pointer - if ((PageCount < 1) || (PageCount > (TotalPagesInLookupTable - PageNumber))) - { - BugCheck((DPRINT_MEMORY, "Invalid page count in lookup table. PageLookupTable[%d].PageAllocationLength = %d\n", PageNumber, RealPageLookupTable[PageNumber].PageAllocationLength)); - } - - // Loop through our array check all the pages - // to make sure they are allocated with a length of 0 - for (Idx=PageNumber+1; Idx<(PageNumber + PageCount); Idx++) - { - if ((RealPageLookupTable[Idx].PageAllocated == LoaderFree) || - (RealPageLookupTable[Idx].PageAllocationLength != 0)) - { - BugCheck((DPRINT_MEMORY, "Invalid page entry in lookup table, PageAllocated should = 1 and PageAllocationLength should = 0 because this is not the first block in the run. PageLookupTable[%d].PageAllocated = %d PageLookupTable[%d].PageAllocationLength = %d\n", PageNumber, RealPageLookupTable[PageNumber].PageAllocated, PageNumber, RealPageLookupTable[PageNumber].PageAllocationLength)); - } - } - -#endif - - /* If this allocation is only a single page, it could be a sub-allocated page. - * Just don't free it */ - if (1 == PageCount) - { - return; - } - - // Loop through our array and mark all the - // blocks as free - for (Idx=PageNumber; Idx<(PageNumber + PageCount); Idx++) - { - RealPageLookupTable[Idx].PageAllocated = LoaderFree; - RealPageLookupTable[Idx].PageAllocationLength = 0; - } - - FreePagesInLookupTable += PageCount; - -#ifdef DBG - DecrementAllocationCount(); - DbgPrint((DPRINT_MEMORY, "Freed %d pages of memory starting at page %d. AllocationCount: %d\n", PageCount, PageNumber, AllocationCount)); - //VerifyHeap(); -#endif // DBG } #ifdef DBG -VOID VerifyHeap(VOID) -{ - ULONG Idx; - ULONG Idx2; - ULONG Count; - PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress; - - if (DUMP_MEM_MAP_ON_VERIFY) - { - DumpMemoryAllocMap(); - } - - // Loop through the array and verify that - // everything is kosher - for (Idx=0; Idx (TotalPagesInLookupTable - Idx))) - { - BugCheck((DPRINT_MEMORY, "Allocation length out of range in heap table. PageLookupTable[Idx].PageAllocationLength = %d\n", RealPageLookupTable[Idx].PageAllocationLength)); - } - - // Now go through and verify that the rest of - // this run has the blocks marked allocated - // with a length of zero but don't check the - // first one because we already did - Count = RealPageLookupTable[Idx].PageAllocationLength; - for (Idx2=1; Idx2Flags & REG_VALUE_NAME_PACKED) { - wName = MmAllocateMemory ((ValueCell->NameSize + 1)*sizeof(WCHAR)); + wName = MmHeapAlloc((ValueCell->NameSize + 1)*sizeof(WCHAR)); for (i = 0; i < ValueCell->NameSize; i++) { wName[i] = ((PCHAR)ValueCell->Name)[i]; @@ -547,7 +547,7 @@ RegImportValue (PHHIVE Hive, } else { - wName = MmAllocateMemory (ValueCell->NameSize + sizeof(WCHAR)); + wName = MmHeapAlloc(ValueCell->NameSize + sizeof(WCHAR)); memcpy (wName, ValueCell->Name, ValueCell->NameSize); @@ -569,7 +569,7 @@ RegImportValue (PHHIVE Hive, if (Error != ERROR_SUCCESS) { DbgPrint((DPRINT_REGISTRY, "RegSetValue() failed!\n")); - MmFreeMemory (wName); + MmHeapFree(wName); return FALSE; } } @@ -587,12 +587,12 @@ RegImportValue (PHHIVE Hive, if (Error != ERROR_SUCCESS) { DbgPrint((DPRINT_REGISTRY, "RegSetValue() failed!\n")); - MmFreeMemory (wName); + MmHeapFree(wName); return FALSE; } } - MmFreeMemory (wName); + MmHeapFree (wName); return TRUE; } @@ -623,7 +623,7 @@ RegImportSubKey(PHHIVE Hive, if (KeyCell->Flags & REG_KEY_NAME_PACKED) { - wName = MmAllocateMemory ((KeyCell->NameSize + 1) * sizeof(WCHAR)); + wName = MmHeapAlloc ((KeyCell->NameSize + 1) * sizeof(WCHAR)); for (i = 0; i < KeyCell->NameSize; i++) { wName[i] = ((PCHAR)KeyCell->Name)[i]; @@ -632,7 +632,7 @@ RegImportSubKey(PHHIVE Hive, } else { - wName = MmAllocateMemory (KeyCell->NameSize + sizeof(WCHAR)); + wName = MmHeapAlloc (KeyCell->NameSize + sizeof(WCHAR)); memcpy (wName, KeyCell->Name, KeyCell->NameSize); @@ -645,7 +645,7 @@ RegImportSubKey(PHHIVE Hive, Error = RegCreateKey (ParentKey, wName, &SubKey); - MmFreeMemory (wName); + MmHeapFree (wName); if (Error != ERROR_SUCCESS) { DbgPrint((DPRINT_REGISTRY, "RegCreateKey() failed!\n")); diff --git a/reactos/registry.c b/reactos/registry.c index 89c440428ee..f02ef8796c5 100644 --- a/reactos/registry.c +++ b/reactos/registry.c @@ -33,7 +33,7 @@ RegInitializeRegistry (VOID) #endif /* Create root key */ - RootKey = (FRLDRHKEY) MmAllocateMemory (sizeof(KEY)); + RootKey = (FRLDRHKEY) MmHeapAlloc (sizeof(KEY)); InitializeListHead (&RootKey->SubKeyList); InitializeListHead (&RootKey->ValueList); @@ -43,7 +43,7 @@ RegInitializeRegistry (VOID) RootKey->ValueCount = 0; RootKey->NameSize = 4; - RootKey->Name = MmAllocateMemory (4); + RootKey->Name = MmHeapAlloc (4); wcscpy (RootKey->Name, L"\\"); RootKey->DataType = 0; @@ -282,7 +282,7 @@ RegCreateKey(FRLDRHKEY ParentKey, if (CmpResult != 0) { /* no key found -> create new subkey */ - NewKey = (FRLDRHKEY)MmAllocateMemory(sizeof(KEY)); + NewKey = (FRLDRHKEY)MmHeapAlloc(sizeof(KEY)); if (NewKey == NULL) return(ERROR_OUTOFMEMORY); @@ -300,7 +300,7 @@ RegCreateKey(FRLDRHKEY ParentKey, CurrentKey->SubKeyCount++; NewKey->NameSize = NameSize; - NewKey->Name = (PWCHAR)MmAllocateMemory(NewKey->NameSize); + NewKey->Name = (PWCHAR)MmHeapAlloc(NewKey->NameSize); if (NewKey->Name == NULL) return(ERROR_OUTOFMEMORY); memcpy(NewKey->Name, name, NewKey->NameSize - sizeof(WCHAR)); @@ -517,7 +517,7 @@ RegSetValue(FRLDRHKEY Key, } else { - Key->Data = MmAllocateMemory(DataSize); + Key->Data = MmHeapAlloc(DataSize); Key->DataSize = DataSize; Key->DataType = Type; memcpy(Key->Data, Data, DataSize); @@ -546,7 +546,7 @@ RegSetValue(FRLDRHKEY Key, /* add new value */ DbgPrint((DPRINT_REGISTRY, "No value found - adding new value\n")); - Value = (PVALUE)MmAllocateMemory(sizeof(VALUE)); + Value = (PVALUE)MmHeapAlloc(sizeof(VALUE)); if (Value == NULL) return(ERROR_OUTOFMEMORY); @@ -554,7 +554,7 @@ RegSetValue(FRLDRHKEY Key, Key->ValueCount++; Value->NameSize = (wcslen(ValueName)+1)*sizeof(WCHAR); - Value->Name = (PWCHAR)MmAllocateMemory(Value->NameSize); + Value->Name = (PWCHAR)MmHeapAlloc(Value->NameSize); if (Value->Name == NULL) return(ERROR_OUTOFMEMORY); wcscpy(Value->Name, ValueName); @@ -577,7 +577,7 @@ RegSetValue(FRLDRHKEY Key, } else { - Value->Data = MmAllocateMemory(DataSize); + Value->Data = MmHeapAlloc(DataSize); if (Value->Data == NULL) return(ERROR_OUTOFMEMORY); Value->DataType = Type; diff --git a/rtl/bget.c b/rtl/bget.c new file mode 100644 index 00000000000..f290a708afa --- /dev/null +++ b/rtl/bget.c @@ -0,0 +1,1593 @@ +/* + + B G E T + + Buffer allocator + + Designed and implemented in April of 1972 by John Walker, based on the + Case Algol OPRO$ algorithm implemented in 1966. + + Reimplemented in 1975 by John Walker for the Interdata 70. + Reimplemented in 1977 by John Walker for the Marinchip 9900. + Reimplemented in 1982 by Duff Kurland for the Intel 8080. + + Portable C version implemented in September of 1990 by an older, wiser + instance of the original implementor. + + Souped up and/or weighed down slightly shortly thereafter by Greg + Lutz. + + AMIX edition, including the new compaction call-back option, prepared + by John Walker in July of 1992. + + Bug in built-in test program fixed, ANSI compiler warnings eradicated, + buffer pool validator implemented, and guaranteed repeatable test + added by John Walker in October of 1995. + + This program is in the public domain. + + 1. This is the book of the generations of Adam. In the day that God + created man, in the likeness of God made he him; + 2. Male and female created he them; and blessed them, and called + their name Adam, in the day when they were created. + 3. And Adam lived an hundred and thirty years, and begat a son in + his own likeness, and after his image; and called his name Seth: + 4. And the days of Adam after he had begotten Seth were eight + hundred years: and he begat sons and daughters: + 5. And all the days that Adam lived were nine hundred and thirty + years: and he died. + 6. And Seth lived an hundred and five years, and begat Enos: + 7. And Seth lived after he begat Enos eight hundred and seven years, + and begat sons and daughters: + 8. And all the days of Seth were nine hundred and twelve years: and + he died. + 9. And Enos lived ninety years, and begat Cainan: + 10. And Enos lived after he begat Cainan eight hundred and fifteen + years, and begat sons and daughters: + 11. And all the days of Enos were nine hundred and five years: and + he died. + 12. And Cainan lived seventy years and begat Mahalaleel: + 13. And Cainan lived after he begat Mahalaleel eight hundred and + forty years, and begat sons and daughters: + 14. And all the days of Cainan were nine hundred and ten years: and + he died. + 15. And Mahalaleel lived sixty and five years, and begat Jared: + 16. And Mahalaleel lived after he begat Jared eight hundred and + thirty years, and begat sons and daughters: + 17. And all the days of Mahalaleel were eight hundred ninety and + five years: and he died. + 18. And Jared lived an hundred sixty and two years, and he begat + Enoch: + 19. And Jared lived after he begat Enoch eight hundred years, and + begat sons and daughters: + 20. And all the days of Jared were nine hundred sixty and two years: + and he died. + 21. And Enoch lived sixty and five years, and begat Methuselah: + 22. And Enoch walked with God after he begat Methuselah three + hundred years, and begat sons and daughters: + 23. And all the days of Enoch were three hundred sixty and five + years: + 24. And Enoch walked with God: and he was not; for God took him. + 25. And Methuselah lived an hundred eighty and seven years, and + begat Lamech. + 26. And Methuselah lived after he begat Lamech seven hundred eighty + and two years, and begat sons and daughters: + 27. And all the days of Methuselah were nine hundred sixty and nine + years: and he died. + 28. And Lamech lived an hundred eighty and two years, and begat a + son: + 29. And he called his name Noah, saying, This same shall comfort us + concerning our work and toil of our hands, because of the ground + which the LORD hath cursed. + 30. And Lamech lived after he begat Noah five hundred ninety and + five years, and begat sons and daughters: + 31. And all the days of Lamech were seven hundred seventy and seven + years: and he died. + 32. And Noah was five hundred years old: and Noah begat Shem, Ham, + and Japheth. + + And buffers begat buffers, and links begat links, and buffer pools + begat links to chains of buffer pools containing buffers, and lo the + buffers and links and pools of buffers and pools of links to chains of + pools of buffers were fruitful and they multiplied and the Operating + System looked down upon them and said that it was Good. + + + INTRODUCTION + ============ + + BGET is a comprehensive memory allocation package which is easily + configured to the needs of an application. BGET is efficient in + both the time needed to allocate and release buffers and in the + memory overhead required for buffer pool management. It + automatically consolidates contiguous space to minimise + fragmentation. BGET is configured by compile-time definitions, + Major options include: + + * A built-in test program to exercise BGET and + demonstrate how the various functions are used. + + * Allocation by either the "first fit" or "best fit" + method. + + * Wiping buffers at release time to catch code which + references previously released storage. + + * Built-in routines to dump individual buffers or the + entire buffer pool. + + * Retrieval of allocation and pool size statistics. + + * Quantisation of buffer sizes to a power of two to + satisfy hardware alignment constraints. + + * Automatic pool compaction, growth, and shrinkage by + means of call-backs to user defined functions. + + Applications of BGET can range from storage management in + ROM-based embedded programs to providing the framework upon which + a multitasking system incorporating garbage collection is + constructed. BGET incorporates extensive internal consistency + checking using the mechanism; all these checks can be + turned off by compiling with NDEBUG defined, yielding a version of + BGET with minimal size and maximum speed. + + The basic algorithm underlying BGET has withstood the test of + time; more than 25 years have passed since the first + implementation of this code. And yet, it is substantially more + efficient than the native allocation schemes of many operating + systems: the Macintosh and Microsoft Windows to name two, on which + programs have obtained substantial speed-ups by layering BGET as + an application level memory manager atop the underlying system's. + + BGET has been implemented on the largest mainframes and the lowest + of microprocessors. It has served as the core for multitasking + operating systems, multi-thread applications, embedded software in + data network switching processors, and a host of C programs. And + while it has accreted flexibility and additional options over the + years, it remains fast, memory efficient, portable, and easy to + integrate into your program. + + + BGET IMPLEMENTATION ASSUMPTIONS + =============================== + + BGET is written in as portable a dialect of C as possible. The + only fundamental assumption about the underlying hardware + architecture is that memory is allocated is a linear array which + can be addressed as a vector of C "char" objects. On segmented + address space architectures, this generally means that BGET should + be used to allocate storage within a single segment (although some + compilers simulate linear address spaces on segmented + architectures). On segmented architectures, then, BGET buffer + pools may not be larger than a segment, but since BGET allows any + number of separate buffer pools, there is no limit on the total + storage which can be managed, only on the largest individual + object which can be allocated. Machines with a linear address + architecture, such as the VAX, 680x0, Sparc, MIPS, or the Intel + 80386 and above in native mode, may use BGET without restriction. + + + GETTING STARTED WITH BGET + ========================= + + Although BGET can be configured in a multitude of fashions, there + are three basic ways of working with BGET. The functions + mentioned below are documented in the following section. Please + excuse the forward references which are made in the interest of + providing a roadmap to guide you to the BGET functions you're + likely to need. + + Embedded Applications + --------------------- + + Embedded applications typically have a fixed area of memory + dedicated to buffer allocation (often in a separate RAM address + space distinct from the ROM that contains the executable code). + To use BGET in such an environment, simply call bpool() with the + start address and length of the buffer pool area in RAM, then + allocate buffers with bget() and release them with brel(). + Embedded applications with very limited RAM but abundant CPU speed + may benefit by configuring BGET for BestFit allocation (which is + usually not worth it in other environments). + + Malloc() Emulation + ------------------ + + If the C library malloc() function is too slow, not present in + your development environment (for example, an a native Windows or + Macintosh program), or otherwise unsuitable, you can replace it + with BGET. Initially define a buffer pool of an appropriate size + with bpool()--usually obtained by making a call to the operating + system's low-level memory allocator. Then allocate buffers with + bget(), bgetz(), and bgetr() (the last two permit the allocation + of buffers initialised to zero and [inefficient] re-allocation of + existing buffers for compatibility with C library functions). + Release buffers by calling brel(). If a buffer allocation request + fails, obtain more storage from the underlying operating system, + add it to the buffer pool by another call to bpool(), and continue + execution. + + Automatic Storage Management + ---------------------------- + + You can use BGET as your application's native memory manager and + implement automatic storage pool expansion, contraction, and + optionally application-specific memory compaction by compiling + BGET with the BECtl variable defined, then calling bectl() and + supplying functions for storage compaction, acquisition, and + release, as well as a standard pool expansion increment. All of + these functions are optional (although it doesn't make much sense + to provide a release function without an acquisition function, + does it?). Once the call-back functions have been defined with + bectl(), you simply use bget() and brel() to allocate and release + storage as before. You can supply an initial buffer pool with + bpool() or rely on automatic allocation to acquire the entire + pool. When a call on bget() cannot be satisfied, BGET first + checks if a compaction function has been supplied. If so, it is + called (with the space required to satisfy the allocation request + and a sequence number to allow the compaction routine to be called + successively without looping). If the compaction function is able + to free any storage (it needn't know whether the storage it freed + was adequate) it should return a nonzero value, whereupon BGET + will retry the allocation request and, if it fails again, call the + compaction function again with the next-higher sequence number. + + If the compaction function returns zero, indicating failure to + free space, or no compaction function is defined, BGET next tests + whether a non-NULL allocation function was supplied to bectl(). + If so, that function is called with an argument indicating how + many bytes of additional space are required. This will be the + standard pool expansion increment supplied in the call to bectl() + unless the original bget() call requested a buffer larger than + this; buffers larger than the standard pool block can be managed + "off the books" by BGET in this mode. If the allocation function + succeeds in obtaining the storage, it returns a pointer to the new + block and BGET expands the buffer pool; if it fails, the + allocation request fails and returns NULL to the caller. If a + non-NULL release function is supplied, expansion blocks which + become totally empty are released to the global free pool by + passing their addresses to the release function. + + Equipped with appropriate allocation, release, and compaction + functions, BGET can be used as part of very sophisticated memory + management strategies, including garbage collection. (Note, + however, that BGET is *not* a garbage collector by itself, and + that developing such a system requires much additional logic and + careful design of the application's memory allocation strategy.) + + + BGET FUNCTION DESCRIPTIONS + ========================== + + Functions implemented in this file (some are enabled by certain of + the optional settings below): + + void bpool(void *buffer, bufsize len); + + Create a buffer pool of bytes, using the storage starting at + . You can call bpool() subsequently to contribute + additional storage to the overall buffer pool. + + void *bget(bufsize size); + + Allocate a buffer of bytes. The address of the buffer is + returned, or NULL if insufficient memory was available to allocate + the buffer. + + void *bgetz(bufsize size); + + Allocate a buffer of bytes and clear it to all zeroes. The + address of the buffer is returned, or NULL if insufficient memory + was available to allocate the buffer. + + void *bgetr(void *buffer, bufsize newsize); + + Reallocate a buffer previously allocated by bget(), changing its + size to and preserving all existing data. NULL is + returned if insufficient memory is available to reallocate the + buffer, in which case the original buffer remains intact. + + void brel(void *buf); + + Return the buffer , previously allocated by bget(), to the + free space pool. + + void bectl(int (*compact)(bufsize sizereq, int sequence), + void *(*acquire)(bufsize size), + void (*release)(void *buf), + bufsize pool_incr); + + Expansion control: specify functions through which the package may + compact storage (or take other appropriate action) when an + allocation request fails, and optionally automatically acquire + storage for expansion blocks when necessary, and release such + blocks when they become empty. If is non-NULL, whenever + a buffer allocation request fails, the function will be + called with arguments specifying the number of bytes (total buffer + size, including header overhead) required to satisfy the + allocation request, and a sequence number indicating the number of + consecutive calls on attempting to satisfy this + allocation request. The sequence number is 1 for the first call + on for a given allocation request, and increments on + subsequent calls, permitting the function to take + increasingly dire measures in an attempt to free up storage. If + the function returns a nonzero value, the allocation + attempt is re-tried. If returns 0 (as it must if it + isn't able to release any space or add storage to the buffer + pool), the allocation request fails, which can trigger automatic + pool expansion if the argument is non-NULL. At the time + the function is called, the state of the buffer + allocator is identical to that at the moment the allocation + request was made; consequently, the function may call + brel(), bpool(), bstats(), and/or directly manipulate the buffer + pool in any manner which would be valid were the application in + control. This does not, however, relieve the function + of the need to ensure that whatever actions it takes do not change + things underneath the application that made the allocation + request. For example, a function that released a buffer + in the process of being reallocated with bgetr() would lead to + disaster. Implementing a safe and effective mechanism + requires careful design of an application's memory architecture, + and cannot generally be easily retrofitted into existing code. + + If is non-NULL, that function will be called whenever an + allocation request fails. If the function succeeds in + allocating the requested space and returns a pointer to the new + area, allocation will proceed using the expanded buffer pool. If + cannot obtain the requested space, it should return NULL + and the entire allocation process will fail. + specifies the normal expansion block size. Providing an + function will cause subsequent bget() requests for buffers too + large to be managed in the linked-block scheme (in other words, + larger than minus the buffer overhead) to be satisfied + directly by calls to the function. Automatic release of + empty pool blocks will occur only if all pool blocks in the system + are the size given by . + + void bstats(bufsize *curalloc, bufsize *totfree, + bufsize *maxfree, long *nget, long *nrel); + + The amount of space currently allocated is stored into the + variable pointed to by . The total free space (sum of + all free blocks in the pool) is stored into the variable pointed + to by , and the size of the largest single block in the + free space pool is stored into the variable pointed to by + . The variables pointed to by and are + filled, respectively, with the number of successful (non-NULL + return) bget() calls and the number of brel() calls. + + void bstatse(bufsize *pool_incr, long *npool, + long *npget, long *nprel, + long *ndget, long *ndrel); + + Extended statistics: The expansion block size will be stored into + the variable pointed to by , or the negative thereof if + automatic expansion block releases are disabled. The number of + currently active pool blocks will be stored into the variable + pointed to by . The variables pointed to by and + will be filled with, respectively, the number of expansion + block acquisitions and releases which have occurred. The + variables pointed to by and will be filled with + the number of bget() and brel() calls, respectively, managed + through blocks directly allocated by the acquisition and release + functions. + + void bufdump(void *buf); + + The buffer pointed to by is dumped on standard output. + + void bpoold(void *pool, int dumpalloc, int dumpfree); + + All buffers in the buffer pool , previously initialised by a + call on bpool(), are listed in ascending memory address order. If + is nonzero, the contents of allocated buffers are + dumped; if is nonzero, the contents of free blocks are + dumped. + + int bpoolv(void *pool); + + The named buffer pool, previously initialised by a call on + bpool(), is validated for bad pointers, overwritten data, etc. If + compiled with NDEBUG not defined, any error generates an assertion + failure. Otherwise 1 is returned if the pool is valid, 0 if an + error is found. + + + BGET CONFIGURATION + ================== +*/ + +/*#define TestProg 20000*/ /* Generate built-in test program + if defined. The value specifies + how many buffer allocation attempts + the test program should make. */ + +#define SizeQuant 4 /* Buffer allocation size quantum: + all buffers allocated are a + multiple of this size. This + MUST be a power of two. */ + +#define BufDump 1 /* Define this symbol to enable the + bpoold() function which dumps the + buffers in a buffer pool. */ + +#define BufValid 1 /* Define this symbol to enable the + bpoolv() function for validating + a buffer pool. */ + +#define DumpData 1 /* Define this symbol to enable the + bufdump() function which allows + dumping the contents of an allocated + or free buffer. */ + +#define BufStats 1 /* Define this symbol to enable the + bstats() function which calculates + the total free space in the buffer + pool, the largest available + buffer, and the total space + currently allocated. */ + +#define FreeWipe 1 /* Wipe free buffers to a guaranteed + pattern of garbage to trip up + miscreants who attempt to use + pointers into released buffers. */ + +#define BestFit 1 /* Use a best fit algorithm when + searching for space for an + allocation request. This uses + memory more efficiently, but + allocation will be much slower. */ + +#define BECtl 1 /* Define this symbol to enable the + bectl() function for automatic + pool space control. */ + +#include + +#ifdef lint +#define NDEBUG /* Exits in asserts confuse lint */ +/* LINTLIBRARY */ /* Don't complain about def, no ref */ +extern char *sprintf(); /* Sun includes don't define sprintf */ +#endif + +#define NDEBUG + +#include +#include + +#ifdef BufDump /* BufDump implies DumpData */ +#ifndef DumpData +#define DumpData 1 +#endif +#endif + +#ifdef DumpData +#include +#endif + +/* Declare the interface, including the requested buffer size type, + bufsize. */ + +#include "bget.h" + +#define MemSize int /* Type for size arguments to memxxx() + functions such as memcmp(). */ + +/* Queue links */ + +struct qlinks { + struct bfhead *flink; /* Forward link */ + struct bfhead *blink; /* Backward link */ +}; + +/* Header in allocated and free buffers */ + +struct bhead { + bufsize prevfree; /* Relative link back to previous + free buffer in memory or 0 if + previous buffer is allocated. */ + bufsize bsize; /* Buffer size: positive if free, + negative if allocated. */ +}; +#define BH(p) ((struct bhead *) (p)) + +/* Header in directly allocated buffers (by acqfcn) */ + +struct bdhead { + bufsize tsize; /* Total size, including overhead */ + struct bhead bh; /* Common header */ +}; +#define BDH(p) ((struct bdhead *) (p)) + +/* Header in free buffers */ + +struct bfhead { + struct bhead bh; /* Common allocated/free header */ + struct qlinks ql; /* Links on free list */ +}; +#define BFH(p) ((struct bfhead *) (p)) + +static struct bfhead freelist = { /* List of free buffers */ + {0, 0}, + {&freelist, &freelist} +}; + + +#ifdef BufStats +static bufsize totalloc = 0; /* Total space currently allocated */ +static long numget = 0, numrel = 0; /* Number of bget() and brel() calls */ +#ifdef BECtl +static long numpblk = 0; /* Number of pool blocks */ +static long numpget = 0, numprel = 0; /* Number of block gets and rels */ +static long numdget = 0, numdrel = 0; /* Number of direct gets and rels */ +#endif /* BECtl */ +#endif /* BufStats */ + +#ifdef BECtl + +/* Automatic expansion block management functions */ + +static int (*compfcn) _((bufsize sizereq, int sequence)) = NULL; +static void *(*acqfcn) _((bufsize size)) = NULL; +static void (*relfcn) _((void *buf)) = NULL; + +static bufsize exp_incr = 0; /* Expansion block size */ +static bufsize pool_len = 0; /* 0: no bpool calls have been made + -1: not all pool blocks are + the same size + >0: (common) block size for all + bpool calls made so far + */ +#endif + +/* Minimum allocation quantum: */ + +#define QLSize (sizeof(struct qlinks)) +#define SizeQ ((SizeQuant > QLSize) ? SizeQuant : QLSize) + +#define V (void) /* To denote unwanted returned values */ + +/* End sentinel: value placed in bsize field of dummy block delimiting + end of pool block. The most negative number which will fit in a + bufsize, defined in a way that the compiler will accept. */ + +#define ESent ((bufsize) (-(((1L << (sizeof(bufsize) * 8 - 2)) - 1) * 2) - 2)) + +/* BGET -- Allocate a buffer. */ + +void *bget(requested_size) + bufsize requested_size; +{ + bufsize size = requested_size; + struct bfhead *b; +#ifdef BestFit + struct bfhead *best; +#endif + void *buf; +#ifdef BECtl + int compactseq = 0; +#endif + + assert(size > 0); + + if (size < SizeQ) { /* Need at least room for the */ + size = SizeQ; /* queue links. */ + } +#ifdef SizeQuant +#if SizeQuant > 1 + size = (size + (SizeQuant - 1)) & (~(SizeQuant - 1)); +#endif +#endif + + size += sizeof(struct bhead); /* Add overhead in allocated buffer + to size required. */ + +#ifdef BECtl + /* If a compact function was provided in the call to bectl(), wrap + a loop around the allocation process to allow compaction to + intervene in case we don't find a suitable buffer in the chain. */ + + while (1) { +#endif + b = freelist.ql.flink; +#ifdef BestFit + best = &freelist; +#endif + + + /* Scan the free list searching for the first buffer big enough + to hold the requested size buffer. */ + +#ifdef BestFit + while (b != &freelist) { + if (b->bh.bsize >= size) { + if ((best == &freelist) || (b->bh.bsize < best->bh.bsize)) { + best = b; + } + } + b = b->ql.flink; /* Link to next buffer */ + } + b = best; +#endif /* BestFit */ + + while (b != &freelist) { + if ((bufsize) b->bh.bsize >= size) { + + /* Buffer is big enough to satisfy the request. Allocate it + to the caller. We must decide whether the buffer is large + enough to split into the part given to the caller and a + free buffer that remains on the free list, or whether the + entire buffer should be removed from the free list and + given to the caller in its entirety. We only split the + buffer if enough room remains for a header plus the minimum + quantum of allocation. */ + + if ((b->bh.bsize - size) > (SizeQ + (sizeof(struct bhead)))) { + struct bhead *ba, *bn; + + ba = BH(((char *) b) + (b->bh.bsize - size)); + bn = BH(((char *) ba) + size); + assert(bn->prevfree == b->bh.bsize); + /* Subtract size from length of free block. */ + b->bh.bsize -= size; + /* Link allocated buffer to the previous free buffer. */ + ba->prevfree = b->bh.bsize; + /* Plug negative size into user buffer. */ + ba->bsize = -(bufsize) size; + /* Mark buffer after this one not preceded by free block. */ + bn->prevfree = 0; + +#ifdef BufStats + totalloc += size; + numget++; /* Increment number of bget() calls */ +#endif + buf = (void *) ((((char *) ba) + sizeof(struct bhead))); + return buf; + } else { + struct bhead *ba; + + ba = BH(((char *) b) + b->bh.bsize); + assert(ba->prevfree == b->bh.bsize); + + /* The buffer isn't big enough to split. Give the whole + shebang to the caller and remove it from the free list. */ + + assert(b->ql.blink->ql.flink == b); + assert(b->ql.flink->ql.blink == b); + b->ql.blink->ql.flink = b->ql.flink; + b->ql.flink->ql.blink = b->ql.blink; + +#ifdef BufStats + totalloc += b->bh.bsize; + numget++; /* Increment number of bget() calls */ +#endif + /* Negate size to mark buffer allocated. */ + b->bh.bsize = -(b->bh.bsize); + + /* Zero the back pointer in the next buffer in memory + to indicate that this buffer is allocated. */ + ba->prevfree = 0; + + /* Give user buffer starting at queue links. */ + buf = (void *) &(b->ql); + return buf; + } + } + b = b->ql.flink; /* Link to next buffer */ + } +#ifdef BECtl + + /* We failed to find a buffer. If there's a compact function + defined, notify it of the size requested. If it returns + TRUE, try the allocation again. */ + + if ((compfcn == NULL) || (!(*compfcn)(size, ++compactseq))) { + break; + } + } + + /* No buffer available with requested size free. */ + + /* Don't give up yet -- look in the reserve supply. */ + + if (acqfcn != NULL) { + if (size > exp_incr - sizeof(struct bhead)) { + + /* Request is too large to fit in a single expansion + block. Try to satisy it by a direct buffer acquisition. */ + + struct bdhead *bdh; + + size += sizeof(struct bdhead) - sizeof(struct bhead); + if ((bdh = BDH((*acqfcn)((bufsize) size))) != NULL) { + + /* Mark the buffer special by setting the size field + of its header to zero. */ + bdh->bh.bsize = 0; + bdh->bh.prevfree = 0; + bdh->tsize = size; +#ifdef BufStats + totalloc += size; + numget++; /* Increment number of bget() calls */ + numdget++; /* Direct bget() call count */ +#endif + buf = (void *) (bdh + 1); + return buf; + } + + } else { + + /* Try to obtain a new expansion block */ + + void *newpool; + + if ((newpool = (*acqfcn)((bufsize) exp_incr)) != NULL) { + bpool(newpool, exp_incr); + buf = bget(requested_size); /* This can't, I say, can't + get into a loop. */ + return buf; + } + } + } + + /* Still no buffer available */ + +#endif /* BECtl */ + + return NULL; +} + +/* BGETZ -- Allocate a buffer and clear its contents to zero. We clear + the entire contents of the buffer to zero, not just the + region requested by the caller. */ + +void *bgetz(size) + bufsize size; +{ + char *buf = (char *) bget(size); + + if (buf != NULL) { + struct bhead *b; + bufsize rsize; + + b = BH(buf - sizeof(struct bhead)); + rsize = -(b->bsize); + if (rsize == 0) { + struct bdhead *bd; + + bd = BDH(buf - sizeof(struct bdhead)); + rsize = bd->tsize - sizeof(struct bdhead); + } else { + rsize -= sizeof(struct bhead); + } + assert(rsize >= size); + V memset(buf, 0, (MemSize) rsize); + } + return ((void *) buf); +} + +/* BGETR -- Reallocate a buffer. This is a minimal implementation, + simply in terms of brel() and bget(). It could be + enhanced to allow the buffer to grow into adjacent free + blocks and to avoid moving data unnecessarily. */ + +void *bgetr(buf, size) + void *buf; + bufsize size; +{ + void *nbuf; + bufsize osize; /* Old size of buffer */ + struct bhead *b; + + if ((nbuf = bget(size)) == NULL) { /* Acquire new buffer */ + return NULL; + } + if (buf == NULL) { + return nbuf; + } + b = BH(((char *) buf) - sizeof(struct bhead)); + osize = -b->bsize; +#ifdef BECtl + if (osize == 0) { + /* Buffer acquired directly through acqfcn. */ + struct bdhead *bd; + + bd = BDH(((char *) buf) - sizeof(struct bdhead)); + osize = bd->tsize - sizeof(struct bdhead); + } else +#endif + osize -= sizeof(struct bhead); + assert(osize > 0); + V memcpy((char *) nbuf, (char *) buf, /* Copy the data */ + (MemSize) ((size < osize) ? size : osize)); + brel(buf); + return nbuf; +} + +/* BREL -- Release a buffer. */ + +void brel(buf) + void *buf; +{ + struct bfhead *b, *bn; + + b = BFH(((char *) buf) - sizeof(struct bhead)); +#ifdef BufStats + numrel++; /* Increment number of brel() calls */ +#endif + assert(buf != NULL); + +#ifdef BECtl + if (b->bh.bsize == 0) { /* Directly-acquired buffer? */ + struct bdhead *bdh; + + bdh = BDH(((char *) buf) - sizeof(struct bdhead)); + assert(b->bh.prevfree == 0); +#ifdef BufStats + totalloc -= bdh->tsize; + assert(totalloc >= 0); + numdrel++; /* Number of direct releases */ +#endif /* BufStats */ +#ifdef FreeWipe + V memset((char *) buf, 0x55, + (MemSize) (bdh->tsize - sizeof(struct bdhead))); +#endif /* FreeWipe */ + assert(relfcn != NULL); + (*relfcn)((void *) bdh); /* Release it directly. */ + return; + } +#endif /* BECtl */ + + /* Buffer size must be negative, indicating that the buffer is + allocated. */ + + if (b->bh.bsize >= 0) { + bn = NULL; + } + assert(b->bh.bsize < 0); + + /* Back pointer in next buffer must be zero, indicating the + same thing: */ + + assert(BH((char *) b - b->bh.bsize)->prevfree == 0); + +#ifdef BufStats + totalloc += b->bh.bsize; + assert(totalloc >= 0); +#endif + + /* If the back link is nonzero, the previous buffer is free. */ + + if (b->bh.prevfree != 0) { + + /* The previous buffer is free. Consolidate this buffer with it + by adding the length of this buffer to the previous free + buffer. Note that we subtract the size in the buffer being + released, since it's negative to indicate that the buffer is + allocated. */ + + register bufsize size = b->bh.bsize; + + /* Make the previous buffer the one we're working on. */ + assert(BH((char *) b - b->bh.prevfree)->bsize == b->bh.prevfree); + b = BFH(((char *) b) - b->bh.prevfree); + b->bh.bsize -= size; + } else { + + /* The previous buffer isn't allocated. Insert this buffer + on the free list as an isolated free block. */ + + assert(freelist.ql.blink->ql.flink == &freelist); + assert(freelist.ql.flink->ql.blink == &freelist); + b->ql.flink = &freelist; + b->ql.blink = freelist.ql.blink; + freelist.ql.blink = b; + b->ql.blink->ql.flink = b; + b->bh.bsize = -b->bh.bsize; + } + + /* Now we look at the next buffer in memory, located by advancing from + the start of this buffer by its size, to see if that buffer is + free. If it is, we combine this buffer with the next one in + memory, dechaining the second buffer from the free list. */ + + bn = BFH(((char *) b) + b->bh.bsize); + if (bn->bh.bsize > 0) { + + /* The buffer is free. Remove it from the free list and add + its size to that of our buffer. */ + + assert(BH((char *) bn + bn->bh.bsize)->prevfree == bn->bh.bsize); + assert(bn->ql.blink->ql.flink == bn); + assert(bn->ql.flink->ql.blink == bn); + bn->ql.blink->ql.flink = bn->ql.flink; + bn->ql.flink->ql.blink = bn->ql.blink; + b->bh.bsize += bn->bh.bsize; + + /* Finally, advance to the buffer that follows the newly + consolidated free block. We must set its backpointer to the + head of the consolidated free block. We know the next block + must be an allocated block because the process of recombination + guarantees that two free blocks will never be contiguous in + memory. */ + + bn = BFH(((char *) b) + b->bh.bsize); + } +#ifdef FreeWipe + V memset(((char *) b) + sizeof(struct bfhead), 0x55, + (MemSize) (b->bh.bsize - sizeof(struct bfhead))); +#endif + assert(bn->bh.bsize < 0); + + /* The next buffer is allocated. Set the backpointer in it to point + to this buffer; the previous free buffer in memory. */ + + bn->bh.prevfree = b->bh.bsize; + +#ifdef BECtl + + /* If a block-release function is defined, and this free buffer + constitutes the entire block, release it. Note that pool_len + is defined in such a way that the test will fail unless all + pool blocks are the same size. */ + + if (relfcn != NULL && + ((bufsize) b->bh.bsize) == (pool_len - sizeof(struct bhead))) { + + assert(b->bh.prevfree == 0); + assert(BH((char *) b + b->bh.bsize)->bsize == ESent); + assert(BH((char *) b + b->bh.bsize)->prevfree == b->bh.bsize); + /* Unlink the buffer from the free list */ + b->ql.blink->ql.flink = b->ql.flink; + b->ql.flink->ql.blink = b->ql.blink; + + (*relfcn)(b); +#ifdef BufStats + numprel++; /* Nr of expansion block releases */ + numpblk--; /* Total number of blocks */ + assert(numpblk == numpget - numprel); +#endif /* BufStats */ + } +#endif /* BECtl */ +} + +#ifdef BECtl + +/* BECTL -- Establish automatic pool expansion control */ + +void bectl(compact, acquire, release, pool_incr) + int (*compact) _((bufsize sizereq, int sequence)); + void *(*acquire) _((bufsize size)); + void (*release) _((void *buf)); + bufsize pool_incr; +{ + compfcn = compact; + acqfcn = acquire; + relfcn = release; + exp_incr = pool_incr; +} +#endif + +/* BPOOL -- Add a region of memory to the buffer pool. */ + +void bpool(buf, len) + void *buf; + bufsize len; +{ + struct bfhead *b = BFH(buf); + struct bhead *bn; + +#ifdef SizeQuant + len &= ~(SizeQuant - 1); +#endif +#ifdef BECtl + if (pool_len == 0) { + pool_len = len; + } else if (len != pool_len) { + pool_len = -1; + } +#ifdef BufStats + numpget++; /* Number of block acquisitions */ + numpblk++; /* Number of blocks total */ + assert(numpblk == numpget - numprel); +#endif /* BufStats */ +#endif /* BECtl */ + + /* Since the block is initially occupied by a single free buffer, + it had better not be (much) larger than the largest buffer + whose size we can store in bhead.bsize. */ + + assert(len - sizeof(struct bhead) <= -((bufsize) ESent + 1)); + + /* Clear the backpointer at the start of the block to indicate that + there is no free block prior to this one. That blocks + recombination when the first block in memory is released. */ + + b->bh.prevfree = 0; + + /* Chain the new block to the free list. */ + + assert(freelist.ql.blink->ql.flink == &freelist); + assert(freelist.ql.flink->ql.blink == &freelist); + b->ql.flink = &freelist; + b->ql.blink = freelist.ql.blink; + freelist.ql.blink = b; + b->ql.blink->ql.flink = b; + + /* Create a dummy allocated buffer at the end of the pool. This dummy + buffer is seen when a buffer at the end of the pool is released and + blocks recombination of the last buffer with the dummy buffer at + the end. The length in the dummy buffer is set to the largest + negative number to denote the end of the pool for diagnostic + routines (this specific value is not counted on by the actual + allocation and release functions). */ + + len -= sizeof(struct bhead); + b->bh.bsize = (bufsize) len; +#ifdef FreeWipe + V memset(((char *) b) + sizeof(struct bfhead), 0x55, + (MemSize) (len - sizeof(struct bfhead))); +#endif + bn = BH(((char *) b) + len); + bn->prevfree = (bufsize) len; + /* Definition of ESent assumes two's complement! */ + assert((~0) == -1); + bn->bsize = ESent; +} + +#ifdef BufStats + +/* BSTATS -- Return buffer allocation free space statistics. */ + +void bstats(curalloc, totfree, maxfree, nget, nrel) + bufsize *curalloc, *totfree, *maxfree; + long *nget, *nrel; +{ + struct bfhead *b = freelist.ql.flink; + + *nget = numget; + *nrel = numrel; + *curalloc = totalloc; + *totfree = 0; + *maxfree = -1; + while (b != &freelist) { + assert(b->bh.bsize > 0); + *totfree += b->bh.bsize; + if (b->bh.bsize > *maxfree) { + *maxfree = b->bh.bsize; + } + b = b->ql.flink; /* Link to next buffer */ + } +} + +#ifdef BECtl + +/* BSTATSE -- Return extended statistics */ + +void bstatse(pool_incr, npool, npget, nprel, ndget, ndrel) + bufsize *pool_incr; + long *npool, *npget, *nprel, *ndget, *ndrel; +{ + *pool_incr = (pool_len < 0) ? -exp_incr : exp_incr; + *npool = numpblk; + *npget = numpget; + *nprel = numprel; + *ndget = numdget; + *ndrel = numdrel; +} +#endif /* BECtl */ +#endif /* BufStats */ + +#ifdef DumpData + +/* BUFDUMP -- Dump the data in a buffer. This is called with the user + data pointer, and backs up to the buffer header. It will + dump either a free block or an allocated one. */ + +void bufdump(buf) + void *buf; +{ + struct bfhead *b; + unsigned char *bdump; + bufsize bdlen; + + b = BFH(((char *) buf) - sizeof(struct bhead)); + assert(b->bh.bsize != 0); + if (b->bh.bsize < 0) { + bdump = (unsigned char *) buf; + bdlen = (-b->bh.bsize) - sizeof(struct bhead); + } else { + bdump = (unsigned char *) (((char *) b) + sizeof(struct bfhead)); + bdlen = b->bh.bsize - sizeof(struct bfhead); + } + + while (bdlen > 0) { + int i, dupes = 0; + bufsize l = bdlen; + char bhex[50], bascii[20]; + + if (l > 16) { + l = 16; + } + + for (i = 0; i < l; i++) { + V sprintf(bhex + i * 3, "%02X ", bdump[i]); + bascii[i] = isprint(bdump[i]) ? bdump[i] : ' '; + } + bascii[i] = 0; + V printf("%-48s %s\n", bhex, bascii); + bdump += l; + bdlen -= l; + while ((bdlen > 16) && (memcmp((char *) (bdump - 16), + (char *) bdump, 16) == 0)) { + dupes++; + bdump += 16; + bdlen -= 16; + } + if (dupes > 1) { + V printf( + " (%d lines [%d bytes] identical to above line skipped)\n", + dupes, dupes * 16); + } else if (dupes == 1) { + bdump -= 16; + bdlen += 16; + } + } +} +#endif + +#ifdef BufDump + +/* BPOOLD -- Dump a buffer pool. The buffer headers are always listed. + If DUMPALLOC is nonzero, the contents of allocated buffers + are dumped. If DUMPFREE is nonzero, free blocks are + dumped as well. If FreeWipe checking is enabled, free + blocks which have been clobbered will always be dumped. */ + +void bpoold(buf, dumpalloc, dumpfree) + void *buf; + int dumpalloc, dumpfree; +{ + struct bfhead *b = BFH(buf); + + while (b->bh.bsize != ESent) { + bufsize bs = b->bh.bsize; + + if (bs < 0) { + bs = -bs; + V printf("Allocated buffer: size %6ld bytes.\n", (long) bs); + if (dumpalloc) { + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + } + } else { + char *lerr = ""; + + assert(bs > 0); + if ((b->ql.blink->ql.flink != b) || + (b->ql.flink->ql.blink != b)) { + lerr = " (Bad free list links)"; + } + V printf("Free block: size %6ld bytes.%s\n", + (long) bs, lerr); +#ifdef FreeWipe + lerr = ((char *) b) + sizeof(struct bfhead); + if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) || + (memcmp(lerr, lerr + 1, + (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) { + V printf( + "(Contents of above free block have been overstored.)\n"); + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + } else +#endif + if (dumpfree) { + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + } + } + b = BFH(((char *) b) + bs); + } +} +#endif /* BufDump */ + +#ifdef BufValid + +/* BPOOLV -- Validate a buffer pool. If NDEBUG isn't defined, + any error generates an assertion failure. */ + +int bpoolv(buf) + void *buf; +{ + struct bfhead *b = BFH(buf); + + while (b->bh.bsize != ESent) { + bufsize bs = b->bh.bsize; + + if (bs < 0) { + bs = -bs; + } else { + char *lerr = ""; + + assert(bs > 0); + if (bs <= 0) { + return 0; + } + if ((b->ql.blink->ql.flink != b) || + (b->ql.flink->ql.blink != b)) { + V printf("Free block: size %6ld bytes. (Bad free list links)\n", + (long) bs); + assert(0); + return 0; + } +#ifdef FreeWipe + lerr = ((char *) b) + sizeof(struct bfhead); + if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) || + (memcmp(lerr, lerr + 1, + (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) { + V printf( + "(Contents of above free block have been overstored.)\n"); + bufdump((void *) (((char *) b) + sizeof(struct bhead))); + assert(0); + return 0; + } +#endif + } + b = BFH(((char *) b) + bs); + } + return 1; +} +#endif /* BufValid */ + + /***********************\ + * * + * Built-in test program * + * * + \***********************/ + +#ifdef TestProg + +#define Repeatable 1 /* Repeatable pseudorandom sequence */ + /* If Repeatable is not defined, a + time-seeded pseudorandom sequence + is generated, exercising BGET with + a different pattern of calls on each + run. */ +#define OUR_RAND /* Use our own built-in version of + rand() to guarantee the test is + 100% repeatable. */ + +#ifdef BECtl +#define PoolSize 300000 /* Test buffer pool size */ +#else +#define PoolSize 50000 /* Test buffer pool size */ +#endif +#define ExpIncr 32768 /* Test expansion block size */ +#define CompactTries 10 /* Maximum tries at compacting */ + +#define dumpAlloc 0 /* Dump allocated buffers ? */ +#define dumpFree 0 /* Dump free buffers ? */ + +#ifndef Repeatable +extern long time(); +#endif + +extern char *malloc(); +extern int free _((char *)); + +static char *bchain = NULL; /* Our private buffer chain */ +static char *bp = NULL; /* Our initial buffer pool */ + +#include + +#ifdef OUR_RAND + +static unsigned long int next = 1; + +/* Return next random integer */ + +int rand() +{ + next = next * 1103515245L + 12345; + return (unsigned int) (next / 65536L) % 32768L; +} + +/* Set seed for random generator */ + +void srand(seed) + unsigned int seed; +{ + next = seed; +} +#endif + +/* STATS -- Edit statistics returned by bstats() or bstatse(). */ + +static void stats(when) + char *when; +{ + bufsize cural, totfree, maxfree; + long nget, nfree; +#ifdef BECtl + bufsize pincr; + long totblocks, npget, nprel, ndget, ndrel; +#endif + + bstats(&cural, &totfree, &maxfree, &nget, &nfree); + V printf( + "%s: %ld gets, %ld releases. %ld in use, %ld free, largest = %ld\n", + when, nget, nfree, (long) cural, (long) totfree, (long) maxfree); +#ifdef BECtl + bstatse(&pincr, &totblocks, &npget, &nprel, &ndget, &ndrel); + V printf( + " Blocks: size = %ld, %ld (%ld bytes) in use, %ld gets, %ld frees\n", + (long)pincr, totblocks, pincr * totblocks, npget, nprel); + V printf(" %ld direct gets, %ld direct frees\n", ndget, ndrel); +#endif /* BECtl */ +} + +#ifdef BECtl +static int protect = 0; /* Disable compaction during bgetr() */ + +/* BCOMPACT -- Compaction call-back function. */ + +static int bcompact(bsize, seq) + bufsize bsize; + int seq; +{ +#ifdef CompactTries + char *bc = bchain; + int i = rand() & 0x3; + +#ifdef COMPACTRACE + V printf("Compaction requested. %ld bytes needed, sequence %d.\n", + (long) bsize, seq); +#endif + + if (protect || (seq > CompactTries)) { +#ifdef COMPACTRACE + V printf("Compaction gave up.\n"); +#endif + return 0; + } + + /* Based on a random cast, release a random buffer in the list + of allocated buffers. */ + + while (i > 0 && bc != NULL) { + bc = *((char **) bc); + i--; + } + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + *((char **) bc) = *((char **) fb); + brel((void *) fb); + return 1; + } + } + +#ifdef COMPACTRACE + V printf("Compaction bailed out.\n"); +#endif +#endif /* CompactTries */ + return 0; +} + +/* BEXPAND -- Expand pool call-back function. */ + +static void *bexpand(size) + bufsize size; +{ + void *np = NULL; + bufsize cural, totfree, maxfree; + long nget, nfree; + + /* Don't expand beyond the total allocated size given by PoolSize. */ + + bstats(&cural, &totfree, &maxfree, &nget, &nfree); + + if (cural < PoolSize) { + np = (void *) malloc((unsigned) size); + } +#ifdef EXPTRACE + V printf("Expand pool by %ld -- %s.\n", (long) size, + np == NULL ? "failed" : "succeeded"); +#endif + return np; +} + +/* BSHRINK -- Shrink buffer pool call-back function. */ + +static void bshrink(buf) + void *buf; +{ + if (((char *) buf) == bp) { +#ifdef EXPTRACE + V printf("Initial pool released.\n"); +#endif + bp = NULL; + } +#ifdef EXPTRACE + V printf("Shrink pool.\n"); +#endif + free((char *) buf); +} + +#endif /* BECtl */ + +/* Restrict buffer requests to those large enough to contain our pointer and + small enough for the CPU architecture. */ + +static bufsize blimit(bs) + bufsize bs; +{ + if (bs < sizeof(char *)) { + bs = sizeof(char *); + } + + /* This is written out in this ugly fashion because the + cool expression in sizeof(int) that auto-configured + to any length int befuddled some compilers. */ + + if (sizeof(int) == 2) { + if (bs > 32767) { + bs = 32767; + } + } else { + if (bs > 200000) { + bs = 200000; + } + } + return bs; +} + +int main() +{ + int i; + double x; + + /* Seed the random number generator. If Repeatable is defined, we + always use the same seed. Otherwise, we seed from the clock to + shake things up from run to run. */ + +#ifdef Repeatable + V srand(1234); +#else + V srand((int) time((long *) NULL)); +#endif + + /* Compute x such that pow(x, p) ranges between 1 and 4*ExpIncr as + p ranges from 0 to ExpIncr-1, with a concentration in the lower + numbers. */ + + x = 4.0 * ExpIncr; + x = log(x); + x = exp(log(4.0 * ExpIncr) / (ExpIncr - 1.0)); + +#ifdef BECtl + bectl(bcompact, bexpand, bshrink, (bufsize) ExpIncr); + bp = malloc(ExpIncr); + assert(bp != NULL); + bpool((void *) bp, (bufsize) ExpIncr); +#else + bp = malloc(PoolSize); + assert(bp != NULL); + bpool((void *) bp, (bufsize) PoolSize); +#endif + + stats("Create pool"); + V bpoolv((void *) bp); + bpoold((void *) bp, dumpAlloc, dumpFree); + + for (i = 0; i < TestProg; i++) { + char *cb; + bufsize bs = pow(x, (double) (rand() & (ExpIncr - 1))); + + assert(bs <= (((bufsize) 4) * ExpIncr)); + bs = blimit(bs); + if (rand() & 0x400) { + cb = (char *) bgetz(bs); + } else { + cb = (char *) bget(bs); + } + if (cb == NULL) { +#ifdef EasyOut + break; +#else + char *bc = bchain; + + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + *((char **) bc) = *((char **) fb); + brel((void *) fb); + } + continue; + } +#endif + } + *((char **) cb) = (char *) bchain; + bchain = cb; + + /* Based on a random cast, release a random buffer in the list + of allocated buffers. */ + + if ((rand() & 0x10) == 0) { + char *bc = bchain; + int i = rand() & 0x3; + + while (i > 0 && bc != NULL) { + bc = *((char **) bc); + i--; + } + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + *((char **) bc) = *((char **) fb); + brel((void *) fb); + } + } + } + + /* Based on a random cast, reallocate a random buffer in the list + to a random size */ + + if ((rand() & 0x20) == 0) { + char *bc = bchain; + int i = rand() & 0x3; + + while (i > 0 && bc != NULL) { + bc = *((char **) bc); + i--; + } + if (bc != NULL) { + char *fb; + + fb = *((char **) bc); + if (fb != NULL) { + char *newb; + + bs = pow(x, (double) (rand() & (ExpIncr - 1))); + bs = blimit(bs); +#ifdef BECtl + protect = 1; /* Protect against compaction */ +#endif + newb = (char *) bgetr((void *) fb, bs); +#ifdef BECtl + protect = 0; +#endif + if (newb != NULL) { + *((char **) bc) = newb; + } + } + } + } + } + stats("\nAfter allocation"); + if (bp != NULL) { + V bpoolv((void *) bp); + bpoold((void *) bp, dumpAlloc, dumpFree); + } + + while (bchain != NULL) { + char *buf = bchain; + + bchain = *((char **) buf); + brel((void *) buf); + } + stats("\nAfter release"); +#ifndef BECtl + if (bp != NULL) { + V bpoolv((void *) bp); + bpoold((void *) bp, dumpAlloc, dumpFree); + } +#endif + + return 0; +} +#endif diff --git a/rtl/libsupp.c b/rtl/libsupp.c index 6236367e414..2c14e3ac997 100644 --- a/rtl/libsupp.c +++ b/rtl/libsupp.c @@ -33,7 +33,7 @@ STDCALL RtlpAllocateMemory(ULONG Bytes, ULONG Tag) { - return MmAllocateMemory(Bytes); + return MmHeapAlloc(Bytes); } @@ -42,5 +42,5 @@ STDCALL RtlpFreeMemory(PVOID Mem, ULONG Tag) { - return MmFreeMemory(Mem); + return MmHeapFree(Mem); } diff --git a/ui/ui.c b/ui/ui.c index 044d521239a..2e0ba7fb535 100644 --- a/ui/ui.c +++ b/ui/ui.c @@ -604,7 +604,7 @@ VOID UiShowMessageBoxesInSection(PCSTR SectionName) //if (MessageBoxTextSize > 0) { // Allocate enough memory to hold the text - MessageBoxText = MmAllocateMemory(MessageBoxTextSize); + MessageBoxText = MmHeapAlloc(MessageBoxTextSize); if (MessageBoxText) { @@ -618,7 +618,7 @@ VOID UiShowMessageBoxesInSection(PCSTR SectionName) UiMessageBox(MessageBoxText); // Free the memory - MmFreeMemory(MessageBoxText); + MmHeapFree(MessageBoxText); } } } diff --git a/windows/peloader.c b/windows/peloader.c index 93bf88be5d7..cc89a33a391 100644 --- a/windows/peloader.c +++ b/windows/peloader.c @@ -170,7 +170,7 @@ WinLdrAllocateDataTableEntry(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock, USHORT Length; /* Allocate memory for a data table entry, zero-initialize it */ - DataTableEntry = (PLDR_DATA_TABLE_ENTRY)MmAllocateMemory(sizeof(LDR_DATA_TABLE_ENTRY)); + DataTableEntry = (PLDR_DATA_TABLE_ENTRY)MmHeapAlloc(sizeof(LDR_DATA_TABLE_ENTRY)); if (DataTableEntry == NULL) return FALSE; RtlZeroMemory(DataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY)); @@ -188,9 +188,12 @@ WinLdrAllocateDataTableEntry(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock, /* Initialize BaseDllName field (UNICODE_STRING) from the Ansi BaseDllName by simple conversion - copying each character */ Length = (USHORT)(strlen(BaseDllName) * sizeof(WCHAR)); - Buffer = (PWSTR)MmAllocateMemory(Length); + Buffer = (PWSTR)MmHeapAlloc(Length); if (Buffer == NULL) + { + MmHeapFree(DataTableEntry); return FALSE; + } RtlZeroMemory(Buffer, Length); DataTableEntry->BaseDllName.Length = Length; @@ -204,9 +207,12 @@ WinLdrAllocateDataTableEntry(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock, /* Initialize FullDllName field (UNICODE_STRING) from the Ansi FullDllName using the same method */ Length = (USHORT)(strlen(FullDllName) * sizeof(WCHAR)); - Buffer = (PWSTR)MmAllocateMemory(Length); + Buffer = (PWSTR)MmHeapAlloc(Length); if (Buffer == NULL) + { + MmHeapFree(DataTableEntry); return FALSE; + } RtlZeroMemory(Buffer, Length); DataTableEntry->FullDllName.Length = Length; diff --git a/windows/winldr.c b/windows/winldr.c index bf184810ca9..db7f51f71cb 100644 --- a/windows/winldr.c +++ b/windows/winldr.c @@ -51,7 +51,7 @@ AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock) PLOADER_PARAMETER_BLOCK LoaderBlock; /* Allocate and zero-init the LPB */ - LoaderBlock = MmAllocateMemory(sizeof(LOADER_PARAMETER_BLOCK)); + LoaderBlock = MmHeapAlloc(sizeof(LOADER_PARAMETER_BLOCK)); RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK)); /* Init three critical lists, used right away */ @@ -60,7 +60,7 @@ AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock) InitializeListHead(&LoaderBlock->BootDriverListHead); /* Alloc space for NLS (it will be converted to VA in WinLdrLoadNLS) */ - LoaderBlock->NlsData = MmAllocateMemory(sizeof(NLS_DATA_BLOCK)); + LoaderBlock->NlsData = MmHeapAlloc(sizeof(NLS_DATA_BLOCK)); if (LoaderBlock->NlsData == NULL) { UiMessageBox("Failed to allocate memory for NLS table data!"); @@ -104,32 +104,32 @@ WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock, DbgPrint((DPRINT_WINDOWS, "Options: %s\n", Options)); /* Fill Arc BootDevice */ - LoaderBlock->ArcBootDeviceName = MmAllocateMemory(strlen(ArcBoot)+1); + LoaderBlock->ArcBootDeviceName = MmHeapAlloc(strlen(ArcBoot)+1); strcpy(LoaderBlock->ArcBootDeviceName, ArcBoot); LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName); /* Fill Arc HalDevice, it matches ArcBoot path */ - LoaderBlock->ArcHalDeviceName = MmAllocateMemory(strlen(ArcBoot)+1); + LoaderBlock->ArcHalDeviceName = MmHeapAlloc(strlen(ArcBoot)+1); strcpy(LoaderBlock->ArcHalDeviceName, ArcBoot); LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName); /* Fill SystemRoot */ - LoaderBlock->NtBootPathName = MmAllocateMemory(strlen(SystemRoot)+1); + LoaderBlock->NtBootPathName = MmHeapAlloc(strlen(SystemRoot)+1); strcpy(LoaderBlock->NtBootPathName, SystemRoot); LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName); /* Fill NtHalPathName */ - LoaderBlock->NtHalPathName = MmAllocateMemory(strlen(HalPath)+1); + LoaderBlock->NtHalPathName = MmHeapAlloc(strlen(HalPath)+1); strcpy(LoaderBlock->NtHalPathName, HalPath); LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName); /* Fill load options */ - LoaderBlock->LoadOptions = MmAllocateMemory(strlen(Options)+1); + LoaderBlock->LoadOptions = MmHeapAlloc(strlen(Options)+1); strcpy(LoaderBlock->LoadOptions, Options); LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions); /* Arc devices */ - LoaderBlock->ArcDiskInformation = (PARC_DISK_INFORMATION)MmAllocateMemory(sizeof(ARC_DISK_INFORMATION)); + LoaderBlock->ArcDiskInformation = (PARC_DISK_INFORMATION)MmHeapAlloc(sizeof(ARC_DISK_INFORMATION)); InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead); /* Convert ARC disk information from freeldr to a correct format */ @@ -138,7 +138,7 @@ WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock, PARC_DISK_SIGNATURE ArcDiskInfo; /* Get the ARC structure */ - ArcDiskInfo = (PARC_DISK_SIGNATURE)MmAllocateMemory(sizeof(ARC_DISK_SIGNATURE));//&BldrDiskInfo[i]; + ArcDiskInfo = (PARC_DISK_SIGNATURE)MmHeapAlloc(sizeof(ARC_DISK_SIGNATURE));//&BldrDiskInfo[i]; RtlZeroMemory(ArcDiskInfo, sizeof(ARC_DISK_SIGNATURE)); /* Copy the data over */ @@ -179,7 +179,7 @@ WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock, List_PaToVa(&LoaderBlock->BootDriverListHead); /* Initialize Extension now */ - Extension = MmAllocateMemory(sizeof(LOADER_PARAMETER_EXTENSION)); + Extension = MmHeapAlloc(sizeof(LOADER_PARAMETER_EXTENSION)); if (Extension == NULL) { UiMessageBox("Failed to allocate LPB Extension!"); diff --git a/windows/wlmemory.c b/windows/wlmemory.c index 9fa72ae562c..8835702a0f5 100644 --- a/windows/wlmemory.c +++ b/windows/wlmemory.c @@ -162,6 +162,9 @@ MempAllocatePageTables() PhysicalPageTablesBuffer = &Buffer[MM_PAGE_SIZE*2]; KernelPageTablesBuffer = PhysicalPageTablesBuffer + NumPageTables*MM_PAGE_SIZE; + // Mark physical PTE's buffer as FirmwareTemporary + //MmSetMemoryType(KernelPageTablesBuffer, NumPageTables*MM_PAGE_SIZE, LoaderFirmwareTemporary); + // Zero counters of page tables used PhysicalPageTables = 0; KernelPageTables = 0; @@ -842,118 +845,9 @@ WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss) // Some unused descriptors should go here // ... - // - // Fill IDT with Traps - // -#if 0 - pIdt[0].Offset = (i386DivideByZero | KSEG0_BASE) & 0xFFFF; - pIdt[0].ExtendedOffset = 0x8; // Selector - pIdt[0].Access = 0x8F00; - pIdt[0].Selector = (i386DivideByZero | KSEG0_BASE) >> 16; // Extended Offset - - pIdt[1].Offset = (i386DebugException | KSEG0_BASE) & 0xFFFF; - pIdt[1].ExtendedOffset = 0x8; // Selector - pIdt[1].Access = 0x8F00; - pIdt[1].Selector = (i386DebugException | KSEG0_BASE) >> 16; // Extended Offset - - pIdt[2].Offset = (i386NMIException | KSEG0_BASE) & 0xFFFF; - pIdt[2].ExtendedOffset = 0x8; // Selector - pIdt[2].Access = 0x8F00; - pIdt[2].Selector = (i386NMIException | KSEG0_BASE) >> 16; // Extended Offset - - pIdt[3].Offset = (i386Breakpoint | KSEG0_BASE) & 0xFFFF; - pIdt[3].ExtendedOffset = 0x8; // Selector - pIdt[3].Access = 0x8F00; - pIdt[3].Selector = (i386Breakpoint | KSEG0_BASE) >> 16; // Extended Offset - - pIdt[4].Offset = (i386Overflow | KSEG0_BASE) & 0xFFFF; - pIdt[4].ExtendedOffset = 0x8; // Selector - pIdt[4].Access = 0x8F00; - pIdt[4].Selector = (i386Overflow | KSEG0_BASE) >> 16; // Extended Offset - - pIdt[5].Selector = (i386BoundException | KSEG0_BASE) >> 16; // Extended Offset - pIdt[5].Offset = (i386BoundException | KSEG0_BASE) & 0xFFFF; - pIdt[5].ExtendedOffset = 0x8; // Selector - pIdt[5].Access = 0x8F00; - - pIdt[6].Selector = (i386InvalidOpcode | KSEG0_BASE) >> 16; // Extended Offset - pIdt[6].Offset = (i386InvalidOpcode | KSEG0_BASE) & 0xFFFF; - pIdt[6].ExtendedOffset = 0x8; // Selector - pIdt[6].Access = 0x8F00; - - pIdt[7].Selector = (i386FPUNotAvailable | KSEG0_BASE) >> 16; // Extended Offset - pIdt[7].Offset = (i386FPUNotAvailable | KSEG0_BASE) & 0xFFFF; - pIdt[7].ExtendedOffset = 0x8; // Selector - pIdt[7].Access = 0x8F00; - - pIdt[8].Selector = (i386DoubleFault | KSEG0_BASE) >> 16; // Extended Offset - pIdt[8].Offset = (i386DoubleFault | KSEG0_BASE) & 0xFFFF; - pIdt[8].ExtendedOffset = 0x8; // Selector - pIdt[8].Access = 0x8F00; - - pIdt[9].Selector = (i386CoprocessorSegment | KSEG0_BASE) >> 16; // Extended Offset - pIdt[9].Offset = (i386CoprocessorSegment | KSEG0_BASE) & 0xFFFF; - pIdt[9].ExtendedOffset = 0x8; // Selector - pIdt[9].Access = 0x8F00; - - pIdt[10].Selector = (i386InvalidTSS | KSEG0_BASE) >> 16; // Extended Offset - pIdt[10].Offset = (i386InvalidTSS | KSEG0_BASE) & 0xFFFF; - pIdt[10].ExtendedOffset = 0x8; // Selector - pIdt[10].Access = 0x8F00; - - pIdt[11].Selector = (i386SegmentNotPresent | KSEG0_BASE) >> 16; // Extended Offset - pIdt[11].Offset = (i386SegmentNotPresent | KSEG0_BASE) & 0xFFFF; - pIdt[11].ExtendedOffset = 0x8; // Selector - pIdt[11].Access = 0x8F00; - - pIdt[12].Selector = (i386StackException | KSEG0_BASE) >> 16; // Extended Offset - pIdt[12].Offset = (i386StackException | KSEG0_BASE) & 0xFFFF; - pIdt[12].ExtendedOffset = 0x8; // Selector - pIdt[12].Access = 0x8F00; - - pIdt[13].Selector = (i386GeneralProtectionFault | KSEG0_BASE) >> 16; // Extended Offset - pIdt[13].Offset = (i386GeneralProtectionFault | KSEG0_BASE) & 0xFFFF; - pIdt[13].ExtendedOffset = 0x8; // Selector - pIdt[13].Access = 0x8F00; - - pIdt[14].Selector = (i386PageFault | KSEG0_BASE) >> 16; // Extended Offset - pIdt[14].Offset = (i386PageFault | KSEG0_BASE) & 0xFFFF; - pIdt[14].ExtendedOffset = 0x8; // Selector - pIdt[14].Access = 0x8F00; - - pIdt[15].Selector = 0; // Extended Offset - pIdt[15].Offset = 0; - pIdt[15].ExtendedOffset = 0; // Selector - pIdt[15].Access = 0; - - pIdt[16].Selector = (i386CoprocessorError | KSEG0_BASE) >> 16; // Extended Offset - pIdt[16].Offset = (i386CoprocessorError | KSEG0_BASE) & 0xFFFF; - pIdt[16].ExtendedOffset = 0x8; // Selector - pIdt[16].Access = 0x8F00; - - pIdt[17].Selector = (i386AlignmentCheck | KSEG0_BASE) >> 16; // Extended Offset - pIdt[17].Offset = (i386AlignmentCheck | KSEG0_BASE) & 0xFFFF; - pIdt[17].ExtendedOffset = 0x8; // Selector - pIdt[17].Access = 0x8F00; -#endif - - /*for (i=0; i<16; i++) - { - //pIdt[i].Offset = ((ULONG_PTR)i386GeneralProtectionFault | KSEG0_BASE) & 0xFFFF; - //pIdt[i].ExtendedOffset = 0x8; // Selector - //pIdt[i].Access = 0x8F00; - //pIdt[i].Selector = ((ULONG_PTR)i386GeneralProtectionFault | KSEG0_BASE) >> 16; // Extended Offset - - pIdt[i].Offset = ((ULONG_PTR)i386GeneralProtectionFault | KSEG0_BASE) & 0xFFFF; - pIdt[i].ExtendedOffset = ((ULONG_PTR)i386GeneralProtectionFault | KSEG0_BASE) >> 16; // Extended Offset - pIdt[i].Access = 0x8F00; - pIdt[i].Selector = 0x8; - }*/ - // Copy the old IDT RtlCopyMemory(pIdt, (PVOID)OldIdt.Base, OldIdt.Limit); - // Mask interrupts //asm("cli\n"); // they are already masked before enabling paged mode diff --git a/windows/wlregistry.c b/windows/wlregistry.c index 95690b8eb22..278a1afd870 100644 --- a/windows/wlregistry.c +++ b/windows/wlregistry.c @@ -669,7 +669,7 @@ WinLdrAddDriverToList(LIST_ENTRY *BootDriverListHead, NTSTATUS Status; ULONG PathLength; - BootDriverEntry = MmAllocateMemory(sizeof(BOOT_DRIVER_LIST_ENTRY)); + BootDriverEntry = MmHeapAlloc(sizeof(BOOT_DRIVER_LIST_ENTRY)); if (!BootDriverEntry) return FALSE; @@ -686,14 +686,21 @@ WinLdrAddDriverToList(LIST_ENTRY *BootDriverListHead, BootDriverEntry->FilePath.Length = 0; BootDriverEntry->FilePath.MaximumLength = PathLength + sizeof(WCHAR); - BootDriverEntry->FilePath.Buffer = MmAllocateMemory(PathLength); + BootDriverEntry->FilePath.Buffer = MmHeapAlloc(PathLength); if (!BootDriverEntry->FilePath.Buffer) + { + MmHeapFree(BootDriverEntry); return FALSE; + } Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, ImagePath); if (!NT_SUCCESS(Status)) + { + MmHeapFree(BootDriverEntry->FilePath.Buffer); + MmHeapFree(BootDriverEntry); return FALSE; + } } else { @@ -701,29 +708,44 @@ WinLdrAddDriverToList(LIST_ENTRY *BootDriverListHead, PathLength = wcslen(ServiceName)*sizeof(WCHAR) + sizeof(L"system32\\drivers\\.sys");; BootDriverEntry->FilePath.Length = 0; BootDriverEntry->FilePath.MaximumLength = PathLength+sizeof(WCHAR); - BootDriverEntry->FilePath.Buffer = MmAllocateMemory(PathLength); + BootDriverEntry->FilePath.Buffer = MmHeapAlloc(PathLength); if (!BootDriverEntry->FilePath.Buffer) + { + MmHeapFree(BootDriverEntry); return FALSE; + } Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, L"system32\\drivers\\"); if (!NT_SUCCESS(Status)) + { + MmHeapFree(BootDriverEntry->FilePath.Buffer); + MmHeapFree(BootDriverEntry); return FALSE; + } Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, ServiceName); if (!NT_SUCCESS(Status)) + { + MmHeapFree(BootDriverEntry->FilePath.Buffer); + MmHeapFree(BootDriverEntry); return FALSE; + } Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, L".sys"); if (!NT_SUCCESS(Status)) + { + MmHeapFree(BootDriverEntry->FilePath.Buffer); + MmHeapFree(BootDriverEntry); return FALSE; + } } // Add registry path PathLength = (wcslen(RegistryPath)+wcslen(ServiceName))*sizeof(WCHAR); BootDriverEntry->RegistryPath.Length = 0; BootDriverEntry->RegistryPath.MaximumLength = PathLength;//+sizeof(WCHAR); - BootDriverEntry->RegistryPath.Buffer = MmAllocateMemory(PathLength); + BootDriverEntry->RegistryPath.Buffer = MmHeapAlloc(PathLength); if (!BootDriverEntry->RegistryPath.Buffer) return FALSE;