init
This commit is contained in:
2
kernel/.gitignore
vendored
Normal file
2
kernel/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/kernel
|
||||
/target
|
||||
18
kernel/Cargo.toml
Normal file
18
kernel/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "RINA"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[[bin]]
|
||||
name = "kernel"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
limine = "0.5"
|
||||
embedded-graphics = "0.8"
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
44
kernel/GNUmakefile
Normal file
44
kernel/GNUmakefile
Normal file
@@ -0,0 +1,44 @@
|
||||
# Nuke built-in rules and variables.
|
||||
MAKEFLAGS += -rR
|
||||
.SUFFIXES:
|
||||
|
||||
# This is the name that our final executable will have.
|
||||
# Change as needed.
|
||||
override OUTPUT := kernel
|
||||
|
||||
# Convenience macro to reliably declare user overridable variables.
|
||||
override USER_VARIABLE = $(if $(filter $(origin $(1)),default undefined),$(eval override $(1) := $(2)))
|
||||
|
||||
# Target architecture to build for. Default to x86_64.
|
||||
$(call USER_VARIABLE,KARCH,x86_64)
|
||||
|
||||
ifeq ($(RUST_TARGET),)
|
||||
override RUST_TARGET := $(KARCH)-unknown-none
|
||||
ifeq ($(KARCH),riscv64)
|
||||
override RUST_TARGET := riscv64gc-unknown-none-elf
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(RUST_PROFILE),)
|
||||
override RUST_PROFILE := dev
|
||||
endif
|
||||
|
||||
override RUST_PROFILE_SUBDIR := $(RUST_PROFILE)
|
||||
ifeq ($(RUST_PROFILE),dev)
|
||||
override RUST_PROFILE_SUBDIR := debug
|
||||
endif
|
||||
|
||||
# Default target.
|
||||
.PHONY: all
|
||||
all:
|
||||
RUSTFLAGS="-C relocation-model=static" cargo build --target $(RUST_TARGET) --profile $(RUST_PROFILE)
|
||||
cp target/$(RUST_TARGET)/$(RUST_PROFILE_SUBDIR)/$$(cd target/$(RUST_TARGET)/$(RUST_PROFILE_SUBDIR) && find -maxdepth 1 -perm -111 -type f) kernel
|
||||
|
||||
# Remove object files and the final executable.
|
||||
.PHONY: clean
|
||||
clean:
|
||||
cargo clean
|
||||
rm -rf kernel
|
||||
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
8
kernel/rust-toolchain.toml
Normal file
8
kernel/rust-toolchain.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
targets = [
|
||||
"x86_64-unknown-none",
|
||||
# "aarch64-unknown-none",
|
||||
# "riscv64gc-unknown-none-elf",
|
||||
# "loongarch64-unknown-none",
|
||||
]
|
||||
193
kernel/src/main.rs
Normal file
193
kernel/src/main.rs
Normal file
@@ -0,0 +1,193 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::arch::asm;
|
||||
use core::fmt::{self, Write};
|
||||
use limine::BaseRevision;
|
||||
use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker};
|
||||
|
||||
use embedded_graphics::{
|
||||
mono_font::{ascii::FONT_6X10, MonoTextStyle},
|
||||
pixelcolor::Rgb888,
|
||||
prelude::*,
|
||||
text::Text,
|
||||
Drawable,
|
||||
};
|
||||
|
||||
// Отрисовка пикселей
|
||||
struct FramebufferDisplay<'a> {
|
||||
framebuffer: &'a limine::framebuffer::Framebuffer<'a>,
|
||||
}
|
||||
|
||||
impl DrawTarget for FramebufferDisplay<'_> {
|
||||
type Color = Rgb888;
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||
where I: IntoIterator<Item = Pixel<Self::Color>> {
|
||||
for Pixel(coord, color) in pixels {
|
||||
if coord.x >= 0 && coord.x < self.framebuffer.width() as i32 &&
|
||||
coord.y >= 0 && coord.y < self.framebuffer.height() as i32 {
|
||||
|
||||
let offset = (coord.y as usize * self.framebuffer.pitch() as usize) + (coord.x as usize * 4);
|
||||
|
||||
unsafe {
|
||||
self.framebuffer.addr().add(offset).cast::<u32>().write(color.into_storage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl OriginDimensions for FramebufferDisplay<'_> {
|
||||
fn size(&self) -> Size {
|
||||
Size::new(self.framebuffer.width() as u32, self.framebuffer.height() as u32)
|
||||
}
|
||||
}
|
||||
|
||||
// Терминальный вывод. Следит за положением курсора и умеет двигать текст
|
||||
struct Console<'a> {
|
||||
display: FramebufferDisplay<'a>,
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
impl<'a> Console<'a> {
|
||||
pub fn new(display: FramebufferDisplay<'a>) -> Self {
|
||||
Self { display, x: 10, y: 20 } // Начальный отступ
|
||||
}
|
||||
|
||||
// Метод для очистки экрана
|
||||
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;
|
||||
}
|
||||
|
||||
// Логика скроллинга. копирует пиксели снизу вверх
|
||||
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 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
|
||||
);
|
||||
}
|
||||
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);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Если достигли низа экрана, то скроллим
|
||||
if self.y > self.display.framebuffer.height() as i32 - 10 {
|
||||
self.scroll();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// boot
|
||||
#[used]
|
||||
#[unsafe(link_section = ".requests")]
|
||||
static BASE_REVISION: BaseRevision = BaseRevision::new();
|
||||
|
||||
#[used]
|
||||
#[unsafe(link_section = ".requests")]
|
||||
static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
|
||||
|
||||
#[used]
|
||||
#[unsafe(link_section = ".requests_start_marker")]
|
||||
static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new();
|
||||
#[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 _ = 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hcf();
|
||||
}
|
||||
|
||||
#[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");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user