//----------------------------------------------------------------------------// // OS on Kaleid // // // // Desc: Mapping and checking memory related functions // // // // // // Copyright © 2018-2020 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 // 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("Failed to initialize the memory map\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); DebugLog("Initiliazing memory map...\n"); // 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++; DebugLog("Zone: %lp type %d with length: %4luMB+%4luKB+%4luB\n", memoryMap.entry[i].addr, memoryMap.entry[i].type, _ADDR_TO_MB(memoryMap.entry[i].length), _ADDR_TO_KB(memoryMap.entry[i].length), _ADDR_TO_B(memoryMap.entry[i].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; DebugLog("Available RAM size : %u MB\n", memoryMap.freeRamSize / MB); 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; } bool MmIsBusyZone(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 1; } } // The zone is free return 0; } bool MmIsFailingZoneSize(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 a failing zone, we can return 1 if ( (memoryMap.entry[i].type == BADRAM_ZONE) && (ulong)start >= (ulong)memoryMap.entry[i].addr && (ulong)start < ((ulong)memoryMap.entry[i].addr + (ulong)memoryMap.entry[i].length) ) { return 1; } } // 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+4096) { return MmGetFirstAvailZone(BtLoaderInfo.stackEndAddr+4096); } // 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[15]; extern int shcol; for (uint i=0; i < memoryMap.length; i++) { switch (memoryMap.entry[i].type) { case AVAILABLE_ZONE: snprintf(avStr, 15, "%CAvailable%C", VGA_COLOR_GREEN, shcol); break; case RESERVED_ZONE: snprintf(avStr, 15, "%CReserved %C", VGA_COLOR_RED, shcol); break; case ACPI_ZONE: snprintf(avStr, 15, "%CACPI %C", VGA_COLOR_LIGHT_BROWN, shcol); break; case NVS_ZONE: snprintf(avStr, 15, "%CNVS %C", VGA_COLOR_LIGHT_BROWN, shcol); break; case BADRAM_ZONE: snprintf(avStr, 15, "%CBAD RAM %C", VGA_COLOR_LIGHT_RED, shcol); break; default:; } ulong len = memoryMap.entry[i].length; KernLog("%Cmem zone:%C %lp %s %Cwith length:%C %4lu%CMB" "+%C%4lu%CKB+%C%4lu%CB\n", VGA_COLOR_DARK_GREY, shcol, memoryMap.entry[i].addr, avStr, VGA_COLOR_DARK_GREY, shcol, _ADDR_TO_MB(len), VGA_COLOR_DARK_GREY, shcol, _ADDR_TO_KB(len), VGA_COLOR_DARK_GREY, shcol, _ADDR_TO_B(len), VGA_COLOR_DARK_GREY, shcol ); } KernLog("\n"); }