2023-10-07 18:28:48 +03:00
|
|
|
|
#include <fb.h>
|
|
|
|
|
#include <limine.h>
|
|
|
|
|
#include <lock.h>
|
|
|
|
|
#include <tool.h>
|
|
|
|
|
|
|
|
|
|
#define BLOCK_SIZE 4096
|
2023-10-15 20:29:21 +03:00
|
|
|
|
#define HHDM_OFFSET (hhdm_request.response->offset)
|
2023-10-12 22:30:54 +03:00
|
|
|
|
|
2023-10-07 18:28:48 +03:00
|
|
|
|
static volatile struct limine_memmap_request memmap_request = {
|
|
|
|
|
.id = LIMINE_MEMMAP_REQUEST,
|
|
|
|
|
.revision = 0,
|
|
|
|
|
.response = (struct limine_memmap_response *)0
|
|
|
|
|
};
|
|
|
|
|
static volatile struct limine_hhdm_request hhdm_request = {
|
|
|
|
|
.id = LIMINE_HHDM_REQUEST,
|
|
|
|
|
.revision = 0,
|
|
|
|
|
.response = (struct limine_hhdm_response *)0
|
|
|
|
|
};
|
|
|
|
|
|
2023-10-15 20:29:21 +03:00
|
|
|
|
struct mem_entry {
|
|
|
|
|
struct mem_entry *next;
|
|
|
|
|
bool free;
|
|
|
|
|
size_t size;
|
|
|
|
|
uint8_t data[0];
|
|
|
|
|
};
|
|
|
|
|
typedef struct mem_entry mem_entry_t;
|
2023-10-12 22:30:54 +03:00
|
|
|
|
|
|
|
|
|
// Битовая карта для отслеживания занятых и свободных фреймов памяти
|
2023-10-07 18:28:48 +03:00
|
|
|
|
uint8_t *bitmap;
|
2023-10-12 22:30:54 +03:00
|
|
|
|
// Объем доступных блоков
|
|
|
|
|
uint64_t bitmap_available = 0;
|
|
|
|
|
// Объем блоков
|
|
|
|
|
uint64_t bitmap_limit = 0;
|
|
|
|
|
// Верхняя граница доступной памяти
|
2023-10-07 18:28:48 +03:00
|
|
|
|
uint64_t limit;
|
2023-10-12 22:30:54 +03:00
|
|
|
|
// Объем всего доступного физического адресного пространства
|
2023-10-07 18:28:48 +03:00
|
|
|
|
uint64_t usable = 0;
|
2023-10-12 22:30:54 +03:00
|
|
|
|
// Объем доступной виртуальной памяти
|
2023-10-07 18:28:48 +03:00
|
|
|
|
uint64_t available = 0;
|
2023-10-12 22:30:54 +03:00
|
|
|
|
// Наивысший адрес в available space
|
2023-10-07 18:28:48 +03:00
|
|
|
|
uint64_t highest = 0;
|
2023-10-12 22:30:54 +03:00
|
|
|
|
// Количество записей в карте памяти
|
2023-10-07 18:28:48 +03:00
|
|
|
|
uint64_t mmmap_count = 0;
|
|
|
|
|
|
2023-10-15 20:29:21 +03:00
|
|
|
|
const char memory_types[8][82] = {
|
2023-10-12 22:30:54 +03:00
|
|
|
|
"Доступно", "Зарезервировано", "ACPI, можно освободить",
|
|
|
|
|
"ACPI NVS", "Плохая память", "Загрузчик, можно освободить",
|
|
|
|
|
"Ядро и модули", "Буфер кадра"
|
|
|
|
|
};
|
2023-10-07 18:28:48 +03:00
|
|
|
|
|
2023-10-15 20:29:21 +03:00
|
|
|
|
struct limine_memmap_response *memmap_response;
|
|
|
|
|
|
|
|
|
|
static mem_entry_t *first_node;
|
|
|
|
|
|
|
|
|
|
namespace mem {
|
|
|
|
|
|
2023-10-19 19:46:58 +03:00
|
|
|
|
void dump_memory( ) {
|
|
|
|
|
mem_entry_t *curr = first_node;
|
|
|
|
|
|
|
|
|
|
while (curr) {
|
2023-10-21 19:37:02 +03:00
|
|
|
|
fb::printf("->0x%x | %u.%u kb | %u | 0x%x\n", &curr->data,
|
|
|
|
|
(curr->size) / 1024, (curr->size) % 1024, curr->free,
|
|
|
|
|
curr->next);
|
2023-10-19 19:46:58 +03:00
|
|
|
|
curr = curr->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-15 20:29:21 +03:00
|
|
|
|
void frame_free(void *addr, uint64_t frames) {
|
2023-10-12 22:30:54 +03:00
|
|
|
|
// Проход по фреймам памяти и очистка битов в битовой карте
|
2023-10-15 20:29:21 +03:00
|
|
|
|
uint64_t frame = (uint64_t)addr / BLOCK_SIZE;
|
2023-10-12 22:30:54 +03:00
|
|
|
|
for (uint64_t i = frame; i < frames + frame; i++) { BIT_CLEAR(i); }
|
2023-10-15 20:29:21 +03:00
|
|
|
|
bitmap_available += frames;
|
2023-10-07 18:28:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 22:30:54 +03:00
|
|
|
|
// Функция выделения памяти
|
2023-10-15 20:29:21 +03:00
|
|
|
|
void *frame_alloc(uint64_t wanted_frames) {
|
|
|
|
|
void *addr;
|
2023-10-12 22:30:54 +03:00
|
|
|
|
|
|
|
|
|
uint64_t available_frames = 0;
|
|
|
|
|
for (uint64_t frame = 1; frame < limit; frame++) {
|
|
|
|
|
if (!BIT_GET(frame)) {
|
|
|
|
|
available_frames++;
|
|
|
|
|
} else if (available_frames != wanted_frames) {
|
|
|
|
|
available_frames = 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (available_frames == wanted_frames) {
|
|
|
|
|
uint64_t i;
|
|
|
|
|
for (i = 0; i < wanted_frames; i++) { BIT_SET(frame - i); }
|
|
|
|
|
frame -= i - 1;
|
2023-10-07 18:28:48 +03:00
|
|
|
|
|
2023-10-15 20:29:21 +03:00
|
|
|
|
addr = (void *)(BLOCK_SIZE * frame);
|
|
|
|
|
bitmap_available -= wanted_frames;
|
|
|
|
|
return addr;
|
2023-10-12 22:30:54 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-10-07 18:28:48 +03:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-15 20:29:21 +03:00
|
|
|
|
void *frame_calloc(uint64_t frames) {
|
|
|
|
|
void *addr = frame_alloc(frames);
|
|
|
|
|
tool::memset(addr + HHDM_OFFSET, 0, frames * BLOCK_SIZE);
|
|
|
|
|
return addr;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-19 19:46:58 +03:00
|
|
|
|
void merge_blocks(mem_entry_t *start) {
|
|
|
|
|
if (!start->free) return;
|
|
|
|
|
mem_entry_t *block = start;
|
|
|
|
|
while (block->next && block->next->free) {
|
|
|
|
|
block->size += block->next->size + sizeof(mem_entry_t);
|
|
|
|
|
block->next = block->next->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-21 19:37:02 +03:00
|
|
|
|
void merge_all_blocks( ) {
|
|
|
|
|
mem_entry_t *curr = first_node;
|
|
|
|
|
|
|
|
|
|
while (curr) {
|
|
|
|
|
merge_blocks(curr);
|
|
|
|
|
curr = curr->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-15 20:29:21 +03:00
|
|
|
|
void add_block(void *addr, size_t size) {
|
|
|
|
|
mem_entry_t *new_entry = (mem_entry_t *)addr;
|
|
|
|
|
|
|
|
|
|
new_entry->size = size - sizeof(mem_entry_t);
|
|
|
|
|
new_entry->free = true;
|
|
|
|
|
|
|
|
|
|
if (first_node == NULL) {
|
|
|
|
|
first_node = new_entry;
|
|
|
|
|
new_entry->next = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
mem_entry_t *curr = first_node;
|
|
|
|
|
while (curr->next != NULL) { curr = curr->next; }
|
|
|
|
|
|
|
|
|
|
curr->next = new_entry;
|
|
|
|
|
new_entry->next = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void alloc_init(void *address, size_t length) {
|
|
|
|
|
first_node = (mem_entry_t *)address;
|
|
|
|
|
|
|
|
|
|
first_node->size = length - sizeof(mem_entry_t);
|
|
|
|
|
first_node->free = true;
|
|
|
|
|
first_node->next = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *alloc_align(size_t size, size_t alignment) {
|
|
|
|
|
mem_entry_t *curr = first_node;
|
|
|
|
|
|
|
|
|
|
while (curr) {
|
|
|
|
|
if (curr->free) {
|
|
|
|
|
void *addr = curr->data + alignment - 1;
|
|
|
|
|
addr -= (uintptr_t)addr % alignment + sizeof(mem_entry_t);
|
|
|
|
|
mem_entry_t *second = (mem_entry_t *)addr;
|
|
|
|
|
if (curr->size >= (second->data - curr->data + size)) {
|
|
|
|
|
mem_entry_t *third = (mem_entry_t *)(second->data + size);
|
|
|
|
|
|
|
|
|
|
third->size = curr->size - (third->data - curr->data);
|
|
|
|
|
third->next = curr->next;
|
|
|
|
|
third->free = 1;
|
|
|
|
|
|
|
|
|
|
second->size = size;
|
|
|
|
|
second->next = third;
|
|
|
|
|
second->free = 0;
|
|
|
|
|
|
|
|
|
|
if (curr != second) {
|
|
|
|
|
curr->next = second;
|
|
|
|
|
curr->size = (uintptr_t)second - (uintptr_t)curr->data;
|
|
|
|
|
curr->free = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return second->data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
curr = curr->next;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *alloc(size_t size) {
|
|
|
|
|
return alloc_align(size, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void free(void *addr) {
|
|
|
|
|
mem_entry_t *curr = first_node, *prev = NULL;
|
|
|
|
|
while (curr != NULL) {
|
|
|
|
|
if (curr->data == addr) {
|
|
|
|
|
curr->free = 1;
|
|
|
|
|
merge_blocks(prev ? prev : curr);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
prev = curr;
|
|
|
|
|
curr = curr->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *realloc(void *addr, size_t size) {
|
|
|
|
|
if (size == 0) {
|
|
|
|
|
free(addr);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (addr == NULL) { return alloc(size); }
|
|
|
|
|
|
|
|
|
|
void *new_addr = alloc(size);
|
|
|
|
|
|
|
|
|
|
if (new_addr == NULL) { return NULL; }
|
|
|
|
|
|
|
|
|
|
tool::memcpy(new_addr, addr, size);
|
|
|
|
|
free(addr);
|
|
|
|
|
|
|
|
|
|
return new_addr;
|
2023-10-07 18:28:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 22:30:54 +03:00
|
|
|
|
// Инициализация менеджера памяти
|
|
|
|
|
void init( ) {
|
|
|
|
|
// Получение информации о доступной памяти из Limine bootloader
|
|
|
|
|
memmap_response = memmap_request.response;
|
|
|
|
|
mmmap_count = memmap_response->entry_count;
|
|
|
|
|
struct limine_memmap_entry **mmaps = memmap_response->entries;
|
|
|
|
|
|
2023-10-21 19:37:02 +03:00
|
|
|
|
fb::printf("Записей в карте памяти: %u\n", memmap_response->entry_count);
|
2023-10-12 22:30:54 +03:00
|
|
|
|
|
|
|
|
|
// Обработка каждой записи в карте памяти
|
|
|
|
|
for (int i = 0; i < mmmap_count; i++) {
|
|
|
|
|
available += mmaps[i]->length;
|
|
|
|
|
|
|
|
|
|
// fb::printf("\t%d: 0x%x\tдлина: 0x%x\tтип: %s\n", i + 1,
|
|
|
|
|
// mmaps[i]->base, mmaps[i]->length, memory_types[mmaps[i]->type]);
|
2023-10-15 20:29:21 +03:00
|
|
|
|
if (mmaps[i]->type == LIMINE_MEMMAP_FRAMEBUFFER) {
|
|
|
|
|
fb::printf("На видеопамять BIOS/UEFI выделено: %u мегабайт + %u "
|
|
|
|
|
"килобайт\n",
|
|
|
|
|
mmaps[i]->length / 1024 / 1024,
|
|
|
|
|
(mmaps[i]->length / 1024) % 1024);
|
|
|
|
|
}
|
|
|
|
|
if (!(mmaps[i]->type == LIMINE_MEMMAP_USABLE)) { continue; }
|
2023-10-12 22:30:54 +03:00
|
|
|
|
|
|
|
|
|
usable += mmaps[i]->length;
|
|
|
|
|
uint64_t top = mmaps[i]->base + mmaps[i]->length;
|
|
|
|
|
if (top > highest) highest = top;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
limit = highest / BLOCK_SIZE;
|
|
|
|
|
uint64_t bitmap_size = ALIGN_UP(highest / BLOCK_SIZE / 8, BLOCK_SIZE);
|
|
|
|
|
|
|
|
|
|
// Находим доступное место для битовой карты и устанавливаем ее
|
|
|
|
|
for (uint64_t i = 0; i < mmmap_count; i++) {
|
|
|
|
|
if (!mmaps[i]->type == LIMINE_MEMMAP_USABLE) continue;
|
|
|
|
|
|
|
|
|
|
if (mmaps[i]->length >= bitmap_size) {
|
|
|
|
|
bitmap = (uint8_t *)mmaps[i]->base;
|
|
|
|
|
tool::memset(bitmap, 0xFF, bitmap_size);
|
|
|
|
|
mmaps[i]->length -= bitmap_size;
|
|
|
|
|
mmaps[i]->base += bitmap_size;
|
|
|
|
|
available -= bitmap_size;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Освобождаем все доступные фреймы памяти
|
|
|
|
|
for (uint64_t i = 0; i < mmmap_count; i++) {
|
|
|
|
|
for (uint64_t t = 0; t < mmaps[i]->length; t += BLOCK_SIZE) {
|
|
|
|
|
bitmap_limit++;
|
|
|
|
|
}
|
2023-10-15 20:29:21 +03:00
|
|
|
|
|
|
|
|
|
if (!(mmaps[i]->type == LIMINE_MEMMAP_USABLE)) { continue; }
|
2023-10-12 22:30:54 +03:00
|
|
|
|
|
|
|
|
|
for (uint64_t t = 0; t < mmaps[i]->length; t += BLOCK_SIZE) {
|
2023-10-15 20:29:21 +03:00
|
|
|
|
frame_free((void *)mmaps[i]->base + t, 1);
|
2023-10-12 22:30:54 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-15 20:29:21 +03:00
|
|
|
|
fb::printf("%u / %u блоков доступно\n", bitmap_available, bitmap_limit);
|
|
|
|
|
fb::printf("Размер битовой карты: %u\n", bitmap_size);
|
2023-10-21 19:37:02 +03:00
|
|
|
|
alloc_init(frame_alloc(1), BLOCK_SIZE);
|
|
|
|
|
for (uint64_t i = 256 * 1024; i > 0; i -= BLOCK_SIZE) {
|
|
|
|
|
add_block(frame_alloc(1024), 1024 * BLOCK_SIZE);
|
2023-10-15 20:29:21 +03:00
|
|
|
|
}
|
2023-10-21 19:37:02 +03:00
|
|
|
|
merge_all_blocks( );
|
2023-10-19 19:46:58 +03:00
|
|
|
|
mem::dump_memory( );
|
2023-10-15 20:29:21 +03:00
|
|
|
|
fb::printf("%u мегабайт выделено в динамичную память\n",
|
2023-10-21 19:37:02 +03:00
|
|
|
|
(256 * 1024 * BLOCK_SIZE + BLOCK_SIZE) / 1024 / 1024);
|
2023-10-12 22:30:54 +03:00
|
|
|
|
fb::printf("%u МБ объем доступной памяти, %u МБ объем виртуальной памяти\n",
|
2023-10-15 20:29:21 +03:00
|
|
|
|
(bitmap_available * BLOCK_SIZE) / 1024 / 1024,
|
|
|
|
|
available / 1024 / 1024);
|
2023-10-12 22:30:54 +03:00
|
|
|
|
|
|
|
|
|
fb::printf("%u / %u блоков доступно\n", bitmap_available, bitmap_limit);
|
2023-10-19 19:46:58 +03:00
|
|
|
|
fb::printf("Проверка менеджера памяти\n");
|
2023-10-07 18:28:48 +03:00
|
|
|
|
}
|
2023-10-12 22:30:54 +03:00
|
|
|
|
|
2023-10-07 18:28:48 +03:00
|
|
|
|
} // namespace mem
|