//----------------------------------------------------------------------------// // GNU GPL OS/K // // // // Desc: Mapping and checking memory 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 // Initializes globally the memory map MemoryMap_t memoryMap = { 0 }; static error_t InitMemoryMap(void); // // Initilization of the memory map, and computation of the available ram size // void MmInitMemoryMap(void) { error_t rc; rc = InitMemoryMap(); if (rc) KeStartPanic("[Mm]\tThe memory map failed to initialize.\nError : %s", strerror(rc) ); } static error_t InitMemoryMap(void) { multiboot_memory_map_t *currentEntry; multiboot_memory_map_t *mapEnd; uint i = 0; // sanity checks if (!BtMemoryInfo.memValid && BtMemoryInfo.mapValid) return ENXIO; if ((BtMemoryInfo.upMemory / (MB/KB)) <= MINIMUM_RAM_SIZE) return ENOMEM; // Ok then we can work // the memory map provided by GRUB via the BIOS currentEntry = (multiboot_memory_map_t*)BtMemoryInfo.mapAddr; // End address of the map mapEnd = (multiboot_memory_map_t*) ((ulong)currentEntry + (ulong)BtMemoryInfo.mapLength); // fill the map while (currentEntry < mapEnd) { // memory zone address memoryMap.entry[i].addr = (void*)((ullong)currentEntry->addr_low + (((ullong)currentEntry->addr_high) << 32 )); // memory zone size in bytes memoryMap.entry[i].length = (ulong)currentEntry->len_low + (((ulong)currentEntry->len_high) << 32); // memory availability memoryMap.entry[i].type = (uint)currentEntry->type; // Adding the size to the size (yup) memoryMap.length++; // moving up ! currentEntry = (multiboot_memory_map_t*) ((ulong)currentEntry + currentEntry->size + sizeof(currentEntry->size)); i++; } // compute the free ram size for (i = 0; i < memoryMap.length; i++) { if (memoryMap.entry[i].type == AVAILABLE_ZONE) { memoryMap.freeRamSize += memoryMap.entry[i].length; } else { memoryMap.nonfreeRamSize += memoryMap.entry[i].length; } } // Trully strange if it happens... if (memoryMap.freeRamSize < MINIMUM_RAM_SIZE) return ENOMEM; KernLog("[Mm]\tAvailable Ram Size : %u Mio\n", memoryMap.freeRamSize / MB); // Magic value in memory to prevent smashing ulong * heapStart = BtLoaderInfo.stackEndAddr + 8; *heapStart = 0xbad00badbad00bad; return EOK; } size_t MmGetAvailZoneSize(void *start) { uint i; // Because the kernel is the kernel if (start < BtLoaderInfo.stackEndAddr + 16) return 0; // Search the zone where the start address is for (i = 0; i < memoryMap.length; i++) { // if the address is in an available zone, we can return the length if ( memoryMap.entry[i].type == AVAILABLE_ZONE && (ulong)start >= (ulong)memoryMap.entry[i].addr && (ulong)start < ((ulong)memoryMap.entry[i].addr + (ulong)memoryMap.entry[i].length) ) { return (size_t)((ulong)memoryMap.entry[i].length - (ulong)start); } } // If there is no zone, we return a 0 size return 0; } void *MmGetFirstAvailZone(void *start) { uint i; void *current = 0; // Because the kernel is the kernel if ((ulong)start < (ulong)BtLoaderInfo.stackEndAddr+16) { return MmGetFirstAvailZone(BtLoaderInfo.stackEndAddr+16); } // Search the zone where the start address is for (i = 0; i < memoryMap.length; i++) { // if the address is in an available zone, we can return the start address if ( memoryMap.entry[i].type == AVAILABLE_ZONE && (ulong)start >= (ulong)memoryMap.entry[i].addr && (ulong)start < ((ulong)memoryMap.entry[i].addr + (ulong)memoryMap.entry[i].length) ) { current = start; break; } } if (current) return current; // Search the first zone from start for (i = 0; i < memoryMap.length; i++) { // Return the first zone that is after start if ( memoryMap.entry[i].type == AVAILABLE_ZONE && (ulong)start <= (ulong)memoryMap.entry[i].addr ) { current = memoryMap.entry[i].addr; break; } } return current; } void MmPrintMemoryMap(void) { char *avStr = ""; for (uint i=0; i < memoryMap.length; i++) { switch (memoryMap.entry[i].type) { case AVAILABLE_ZONE: avStr="Available"; break; case RESERVED_ZONE: avStr="Reserved"; break; case ACPI_ZONE: avStr="ACPI "; break; case NVS_ZONE: avStr="NVS "; break; case BADRAM_ZONE: avStr="Bad Ram"; break; default:; } ulong len = memoryMap.entry[i].length; KernLog("mem zone: %lp\t%s\twith length: %4luMB + %4luKB + %4luB\n", memoryMap.entry[i].addr, avStr, _ADDR_TO_MB(len), _ADDR_TO_KB(len), _ADDR_TO_B(len) ); } }