feat: add pmm, add vmm, add allocator, create memory management foundation

This commit is contained in:
Faynot
2026-03-29 19:07:41 +03:00
parent 83117c0a65
commit 7860db3814
9 changed files with 578 additions and 66 deletions

View File

@@ -1,10 +1,25 @@
#![no_std]
#![no_main]
extern crate alloc;
use core::arch::asm;
use core::fmt::{self, Write};
use alloc::vec::Vec;
use limine::BaseRevision;
use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker};
use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker, HhdmRequest, MemoryMapRequest, ExecutableAddressRequest};
use crate::mem::paging::{PageTable, PageTableFlags};
use crate::mem::address::{PhysAddr, VirtAddr};
mod mem;
#[macro_use]
pub mod debug;
pub mod allocator {
pub use crate::mem::allocator::ALLOCATOR;
}
use embedded_graphics::{
mono_font::{ascii::FONT_6X10, MonoTextStyle},
@@ -14,7 +29,7 @@ use embedded_graphics::{
Drawable,
};
// Отрисовка пикселей
/// Low-level pixel rendering engine
struct FramebufferDisplay<'a> {
framebuffer: &'a limine::framebuffer::Framebuffer<'a>,
}
@@ -46,82 +61,70 @@ impl OriginDimensions for FramebufferDisplay<'_> {
}
}
// Терминальный вывод. Следит за положением курсора и умеет двигать текст
/// High-level console for terminal-like output
struct Console<'a> {
display: FramebufferDisplay<'a>,
x: i32,
y: i32,
current_color: Rgb888,
}
impl<'a> Console<'a> {
pub fn new(display: FramebufferDisplay<'a>) -> Self {
Self { display, x: 10, y: 20 } // Начальный отступ
Self { display, x: 10, y: 20, current_color: Rgb888::WHITE }
}
pub fn set_color(&mut self, color: Rgb888) {
self.current_color = color;
}
// Метод для очистки экрана
pub fn clear(&mut self) {
let size = self.display.size();
let fb = self.display.framebuffer;
unsafe {
// Быстрая очистка через заполнение памяти нулями
core::ptr::write_bytes(fb.addr(), 0, fb.pitch() as usize * fb.height() as usize);
}
self.x = 10;
self.y = 20;
}
// Логика скроллинга. копирует пиксели снизу вверх
/// Shifts pixels upward to make room for new lines
fn scroll(&mut self) {
let fb = self.display.framebuffer;
let pitch = fb.pitch() as usize;
let height = fb.height() as usize;
let font_height = 10; // Высота FONT_6X10
let font_height = 10;
let shift = font_height * pitch;
unsafe {
let addr = fb.addr();
// Копируем всё содержимое экрана на одну строку вверх
core::ptr::copy(
addr.add(shift),
addr,
pitch * (height - font_height)
);
// Очищаем последнюю строку
core::ptr::write_bytes(
addr.add(pitch * (height - font_height)),
0,
shift
);
core::ptr::copy(addr.add(shift), addr, pitch * (height - font_height));
core::ptr::write_bytes(addr.add(pitch * (height - font_height)), 0, shift);
}
self.y -= font_height as i32;
}
}
// Вывод текста. write!(console, "Hello {}", name)
impl fmt::Write for Console<'_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
let style = MonoTextStyle::new(&FONT_6X10, Rgb888::WHITE);
let style = MonoTextStyle::new(&FONT_6X10, self.current_color);
for c in s.chars() {
if c == '\n' {
self.x = 10;
self.y += 10;
} else {
// Если текст выходит за границы экрана — перенос строки
if self.x + 6 > self.display.framebuffer.width() as i32 {
self.x = 10;
self.y += 10;
}
// Рисуем символ (превращаем char в временную строку &str)
let mut buf = [0u8; 4];
let s_char = c.encode_utf8(&mut buf);
let _ = Text::new(s_char, Point::new(self.x, self.y), style).draw(&mut self.display);
self.x += 6; // Ширина FONT_6X10
self.x += 6;
}
// Если достигли низа экрана, то скроллим
if self.y > self.display.framebuffer.height() as i32 - 10 {
self.scroll();
}
@@ -130,64 +133,113 @@ impl fmt::Write for Console<'_> {
}
}
// boot
#[used]
#[unsafe(link_section = ".requests")]
// --- Limine Requests ---
#[used] #[unsafe(link_section = ".requests")]
static MEMORY_MAP_REQUEST: MemoryMapRequest = MemoryMapRequest::new();
#[used] #[unsafe(link_section = ".requests")]
static HHDM_REQUEST: HhdmRequest = HhdmRequest::new();
#[used] #[unsafe(link_section = ".requests")]
static KERNEL_ADDR_REQUEST: ExecutableAddressRequest = ExecutableAddressRequest::new();
#[used] #[unsafe(link_section = ".requests")]
static BASE_REVISION: BaseRevision = BaseRevision::new();
#[used]
#[unsafe(link_section = ".requests")]
#[used] #[unsafe(link_section = ".requests")]
static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
#[used]
#[unsafe(link_section = ".requests_start_marker")]
#[used] #[unsafe(link_section = ".requests_start_marker")]
static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new();
#[used]
#[unsafe(link_section = ".requests_end_marker")]
#[used] #[unsafe(link_section = ".requests_end_marker")]
static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new();
#[unsafe(no_mangle)]
unsafe extern "C" fn kmain() -> ! {
assert!(BASE_REVISION.is_supported());
if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() {
if let Some(fb) = framebuffer_response.framebuffers().next() {
// Инициализируем консоль
let mut console = Console::new(FramebufferDisplay { framebuffer: &fb });
console.clear();
let fb_res = FRAMEBUFFER_REQUEST.get_response().expect("Limine: No Framebuffer");
let mmap_res = MEMORY_MAP_REQUEST.get_response().expect("Limine: No Memory Map");
let hhdm_res = HHDM_REQUEST.get_response().expect("Limine: No HHDM");
let kaddr_res = KERNEL_ADDR_REQUEST.get_response().expect("Limine: No Kernel Address");
let hhdm_offset = hhdm_res.offset();
let _ = writeln!(console, "RINA Kernel");
let _ = writeln!(console, "-----------------------");
let _ = writeln!(console, "Framebuffer: {}x{}", fb.width(), fb.height());
let _ = writeln!(console, "Memory mapping... OK");
let _ = writeln!(console, "Hello, Arina! Terminal mode active :3");
// Тест скроллинга: выведем много строк
for i in 0..5 {
let _ = writeln!(console, "System log entry #{}", i);
}
let fb = fb_res.framebuffers().next().expect("Limine: No active framebuffer found");
let mut console = Console::new(FramebufferDisplay { framebuffer: &fb });
console.clear();
info!(console, "BOOT", "RINA Kernel Starting...");
// Initialize Physical Memory Manager
unsafe { mem::pmm::BitmapPMM::init(&mmap_res, hhdm_offset); }
info!(console, "MEM", "Physical Memory Manager initialized.");
// Prepare Kernel Page Tables (P4)
let p4_phys = mem::pmm::alloc_page().expect("OOM: Failed to allocate P4 table");
let p4 = unsafe { &mut *p4_phys.to_virt(hhdm_offset).as_mut_ptr::<PageTable>() };
unsafe { core::ptr::write_bytes(p4 as *mut _ as *mut u8, 0, 4096); }
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
// Mapping Strategy: HHDM + Identity Mapping for active segments
for entry in mmap_res.entries() {
let phys = PhysAddr(entry.base);
let virt_hhdm = phys.to_virt(hhdm_offset);
p4.map_region(virt_hhdm, phys, entry.length, flags, hhdm_offset);
if entry.entry_type != limine::memory_map::EntryType::RESERVED {
p4.map_region(VirtAddr(entry.base), phys, entry.length, flags, hhdm_offset);
}
}
hcf();
}
// Map the kernel itself based on provided executable addresses
p4.map_region(
VirtAddr(kaddr_res.virtual_base()),
PhysAddr(kaddr_res.physical_base()),
0x1000 * 1024, // 4MB default
flags,
hhdm_offset
);
info!(console, "MMU", "Switching to Kernel Page Tables...");
unsafe { p4.activate(p4_phys); }
// Initialize Global Heap
let heap_start = 0xFFFF_9000_0000_0000;
let heap_size = 8 * 1024 * 1024;
for i in (0..heap_size).step_by(4096) {
let frame = mem::pmm::alloc_page().expect("OOM: Heap allocation failed");
p4.map_page(VirtAddr(heap_start + i as u64), frame, flags, hhdm_offset);
}
{
let mut allocator = allocator::ALLOCATOR.lock();
allocator.init(heap_start as usize, heap_size);
}
info!(console, "HEAP", "Global Allocator is online.");
// Integrity Test
let mut test_vec = Vec::new();
test_vec.push(42);
info!(console, "CORE", "Vec test passed. Pointer: {:?}", test_vec.as_ptr());
#[panic_handler]
fn rust_panic(_info: &core::panic::PanicInfo) -> ! {
// В будущем тут будет выводиться текст ошибки
hcf();
}
fn hcf() -> ! {
loop {
unsafe {
#[cfg(target_arch = "x86_64")]
asm!("hlt");
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
asm!("wfi");
#[cfg(target_arch = "loongarch64")]
asm!("idle 0");
}
unsafe { asm!("hlt", options(nomem, nostack, preserves_flags)); }
}
}
#[panic_handler]
fn rust_panic(info: &core::panic::PanicInfo) -> ! {
let mut sp = unsafe { debug::serial::SerialPort::init() };
let _ = writeln!(sp, "KERNEL PANIC: {:?}", info);
hcf();
}