Skip to content

Commit 5ba6f3d

Browse files
committed
improve memory allocators methods, improve paging, update readme
1 parent 1257a00 commit 5ba6f3d

File tree

7 files changed

+207
-29
lines changed

7 files changed

+207
-29
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
commit 1257a001f3ade050a2d997495921417e27a880d4
2+
Author: Alexeev Bronislav <[email protected]>
3+
Date: Mon Aug 25 03:18:16 2025 +0700
4+
5+
improve kklibc stdlib and stdio, add kernel panic red screen
6+
17
commit f1d82ba66c77d46c2b727a6af6c8ce7e559b3c07
28
Author: Alexeev Bronislav <[email protected]>
39
Date: Mon Aug 25 02:42:53 2025 +0700

image.png

6.56 KB
Loading

src/kernel/kernel/kernel.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include "../kklibc/paging.h"
1414
#include "../kklibc/kklibc.h"
1515

16+
#define MAX_ARGS 32
17+
1618
int shell_cursor_offset = 0;
1719
int shell_prompt_offset = 0;
1820

@@ -38,12 +40,17 @@ void kmain() {
3840

3941
char** get_args(char *input) {
4042
char *token = strtok(input, " ");
41-
char** args;
43+
static char* args[MAX_ARGS + 1];
4244
int arg_counter = 0;
4345

4446
while(token) {
4547
token = strtok(NULL, " ");
4648

49+
if (arg_counter + 1 > MAX_ARGS + 1) {
50+
printf_colored("Error when parsing args: %d args exceed the limit %d\n", RED_ON_BLACK_CLR_CODE, arg_counter + 1, MAX_ARGS + 1);
51+
break;
52+
}
53+
4754
args[arg_counter] = token;
4855
arg_counter++;
4956
}

src/kernel/kklibc/mem.c

Lines changed: 180 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
#include "ctypes.h"
1111
#include "stdio.h"
1212
#include "stdlib.h"
13+
#include "paging.h"
1314

1415
u32 free_mem_addr_guard1 = 0xDEADBEEF;
1516
u32 free_mem_addr = HEAP_START;
1617
u32 free_mem_addr_guard2 = 0xCAFEBABE;
1718
static mem_block_t *free_blocks = NULL;
19+
u32 heap_current_end = HEAP_START + HEAP_SIZE;
1820

1921
// Инициализация памяти heap
2022
void heap_init() {
@@ -24,13 +26,57 @@ void heap_init() {
2426
free_blocks->next = NULL;
2527
free_blocks->is_free = 1;
2628

29+
// Обновим текущий конец кучи
30+
heap_current_end = HEAP_START + HEAP_SIZE;
31+
2732
kprint("Heap initialized at ");
2833
char buf[32] = "";
2934
hex_to_ascii(HEAP_START, buf);
3035
kprint(buf);
3136
kprint("\n");
3237
}
3338

39+
int expand_heap(u32 size) {
40+
// Выравниваем размер вверх до границы страницы
41+
u32 num_pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
42+
u32 expand_size = num_pages * PAGE_SIZE;
43+
44+
printf("Expanding heap by %d bytes (%d pages)\n", expand_size, num_pages);
45+
46+
// Мы будем расширять кучу начиная с адреса heap_current_end
47+
u32 virtual_address = heap_current_end;
48+
49+
for (u32 i = 0; i < num_pages; i++) {
50+
// Запрашиваем физический фрейм
51+
page_t *page = get_page(virtual_address, 1, kernel_directory);
52+
if (!page) {
53+
kprint("Failed to get page for heap expansion!\n");
54+
return 0;
55+
}
56+
57+
// Выделяем фрейм для страницы (с флагами ядра и записи)
58+
alloc_frame(page, 0, 1);
59+
60+
// Обновляем виртуальный адрес для следующей страницы
61+
virtual_address += PAGE_SIZE;
62+
}
63+
64+
// Теперь нам нужно добавить новую область памяти в список свободных блоков
65+
mem_block_t *new_block = (mem_block_t *)heap_current_end;
66+
new_block->size = expand_size - sizeof(mem_block_t); // Учитываем заголовок
67+
new_block->is_free = 1;
68+
new_block->next = free_blocks; // Добавляем в начало списка
69+
70+
// Обновляем глобальный список свободных блоков
71+
free_blocks = new_block;
72+
73+
// Обновляем текущий конец кучи
74+
heap_current_end += expand_size;
75+
76+
printf("Heap expanded successfully. New end: %x\n", heap_current_end);
77+
return 1;
78+
}
79+
3480
void *kmalloc(u32 size) {
3581
// Выравниваем размер до границы BLOCK_SIZE
3682
if (size % BLOCK_SIZE != 0) {
@@ -47,13 +93,9 @@ void *kmalloc(u32 size) {
4793
// самого блока
4894
if (current->size > size + sizeof(mem_block_t) + BLOCK_SIZE) {
4995
// Можем разделить блок
50-
mem_block_t *new_block =
51-
(mem_block_t *)((u32)current + sizeof(mem_block_t) +
96+
mem_block_t *new_block = (mem_block_t *)((u32)current + sizeof(mem_block_t) +
5297
size); // поинтер на новый блок
53-
new_block->size =
54-
current->size - size -
55-
sizeof(
56-
mem_block_t); // размер текущего - выделяемый - размер структуры
98+
new_block->size = current->size - size - sizeof(mem_block_t); // размер текущего - выделяемый - размер структуры
5799
new_block->is_free = 1; // свободен
58100
new_block->next = current->next;
59101

@@ -70,20 +112,68 @@ void *kmalloc(u32 size) {
70112
current = current->next;
71113
}
72114

73-
kprint("No free blocks found\n");
74-
return NULL;
115+
// Если дошли сюда, значит, подходящего блока не найдено -> пробуем расширить кучу
116+
printf("No free block found for size %d. Trying to expand heap...\n", size);
117+
if (expand_heap(size)) {
118+
// После расширения кучи пробуем аллоцировать снова (рекурсивно)
119+
return kmalloc(size);
120+
} else {
121+
kprint("Heap expansion failed!\n");
122+
return NULL;
123+
}
75124
}
76125

77126
void *krealloc(void *ptr, u32 size) {
78-
if (!ptr) return kmalloc(size); // если нет указателя то просто аллоцируем память
79-
if (size == 0) { kfree(ptr); return NULL; } // если размер нулевой освобождаем поинтер
127+
if (!ptr)
128+
return kmalloc(size);
129+
130+
if (size == 0) {
131+
kfree(ptr);
132+
return NULL;
133+
}
134+
135+
// Получаем заголовок блока
136+
mem_block_t *block = (mem_block_t *)((u32)ptr - sizeof(mem_block_t));
137+
138+
// Если текущий блок достаточно большой
139+
if (block->size >= size) {
140+
// Можно ли разделить блок?
141+
if (block->size - size >= sizeof(mem_block_t) + BLOCK_SIZE) {
142+
mem_block_t *new_block = (mem_block_t *)((u32)block + sizeof(mem_block_t) + size);
143+
new_block->size = block->size - size - sizeof(mem_block_t);
144+
new_block->is_free = 1;
145+
new_block->next = block->next;
146+
147+
block->size = size;
148+
block->next = new_block;
149+
}
150+
return ptr;
151+
}
152+
153+
// Пытаемся объединить с последующим свободным блоком
154+
if (block->next && block->next->is_free) {
155+
u32 total_size = block->size + sizeof(mem_block_t) + block->next->size;
156+
if (total_size >= size) {
157+
block->size = total_size;
158+
block->next = block->next->next;
80159

81-
mem_block_t *block = (mem_block_t*)((u32)ptr - sizeof(mem_block_t)); // создаем блок
82-
if (block->size >= size) return ptr; // если текущий блок достаточно большой
160+
// Разделяем блок, если осталось место
161+
if (total_size - size >= sizeof(mem_block_t) + BLOCK_SIZE) {
162+
mem_block_t *new_block = (mem_block_t *)((u32)block + sizeof(mem_block_t) + size);
163+
new_block->size = total_size - size - sizeof(mem_block_t);
164+
new_block->is_free = 1;
165+
new_block->next = block->next;
166+
block->next = new_block;
167+
block->size = size;
168+
}
169+
return ptr;
170+
}
171+
}
83172

84-
void *new_ptr = kmalloc(size); // новый поинтер
85-
if (new_ptr) { // если все ок то копируем память и освобождаем старый поинтер
86-
memory_copy(ptr, new_ptr, block->size);
173+
// Если не можем расширить, выделяем новый блок и копируем данные
174+
void *new_ptr = kmalloc(size);
175+
if (new_ptr) {
176+
memcpy(new_ptr, ptr, block->size);
87177
kfree(ptr);
88178
}
89179
return new_ptr;
@@ -93,25 +183,64 @@ void kfree(void *ptr) {
93183
if (!ptr)
94184
return;
95185

96-
// получаем указатель на заголовок блока
186+
// Получаем указатель на заголовок блока
97187
mem_block_t *block = (mem_block_t *)((u32)ptr - sizeof(mem_block_t));
98188

99-
if (block->is_free) { // блок уже освобожден
189+
if (block->is_free) {
100190
kprint("Double free detected!\n");
101191
return;
102192
}
103193

104194
block->is_free = 1;
105195

106-
/* попробуем объединить с соседними свободными блоками*/
196+
// Попробуем объединить с соседними свободными блоками
107197
mem_block_t *current = free_blocks;
198+
mem_block_t *prev = NULL;
199+
108200
while (current) {
109201
if (current->is_free && current->next && current->next->is_free) {
110-
// соединим текущий блок со следующим
202+
// Объединяем текущий блок со следующим
111203
current->size += sizeof(mem_block_t) + current->next->size;
112204
current->next = current->next->next;
113-
free_mem_addr -= current->size;
114205
}
206+
207+
// Проверяем, можно ли освободить страницы
208+
if (current->is_free) {
209+
u32 block_start = (u32)current;
210+
u32 block_end = block_start + sizeof(mem_block_t) + current->size;
211+
212+
// Выравниваем границы блока по границам страниц
213+
u32 start_page = block_start & ~(PAGE_SIZE - 1);
214+
u32 end_page = (block_end + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
215+
216+
// Проверяем, полностью ли свободны страницы в этом блоке
217+
for (u32 page = start_page; page < end_page; page += PAGE_SIZE) {
218+
page_t *page_entry = get_page(page, 0, kernel_directory);
219+
if (page_entry && page_entry->present) {
220+
// Проверяем, нет ли занятых блоков в этой странице
221+
int page_is_free = 1;
222+
mem_block_t *check = free_blocks;
223+
while (check) {
224+
u32 check_start = (u32)check;
225+
u32 check_end = check_start + sizeof(mem_block_t) + check->size;
226+
227+
if (!check->is_free && check_start < page + PAGE_SIZE && check_end > page) {
228+
page_is_free = 0;
229+
break;
230+
}
231+
check = check->next;
232+
}
233+
234+
if (page_is_free) {
235+
// Освобождаем фрейм и страницу
236+
free_frame(page_entry);
237+
page_entry->present = 0;
238+
}
239+
}
240+
}
241+
}
242+
243+
prev = current;
115244
current = current->next;
116245
}
117246
}
@@ -153,14 +282,44 @@ void kmemdump() {
153282
u32 counter = 0;
154283

155284
printf("Heap: %x - %x (%d bytes)\n", info.heap_start,
156-
info.heap_start + info.heap_size, info.heap_size);
285+
info.heap_current_end, info.heap_current_end - info.heap_start);
157286
printf("Block size: %d bytes\n", info.block_size);
158287
printf("Total: USED=%d bytes, FREE=%d bytes, in %d blocks\n\n",
159288
info.total_used, info.total_free, info.block_count);
160289

290+
// Вывод информации о страницах хипа
291+
292+
int present_pages_count = 0;
293+
int not_present_pages_count = 0;
294+
for (u32 addr = info.heap_start; addr < info.heap_current_end; addr += PAGE_SIZE) {
295+
page_t *page = get_page(addr, 0, kernel_directory);
296+
if (page && page->present) {
297+
present_pages_count += 1;
298+
} else {
299+
not_present_pages_count += 1;
300+
}
301+
}
302+
303+
printf("Heap pages: PRESENT=%d | NOT PRESENT=%d", present_pages_count, not_present_pages_count);
304+
305+
printf("\nMemory blocks:\n");
161306
while (current) {
162307
printf("Block %d: %x, Size=%d, %s\n", counter++, (u32)current,
163308
current->size, current->is_free ? "FREE" : "USED");
309+
310+
// Дополнительная информация о страницах этого блока
311+
u32 block_start = (u32)current;
312+
u32 block_end = block_start + sizeof(mem_block_t) + current->size;
313+
u32 start_page = block_start & ~(PAGE_SIZE - 1);
314+
u32 end_page = (block_end + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
315+
316+
for (u32 page_addr = start_page; page_addr < end_page; page_addr += PAGE_SIZE) {
317+
page_t *page = get_page(page_addr, 0, kernel_directory);
318+
if (page && page->present) {
319+
printf(" Page %x -> Frame %x\n", page_addr, page->frame * PAGE_SIZE);
320+
}
321+
}
322+
164323
current = current->next;
165324
}
166325
}

src/kernel/kklibc/mem.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ typedef struct mem_block {
2323
typedef struct meminfo {
2424
u32 heap_start;
2525
u32 heap_size;
26+
u32 heap_current_end;
2627
u32 block_size;
2728
mem_block_t* free_blocks;
2829
u32 total_used;
@@ -33,9 +34,10 @@ typedef struct meminfo {
3334
meminfo_t get_meminfo();
3435
void get_freememaddr();
3536

36-
// Новые функции
37+
int expand_heap(u32 size);
3738
void heap_init();
3839
void* kmalloc(u32 size);
40+
void *krealloc(void *ptr, u32 size);
3941
void kfree(void* ptr);
4042
void kmemdump();
4143

src/kernel/kklibc/paging.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ static u32 first_frame() {
9090
}
9191

9292
/* Выделение фрейма для страницы */
93-
void alloc_frame(page_t *page, int is_kernel, int is_writeable)
94-
{
93+
void alloc_frame(page_t *page, int is_kernel, int is_writeable) {
9594
if (page->frame != 0) {
9695
return; // Фрейм уже выделен
9796
} else {

src/kernel/kklibc/paging.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
#include "ctypes.h"
55
#include "../cpu/isr.h"
66

7+
/* Макросы для работы с битовыми массивами */
8+
#define INDEX_FROM_BIT(a) (a/(8*4))
9+
#define OFFSET_FROM_BIT(a) (a%(8*4))
10+
11+
#define PAGE_SIZE 0x1000
12+
713
/* Внутренняя функция выделения памяти */
814
u32 pkmalloc_internal(u32 sz, int align, u32 *phys);
915

@@ -19,10 +25,6 @@ u32 pkmalloc_ap(u32 sz, u32 *phys);
1925
/* Обычное выделение памяти */
2026
u32 pkmalloc(u32 sz);
2127

22-
/* Макросы для работы с битовыми массивами */
23-
#define INDEX_FROM_BIT(a) (a/(8*4))
24-
#define OFFSET_FROM_BIT(a) (a%(8*4))
25-
2628
/* Внешняя переменная текущего адреса свободной памяти */
2729
extern u32 free_mem_addr;
2830

@@ -89,4 +91,7 @@ page_t *get_page(u32 address, int make, page_directory_t *dir);
8991
**/
9092
void page_fault(registers_t regs);
9193

94+
void alloc_frame(page_t *page, int is_kernel, int is_writeable);
95+
void free_frame(page_t *page);
96+
9297
#endif

0 commit comments

Comments
 (0)