feat: add pmm, add vmm, add allocator, create memory management foundation
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user