KERNEL: добавлен физический менеджер памяти
This commit is contained in:
parent
a66b0416d5
commit
ea0a395cc5
8 changed files with 293 additions and 4 deletions
3
Makefile
3
Makefile
|
|
@ -1,5 +1,5 @@
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -m32 -ffreestanding -O2 -Wall -Wextra -Iinclude -fno-stack-protector
|
CFLAGS = -m32 -nostdlib -fno-builtin -fno-stack-protector -ffreestanding -mno-red-zone -mno-mmx -mno-sse -mno-sse2
|
||||||
|
|
||||||
AS = nasm
|
AS = nasm
|
||||||
ASFLAGS = -f elf32
|
ASFLAGS = -f elf32
|
||||||
|
|
@ -21,6 +21,7 @@ OBJ = boot/boot.o \
|
||||||
kernel/io.o \
|
kernel/io.o \
|
||||||
kernel/pic.o \
|
kernel/pic.o \
|
||||||
kernel/string.o \
|
kernel/string.o \
|
||||||
|
kernel/pmm.o \
|
||||||
drivers/serial.o \
|
drivers/serial.o \
|
||||||
drivers/vga.o \
|
drivers/vga.o \
|
||||||
drivers/speaker.o \
|
drivers/speaker.o \
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
## 2. Процессы, память, user mode, еще драйвера
|
## 2. Процессы, память, user mode, еще драйвера
|
||||||
|
|
||||||
- [ ] Физ. менеджер памяти
|
- [x] Физ. менеджер памяти
|
||||||
- [ ] Вирт. менеджер памяти
|
- [ ] Вирт. менеджер памяти
|
||||||
- [ ] Куча ядра
|
- [ ] Куча ядра
|
||||||
- [ ] Потоки ядра
|
- [ ] Потоки ядра
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ extern kernel_main ; Наша функция из Си-файла
|
||||||
|
|
||||||
_start:
|
_start:
|
||||||
mov esp, stack_space ; Выделяем указатель на стек
|
mov esp, stack_space ; Выделяем указатель на стек
|
||||||
|
; Передаем параметры от GRUB в Си-код по стандарту cdecl
|
||||||
|
push ebx ; Аргумент 2: Адрес структуры Multiboot
|
||||||
|
push eax ; Аргумент 1: Магическое число Multiboot
|
||||||
call kernel_main ; Прыгаем в Си!
|
call kernel_main ; Прыгаем в Си!
|
||||||
jmp $ ; Если Си-функция вернется — виснем в вечном цикле
|
jmp $ ; Если Си-функция вернется — виснем в вечном цикле
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,27 @@
|
||||||
#include "../drivers/speaker.h"
|
#include "../drivers/speaker.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
|
#include "pmm.h"
|
||||||
#include "pic.h"
|
#include "pic.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "multiboot.h"
|
||||||
|
|
||||||
void kernel_main(void) {
|
extern uint32_t end; // Символ 'end' прописан в конце любого стандартного linker.ld
|
||||||
|
uint32_t kernel_end = (uint32_t)&end;
|
||||||
|
|
||||||
|
void kernel_main(uint32_t magic, uint32_t mboot_addr) {
|
||||||
log_info(LOG_NORMAL, "Initializing serial...");
|
log_info(LOG_NORMAL, "Initializing serial...");
|
||||||
serial_init();
|
serial_init();
|
||||||
|
if (magic != MULTIBOOT_BOOTLOADER_MAGIC) {
|
||||||
|
log_error(LOG_NORMAL, "fuck, i got invalid multiboot magic. IS THAT REALLY THE MULTIBOOT YOU TALKED ABOUT?");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
struct multiboot_info* mbi = (struct multiboot_info*)mboot_addr;
|
||||||
|
if (!(mbi->flags & (1 << 6))) {
|
||||||
|
log_error(LOG_NORMAL, "fuck, i haven't got a memory map. IS THAT REALLY THE MULTIBOOT YOU TALKED ABOUT?");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
log_info(LOG_NORMAL, "Initializing VGA...");
|
log_info(LOG_NORMAL, "Initializing VGA...");
|
||||||
vga_init();
|
vga_init();
|
||||||
log_info(LOG_NORMAL, "Setting color white on black");
|
log_info(LOG_NORMAL, "Setting color white on black");
|
||||||
|
|
@ -33,6 +48,8 @@ void kernel_main(void) {
|
||||||
timer_init(100);
|
timer_init(100);
|
||||||
log_info(LOG_NORMAL, "Registering mouse");
|
log_info(LOG_NORMAL, "Registering mouse");
|
||||||
mouse_init();
|
mouse_init();
|
||||||
|
log_info(LOG_NORMAL, "Enabling PMM...");
|
||||||
|
pmm_init(mbi, (uint32_t)&end);
|
||||||
log_info(LOG_NORMAL, "Enabling IRQ...");
|
log_info(LOG_NORMAL, "Enabling IRQ...");
|
||||||
__asm__ __volatile__("sti");
|
__asm__ __volatile__("sti");
|
||||||
vga_set_color(VGA_COLOR_LIGHT_GREEN, VGA_COLOR_BLACK);
|
vga_set_color(VGA_COLOR_LIGHT_GREEN, VGA_COLOR_BLACK);
|
||||||
|
|
@ -60,5 +77,76 @@ void kernel_main(void) {
|
||||||
speaker_beep(350, 400);
|
speaker_beep(350, 400);
|
||||||
vga_init();
|
vga_init();
|
||||||
vga_set_color(VGA_COLOR_LIGHT_GRAY, VGA_COLOR_BLACK);
|
vga_set_color(VGA_COLOR_LIGHT_GRAY, VGA_COLOR_BLACK);
|
||||||
|
kprint_serial("--- Memory Map From GRUB ---");
|
||||||
|
struct multiboot_mmap_entry* mmap = (struct multiboot_mmap_entry*)mbi->mmap_addr;
|
||||||
|
|
||||||
|
while((uint32_t)mmap < mbi->mmap_addr + mbi->mmap_length) {
|
||||||
|
char addr_buf[32];
|
||||||
|
char len_buf[32];
|
||||||
|
|
||||||
|
itoa((uint32_t)mmap->addr, addr_buf, 16);
|
||||||
|
itoa((uint32_t)mmap->len, len_buf, 10);
|
||||||
|
|
||||||
|
kprint_serial("Region: Base=0x");
|
||||||
|
kprint_serial(addr_buf);
|
||||||
|
kprint_serial(" Size=");
|
||||||
|
kprint_serial(len_buf);
|
||||||
|
|
||||||
|
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) {
|
||||||
|
kprint_serial(" [FREE RAM]\n");
|
||||||
|
} else {
|
||||||
|
kprint_serial(" [RESERVED]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Переходим к следующей записи (учитываем поле size)
|
||||||
|
mmap = (struct multiboot_mmap_entry*)((uint32_t)mmap + mmap->size + sizeof(mmap->size));
|
||||||
|
}
|
||||||
|
kprint_serial("--- trying to allocate some fucking memory... ---\n");
|
||||||
|
kprint_serial("page 1... ");
|
||||||
|
void* p1 = pmm_alloc_page();
|
||||||
|
kprint_serial("page 2...");
|
||||||
|
void* p2 = pmm_alloc_page();
|
||||||
|
kprint_serial("ok!");
|
||||||
|
char buf[32];
|
||||||
|
kprint_serial("PMM TEST: Page 1 allocated at 0x");
|
||||||
|
itoa((uint32_t)p1, buf, 16);
|
||||||
|
kprint_serial(buf);
|
||||||
|
kprint_serial("\n");
|
||||||
|
|
||||||
|
kprint_serial("PMM TEST: Page 2 allocated at 0x");
|
||||||
|
itoa((uint32_t)p2, buf, 16);
|
||||||
|
kprint_serial(buf);
|
||||||
|
kprint_serial("\n");
|
||||||
|
|
||||||
|
kprint_serial("freeing the pages back... page 1... ");
|
||||||
|
pmm_free_page(p1);
|
||||||
|
kprint_serial("page 2... ");
|
||||||
|
pmm_free_page(p2);
|
||||||
|
kprint_serial("it don't died!\n");
|
||||||
|
|
||||||
|
kprint_serial("\n--- PMM MEMORY STATS ---\n");
|
||||||
|
|
||||||
|
pmm_get_stats(); // Просто запускаем сбор, она запишет всё в глобальную переменную
|
||||||
|
|
||||||
|
// Берем указатель на глобальную переменную
|
||||||
|
pmm_stats_t* my_stats = pmm_get_stats_ptr();
|
||||||
|
|
||||||
|
kprint_serial("Total Memory: ");
|
||||||
|
itoa(my_stats->total_memory >> 20, buf, 10);
|
||||||
|
kprint_serial(buf);
|
||||||
|
kprint_serial(" MB\n");
|
||||||
|
|
||||||
|
kprint_serial("Used Memory: ");
|
||||||
|
itoa(my_stats->used_memory >> 10, buf, 10);
|
||||||
|
kprint_serial(buf);
|
||||||
|
kprint_serial(" KB\n");
|
||||||
|
|
||||||
|
kprint_serial("Free Memory: ");
|
||||||
|
itoa(my_stats->free_memory >> 20, buf, 10);
|
||||||
|
kprint_serial(buf);
|
||||||
|
kprint_serial(" MB\n");
|
||||||
|
|
||||||
|
kprint_serial("------------------------\n\n");
|
||||||
|
|
||||||
while (1);
|
while (1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
47
kernel/multiboot.h
Normal file
47
kernel/multiboot.h
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef MULTIBOOT_H
|
||||||
|
#define MULTIBOOT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
|
||||||
|
|
||||||
|
struct multiboot_mmap_entry {
|
||||||
|
uint32_t size;
|
||||||
|
uint64_t addr;
|
||||||
|
uint64_t len;
|
||||||
|
#define MULTIBOOT_MEMORY_AVAILABLE 1
|
||||||
|
#define MULTIBOOT_MEMORY_RESERVED 2
|
||||||
|
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
|
||||||
|
#define MULTIBOOT_MEMORY_NVS 4
|
||||||
|
#define MULTIBOOT_MEMORY_BADRAM 5
|
||||||
|
uint32_t type;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct multiboot_info {
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t mem_lower;
|
||||||
|
uint32_t mem_upper;
|
||||||
|
uint32_t boot_device;
|
||||||
|
uint32_t cmdline;
|
||||||
|
uint32_t mods_count;
|
||||||
|
uint32_t mods_addr;
|
||||||
|
uint32_t num;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t shndx;
|
||||||
|
uint32_t mmap_length;
|
||||||
|
uint32_t mmap_addr; // <-- Вот это нам нужно! Адрес карты памяти
|
||||||
|
uint32_t drives_length;
|
||||||
|
uint32_t drives_addr;
|
||||||
|
uint32_t config_table;
|
||||||
|
uint32_t boot_loader_name;
|
||||||
|
uint32_t apm_table;
|
||||||
|
uint32_t vbe_control_info;
|
||||||
|
uint32_t vbe_mode_info;
|
||||||
|
uint16_t vbe_mode;
|
||||||
|
uint16_t vbe_interface_seg;
|
||||||
|
uint16_t vbe_interface_off;
|
||||||
|
uint16_t vbe_interface_len;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#endif
|
||||||
119
kernel/pmm.c
Normal file
119
kernel/pmm.c
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
#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;
|
||||||
|
}
|
||||||
30
kernel/pmm.h
Normal file
30
kernel/pmm.h
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef PMM_H
|
||||||
|
#define PMM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "multiboot.h"
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
|
||||||
|
// Инициализация: передаем инфу от GRUB и адрес конца ядра из линкера
|
||||||
|
void pmm_init(struct multiboot_info* mbi, uint32_t kernel_end);
|
||||||
|
|
||||||
|
// Выделить одну страницу памяти (возвращает физический адрес)
|
||||||
|
void* pmm_alloc_page(void);
|
||||||
|
|
||||||
|
// Освободить страницу памяти по адресу
|
||||||
|
void pmm_free_page(void* addr);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t total_memory; // Всего памяти в байтах
|
||||||
|
uint32_t used_memory; // Занято в байтах
|
||||||
|
uint32_t free_memory; // Свободно в байтах
|
||||||
|
uint32_t total_pages; // Всего страниц
|
||||||
|
uint32_t used_pages; // Занято страниц
|
||||||
|
uint32_t free_pages; // Свободно страниц
|
||||||
|
} pmm_stats_t;
|
||||||
|
|
||||||
|
void pmm_get_stats(void);
|
||||||
|
pmm_stats_t* pmm_get_stats_ptr(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -30,4 +30,5 @@ SECTIONS
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
}
|
}
|
||||||
|
end = .;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue