убрана лишняя отладка; фикс аллокатора; двойная буферизация
This commit is contained in:
parent
94b03ee1f3
commit
17cb0f47f7
14 changed files with 207 additions and 425 deletions
|
|
@ -25,9 +25,8 @@ ZalupaCalc 2 - это инновационная операционная сис
|
||||||
- [x] Вывод на экран прямоугольников и прочих фигур
|
- [x] Вывод на экран прямоугольников и прочих фигур
|
||||||
- [x] Вывод на экран BMP
|
- [x] Вывод на экран BMP
|
||||||
- [x] Вывод на экран текста
|
- [x] Вывод на экран текста
|
||||||
- [ ] Двойная буферизация
|
- [x] Двойная буферизация
|
||||||
- [ ] Вывод курсора мыши на экран, движение
|
- [x] Вывод курсора мыши на экран, движение
|
||||||
- [ ] Кнопки (touch zones, массив в памяти где будут координаты областей и действия при нажатии)
|
|
||||||
|
|
||||||
### 3. Математика
|
### 3. Математика
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
#include "drawing.h"
|
#include "drawing.h"
|
||||||
#include "multiboot.h"
|
#include "multiboot.h"
|
||||||
#include "serial.h"
|
#include "string.h"
|
||||||
#include "vmm.h" // Для маппинга
|
#include "heap.h"
|
||||||
|
#include "vmm.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#define TRANSPARENT_COLOR 0xFF00FF
|
#define TRANSPARENT_COLOR 0xFF00FF
|
||||||
|
|
||||||
uint32_t* fb_ptr = 0;
|
uint32_t* fb_ptr = 0;
|
||||||
|
uint32_t* backbuffer = 0;
|
||||||
uint32_t screen_width = 0;
|
uint32_t screen_width = 0;
|
||||||
uint32_t screen_height = 0;
|
uint32_t screen_height = 0;
|
||||||
|
|
||||||
void draw_init(struct multiboot_info* mbi) {
|
void draw_init(struct multiboot_info* mbi) {
|
||||||
if (!(mbi->flags & (1 << 12))) {
|
if (!(mbi->flags & (1 << 12))) {
|
||||||
kprint_serial("DRAWING: NO FRAMEBUFFER!");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -19,25 +20,25 @@ void draw_init(struct multiboot_info* mbi) {
|
||||||
uint32_t width = mbi->framebuffer_width;
|
uint32_t width = mbi->framebuffer_width;
|
||||||
uint32_t height = mbi->framebuffer_height;
|
uint32_t height = mbi->framebuffer_height;
|
||||||
|
|
||||||
// Считаем размер и мапим сразу внутри
|
|
||||||
uint32_t size = width * height * 4;
|
uint32_t size = width * height * 4;
|
||||||
uint32_t num_pages = (size + 0xFFF) / 0x1000;
|
uint32_t num_pages = (size + 0xFFF) / 0x1000;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < num_pages; i++) {
|
for (uint32_t i = 0; i < num_pages; i++) {
|
||||||
vmm_map_page(fb_phys + (i * 0x1000),
|
vmm_map_page(fb_phys + (i * 0x1000),
|
||||||
fb_phys + (i * 0x1000),
|
fb_phys + (i * 0x1000),
|
||||||
0x3 | 0x10); // Present + RW + PCD
|
0x3 | 0x10);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Сохраняем в глобальные переменные модуля
|
|
||||||
fb_ptr = (uint32_t*)fb_phys;
|
fb_ptr = (uint32_t*)fb_phys;
|
||||||
screen_width = width;
|
screen_width = width;
|
||||||
screen_height = height;
|
screen_height = height;
|
||||||
|
|
||||||
|
backbuffer = (uint32_t*)kmalloc(1024 * 768 * sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void put_pixel(int x, int y, uint32_t color) {
|
void put_pixel(int x, int y, uint32_t color) {
|
||||||
if (x >= 0 && x < (int)screen_width && y >= 0 && y < (int)screen_height) {
|
if (x >= 0 && x < (int)screen_width && y >= 0 && y < (int)screen_height) {
|
||||||
fb_ptr[y * screen_width + x] = color;
|
backbuffer[y * screen_width + x] = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,24 +87,18 @@ void draw_bmp(uint8_t* data, int x, int y) {
|
||||||
int w = dh->width;
|
int w = dh->width;
|
||||||
int h = dh->height;
|
int h = dh->height;
|
||||||
|
|
||||||
// 24-битный BMP: каждый ряд выровнен по 4 байтам
|
|
||||||
// Считаем размер ряда в байтах
|
|
||||||
int row_size = (w * 3 + 3) & ~3;
|
int row_size = (w * 3 + 3) & ~3;
|
||||||
uint8_t* pixels = data + bh->offset;
|
uint8_t* pixels = data + bh->offset;
|
||||||
|
|
||||||
for (int i = 0; i < h; i++) {
|
for (int i = 0; i < h; i++) {
|
||||||
// BMP хранятся снизу вверх, поэтому i идет от 0 до h,
|
|
||||||
// а рисуем мы начиная с y + h - 1
|
|
||||||
int draw_y = y + (h - 1 - i);
|
int draw_y = y + (h - 1 - i);
|
||||||
|
|
||||||
for (int j = 0; j < w; j++) {
|
for (int j = 0; j < w; j++) {
|
||||||
// Берем 3 байта BGR
|
|
||||||
uint8_t* pixel_ptr = pixels + (i * row_size) + (j * 3);
|
uint8_t* pixel_ptr = pixels + (i * row_size) + (j * 3);
|
||||||
uint8_t b = pixel_ptr[0];
|
uint8_t b = pixel_ptr[0];
|
||||||
uint8_t g = pixel_ptr[1];
|
uint8_t g = pixel_ptr[1];
|
||||||
uint8_t r = pixel_ptr[2];
|
uint8_t r = pixel_ptr[2];
|
||||||
|
|
||||||
// Собираем в 0x00RRGGBB
|
|
||||||
uint32_t color = (r << 16) | (g << 8) | b;
|
uint32_t color = (r << 16) | (g << 8) | b;
|
||||||
|
|
||||||
put_pixel(x + j, draw_y, color);
|
put_pixel(x + j, draw_y, color);
|
||||||
|
|
@ -126,7 +121,6 @@ void draw_cursor_sprite(uint8_t* bmp_data, int x, int y) {
|
||||||
uint8_t* p = pixels + (i * row_size) + (j * 3);
|
uint8_t* p = pixels + (i * row_size) + (j * 3);
|
||||||
uint32_t color = (p[2] << 16) | (p[1] << 8) | p[0];
|
uint32_t color = (p[2] << 16) | (p[1] << 8) | p[0];
|
||||||
|
|
||||||
// Если цвет не прозрачный — рисуем
|
|
||||||
if (color != TRANSPARENT_COLOR) {
|
if (color != TRANSPARENT_COLOR) {
|
||||||
put_pixel(x + j, draw_y, color);
|
put_pixel(x + j, draw_y, color);
|
||||||
}
|
}
|
||||||
|
|
@ -135,13 +129,12 @@ void draw_cursor_sprite(uint8_t* bmp_data, int x, int y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void put_char(char c, int x, int y, uint32_t color) {
|
void put_char(char c, int x, int y, uint32_t color) {
|
||||||
if (c < 32 || c > 126) c = 32; // Если символ вне диапазона — рисуем пробел
|
if (c < 32 || c > 126) c = 32;
|
||||||
|
|
||||||
const uint8_t* glyph = font8x8[c - 32];
|
const uint8_t* glyph = font8x8[c - 32];
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
for (int j = 0; j < 8; j++) {
|
for (int j = 0; j < 8; j++) {
|
||||||
// Если бит в строке установлен — рисуем пиксель
|
|
||||||
if (glyph[i] & (1 << (7 - j))) {
|
if (glyph[i] & (1 << (7 - j))) {
|
||||||
put_pixel(x + j, y + i, color);
|
put_pixel(x + j, y + i, color);
|
||||||
}
|
}
|
||||||
|
|
@ -154,14 +147,17 @@ void draw_string(const char* str, int x, int y, uint32_t color) {
|
||||||
int cursor_y = y;
|
int cursor_y = y;
|
||||||
|
|
||||||
while (*str != '\0') {
|
while (*str != '\0') {
|
||||||
// Если встретили символ переноса строки
|
|
||||||
if (*str == '\n') {
|
if (*str == '\n') {
|
||||||
cursor_x = x;
|
cursor_x = x;
|
||||||
cursor_y += 10; // 8 пикселей высота буквы + 2 пикселя отступ
|
cursor_y += 10;
|
||||||
} else {
|
} else {
|
||||||
put_char(*str, cursor_x, cursor_y, color);
|
put_char(*str, cursor_x, cursor_y, color);
|
||||||
cursor_x += 9; // 8 пикселей ширина буквы + 1 пиксель пробел между ними
|
cursor_x += 9;
|
||||||
}
|
}
|
||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void flip_buffer() {
|
||||||
|
memcpy((void*)fb_ptr, (void*)backbuffer, 1024 * 768 * 4);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,5 +17,6 @@ void draw_bmp(uint8_t* data, int x, int y);
|
||||||
void draw_cursor_sprite(uint8_t* bmp_data, int x, int y);
|
void draw_cursor_sprite(uint8_t* bmp_data, int x, int y);
|
||||||
void put_char(char c, int x, int y, uint32_t color);
|
void put_char(char c, int x, int y, uint32_t color);
|
||||||
void draw_string(const char* str, int x, int y, uint32_t color);
|
void draw_string(const char* str, int x, int y, uint32_t color);
|
||||||
|
void flip_buffer(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
76
src/heap.c
76
src/heap.c
|
|
@ -1,81 +1,89 @@
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "vmm.h"
|
#include "vmm.h"
|
||||||
#include "pmm.h"
|
#include "pmm.h"
|
||||||
#include "serial.h"
|
|
||||||
|
|
||||||
static heap_chunk_t* heap_start_chunk = NULL;
|
static heap_chunk_t* heap_start_chunk = NULL;
|
||||||
|
|
||||||
|
static uint32_t current_heap_top = HEAP_START + PAGE_SIZE;
|
||||||
|
|
||||||
|
int heap_expand(size_t size) {
|
||||||
|
size_t total_needed = size + sizeof(heap_chunk_t);
|
||||||
|
size_t pages_needed = (total_needed + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||||
|
|
||||||
|
heap_chunk_t* new_chunk = (heap_chunk_t*)current_heap_top;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pages_needed; i++) {
|
||||||
|
void* phys = pmm_alloc_page();
|
||||||
|
if (!phys) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vmm_map_page((uint32_t)phys, current_heap_top, 3);
|
||||||
|
|
||||||
|
if (i < pages_needed - 1) {
|
||||||
|
current_heap_top += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new_chunk->size = (pages_needed * PAGE_SIZE) - sizeof(heap_chunk_t);
|
||||||
|
new_chunk->is_free = 1;
|
||||||
|
new_chunk->next = NULL;
|
||||||
|
|
||||||
|
heap_chunk_t* curr = heap_start_chunk;
|
||||||
|
while (curr->next != NULL) {
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
curr->next = new_chunk;
|
||||||
|
|
||||||
|
current_heap_top += PAGE_SIZE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void kheap_init(void) {
|
void kheap_init(void) {
|
||||||
kprint_serial("HEAP: Initializing Kernel Heap...\n");
|
|
||||||
|
|
||||||
// 1. Выделяем одну физ. страницу под старт кучи
|
|
||||||
void* phys_page = pmm_alloc_page();
|
void* phys_page = pmm_alloc_page();
|
||||||
|
if (phys_page == NULL) {
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Мапим её на виртуальный адрес HEAP_START
|
|
||||||
// Нам нужны флаги Present (1) + Write (2) = 3
|
|
||||||
vmm_map_page((uint32_t)phys_page, HEAP_START, 3);
|
vmm_map_page((uint32_t)phys_page, HEAP_START, 3);
|
||||||
|
|
||||||
// 3. Создаем базовый блок на всю эту страницу
|
|
||||||
heap_start_chunk = (heap_chunk_t*)HEAP_START;
|
heap_start_chunk = (heap_chunk_t*)HEAP_START;
|
||||||
heap_start_chunk->size = PAGE_SIZE - sizeof(heap_chunk_t);
|
heap_start_chunk->size = PAGE_SIZE - sizeof(heap_chunk_t);
|
||||||
heap_start_chunk->is_free = 1;
|
heap_start_chunk->is_free = 1;
|
||||||
heap_start_chunk->next = NULL;
|
heap_start_chunk->next = NULL;
|
||||||
|
|
||||||
kprint_serial("HEAP: Kernel Heap initialized successfully at 0x00400000!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* kmalloc(size_t size) {
|
void* kmalloc(size_t size) {
|
||||||
if (size == 0) return NULL;
|
if (size == 0) return NULL;
|
||||||
|
|
||||||
// Выравниваем размер по 4 байта для стабильности на x86
|
|
||||||
size = (size + 3) & ~3;
|
size = (size + 3) & ~3;
|
||||||
|
|
||||||
heap_chunk_t* current = heap_start_chunk;
|
heap_chunk_t* current = heap_start_chunk;
|
||||||
|
|
||||||
// Ищем подходящий свободный блок (First Fit)
|
|
||||||
while (current != NULL) {
|
while (current != NULL) {
|
||||||
if (current->is_free && current->size >= size) {
|
if (current->is_free && current->size >= size) {
|
||||||
|
|
||||||
// Если блок сильно больше, чем надо, дробим его
|
|
||||||
// sizeof(heap_chunk_t) + 4 байта минимально на остаток
|
|
||||||
if (current->size >= size + sizeof(heap_chunk_t) + 4) {
|
|
||||||
heap_chunk_t* new_chunk = (heap_chunk_t*)((uint32_t)current + sizeof(heap_chunk_t) + size);
|
|
||||||
new_chunk->size = current->size - size - sizeof(heap_chunk_t);
|
|
||||||
new_chunk->is_free = 1;
|
|
||||||
new_chunk->next = current->next;
|
|
||||||
|
|
||||||
current->size = size;
|
|
||||||
current->next = new_chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
current->is_free = 0;
|
current->is_free = 0;
|
||||||
|
|
||||||
// Возвращаем указатель на память СРАЗУ ЗА заголовком
|
|
||||||
return (void*)((uint32_t)current + sizeof(heap_chunk_t));
|
return (void*)((uint32_t)current + sizeof(heap_chunk_t));
|
||||||
}
|
}
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// По-хорошему, если памяти не хватило, нужно выделить еще страницу из PMM
|
if (!heap_expand(size)) {
|
||||||
// и расширить кучу. Но для первого теста выкинем панику.
|
return NULL;
|
||||||
kprint_serial("HEAP ERROR: OUT OF KERNEL HEAP MEMORY!\n");
|
}
|
||||||
return NULL;
|
return kmalloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kfree(void* ptr) {
|
void kfree(void* ptr) {
|
||||||
if (ptr == NULL) return;
|
if (ptr == NULL) return;
|
||||||
|
|
||||||
// Смещаемся назад, чтобы получить доступ к заголовку блока
|
|
||||||
heap_chunk_t* chunk = (heap_chunk_t*)((uint32_t)ptr - sizeof(heap_chunk_t));
|
heap_chunk_t* chunk = (heap_chunk_t*)((uint32_t)ptr - sizeof(heap_chunk_t));
|
||||||
chunk->is_free = 1;
|
chunk->is_free = 1;
|
||||||
|
|
||||||
// Склеиваем последовательные свободные блоки (Coalescing), чтобы не было фрагментации
|
|
||||||
heap_chunk_t* current = heap_start_chunk;
|
heap_chunk_t* current = heap_start_chunk;
|
||||||
while (current != NULL) {
|
while (current != NULL) {
|
||||||
if (current->is_free && current->next && current->next->is_free) {
|
if (current->is_free && current->next && current->next->is_free) {
|
||||||
current->size += sizeof(heap_chunk_t) + current->next->size;
|
current->size += sizeof(heap_chunk_t) + current->next->size;
|
||||||
current->next = current->next->next;
|
current->next = current->next->next;
|
||||||
// Не шагаем вперед, проверяем текущий блок еще раз с новым next
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
current = current->next;
|
current = current->next;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
// Начальный виртуальный адрес кучи ядра (3 МБ)
|
// Начальный виртуальный адрес кучи ядра (3 МБ)
|
||||||
#define HEAP_START 0x00300000
|
#define HEAP_START 0x1400000
|
||||||
|
|
||||||
// Структура заголовка блока памяти
|
// Структура заголовка блока памяти
|
||||||
typedef struct heap_chunk {
|
typedef struct heap_chunk {
|
||||||
|
|
|
||||||
34
src/idt.c
34
src/idt.c
|
|
@ -50,8 +50,37 @@ void idt_init(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void isr_handler(struct registers *regs) {
|
void isr_handler(struct registers *regs) {
|
||||||
kprint_serial("Exception: ");
|
kprint_serial("\n!!! EXCEPTION !!!\n");
|
||||||
|
kprint_serial(" int_no=");
|
||||||
kprint_serial_dec(regs->int_no);
|
kprint_serial_dec(regs->int_no);
|
||||||
|
kprint_serial(" err_code=");
|
||||||
|
kprint_serial_dec(regs->err_code);
|
||||||
|
kprint_serial("\n EIP=0x");
|
||||||
|
kprint_serial_hex(regs->eip);
|
||||||
|
kprint_serial(" CS=0x");
|
||||||
|
kprint_serial_hex(regs->cs);
|
||||||
|
kprint_serial(" EFLAGS=0x");
|
||||||
|
kprint_serial_hex(regs->eflags);
|
||||||
|
kprint_serial("\n EAX=0x");
|
||||||
|
kprint_serial_hex(regs->eax);
|
||||||
|
kprint_serial(" EBX=0x");
|
||||||
|
kprint_serial_hex(regs->ebx);
|
||||||
|
kprint_serial(" ECX=0x");
|
||||||
|
kprint_serial_hex(regs->ecx);
|
||||||
|
kprint_serial(" EDX=0x");
|
||||||
|
kprint_serial_hex(regs->edx);
|
||||||
|
kprint_serial("\n ESP=0x");
|
||||||
|
kprint_serial_hex(regs->esp);
|
||||||
|
kprint_serial(" EBP=0x");
|
||||||
|
kprint_serial_hex(regs->ebp);
|
||||||
|
kprint_serial(" ESI=0x");
|
||||||
|
kprint_serial_hex(regs->esi);
|
||||||
|
kprint_serial(" EDI=0x");
|
||||||
|
kprint_serial_hex(regs->edi);
|
||||||
|
kprint_serial("\n CR2=0x");
|
||||||
|
uint32_t cr2;
|
||||||
|
__asm__ __volatile__("mov %%cr2, %0" : "=r"(cr2));
|
||||||
|
kprint_serial_hex(cr2);
|
||||||
kprint_serial("\nSystem Halted.\n");
|
kprint_serial("\nSystem Halted.\n");
|
||||||
while(1) asm("hlt");
|
while(1) asm("hlt");
|
||||||
}
|
}
|
||||||
|
|
@ -64,9 +93,6 @@ void irq_handler(struct registers *regs) {
|
||||||
} else if (regs->int_no == 44) {
|
} else if (regs->int_no == 44) {
|
||||||
mouse_handler();
|
mouse_handler();
|
||||||
} else {
|
} else {
|
||||||
kprint_serial("Unknown IRQ: ");
|
|
||||||
kprint_serial_dec(regs->int_no);
|
|
||||||
kprint_serial("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regs->int_no >= 40) outb(0xA0, 0x20); // Slave
|
if (regs->int_no >= 40) outb(0xA0, 0x20); // Slave
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,19 @@
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "serial.h"
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
// Состояние модификаторов клавиатуры
|
|
||||||
static int is_e0 = 0;
|
static int is_e0 = 0;
|
||||||
static int shift_pressed = 0;
|
static int shift_pressed = 0;
|
||||||
static int caps_lock_active = 0;
|
static int caps_lock_active = 0;
|
||||||
|
|
||||||
// Скан-коды управления (Set 1)
|
|
||||||
#define SCAN_LSHIFT 0x2A
|
#define SCAN_LSHIFT 0x2A
|
||||||
#define SCAN_RSHIFT 0x36
|
#define SCAN_RSHIFT 0x36
|
||||||
#define SCAN_CAPS_LOCK 0x3A
|
#define SCAN_CAPS_LOCK 0x3A
|
||||||
|
|
||||||
// Скан-коды стрелок (после 0xE0)
|
|
||||||
#define SCAN_UP 0x48
|
#define SCAN_UP 0x48
|
||||||
#define SCAN_DOWN 0x50
|
#define SCAN_DOWN 0x50
|
||||||
#define SCAN_LEFT 0x4B
|
#define SCAN_LEFT 0x4B
|
||||||
#define SCAN_RIGHT 0x4D
|
#define SCAN_RIGHT 0x4D
|
||||||
|
|
||||||
// Таблица 1: Обычные символы (без Shift)
|
|
||||||
static const char kbdus_lower[128] = {
|
static const char kbdus_lower[128] = {
|
||||||
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||||
|
|
@ -29,7 +24,6 @@ static const char kbdus_lower[128] = {
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
// Таблица 2: Символы при зажатом Shift
|
|
||||||
static const char kbdus_upper[128] = {
|
static const char kbdus_upper[128] = {
|
||||||
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
|
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
|
||||||
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
|
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
|
||||||
|
|
@ -44,54 +38,45 @@ void keyboard_init(void) {
|
||||||
shift_pressed = 0;
|
shift_pressed = 0;
|
||||||
caps_lock_active = 0;
|
caps_lock_active = 0;
|
||||||
is_e0 = 0;
|
is_e0 = 0;
|
||||||
kprint_serial("[INFO] Full keyboard driver with Modifiers initialized.\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void keyboard_handler(void) {
|
void keyboard_handler(void) {
|
||||||
uint8_t status = inb(0x64);
|
uint8_t status = inb(0x64);
|
||||||
|
|
||||||
// Бит 5 равен 1, если данные пришли от мыши (Auxiliary Device)
|
|
||||||
// Мышь не должна обрабатываться здесь!
|
|
||||||
if (status & 0x20) {
|
if (status & 0x20) {
|
||||||
// Очистим порт, чтобы не висел, но не обрабатываем как клаву
|
|
||||||
inb(0x60);
|
inb(0x60);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если мы здесь, значит это точно клавиатура
|
if (!(status & 0x01)) return;
|
||||||
if (!(status & 0x01)) return; // Нет данных
|
|
||||||
|
|
||||||
uint8_t scancode = inb(0x60);
|
uint8_t scancode = inb(0x60);
|
||||||
|
|
||||||
// Обработка префикса 0xE0
|
|
||||||
if (scancode == 0xE0) {
|
if (scancode == 0xE0) {
|
||||||
is_e0 = 1;
|
is_e0 = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обработка Break Code (отпускание)
|
|
||||||
if (scancode & 0x80) {
|
if (scancode & 0x80) {
|
||||||
uint8_t released_code = scancode & 0x7F;
|
uint8_t released_code = scancode & 0x7F;
|
||||||
if (released_code == SCAN_LSHIFT || released_code == SCAN_RSHIFT) {
|
if (released_code == SCAN_LSHIFT || released_code == SCAN_RSHIFT) {
|
||||||
shift_pressed = 0;
|
shift_pressed = 0;
|
||||||
}
|
}
|
||||||
is_e0 = 0; // Сброс префикса
|
is_e0 = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обработка стрелок (расширенные)
|
|
||||||
if (is_e0) {
|
if (is_e0) {
|
||||||
is_e0 = 0;
|
is_e0 = 0;
|
||||||
switch (scancode) {
|
switch (scancode) {
|
||||||
case SCAN_UP: /* ... */ break;
|
case SCAN_UP: break;
|
||||||
case SCAN_DOWN: /* ... */ break;
|
case SCAN_DOWN: break;
|
||||||
case SCAN_LEFT: /* ... */ break;
|
case SCAN_LEFT: break;
|
||||||
case SCAN_RIGHT: /* ... */ break;
|
case SCAN_RIGHT: break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обычные модификаторы
|
|
||||||
if (scancode == SCAN_LSHIFT || scancode == SCAN_RSHIFT) {
|
if (scancode == SCAN_LSHIFT || scancode == SCAN_RSHIFT) {
|
||||||
shift_pressed = 1;
|
shift_pressed = 1;
|
||||||
return;
|
return;
|
||||||
|
|
@ -102,7 +87,6 @@ void keyboard_handler(void) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Печать символов
|
|
||||||
if (scancode < 128) {
|
if (scancode < 128) {
|
||||||
char c = 0;
|
char c = 0;
|
||||||
int use_upper = shift_pressed;
|
int use_upper = shift_pressed;
|
||||||
|
|
@ -113,9 +97,6 @@ void keyboard_handler(void) {
|
||||||
|
|
||||||
c = (use_upper) ? kbdus_upper[scancode] : kbdus_lower[scancode];
|
c = (use_upper) ? kbdus_upper[scancode] : kbdus_lower[scancode];
|
||||||
|
|
||||||
if (c != 0) {
|
(void)c;
|
||||||
char str[2] = {c, 0};
|
|
||||||
kprint_serial(str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
180
src/kmain.c
180
src/kmain.c
|
|
@ -9,215 +9,65 @@
|
||||||
#include "pmm.h"
|
#include "pmm.h"
|
||||||
#include "vmm.h"
|
#include "vmm.h"
|
||||||
#include "pic.h"
|
#include "pic.h"
|
||||||
#include "logger.h"
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "multiboot.h"
|
#include "multiboot.h"
|
||||||
|
|
||||||
uint32_t bg_color = 0x00008080;
|
|
||||||
uint32_t color_sky_blue = 0x0087CEEB;
|
|
||||||
uint32_t color_orange = 0x00FFA500;
|
|
||||||
uint32_t color_white = 0x00FFFFFF;
|
uint32_t color_white = 0x00FFFFFF;
|
||||||
uint32_t color_black = 0x00000000;
|
extern uint32_t* fb_ptr;
|
||||||
|
extern uint32_t* backbuffer;
|
||||||
|
extern uint32_t screen_width;
|
||||||
|
extern uint32_t screen_height;
|
||||||
extern uint8_t _binary_assets_logo_bmp_start[];
|
extern uint8_t _binary_assets_logo_bmp_start[];
|
||||||
extern uint8_t _binary_assets_bg_bmp_start[];
|
extern uint8_t _binary_assets_bg_bmp_start[];
|
||||||
extern uint8_t _binary_assets_cursor_bmp_start[];
|
extern uint8_t _binary_assets_cursor_bmp_start[];
|
||||||
|
|
||||||
uint32_t frame_count = 0; // Сколько раз отрисовали за секунду
|
uint32_t frame_count = 0;
|
||||||
uint32_t last_fps_ticks = 0; // Когда последний раз обновляли FPS
|
uint32_t last_fps_ticks = 0;
|
||||||
uint32_t current_fps = 0; // Результат (число FPS)
|
uint32_t current_fps = 0;
|
||||||
|
|
||||||
extern uint32_t _kernel_end; // Символ 'end' прописан в конце любого стандартного linker.ld
|
extern uint32_t _kernel_end;
|
||||||
uint32_t kernel_end = (uint32_t)&_kernel_end;
|
uint32_t kernel_end = (uint32_t)&_kernel_end;
|
||||||
|
|
||||||
void kernel_main(uint32_t mboot_addr, uint32_t magic) {
|
void kernel_main(uint32_t mboot_addr, uint32_t magic) {
|
||||||
log_info(LOG_NORMAL, "Initializing serial...");
|
|
||||||
serial_init();
|
serial_init();
|
||||||
if (magic != MULTIBOOT_BOOTLOADER_MAGIC) {
|
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);
|
while(1);
|
||||||
}
|
}
|
||||||
struct multiboot_info* mbi = (struct multiboot_info*)mboot_addr;
|
struct multiboot_info* mbi = (struct multiboot_info*)mboot_addr;
|
||||||
if (!(mbi->flags & (1 << 6))) {
|
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);
|
while(1);
|
||||||
}
|
}
|
||||||
log_info(LOG_NORMAL, "Initializing GDT...");
|
|
||||||
gdt_init();
|
gdt_init();
|
||||||
log_info(LOG_NORMAL, "Initializing IDT...");
|
|
||||||
idt_init();
|
idt_init();
|
||||||
log_info(LOG_NORMAL, "Remapping PIC...");
|
|
||||||
pic_remap(32, 40);
|
pic_remap(32, 40);
|
||||||
log_info(LOG_NORMAL, "Unmasking IRQ 0... (timer)");
|
|
||||||
pic_clear_mask(0);
|
pic_clear_mask(0);
|
||||||
log_info(LOG_NORMAL, "Unmasking IRQ 1... (keyboard)");
|
|
||||||
pic_clear_mask(1);
|
pic_clear_mask(1);
|
||||||
log_info(LOG_NORMAL, "Unmasking IRQ 2... (slave pic)");
|
|
||||||
pic_clear_mask(2);
|
pic_clear_mask(2);
|
||||||
log_info(LOG_NORMAL, "Unmasking IRQ 12... (mouse)");
|
|
||||||
pic_clear_mask(12);
|
pic_clear_mask(12);
|
||||||
log_info(LOG_NORMAL, "Registering timer at 100Hz");
|
|
||||||
timer_init(100);
|
timer_init(100);
|
||||||
log_info(LOG_NORMAL, "Registering mouse");
|
|
||||||
mouse_init();
|
mouse_init();
|
||||||
kprint_serial("--------------------\n");
|
pmm_init(mbi, (uint32_t)&_kernel_end);
|
||||||
log_info(LOG_NORMAL, "Enabling PMM...");
|
|
||||||
pmm_init(mbi, (uint32_t)&_kernel_end);
|
|
||||||
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");
|
|
||||||
log_info(LOG_NORMAL, "Enabling VMM...");
|
|
||||||
vmm_init();
|
vmm_init();
|
||||||
log_info(LOG_NORMAL, "Enabling KHeap...");
|
kheap_init();
|
||||||
kheap_init();
|
|
||||||
|
|
||||||
kprint_serial("--- HEAP TESTING ---\n");
|
if (mbi->flags & (1 << 12)) {
|
||||||
|
|
||||||
// Выделяем три разных куска памяти
|
|
||||||
int* arr1 = (int*)kmalloc(10 * sizeof(int));
|
|
||||||
char* str = (char*)kmalloc(64);
|
|
||||||
int* arr2 = (int*)kmalloc(5 * sizeof(int));
|
|
||||||
char hbuf[32];
|
|
||||||
kprint_serial("Allocated arr1 at virtual address: 0x");
|
|
||||||
itoa((uint32_t)arr1, hbuf, 16);
|
|
||||||
kprint_serial(hbuf);
|
|
||||||
kprint_serial("\n");
|
|
||||||
kprint_serial("Allocated str at virtual address: 0x");
|
|
||||||
itoa((uint32_t)str, hbuf, 16);
|
|
||||||
kprint_serial(hbuf);
|
|
||||||
kprint_serial("\n");
|
|
||||||
// Запишем туда данные, чтобы проверить, что маппинг страниц не падает при записи
|
|
||||||
arr1[0] = 1337;
|
|
||||||
str[0] = 'H';
|
|
||||||
str[1] = 'A';
|
|
||||||
str[2] = 'I';
|
|
||||||
str[3] = '\0';
|
|
||||||
kprint_serial("Data integrity check: str is ");
|
|
||||||
kprint_serial(str);
|
|
||||||
kprint_serial("\n");
|
|
||||||
// Освобождаем память обратно
|
|
||||||
kfree(arr1);
|
|
||||||
kfree(str);
|
|
||||||
kfree(arr2);
|
|
||||||
|
|
||||||
kprint_serial("Kfree done. It don't died twice!\n");
|
|
||||||
if (mbi->flags & (1 << 12)) {
|
|
||||||
log_info(LOG_NORMAL, "Framebuffer detected!");
|
|
||||||
|
|
||||||
uint32_t fb_addr = mbi->framebuffer_addr;
|
|
||||||
uint32_t width = mbi->framebuffer_width;
|
|
||||||
uint32_t height = mbi->framebuffer_height;
|
|
||||||
uint32_t bpp = mbi->framebuffer_bpp;
|
|
||||||
|
|
||||||
char buf[16];
|
|
||||||
kprint_serial("FB Addr: ");
|
|
||||||
kprint_serial_hex(fb_addr);
|
|
||||||
kprint_serial("\nSize: ");
|
|
||||||
kprint_serial_dec(width);
|
|
||||||
kprint_serial("x");
|
|
||||||
kprint_serial_dec(height);
|
|
||||||
kprint_serial("\n");
|
|
||||||
draw_init(mbi);
|
draw_init(mbi);
|
||||||
} else {
|
|
||||||
log_error(LOG_NORMAL, "No Framebuffer provided by GRUB!");
|
|
||||||
}
|
}
|
||||||
log_info(LOG_NORMAL, "Enabling IRQ...");
|
|
||||||
__asm__ __volatile__("sti");
|
__asm__ __volatile__("sti");
|
||||||
speaker_beep(100, 10);
|
|
||||||
speaker_beep(125, 10);
|
|
||||||
speaker_beep(150, 10);
|
|
||||||
speaker_beep(175, 10);
|
|
||||||
speaker_beep(200, 10);
|
|
||||||
speaker_beep(225, 10);
|
|
||||||
speaker_beep(250, 10);
|
|
||||||
speaker_beep(275, 10);
|
|
||||||
speaker_beep(300, 10);
|
|
||||||
speaker_beep(325, 10);
|
|
||||||
speaker_beep(350, 400);
|
|
||||||
log_info(LOG_NORMAL, "OK!");
|
|
||||||
int old_mouse_x = 0;
|
|
||||||
int old_mouse_y = 0;
|
|
||||||
char fpsbuf[4];
|
char fpsbuf[4];
|
||||||
while (1) {
|
while (1) {
|
||||||
// 1. Всегда рисуем фон и элементы
|
|
||||||
draw_bmp(_binary_assets_bg_bmp_start, 0, 0);
|
draw_bmp(_binary_assets_bg_bmp_start, 0, 0);
|
||||||
draw_cursor_sprite(_binary_assets_cursor_bmp_start, mouse_x, mouse_y);
|
draw_cursor_sprite(_binary_assets_cursor_bmp_start, mouse_x, mouse_y);
|
||||||
|
|
||||||
// 2. Всегда рисуем FPS
|
|
||||||
draw_string("FPS: ", 0, 0, color_white);
|
draw_string("FPS: ", 0, 0, color_white);
|
||||||
itoa(current_fps, fpsbuf, 10);
|
itoa(current_fps, fpsbuf, 10);
|
||||||
draw_string(fpsbuf, 40, 0, color_white);
|
draw_string(fpsbuf, 40, 0, color_white);
|
||||||
|
|
||||||
// 3. Считаем кадр
|
flip_buffer();
|
||||||
|
|
||||||
frame_count++;
|
frame_count++;
|
||||||
|
|
||||||
// 4. Логика обновления FPS (раз в секунду)
|
|
||||||
if (system_ticks - last_fps_ticks >= 100) {
|
if (system_ticks - last_fps_ticks >= 100) {
|
||||||
current_fps = frame_count;
|
current_fps = frame_count;
|
||||||
frame_count = 0;
|
frame_count = 0;
|
||||||
|
|
|
||||||
53
src/mouse.c
53
src/mouse.c
|
|
@ -1,7 +1,5 @@
|
||||||
#include "mouse.h"
|
#include "mouse.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "string.h"
|
|
||||||
#include "serial.h" // Для kprint_serial
|
|
||||||
|
|
||||||
#define PS2_DATA 0x60
|
#define PS2_DATA 0x60
|
||||||
#define PS2_STATUS 0x64
|
#define PS2_STATUS 0x64
|
||||||
|
|
@ -17,7 +15,7 @@ static void ps2_wait_read(void) {
|
||||||
|
|
||||||
static void mouse_write(uint8_t data) {
|
static void mouse_write(uint8_t data) {
|
||||||
ps2_wait_write();
|
ps2_wait_write();
|
||||||
outb(PS2_COMMAND, 0xD4); // Сигнал: шлем команду именно мыши
|
outb(PS2_COMMAND, 0xD4);
|
||||||
ps2_wait_write();
|
ps2_wait_write();
|
||||||
outb(PS2_DATA, data);
|
outb(PS2_DATA, data);
|
||||||
}
|
}
|
||||||
|
|
@ -30,34 +28,26 @@ static uint8_t mouse_read(void) {
|
||||||
void mouse_init(void) {
|
void mouse_init(void) {
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
|
||||||
kprint_serial("Initializing PS/2 Mouse...\n");
|
|
||||||
|
|
||||||
// Включаем второй порт PS/2 (мышь)
|
|
||||||
ps2_wait_write();
|
ps2_wait_write();
|
||||||
outb(PS2_COMMAND, 0xA8);
|
outb(PS2_COMMAND, 0xA8);
|
||||||
io_wait();
|
io_wait();
|
||||||
|
|
||||||
// Читаем Command Byte, чтобы включить прерывания
|
|
||||||
ps2_wait_write();
|
ps2_wait_write();
|
||||||
outb(PS2_COMMAND, 0x20);
|
outb(PS2_COMMAND, 0x20);
|
||||||
ps2_wait_read();
|
ps2_wait_read();
|
||||||
status = inb(PS2_DATA) | 2; // Бит 1 — прерывания IRQ12 от мыши
|
status = inb(PS2_DATA) | 2;
|
||||||
status &= ~0x20; // Сбрасываем Бит 5 — активируем Mouse Clock
|
status &= ~0x20;
|
||||||
|
|
||||||
// Записываем Command Byte обратно
|
|
||||||
ps2_wait_write();
|
ps2_wait_write();
|
||||||
outb(PS2_COMMAND, 0x60);
|
outb(PS2_COMMAND, 0x60);
|
||||||
ps2_wait_write();
|
ps2_wait_write();
|
||||||
outb(PS2_DATA, status);
|
outb(PS2_DATA, status);
|
||||||
|
|
||||||
// Настраиваем саму мышь
|
mouse_write(0xF6);
|
||||||
mouse_write(0xF6); // Загрузить дефолтные параметры
|
mouse_read();
|
||||||
mouse_read(); // Читаем ACK (0xFA)
|
|
||||||
|
|
||||||
mouse_write(0xF4); // Включаем передачу пакетов (Data Reporting)
|
mouse_write(0xF4);
|
||||||
mouse_read(); // Читаем ACK (0xFA)
|
mouse_read();
|
||||||
|
|
||||||
kprint_serial("Mouse initialized successfully.\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t mouse_cycle = 0;
|
static uint8_t mouse_cycle = 0;
|
||||||
|
|
@ -70,22 +60,15 @@ volatile int right_click = 0;
|
||||||
void mouse_handler(void) {
|
void mouse_handler(void) {
|
||||||
uint8_t status = inb(PS2_STATUS);
|
uint8_t status = inb(PS2_STATUS);
|
||||||
|
|
||||||
// Проверяем, что в буфере реально есть данные и они от мыши (бит 5 выставлен)
|
|
||||||
if (!(status & 0x01) || !(status & 0x20)) {
|
if (!(status & 0x01) || !(status & 0x20)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ДЕБАГ: выводим каждый байт
|
|
||||||
kprint_serial("M_BYTE: ");
|
|
||||||
kprint_serial_hex(status);
|
|
||||||
kprint_serial("\n");
|
|
||||||
|
|
||||||
mouse_packet[mouse_cycle++] = inb(PS2_DATA);
|
mouse_packet[mouse_cycle++] = inb(PS2_DATA);
|
||||||
|
|
||||||
if (mouse_cycle == 3) {
|
if (mouse_cycle == 3) {
|
||||||
mouse_cycle = 0;
|
mouse_cycle = 0;
|
||||||
|
|
||||||
// Бит 3 первого байта всегда должен быть равен 1 (проверка синхронизации)
|
|
||||||
if (!(mouse_packet[0] & 0x08)) {
|
if (!(mouse_packet[0] & 0x08)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -94,36 +77,18 @@ void mouse_handler(void) {
|
||||||
int offset_x = (int)mouse_packet[1];
|
int offset_x = (int)mouse_packet[1];
|
||||||
int offset_y = (int)mouse_packet[2];
|
int offset_y = (int)mouse_packet[2];
|
||||||
|
|
||||||
// Обработка знаков смещения (8 бит -> 32 бита с сохранением знака)
|
|
||||||
if (flags & 0x10) offset_x |= 0xFFFFFF00;
|
if (flags & 0x10) offset_x |= 0xFFFFFF00;
|
||||||
if (flags & 0x20) offset_y |= 0xFFFFFF00;
|
if (flags & 0x20) offset_y |= 0xFFFFFF00;
|
||||||
|
|
||||||
mouse_x += offset_x;
|
mouse_x += offset_x;
|
||||||
mouse_y -= offset_y; // Инвертируем Y, так как в VGA координатах 0 верх
|
mouse_y -= offset_y;
|
||||||
|
|
||||||
if (mouse_x < 0) mouse_x = 0;
|
if (mouse_x < 0) mouse_x = 0;
|
||||||
if (mouse_x >= 1024) mouse_x = 1023;
|
if (mouse_x >= 1024) mouse_x = 1023;
|
||||||
if (mouse_y < 0) mouse_y = 0;
|
if (mouse_y < 0) mouse_y = 0;
|
||||||
if (mouse_y >= 768) mouse_y = 767;
|
if (mouse_y >= 768) mouse_y = 767;
|
||||||
|
|
||||||
// Чек кнопок
|
|
||||||
left_click = flags & 0x01;
|
left_click = flags & 0x01;
|
||||||
right_click = flags & 0x02;
|
right_click = flags & 0x02;
|
||||||
|
|
||||||
// Выводим инфу в UART через itoa
|
|
||||||
char buf[16];
|
|
||||||
|
|
||||||
kprint_serial("Mouse: X=");
|
|
||||||
itoa(mouse_x, buf, 10);
|
|
||||||
kprint_serial(buf);
|
|
||||||
|
|
||||||
kprint_serial(" Y=");
|
|
||||||
itoa(mouse_y, buf, 10);
|
|
||||||
kprint_serial(buf);
|
|
||||||
|
|
||||||
if (left_click) kprint_serial(" [LEFT]");
|
|
||||||
if (right_click) kprint_serial(" [RIGHT]");
|
|
||||||
|
|
||||||
kprint_serial("\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
27
src/pic.c
27
src/pic.c
|
|
@ -1,55 +1,43 @@
|
||||||
#include "pic.h"
|
#include "pic.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
#define PIC1_COMMAND 0x20
|
#define PIC1_COMMAND 0x20
|
||||||
#define PIC1_DATA 0x21
|
#define PIC1_DATA 0x21
|
||||||
#define PIC2_COMMAND 0xA0
|
#define PIC2_COMMAND 0xA0
|
||||||
#define PIC2_DATA 0xA1
|
#define PIC2_DATA 0xA1
|
||||||
|
|
||||||
#define ICW1_INIT 0x10 // Инициализация
|
#define ICW1_INIT 0x10
|
||||||
#define ICW1_IC4 0x01 // Будет ICW4
|
#define ICW1_IC4 0x01
|
||||||
#define ICW4_8086 0x01 // Режим 8086/8186
|
#define ICW4_8086 0x01
|
||||||
|
|
||||||
void pic_remap(uint8_t master_offset, uint8_t slave_offset) {
|
void pic_remap(uint8_t master_offset, uint8_t slave_offset) {
|
||||||
log_info(LOG_DETAIL, "Remapping PIC...");
|
|
||||||
|
|
||||||
// Сохраняем текущие маски прерываний (какое железо сейчас отключено)
|
|
||||||
uint8_t a1 = inb(PIC1_DATA);
|
uint8_t a1 = inb(PIC1_DATA);
|
||||||
uint8_t a2 = inb(PIC2_DATA);
|
uint8_t a2 = inb(PIC2_DATA);
|
||||||
|
|
||||||
// Свисток к началу инициализации (ICW1)
|
|
||||||
outb(PIC1_COMMAND, ICW1_INIT | ICW1_IC4);
|
outb(PIC1_COMMAND, ICW1_INIT | ICW1_IC4);
|
||||||
io_wait();
|
io_wait();
|
||||||
outb(PIC2_COMMAND, ICW1_INIT | ICW1_IC4);
|
outb(PIC2_COMMAND, ICW1_INIT | ICW1_IC4);
|
||||||
io_wait();
|
io_wait();
|
||||||
|
|
||||||
// Задаем новые смещения векторов (ICW2)
|
outb(PIC1_DATA, master_offset);
|
||||||
outb(PIC1_DATA, master_offset); // Master IRQ 0-7 -> вешаем на master_offset (32)
|
|
||||||
io_wait();
|
io_wait();
|
||||||
outb(PIC2_DATA, slave_offset); // Slave IRQ 8-15 -> вешаем на slave_offset (40)
|
outb(PIC2_DATA, slave_offset);
|
||||||
io_wait();
|
io_wait();
|
||||||
|
|
||||||
// Связываем Master и Slave между собой (ICW3)
|
outb(PIC1_DATA, 4);
|
||||||
outb(PIC1_DATA, 4); // Сообщаем Master, что Slave сидит на IRQ2 (00000100б = 4)
|
|
||||||
io_wait();
|
io_wait();
|
||||||
outb(PIC2_DATA, 2); // Сообщаем Slave его каскадный ID (2)
|
outb(PIC2_DATA, 2);
|
||||||
io_wait();
|
io_wait();
|
||||||
|
|
||||||
// Включаем режим 8086 (ICW4)
|
|
||||||
outb(PIC1_DATA, ICW4_8086);
|
outb(PIC1_DATA, ICW4_8086);
|
||||||
io_wait();
|
io_wait();
|
||||||
outb(PIC2_DATA, ICW4_8086);
|
outb(PIC2_DATA, ICW4_8086);
|
||||||
io_wait();
|
io_wait();
|
||||||
|
|
||||||
// Восстанавливаем сохраненные маски
|
|
||||||
outb(PIC1_DATA, a1);
|
outb(PIC1_DATA, a1);
|
||||||
outb(PIC2_DATA, a2);
|
outb(PIC2_DATA, a2);
|
||||||
|
|
||||||
log_info(LOG_DETAIL, "PIC remapped");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Запретить прерывание от конкретного IRQ
|
|
||||||
void pic_set_mask(uint8_t irq_line) {
|
void pic_set_mask(uint8_t irq_line) {
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
if (irq_line < 8) {
|
if (irq_line < 8) {
|
||||||
|
|
@ -62,7 +50,6 @@ void pic_set_mask(uint8_t irq_line) {
|
||||||
outb(port, value);
|
outb(port, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Разрешить прерывание от конкретного IRQ
|
|
||||||
void pic_clear_mask(uint8_t irq_line) {
|
void pic_clear_mask(uint8_t irq_line) {
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
if (irq_line < 8) {
|
if (irq_line < 8) {
|
||||||
|
|
|
||||||
37
src/pmm.c
37
src/pmm.c
|
|
@ -1,16 +1,12 @@
|
||||||
#include "pmm.h"
|
#include "pmm.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "logger.h"
|
|
||||||
#include "serial.h"
|
|
||||||
|
|
||||||
// Указатель на начало нашей битовой карты в памяти
|
|
||||||
static uint32_t* pmm_bitmap = NULL;
|
static uint32_t* pmm_bitmap = NULL;
|
||||||
static uint32_t pmm_bitmap_size = 0;
|
static uint32_t pmm_bitmap_size = 0;
|
||||||
static uint32_t total_pages = 0;
|
static uint32_t total_pages = 0;
|
||||||
|
|
||||||
static pmm_stats_t global_stats;
|
static pmm_stats_t global_stats;
|
||||||
|
|
||||||
// Вспомогательные инлайны для быстрой работы с битами ядра
|
|
||||||
static inline void bitmap_set(uint32_t page_index) {
|
static inline void bitmap_set(uint32_t page_index) {
|
||||||
pmm_bitmap[page_index / 32] |= (1 << (page_index % 32));
|
pmm_bitmap[page_index / 32] |= (1 << (page_index % 32));
|
||||||
}
|
}
|
||||||
|
|
@ -24,24 +20,19 @@ static inline int bitmap_test(uint32_t page_index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void pmm_init(struct multiboot_info* mbi, uint32_t kernel_end) {
|
void pmm_init(struct multiboot_info* mbi, uint32_t kernel_end) {
|
||||||
// Рассчитываем менеджер на 128 МБ памяти
|
|
||||||
uint32_t mem_size = 128 * 1024 * 1024;
|
uint32_t mem_size = 128 * 1024 * 1024;
|
||||||
total_pages = mem_size / PAGE_SIZE;
|
total_pages = mem_size / PAGE_SIZE;
|
||||||
|
|
||||||
// Саму карту пихаем прямо за концом ядра (куда указывает линкер)
|
pmm_bitmap = (uint32_t*)0x1000000;
|
||||||
pmm_bitmap = (uint32_t*)kernel_end;
|
pmm_bitmap_size = total_pages / 8;
|
||||||
pmm_bitmap_size = total_pages / 8; // Размер карты в байтах (4096 байт)
|
|
||||||
|
|
||||||
uint32_t bitmap_end = kernel_end + pmm_bitmap_size;
|
uint32_t bitmap_end = kernel_end + pmm_bitmap_size;
|
||||||
|
|
||||||
// Шаг 1: Помечаем вообще всё как занятое (1). Безопасность превыше всего.
|
|
||||||
memset(pmm_bitmap, 0xFF, pmm_bitmap_size);
|
memset(pmm_bitmap, 0xFF, pmm_bitmap_size);
|
||||||
|
|
||||||
// Шаг 2: Парсим карту памяти от GRUB и открываем доступные регионы
|
|
||||||
struct multiboot_mmap_entry* mmap = (struct multiboot_mmap_entry*)mbi->mmap_addr;
|
struct multiboot_mmap_entry* mmap = (struct multiboot_mmap_entry*)mbi->mmap_addr;
|
||||||
|
|
||||||
while((uint32_t)mmap < mbi->mmap_addr + mbi->mmap_length) {
|
while((uint32_t)mmap < mbi->mmap_addr + mbi->mmap_length) {
|
||||||
// Если GRUB говорит, что этот кусок RAM свободен для юзания
|
|
||||||
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) {
|
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) {
|
||||||
uint32_t start_addr = (uint32_t)mmap->addr;
|
uint32_t start_addr = (uint32_t)mmap->addr;
|
||||||
uint32_t end_addr = start_addr + (uint32_t)mmap->len;
|
uint32_t end_addr = start_addr + (uint32_t)mmap->len;
|
||||||
|
|
@ -49,46 +40,36 @@ void pmm_init(struct multiboot_info* mbi, uint32_t kernel_end) {
|
||||||
for (uint32_t addr = start_addr; addr < end_addr; addr += PAGE_SIZE) {
|
for (uint32_t addr = start_addr; addr < end_addr; addr += PAGE_SIZE) {
|
||||||
uint32_t page_idx = addr / PAGE_SIZE;
|
uint32_t page_idx = addr / PAGE_SIZE;
|
||||||
if (page_idx < total_pages) {
|
if (page_idx < total_pages) {
|
||||||
bitmap_clear(page_idx); // Ставим 0 (страница свободна)
|
bitmap_clear(page_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Шагаем к следующей записи в таблице Multiboot
|
|
||||||
mmap = (struct multiboot_mmap_entry*)((uint32_t)mmap + mmap->size + sizeof(mmap->size));
|
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) {
|
for (uint32_t addr = 0; addr < bitmap_end; addr += PAGE_SIZE) {
|
||||||
bitmap_set(addr / PAGE_SIZE);
|
bitmap_set(addr / PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info(LOG_NORMAL, "pmm works.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* pmm_alloc_page(void) {
|
void* pmm_alloc_page(void) {
|
||||||
// Тупо линейно ищем первый попавшийся бит, равный 0
|
|
||||||
for (uint32_t i = 0; i < total_pages; i++) {
|
for (uint32_t i = 0; i < total_pages; i++) {
|
||||||
if (!bitmap_test(i)) {
|
if (!bitmap_test(i)) {
|
||||||
bitmap_set(i); // Застолбили страницу (поставили 1)
|
bitmap_set(i);
|
||||||
return (void*)(i * PAGE_SIZE); // Считаем её реальный физический адрес
|
return (void*)(i * PAGE_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log_error(LOG_NORMAL, "PMM: FUCK, WHERE IS ALL OUR FUCKING MEMORY?!");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pmm_free_page(void* addr) {
|
void pmm_free_page(void* addr) {
|
||||||
uint32_t page_idx = ((uint32_t)addr) / PAGE_SIZE;
|
uint32_t page_idx = ((uint32_t)addr) / PAGE_SIZE;
|
||||||
if (page_idx < total_pages) {
|
if (page_idx < total_pages) {
|
||||||
bitmap_clear(page_idx); // Сбросили в 0, страница снова чиста
|
bitmap_clear(page_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pmm_get_stats(void) {
|
void pmm_get_stats(void) {
|
||||||
kprint_serial("Someone wants memory stats! Running the test!\n");
|
|
||||||
uint32_t used = 0;
|
uint32_t used = 0;
|
||||||
uint32_t free = 0;
|
uint32_t free = 0;
|
||||||
|
|
||||||
|
|
@ -100,20 +81,14 @@ void pmm_get_stats(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kprint_serial("Okay, i am collected the stats. ");
|
|
||||||
|
|
||||||
// Пишем в ГЛОБАЛЬНУЮ переменную
|
|
||||||
global_stats.total_pages = total_pages;
|
global_stats.total_pages = total_pages;
|
||||||
global_stats.used_pages = used;
|
global_stats.used_pages = used;
|
||||||
global_stats.free_pages = free;
|
global_stats.free_pages = free;
|
||||||
global_stats.total_memory = total_pages << 12;
|
global_stats.total_memory = total_pages << 12;
|
||||||
global_stats.used_memory = used << 12;
|
global_stats.used_memory = used << 12;
|
||||||
global_stats.free_memory = free << 12;
|
global_stats.free_memory = free << 12;
|
||||||
|
|
||||||
kprint_serial("Goodbye!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Добавим функцию-геттер, которая просто вернет указатель на эту глобальную память
|
|
||||||
pmm_stats_t* pmm_get_stats_ptr(void) {
|
pmm_stats_t* pmm_get_stats_ptr(void) {
|
||||||
return &global_stats;
|
return &global_stats;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
src/timer.c
11
src/timer.c
|
|
@ -1,25 +1,14 @@
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "serial.h"
|
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
// Глобальный счетчик тиков системы
|
|
||||||
uint32_t system_ticks = 0;
|
uint32_t system_ticks = 0;
|
||||||
|
|
||||||
void timer_init(uint32_t frequency) {
|
void timer_init(uint32_t frequency) {
|
||||||
log_info(LOG_NORMAL, "Initializing PIT Timer...");
|
|
||||||
|
|
||||||
// Вычисляем делитель частоты
|
|
||||||
uint32_t divisor = 1193182 / frequency;
|
uint32_t divisor = 1193182 / frequency;
|
||||||
|
|
||||||
// Шлем команду: Канал 0, Режим 3 (генератор меандра), доступ по очереди Младший/Старший байт
|
|
||||||
outb(0x43, 0x36);
|
outb(0x43, 0x36);
|
||||||
|
|
||||||
// Раскалываем 16-битный делитель на два байта и шлем в порт данных Канала 0 (0x40)
|
|
||||||
outb(0x40, (uint8_t)(divisor & 0xFF));
|
outb(0x40, (uint8_t)(divisor & 0xFF));
|
||||||
outb(0x40, (uint8_t)((divisor >> 8) & 0xFF));
|
outb(0x40, (uint8_t)((divisor >> 8) & 0xFF));
|
||||||
|
|
||||||
log_info(LOG_NORMAL, "Timer registered");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer_handler(void) {
|
void timer_handler(void) {
|
||||||
|
|
|
||||||
80
src/vmm.c
80
src/vmm.c
|
|
@ -1,75 +1,77 @@
|
||||||
#include "vmm.h"
|
#include "vmm.h"
|
||||||
#include "pmm.h"
|
#include "pmm.h"
|
||||||
#include "serial.h"
|
|
||||||
|
|
||||||
// 1. Обязательное выравнивание для CR3 и таблиц страниц
|
|
||||||
uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
||||||
uint32_t first_page_table[1024] __attribute__((aligned(4096)));
|
uint32_t first_page_table[1024] __attribute__((aligned(4096)));
|
||||||
|
|
||||||
|
static uint32_t temp_table_phys = 0;
|
||||||
|
|
||||||
extern void vmm_enable_paging(uint32_t* page_directory);
|
extern void vmm_enable_paging(uint32_t* page_directory);
|
||||||
|
|
||||||
void vmm_init(void) {
|
void vmm_init(void) {
|
||||||
kprint_serial("VMM: Initializing paging...\n");
|
|
||||||
|
|
||||||
// 2. Очищаем каталог (ставим Not Present)
|
|
||||||
for (int i = 0; i < 1024; i++) {
|
for (int i = 0; i < 1024; i++) {
|
||||||
page_directory[i] = 0x00000002; // Read/Write, Not Present
|
page_directory[i] = 0x00000002;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Identity Map для первых 4 МБ
|
|
||||||
// i * 4096 дает физический адрес страницы
|
|
||||||
for (uint32_t i = 0; i < 1024; i++) {
|
for (uint32_t i = 0; i < 1024; i++) {
|
||||||
first_page_table[i] = (i * 0x1000) | 0x3; // Present + RW
|
first_page_table[i] = (i * 0x1000) | 0x3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Указываем каталогу на таблицу
|
|
||||||
// (uint32_t)first_page_table — это уже физический адрес,
|
|
||||||
// если ядро по 1МБ и мы не используем сложные смещения.
|
|
||||||
page_directory[0] = ((uint32_t)first_page_table) | 0x3;
|
page_directory[0] = ((uint32_t)first_page_table) | 0x3;
|
||||||
|
|
||||||
kprint_serial("DEBUG: page_directory is at: 0x");
|
temp_table_phys = (uint32_t)pmm_alloc_page();
|
||||||
kprint_serial_hex((uint32_t)page_directory);
|
page_directory[1023] = (temp_table_phys & 0xFFFFF000) | 0x3;
|
||||||
kprint_serial("\n");
|
|
||||||
|
|
||||||
kprint_serial("DEBUG: page_directory[0] contains: 0x");
|
uint32_t* temp_table = (uint32_t*)temp_table_phys;
|
||||||
kprint_serial_hex(page_directory[0]);
|
for (int i = 0; i < 1024; i++) temp_table[i] = 0;
|
||||||
kprint_serial("\n");
|
|
||||||
|
|
||||||
kprint_serial("VMM: Paging configured. Enabling CR0...\n");
|
uint32_t bitmap_phys = 0x1000000;
|
||||||
|
uint32_t bitmap_pd_idx = bitmap_phys >> 22;
|
||||||
|
uint32_t bitmap_pt_idx = (bitmap_phys >> 12) & 0x3FF;
|
||||||
|
uint32_t bitmap_pt_phys = (uint32_t)pmm_alloc_page();
|
||||||
|
page_directory[bitmap_pd_idx] = (bitmap_pt_phys & 0xFFFFF000) | 0x3;
|
||||||
|
uint32_t* bitmap_pt = (uint32_t*)bitmap_pt_phys;
|
||||||
|
for (int i = 0; i < 1024; i++) bitmap_pt[i] = 0;
|
||||||
|
bitmap_pt[bitmap_pt_idx] = (bitmap_phys & 0xFFFFF000) | 0x3;
|
||||||
|
|
||||||
// 5. Включаем
|
|
||||||
vmm_enable_paging(page_directory);
|
vmm_enable_paging(page_directory);
|
||||||
|
|
||||||
kprint_serial("VMM: FUCK, IT WORKS!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vmm_map_page(uint32_t phys, uint32_t virt, uint32_t flags) {
|
void vmm_map_page(uint32_t phys, uint32_t virt, uint32_t flags) {
|
||||||
// Выковыриваем индексы из виртуального адреса
|
uint32_t pd_idx = virt >> 22;
|
||||||
uint32_t pd_idx = virt >> 22; // Старшие 10 бит — индекс каталога
|
uint32_t pt_idx = (virt >> 12) & 0x3FF;
|
||||||
uint32_t pt_idx = (virt >> 12) & 0x3FF; // Средние 10 бит — индекс таблицы
|
uint32_t temp_pt_idx = (VMM_TEMP_MAP >> 12) & 0x3FF;
|
||||||
|
uint32_t* tmp = (uint32_t*)temp_table_phys;
|
||||||
|
|
||||||
if (!(page_directory[pd_idx] & 1)) {
|
if (!(page_directory[pd_idx] & 1)) {
|
||||||
// 1. Выделяем физическую страницу под НОВУЮ таблицу
|
|
||||||
uint32_t phys_table = (uint32_t)pmm_alloc_page();
|
uint32_t phys_table = (uint32_t)pmm_alloc_page();
|
||||||
|
if (!phys_table) {
|
||||||
// 2. Ставим её в каталог (Present + Write)
|
return;
|
||||||
|
}
|
||||||
page_directory[pd_idx] = (phys_table & 0xFFFFF000) | 3;
|
page_directory[pd_idx] = (phys_table & 0xFFFFF000) | 3;
|
||||||
|
|
||||||
// 3. Очищаем новую таблицу (важно!)
|
tmp[temp_pt_idx] = (phys_table & 0xFFFFF000) | 3;
|
||||||
uint32_t* new_table = (uint32_t*)(page_directory[pd_idx] & 0xFFFFF000);
|
__asm__ __volatile__("invlpg (%0)" : : "r"(VMM_TEMP_MAP) : "memory");
|
||||||
for(int i=0; i<1024; i++) new_table[i] = 0;
|
|
||||||
|
uint32_t* new_table = (uint32_t*)VMM_TEMP_MAP;
|
||||||
|
for (int i = 0; i < 1024; i++) new_table[i] = 0;
|
||||||
|
|
||||||
|
new_table[pt_idx] = (phys & 0xFFFFF000) | flags;
|
||||||
|
|
||||||
|
tmp[temp_pt_idx] = 0;
|
||||||
|
__asm__ __volatile__("invlpg (%0)" : : "r"(VMM_TEMP_MAP) : "memory");
|
||||||
|
__asm__ __volatile__("invlpg (%0)" : : "r"(virt) : "memory");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Достаем адрес таблицы страниц из каталога (обнуляем нижние 12 бит флагов)
|
uint32_t table_phys = page_directory[pd_idx] & 0xFFFFF000;
|
||||||
uint32_t* table = (uint32_t*)(page_directory[pd_idx] & 0xFFFFF000);
|
tmp[temp_pt_idx] = table_phys | 3;
|
||||||
|
__asm__ __volatile__("invlpg (%0)" : : "r"(VMM_TEMP_MAP) : "memory");
|
||||||
|
|
||||||
// Запихиваем физический адрес и флаги в таблицу страниц
|
uint32_t* table = (uint32_t*)VMM_TEMP_MAP;
|
||||||
// PAGE_SIZE у нас 4096, поэтому phys должен быть выровнен (нижние 12 бит затрутся флагами)
|
|
||||||
table[pt_idx] = (phys & 0xFFFFF000) | flags;
|
table[pt_idx] = (phys & 0xFFFFF000) | flags;
|
||||||
|
|
||||||
// ВАЖНО: Процессор кэширует таблицы в TLB (Translation Lookaside Buffer).
|
tmp[temp_pt_idx] = 0;
|
||||||
// Если мы изменили маппинг существующей страницы, процессор об этом не узнает.
|
__asm__ __volatile__("invlpg (%0)" : : "r"(VMM_TEMP_MAP) : "memory");
|
||||||
// Нужно сбросить кэш для этого адреса инструкцией invlpg:
|
|
||||||
__asm__ __volatile__("invlpg (%0)" : : "r"(virt) : "memory");
|
__asm__ __volatile__("invlpg (%0)" : : "r"(virt) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@
|
||||||
#define PAGE_WRITE 0x2 // Можно писать (Read/Write)
|
#define PAGE_WRITE 0x2 // Можно писать (Read/Write)
|
||||||
#define PAGE_USER 0x4 // Доступно из Ring 3 (User mode)
|
#define PAGE_USER 0x4 // Доступно из Ring 3 (User mode)
|
||||||
|
|
||||||
|
// Временный маппинг для доступа к физической памяти (pd_idx=1023)
|
||||||
|
#define VMM_TEMP_MAP 0xFFC00000
|
||||||
|
|
||||||
// Инициализация страничного обмена
|
// Инициализация страничного обмена
|
||||||
void vmm_init(void);
|
void vmm_init(void);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue