peredOS/kernel/pmm.c

119 lines
4.7 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "pmm.h"
#include "string.h"
#include "logger.h"
#include "../drivers/serial.h"
// Указатель на начало нашей битовой карты в памяти
static uint32_t* pmm_bitmap = NULL;
static uint32_t pmm_bitmap_size = 0;
static uint32_t total_pages = 0;
static pmm_stats_t global_stats;
// Вспомогательные инлайны для быстрой работы с битами ядра
static inline void bitmap_set(uint32_t page_index) {
pmm_bitmap[page_index / 32] |= (1 << (page_index % 32));
}
static inline void bitmap_clear(uint32_t page_index) {
pmm_bitmap[page_index / 32] &= ~(1 << (page_index % 32));
}
static inline int bitmap_test(uint32_t page_index) {
return (pmm_bitmap[page_index / 32] & (1 << (page_index % 32))) != 0;
}
void pmm_init(struct multiboot_info* mbi, uint32_t kernel_end) {
// Рассчитываем менеджер на 128 МБ памяти
uint32_t mem_size = 128 * 1024 * 1024;
total_pages = mem_size / PAGE_SIZE;
// Саму карту пихаем прямо за концом ядра (куда указывает линкер)
pmm_bitmap = (uint32_t*)kernel_end;
pmm_bitmap_size = total_pages / 8; // Размер карты в байтах (4096 байт)
uint32_t bitmap_end = kernel_end + pmm_bitmap_size;
// Шаг 1: Помечаем вообще всё как занятое (1). Безопасность превыше всего.
memset(pmm_bitmap, 0xFF, pmm_bitmap_size);
// Шаг 2: Парсим карту памяти от GRUB и открываем доступные регионы
struct multiboot_mmap_entry* mmap = (struct multiboot_mmap_entry*)mbi->mmap_addr;
while((uint32_t)mmap < mbi->mmap_addr + mbi->mmap_length) {
// Если GRUB говорит, что этот кусок RAM свободен для юзания
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) {
uint32_t start_addr = (uint32_t)mmap->addr;
uint32_t end_addr = start_addr + (uint32_t)mmap->len;
for (uint32_t addr = start_addr; addr < end_addr; addr += PAGE_SIZE) {
uint32_t page_idx = addr / PAGE_SIZE;
if (page_idx < total_pages) {
bitmap_clear(page_idx); // Ставим 0 (страница свободна)
}
}
}
// Шагаем к следующей записи в таблице Multiboot
mmap = (struct multiboot_mmap_entry*)((uint32_t)mmap + mmap->size + sizeof(mmap->size));
}
// Шаг 3: Жестко защищаем саму ОС!
// Всё, что лежит от физического адреса 0x0 до bitmap_end (код ядра, стек, сама битовая карта),
// мы принудительно забиваем единицами, чтобы аллокатор туда никогда не залез.
for (uint32_t addr = 0; addr < bitmap_end; addr += PAGE_SIZE) {
bitmap_set(addr / PAGE_SIZE);
}
log_info(LOG_NORMAL, "pmm works.");
}
void* pmm_alloc_page(void) {
// Тупо линейно ищем первый попавшийся бит, равный 0
for (uint32_t i = 0; i < total_pages; i++) {
if (!bitmap_test(i)) {
bitmap_set(i); // Застолбили страницу (поставили 1)
return (void*)(i * PAGE_SIZE); // Считаем её реальный физический адрес
}
}
log_error(LOG_NORMAL, "PMM: FUCK, WHERE IS ALL OUR FUCKING MEMORY?!");
return NULL;
}
void pmm_free_page(void* addr) {
uint32_t page_idx = ((uint32_t)addr) / PAGE_SIZE;
if (page_idx < total_pages) {
bitmap_clear(page_idx); // Сбросили в 0, страница снова чиста
}
}
void pmm_get_stats(void) {
kprint_serial("Someone wants memory stats! Running the test!\n");
uint32_t used = 0;
uint32_t free = 0;
for (uint32_t i = 0; i < total_pages; i++) {
if (bitmap_test(i)) {
used++;
} else {
free++;
}
}
kprint_serial("Okay, i am collected the stats. ");
// Пишем в ГЛОБАЛЬНУЮ переменную
global_stats.total_pages = total_pages;
global_stats.used_pages = used;
global_stats.free_pages = free;
global_stats.total_memory = total_pages << 12;
global_stats.used_memory = used << 12;
global_stats.free_memory = free << 12;
kprint_serial("Goodbye!\n");
}
// Добавим функцию-геттер, которая просто вернет указатель на эту глобальную память
pmm_stats_t* pmm_get_stats_ptr(void) {
return &global_stats;
}