//----------------------------------------------------------------------------// // GNU GPL OS/K // // // // Desc: Page allocator related functions // // // // // // Copyright © 2018-2019 The OS/K Team // // // // This file is part of OS/K. // // // // OS/K is free software: you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation, either version 3 of the License, or // // any later version. // // // // OS/K is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY//without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License for more details. // // // // You should have received a copy of the GNU General Public License // // along with OS/K. If not, see . // //----------------------------------------------------------------------------// #include #include #include #include #include #include #include #include #include //--------- enum { Whatever = 1UL << 52, Whatever2 = 1UL << 62 }; static AllocatedPage_t busyPagesList = { (void*)0, (void*)0, 0, (AllocatedPage_t*)0 }; extern MemoryMap_t memoryMap; extern ulong MmPhysLastKernAddress; static ulong NSuccessfulAlloc = 0; static ulong NSuccessfulFree = 0; //--------- // Returns 0 if page is not busy, its last address if yes static ulong isPageBusy(void *phyPageAddr) { AllocatedPage_t *busyPage = &busyPagesList; ulong isBusy = 0; // In case of NVS, ACPI or BADRAM zone, considered busy if (!MmGetAvailZoneSize(phyPageAddr)) return true; // Search in the busylist if the phy addr is here while(busyPage->next) { busyPage = busyPage->next; if (phyPageAddr >= busyPage->phyAddressBegin && phyPageAddr <= busyPage->phyAddressEnd ) { isBusy = (ulong)busyPage->phyAddressEnd; break; } } return isBusy; } static void printBusyPages(void) { AllocatedPage_t *busyPage = &busyPagesList; if (!busyPage->next) { KernLog("No busy page\n"); } else { while(busyPage->next) { busyPage = busyPage->next; KernLog("Busy page at %p-%p\n", busyPage->phyAddressBegin, busyPage->phyAddressEnd); } } } static ulong MmBusyPagesSpace(void) { ulong c = 0; AllocatedPage_t *busyPage = &busyPagesList; if (!busyPage->next) { return 0; } else { while(busyPage->next) { busyPage = busyPage->next; c += 4096 + (busyPage->phyAddressEnd - busyPage->phyAddressBegin); } } return c; } static void addPageToBusyList(void *phyPageAddrBegin, void *phyPageAddrEnd, ulong id) { AllocatedPage_t *busyPage = &busyPagesList; AllocatedPage_t *prevBusyPage = NULL; while(busyPage->next) { prevBusyPage = busyPage; busyPage = busyPage->next; if (busyPage->phyAddressBegin > phyPageAddrEnd) { busyPage = prevBusyPage; break; } } AllocatedPage_t *newBusyPage = (AllocatedPage_t*)malloc(sizeof(AllocatedPage_t)); newBusyPage->phyAddressBegin = phyPageAddrBegin; newBusyPage->phyAddressEnd = phyPageAddrEnd; newBusyPage->id = id; newBusyPage->next = busyPage->next; busyPage->next = newBusyPage; } static void removePageFromBusyList(void *phyPageAddrBegin) { AllocatedPage_t *busyPage = &busyPagesList; AllocatedPage_t *prevBusyPage = NULL; while(busyPage->next) { prevBusyPage = busyPage; busyPage = busyPage->next; if (phyPageAddrBegin == busyPage->phyAddressBegin) { prevBusyPage->next = busyPage->next; free(busyPage); break; } } } // // Returns an id to identify a page frame allocated (kernel) // ulong MmAllocPageFrame(size_t size, bool contiguous) { static ulong id = 0; ulong pageNumber = (((ulong)size - 1) / KPAGESIZE) + 1; size_t curNumber = 0; void *futureBegin = 0; void *futureEnd = 0; ulong busyLastAddr = 0; // Incrementing id id++; // Maximum PHYSICAL address in memory ulong phRamSize = memoryMap.freeRamSize + memoryMap.nonfreeRamSize; DebugLog("Allocating %d pages...\n", pageNumber); for (void *curPage = (void*)(MmPhysLastKernAddress + KPAGESIZE); curPage < (void*)phRamSize; curPage += KPAGESIZE) { busyLastAddr = isPageBusy(curPage); if (!busyLastAddr) { if (!futureBegin) { futureBegin = curPage; //DebugLog("Select begin : %p\n", curPage); } futureEnd = curPage; //DebugLog("Select page : %p\n", curPage); if (++curNumber >= pageNumber) { break; } } else { if (!contiguous) { if (futureBegin && futureEnd) addPageToBusyList(futureBegin, futureEnd, id); futureBegin = 0; } else { curNumber = 0; futureBegin = 0; } } } if (curNumber != pageNumber) { KeStartPanic("MmAllocPageFrame() : No more free pages to allocate"); } if (futureBegin && futureEnd) addPageToBusyList(futureBegin, futureEnd, id); NSuccessfulAlloc++; return id; } // // Frees a page frame by its id // void MmFreePageFrame(ulong id) { AllocatedPage_t *busyPage = &busyPagesList; bool success = false; while(busyPage->next) { busyPage = busyPage->next; if (id == busyPage->id) { removePageFromBusyList(busyPage->phyAddressBegin); success = true; } } if (success) NSuccessfulFree++; } // // Maps an allocated page frame to the given address // error_t MmMapPageFrame(ulong id, void *virtAddr, ulong flags) { AllocatedPage_t *busyPage = &busyPagesList; while(busyPage->next) { busyPage = busyPage->next; if (id == busyPage->id) { for (void *addr = busyPage->phyAddressBegin; addr <= busyPage->phyAddressEnd; addr += KPAGESIZE) { if (MmTransPhyToVirtAddr(addr)) { return EADDRINUSE; } //DebugLog("Map %p at %p\n", addr, virtAddr); MmMapPage((void*)((ulong)virtAddr), (void*)addr, flags); virtAddr += KPAGESIZE; } } } return EOK; } error_t MmUnmapPageFrame(ulong id) { AllocatedPage_t *busyPage = &busyPagesList; void *actualPhys = 0; while(busyPage->next) { busyPage = busyPage->next; if (id == busyPage->id) { for (void *addr = busyPage->phyAddressBegin; addr <= busyPage->phyAddressEnd; addr += KPAGESIZE) { actualPhys = MmTransPhyToVirtAddr(addr); //DebugLog("Map %p at %p\n", addr, virtAddr); if (actualPhys && id == busyPage->id) { MmUnmapPage(MmTransPhyToVirtAddr(addr)); } } } } return EOK; } ulong tab[4000] = {0}; error_t MmTestBusyPage(ulong size, ulong flags) { /* for (int i = 0; i < 2000; i++) { */ /* if (rand() %2) { */ /* if (rand() %2) { */ /* tab[j++] = MmAllocPageFrame(rand()%6553689, NORMAL); */ /* } else { */ /* tab[j++] = MmAllocPageFrame(rand()%6553689, CONTIGUOUS); */ /* } */ /* } else { */ /* MmFreePageFrame(tab[rand() % (j+1)]); */ /* } */ /* //DebugLog("Alloc : %d; Free : %d; Count : %lu Mo\n", NSuccessfulAlloc, NSuccessfulFree, MmBusyPagesSpace() / MB); */ /* } */ ulong a = KeGetTicks(); DebugLog("Start alloc 1: %lu s\n", a/1000); tab[0] = MmAllocPageFrame(size*KB, NORMAL); ulong b = KeGetTicks(); DebugLog("End alloc : %lu s\n", b/1000); DebugLog("Alloc time : %lu s\n", (b-a)/1000); DebugLog("Alloc : %d; Free : %d; Count : %lu Mo\n", NSuccessfulAlloc, NSuccessfulFree, MmBusyPagesSpace() / MB); printBusyPages(); a = KeGetTicks(); DebugLog("Start map at %p wit %p: %lu ms\n", USERSPACE, flags, a); MmMapPageFrame(tab[0], (void*)(USERSPACE), flags); b = KeGetTicks(); DebugLog("End map : %lu ms\n", b); DebugLog("Map time : %lu ms\n", (b-a)); a = KeGetTicks(); DebugLog("Start unmap at %p wit %p: %lu ms\n", USERSPACE, flags, a); MmUnmapPageFrame(tab[0]); b = KeGetTicks(); DebugLog("End map : %lu ms\n", b); DebugLog("Map time : %lu ms\n", (b-a)); DebugLog("Finished !\n"); return EOK; }