merge branch memory-shit into higher-half

This commit is contained in:
2025-05-10 15:48:10 +03:00
parent 65f543fa92
commit 767e74976f
14 changed files with 419 additions and 178 deletions
+7 -1
View File
@@ -33,7 +33,7 @@ void heap_init() {
kernel_heap.first = initial_block;
}
/*
void* heap_alloc(uint32_t size) {
// Выравниваем размер до 4 байт
size = (size + 3) & ~3;
@@ -98,6 +98,12 @@ void* heap_alloc(uint32_t size) {
// Если что-то пошло не так, возвращаем NULL
return (void*)0;
}
*/
//TODO: fix it yo
void *heap_alloc(uint32_t size)
{
return alloc_page();
}
void heap_free(void* ptr) {
if (!ptr || (uint32_t)ptr < (uint32_t)kernel_heap.start) return;
+33 -50
View File
@@ -1,61 +1,61 @@
#include "../include/paging.h"
#include <stdint.h>
#include "../include/stdio.h"
#define PAGE_SIZE 0x1000 // 4 КБ
// Общий размер памяти
#define MEMORY_SIZE 0x100000000 // 4 ГБ
// Количество страниц
#define PAGE_COUNT (MEMORY_SIZE / PAGE_SIZE) // 1 048 576 страниц
// Размер битмапа в байтах (округлено вверх)
#define BITMAP_SIZE (PAGE_COUNT / 8) // 131 072 байт
#include "../include/string.h"
// Битмап для отслеживания страниц
// Каждый бит представляет одну страницу: 0 = свободна, 1 = занята
uint8_t page_bitmap[BITMAP_SIZE];
// Установить бит (пометить страницу как занятую)
void set_bit(uint32_t page_index) {
uint32_t byte_index = page_index / 8; // Номер байта в битовой карте
uint8_t bit_offset = page_index % 8; // Смещение бита в байте
page_bitmap[byte_index] |= (1 << bit_offset); // Устанавливаем бит
}
// Сбросить бит (пометить страницу как свободную)
void clear_bit(uint32_t page_index) {
if (page_index >= PAGE_COUNT) {
printf("clear_bit: address out of range\n");
return;
}
uint32_t byte_index = page_index / 8;
uint8_t bit_offset = page_index % 8;
//check if this is needed at all except for debug purposes
if(!(page_bitmap[byte_index] & (1 << bit_offset)))
{
printf("clear_bit: page #0x%X already free\n", page_index);
return;
}
page_bitmap[byte_index] &= ~(1 << bit_offset); // Сбрасываем бит
}
// Инициализация аллокатора страниц
void init_allocator() {
int i;
// Помечаем все страницы как свободные (0)
for (i = 0; i < BITMAP_SIZE; i++) {
page_bitmap[i] = 0;
}
// Резервируем первые 4 МБ для ядра (0x00000000-0x003FFFFF)
// Это 1024 страницы или 128 байт битмапа
for (i = 0; i < 1024 / 8; i++) {
page_bitmap[i] = 0xFF; // Все биты = 1 (занято)
}
// Если вы используете higher-half kernel, то нужно также
// зарезервировать соответствующую область в верхней части памяти
// Например, если ядро отображено начиная с 0xC0000000 (3 ГБ):
uint32_t kernel_higher_start = 0xC0000000 / PAGE_SIZE / 8; // Индекс в битмапе
for (i = kernel_higher_start; i < kernel_higher_start + 1024 / 8; i++) {
page_bitmap[i] = 0xFF;
}
memset(page_bitmap, 0x00, BITMAP_SIZE);
}
void* alloc_page() {
int i, j;
// Проходим по всему битмапу
for (i = 0; i < BITMAP_SIZE; i++) {
if (page_bitmap[i] != 0xFF) { // Если в этом байте есть свободная страница
//printf("!!!free page at 0x%X!!!\n", i);
for (j = 0; j < 8; j++) {
if (!(page_bitmap[i] & (1 << j))) { // Если этот бит = 0 (свободен)
page_bitmap[i] |= (1 << j); // Помечаем как занятый
// Вычисляем физический адрес страницы
uint32_t page_num = i * 8 + j;
void* addr = (void*)(page_num * PAGE_SIZE);
void* addr = (void*)(page_num * PAGE_SIZE);
printf("allocated page at 0x%X (page #0x%X)\n", addr, page_num);
//printf("allocated page at 0x%X (page #0x%X)\n", addr, page_num);
return (void*)(page_num * PAGE_SIZE);
}
@@ -79,22 +79,5 @@ void free_page(void* physaddr) {
// Вычисляем номер страницы
uint32_t page_num = addr / PAGE_SIZE;
// Проверка границ
if (page_num >= PAGE_COUNT) {
printf("free_page: address out of range\n");
return;
}
// Вычисляем индекс байта и бита в битмапе
uint32_t byte_idx = page_num / 8;
uint32_t bit_idx = page_num % 8;
// Проверяем, не освобождаем ли уже свободную страницу
if (!(page_bitmap[byte_idx] & (1 << bit_idx))) {
printf("free_page: page already free\n");
return;
}
// Освобождаем страницу
page_bitmap[byte_idx] &= ~(1 << bit_idx);
clear_bit(page_num);
}
+106 -36
View File
@@ -1,17 +1,67 @@
#include "../include/paging.h"
#include <stdint.h>
#include "../include/string.h"
uint32_t get_pte(void *virtualaddr) {
uint32_t pdindex = (uint32_t)virtualaddr >> 22;
uint32_t ptindex = (uint32_t)virtualaddr >> 12 & 0x3FF;
uint32_t *pd = (uint32_t *)0xFFFFF000;
if (!(pd[pdindex] & 0x1)) {
printf("GET_PTE ERROR: PT not present\n");
return 0;
}
uint32_t *pt = (uint32_t*)(0xFFC00000 + (pdindex << 12));
return pt[ptindex];
}
static uint32_t next_user_virt = 0x00400000;
void* setup_user_process(void* user_code_phys, uint32_t* user_stack_top) {
if ((uint32_t)user_code_phys & 0xFFF) {
printf("SETUP_USER_PROCESS ERROR: user_code_phys not aligned\n");
return 0;
}
void* stack_phys = alloc_page();
if (!stack_phys) return 0;
uint32_t code_virt = next_user_virt;
uint32_t stack_virt = code_virt + 0x3FF000; // 4 МБ - 4 КБ
if (next_user_virt >= 0xC0000000 - 0x400000) {
printf("SETUP_USER_PROCESS ERROR: out of user address space\n");
return 0;
}
unmap_page((void*)code_virt);
unmap_page((void*)stack_virt);
map_page(user_code_phys, (void*)code_virt, 0x7);
map_page(stack_phys, (void*)stack_virt, 0x7);
// Verify mappings
uint32_t code_pte = get_pte((void*)code_virt);
uint32_t stack_pte = get_pte((void*)stack_virt);
uint32_t check_pte = get_pte((void*)0x00400000);
*user_stack_top = stack_virt + 0x1000;
printf("Code PTE at 0x%x: 0x%x (phys 0x%x, %s, %s)\n",
code_virt, code_pte, code_pte & ~0xFFF,
(code_pte & 0x2) ? "writable" : "read-only",
(code_pte & 0x4) ? "user" : "supervisor");
printf("Stack PTE at 0x%x: 0x%x (phys 0x%x, %s, %s)\n",
stack_virt, stack_pte, stack_pte & ~0xFFF,
(stack_pte & 0x2) ? "writable" : "read-only",
(stack_pte & 0x4) ? "user" : "supervisor");
printf("PTE for 0x00400000: 0x%x (phys 0x%x, %s, %s)\n",
check_pte, check_pte & ~0xFFF,
(check_pte & 0x2) ? "writable" : "read-only",
(check_pte & 0x4) ? "user" : "supervisor");
*user_stack_top = stack_virt + 0x1000 -4;//here we place the stack pointer to its top (because the stack is growing down)
next_user_virt += 0x400000; // Следующий 4 МБ блок
return (void*)code_virt;
}
@@ -34,41 +84,62 @@ void *get_physaddr(void *virtualaddr) {
return (void *)((pt[ptindex] & ~0xFFF) + ((unsigned long)virtualaddr & 0xFFF));
}
void map_page(void* physaddr, void* virtualaddr, unsigned int flags) {
// Убеждаемся, что адреса выровнены по 4 КБ
uint32_t phys = (uint32_t)physaddr & ~0xFFF; // Обнуляем младшие 12 бит
uint32_t virt = (uint32_t)virtualaddr & ~0xFFF;
// Вычисляем индексы
uint32_t pdindex = virt >> 22; // Индекс в каталоге страниц
uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц
uint32_t *pd = (uint32_t *)0xFFFFF000; // Адрес каталога страниц в виртуальной памяти
// Проверяем, существует ли таблица страниц
if (!(pd[pdindex] & 0x1)) { // Бит 0 — "present"
// Если таблицы нет, создаём новую
void *new_pt = alloc_page();
if (!new_pt) while (1); // Нет памяти
pd[pdindex] = (uint32_t)new_pt | 0x3; // present, writable
// Очищаем новую таблицу
uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex);
for (int i = 0; i < 1024; i++) {
pt[i] = 0; // Все страницы "не присутствуют"
}
void map_page(void *physaddr, void *virtualaddr, unsigned int flags) {
// Make sure that both addresses are page-aligned.
if ((unsigned long)physaddr & 0xFFF || (unsigned long)virtualaddr & 0xFFF) {
// Error handling: addresses not page-aligned
printf("MAP_PAGE ERROR: address not page-aligned\n");
return;
}
// Получаем адрес таблицы страниц
uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex);
// Устанавливаем отображение
pt[ptindex] = phys | (flags & 0xFFF) | 0x1; // Флаги + present
unsigned long pdindex = (unsigned long)virtualaddr >> 22;
unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF;
// Сбрасываем TLB для этого адреса
unsigned long *pd = (unsigned long *)0xFFFFF000;
// Here you need to check whether the PD entry is present.
// When it is not present, you need to create a new empty PT and
// adjust the PDE accordingly.
if (!(pd[pdindex] & 0x1)) { // If PDE not present
unsigned long *new_pt = alloc_page();
unsigned long *virt_pt = (unsigned long *)(0xC0000000 + new_pt);
memset(virt_pt, 0, 4096);
//pd[pdindex] = (uint32_t)new_pt | 0x3; // Present, R/W
pd[pdindex] = (uint32_t)new_pt | (flags & 0x7); // Add User bit if needed
}
unsigned long *pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex);
// Here you need to check whether the PT entry is present.
// When it is, then there is already a mapping present. What do you do now?
pt[ptindex] = ((unsigned long)physaddr) | (flags & 0xFFF); // Present
// Now you need to flush the entry in the TLB
// or you might not notice the change.
asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory");
}
void unmap_page(void *virtualaddr) {
// Calculate page directory and page table indices
unsigned long pdindex = (unsigned long)virtualaddr >> 22;
unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF;
// Get the page directory
unsigned long *pd = (unsigned long *)0xFFFFF000;
if (pd[pdindex] & 0x1) { // Check if the page directory entry is present
// Get the page table
unsigned long *pt = (unsigned long *)(0xFFC00000 + (pdindex << 12));
// Clear the page table entry (remove the mapping)
pt[ptindex] = 0;
// Invalidate the TLB entry for this virtual address
asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory");
}
}
void map_kernel_page(void* virtualaddr, unsigned int flags) {
uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; // Выравниваем по 4 КБ
if (virt < 0xC0000000) while(1); // Ошибка: ядро только выше 3 ГБ
@@ -76,27 +147,26 @@ void map_kernel_page(void* virtualaddr, unsigned int flags) {
uint32_t pdindex = virt >> 22; // Индекс в каталоге
uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц
uint32_t* pd = (uint32_t*)0xFFFFF000; // Каталог страниц
// Проверяем, существует ли таблица страниц
if (!(pd[pdindex] & 0x1)) {
if (!(kpage_dir[pdindex] & 0x1)) {
void* new_pt = alloc_page();
if (!new_pt) while(1); // Нет памяти
// Убеждаемся, что адрес выровнен
if ((uint32_t)new_pt & 0xFFF) while(1); // Ошибка выравнивания
pd[pdindex] = ((uint32_t)new_pt) | 0x3; // Временно записываем в каталог
asm volatile("invlpg (%0)" : : "r" ((uint32_t)&pd[pdindex]) : "memory"); // Инвалидируем TLB
kpage_dir[pdindex] = ((uint32_t)new_pt) | 0x3; // Временно записываем в каталог
asm volatile("invlpg (%0)" : : "r" ((uint32_t)&kpage_dir[pdindex]) : "memory"); // Инвалидируем TLB
uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex);
uint32_t* pt = ((uint32_t*)kpage_dir+0x1000) + (0x400 * pdindex);
for (int i = 0; i < 1024; i++) {
pt[i] = 0;
}
}
// Получаем таблицу страниц
uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex);
uint32_t* pt = ((uint32_t*)kpage_dir+0x1000) + (0x400 * pdindex);
void* phys = alloc_page();
if (!phys) while(1);
+67 -48
View File
@@ -10,56 +10,51 @@ uint32_t *kpage_dir;
uint32_t setup_tmp_pgdir(uint32_t magic, uint32_t info)
{
int n, pd;
uint32_t pagedir_address, memksize;
uint32_t *page_table;
struct multiboot_info *mbi;
int n, pd;
uint32_t pagedir_address, memksize;
uint32_t *page_table;
struct multiboot_info *mbi;
if(magic != MULTIBOOT_BOOTLOADER_MAGIC) {
/* 4MB of memory assumed */
memksize = 4096;
} else {
mbi = (struct multiboot_info *)(PAGE_OFFSET + info);
if(!(mbi->flags & MULTIBOOT_INFO_MEMORY)) {
/* 4MB of memory assumed */
memksize = 4096;
} else {
/* we need to add the first 1MB to memksize */
memksize = (uint32_t)mbi->mem_upper + 1024;
if(memksize > ((0xFFFFFFFF - PAGE_OFFSET) / 1024)) {
memksize = (0xFFFFFFFF - PAGE_OFFSET) / 1024;
}
}
}
if(magic != MULTIBOOT_BOOTLOADER_MAGIC) {
memksize = 4096;
} else {
mbi = (struct multiboot_info *)(PAGE_OFFSET + info);
if(!(mbi->flags & MULTIBOOT_INFO_MEMORY)) {
memksize = 4096;
} else {
memksize = (uint32_t)mbi->mem_upper + 1024;
if(memksize > ((0xFFFFFFFF - PAGE_OFFSET) / 1024)) {
memksize = (0xFFFFFFFF - PAGE_OFFSET) / 1024;
}
}
}
/* address becomes PAGE_OFFSET (0xC0000000) plus the size of memory minus the first page */
/* TODO: check if I wrote the comment above correctly*/
pagedir_address = PAGE_OFFSET + (memksize * 1024) - memksize;
pagedir_address = PAGE_ALIGN(pagedir_address);
/* Address is PAGE_OFFSET plus memory size minus 4KB */
pagedir_address = PAGE_OFFSET + (memksize * 1024) - 4096;
pagedir_address = PAGE_ALIGN(pagedir_address);
/*
memory pages:
0 -> page directory
1 -> page table
*/
kpage_dir = (uint32_t *)pagedir_address;
memset(kpage_dir, 0, PAGE_SIZE);
kpage_dir = (uint32_t *)pagedir_address;
memset(kpage_dir, 0, PAGE_SIZE);
pagedir_address += PAGE_SIZE;
page_table = (uint32_t *)pagedir_address;
memset(page_table, 0, memksize);
pagedir_address += PAGE_SIZE;
page_table = (uint32_t *)pagedir_address;
memset(page_table, 0, memksize);
/* if we have 4MB assumed earlier, the memksize will be 4096 and this loop will run while n < 1024 */
/* so basically 4MB is 1024 pages */
for(n = 0; n < memksize / sizeof(uint32_t); n++) {
page_table[n] = (n << PAGE_SHIFT) | PAGE_PRESENT | PAGE_RW;
if(!(n % 1024)) {
pd = n / 1024;
kpage_dir[pd] = (uint32_t)(pagedir_address + (PAGE_SIZE * pd) + GDT_BASE) | PAGE_PRESENT | PAGE_RW;
kpage_dir[GET_PGDIR(PAGE_OFFSET) + pd] = (uint32_t)(pagedir_address + (PAGE_SIZE * pd) + GDT_BASE) | PAGE_PRESENT | PAGE_RW;
}
}
return (uint32_t)kpage_dir - PAGE_OFFSET;
for(n = 0; n < memksize / sizeof(uint32_t); n++) {
page_table[n] = (n << PAGE_SHIFT) | PAGE_PRESENT | PAGE_RW;
if(!(n % 1024)) {
pd = n / 1024;
uint32_t pt_phys = (uint32_t)page_table - PAGE_OFFSET + (PAGE_SIZE * pd);
kpage_dir[pd] = pt_phys | PAGE_PRESENT | PAGE_RW | PAGE_USER;//TODO: fix, I don't think pd should have DPL3
kpage_dir[GET_PGDIR(PAGE_OFFSET) + pd] = pt_phys | PAGE_PRESENT | PAGE_RW | PAGE_USER;//TODO: fix, I don't think pd should have DPL3
}
}
uint32_t pd_phys = (uint32_t)kpage_dir - PAGE_OFFSET;
kpage_dir[1023] = pd_phys | PAGE_PRESENT | PAGE_RW; // Recursive mapping
return (uint32_t)kpage_dir - PAGE_OFFSET;
}
void grub_memory_map(unsigned int magic, struct multiboot_info* mbi)
@@ -79,16 +74,40 @@ void grub_memory_map(unsigned int magic, struct multiboot_info* mbi)
(multiboot_memory_map_t*) (mbi->mmap_addr + i);
printf("Start Addr: %x | Length: %x | Size: %x | Type: %x\n",
mmmt->addr, mmmt->len, mmmt->size, mmmt->type);
mmmt->addr_low, mmmt->len_low, mmmt->size, mmmt->type);
if(mmmt->type == MULTIBOOT_MEMORY_AVAILABLE) {
if(mmmt->type != MULTIBOOT_MEMORY_AVAILABLE) {
/*
* Do something with this memory block!
* BE WARNED that some of memory shown as availiable is actually
* actively being used by the kernel! You'll need to take that
* into account before writing to memory!
*/
printf("available\n");
printf("not available\n");
uint32_t size_in_pages = mmmt->len_low / PAGE_SIZE;
printf("size_in_pages: 0x%X\n", size_in_pages);
uint32_t base_page = mmmt->addr_low / PAGE_SIZE;
uint32_t page_count = mmmt->len_low / PAGE_SIZE;
printf("page_base: %X, page_count: %X\n", base_page, page_count);
for (uint32_t j = 0; j < page_count; j++) {
set_bit(base_page + j);
}
}
}
extern uint32_t _start, _end; // From linker script
uint32_t kernel_start_phys = (uint32_t)&_start - 0xC0000000;
uint32_t kernel_end_phys = (uint32_t)&_end - 0xC0000000;
uint32_t kernel_start_page = kernel_start_phys / PAGE_SIZE;
uint32_t kernel_end_page = (kernel_end_phys + PAGE_SIZE - 1) / PAGE_SIZE;
printf("Kernel phys range: 0x%X to 0x%X, pages: 0x%X to 0x%X\n",
kernel_start_phys, kernel_end_phys, kernel_start_page, kernel_end_page);
for (uint32_t i = kernel_start_page; i < kernel_end_page; i++) {
if (i < BITMAP_SIZE) {
set_bit(i);
} else {
printf("Bitmap overflow at kernel page %u\n", i);
}
}
}