246 lines
7.6 KiB
Rust
246 lines
7.6 KiB
Rust
use core::{cmp, slice};
|
|
use ransid::{Console, Event};
|
|
use spin::Mutex;
|
|
|
|
use memory::Frame;
|
|
use paging::{ActivePageTable, Page, PhysicalAddress, VirtualAddress, entry};
|
|
|
|
#[cfg(target_arch = "x86_64")]
|
|
#[allow(unused_assignments)]
|
|
#[inline(always)]
|
|
#[cold]
|
|
unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) {
|
|
asm!("cld
|
|
rep movsq"
|
|
:
|
|
: "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
|
|
: "cc", "memory"
|
|
: "intel", "volatile");
|
|
}
|
|
|
|
#[cfg(target_arch = "x86_64")]
|
|
#[allow(unused_assignments)]
|
|
#[inline(always)]
|
|
#[cold]
|
|
unsafe fn fast_set(dst: *mut u32, src: u32, len: usize) {
|
|
asm!("cld
|
|
rep stosd"
|
|
:
|
|
: "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len)
|
|
: "cc", "memory"
|
|
: "intel", "volatile");
|
|
}
|
|
|
|
#[cfg(target_arch = "x86_64")]
|
|
#[allow(unused_assignments)]
|
|
#[inline(always)]
|
|
#[cold]
|
|
unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) {
|
|
asm!("cld
|
|
rep stosq"
|
|
:
|
|
: "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len)
|
|
: "cc", "memory"
|
|
: "intel", "volatile");
|
|
}
|
|
|
|
/// The info of the VBE mode
|
|
#[derive(Copy, Clone, Default, Debug)]
|
|
#[repr(packed)]
|
|
pub struct VBEModeInfo {
|
|
attributes: u16,
|
|
win_a: u8,
|
|
win_b: u8,
|
|
granularity: u16,
|
|
winsize: u16,
|
|
segment_a: u16,
|
|
segment_b: u16,
|
|
winfuncptr: u32,
|
|
bytesperscanline: u16,
|
|
pub xresolution: u16,
|
|
pub yresolution: u16,
|
|
xcharsize: u8,
|
|
ycharsize: u8,
|
|
numberofplanes: u8,
|
|
bitsperpixel: u8,
|
|
numberofbanks: u8,
|
|
memorymodel: u8,
|
|
banksize: u8,
|
|
numberofimagepages: u8,
|
|
unused: u8,
|
|
redmasksize: u8,
|
|
redfieldposition: u8,
|
|
greenmasksize: u8,
|
|
greenfieldposition: u8,
|
|
bluemasksize: u8,
|
|
bluefieldposition: u8,
|
|
rsvdmasksize: u8,
|
|
rsvdfieldposition: u8,
|
|
directcolormodeinfo: u8,
|
|
physbaseptr: u32,
|
|
offscreenmemoryoffset: u32,
|
|
offscreenmemsize: u16,
|
|
}
|
|
|
|
pub static CONSOLE: Mutex<Option<Console>> = Mutex::new(None);
|
|
|
|
pub static DISPLAY: Mutex<Option<Display>> = Mutex::new(None);
|
|
|
|
static FONT: &'static [u8] = include_bytes!("../../../../res/unifont.font");
|
|
|
|
pub unsafe fn init(active_table: &mut ActivePageTable) {
|
|
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE);
|
|
|
|
let mode_info = &*(0x5200 as *const VBEModeInfo);
|
|
if mode_info.physbaseptr > 0 {
|
|
let width = mode_info.xresolution as usize;
|
|
let height = mode_info.yresolution as usize;
|
|
let onscreen = mode_info.physbaseptr as usize + ::KERNEL_OFFSET;
|
|
let size = width * height;
|
|
|
|
{
|
|
let start_page = Page::containing_address(VirtualAddress::new(onscreen));
|
|
let end_page = Page::containing_address(VirtualAddress::new(onscreen + size * 4 - 1));
|
|
for page in Page::range_inclusive(start_page, end_page) {
|
|
let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get() - ::KERNEL_OFFSET));
|
|
active_table.map_to(page, frame, /*actually sets PAT for write combining*/ entry::HUGE_PAGE | entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
|
|
}
|
|
}
|
|
|
|
fast_set64(onscreen as *mut u64, 0, size/2);
|
|
|
|
let offscreen = ::allocator::__rust_allocate(size * 4, 4096);
|
|
fast_set64(offscreen as *mut u64, 0, size/2);
|
|
|
|
*DISPLAY.lock() = Some(Display::new(width, height,
|
|
slice::from_raw_parts_mut(onscreen as *mut u32, size),
|
|
slice::from_raw_parts_mut(offscreen as *mut u32, size)
|
|
));
|
|
*CONSOLE.lock() = Some(Console::new(width/8, height/16));
|
|
}
|
|
|
|
active_table.unmap(Page::containing_address(VirtualAddress::new(0x5200)));
|
|
}
|
|
|
|
/// A display
|
|
pub struct Display {
|
|
pub width: usize,
|
|
pub height: usize,
|
|
pub onscreen: &'static mut [u32],
|
|
pub offscreen: &'static mut [u32],
|
|
}
|
|
|
|
impl Display {
|
|
fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display {
|
|
Display {
|
|
width: width,
|
|
height: height,
|
|
onscreen: onscreen,
|
|
offscreen: offscreen,
|
|
}
|
|
}
|
|
|
|
/// Draw a rectangle
|
|
fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) {
|
|
let start_y = cmp::min(self.height - 1, y);
|
|
let end_y = cmp::min(self.height, y + h);
|
|
|
|
let start_x = cmp::min(self.width - 1, x);
|
|
let len = cmp::min(self.width, x + w) - start_x;
|
|
|
|
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
|
|
let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;
|
|
|
|
let stride = self.width * 4;
|
|
|
|
let offset = y * stride + start_x * 4;
|
|
offscreen_ptr += offset;
|
|
onscreen_ptr += offset;
|
|
|
|
let mut rows = end_y - start_y;
|
|
while rows > 0 {
|
|
unsafe {
|
|
fast_set(offscreen_ptr as *mut u32, color, len);
|
|
fast_set(onscreen_ptr as *mut u32, color, len);
|
|
}
|
|
offscreen_ptr += stride;
|
|
onscreen_ptr += stride;
|
|
rows -= 1;
|
|
}
|
|
}
|
|
|
|
/// Draw a character
|
|
fn char(&mut self, x: usize, y: usize, character: char, color: u32) {
|
|
if x + 8 <= self.width && y + 16 <= self.height {
|
|
let mut font_i = 16 * (character as usize);
|
|
let font_end = font_i + 16;
|
|
if font_end <= FONT.len() {
|
|
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
|
|
let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;
|
|
|
|
let stride = self.width * 4;
|
|
|
|
let offset = y * stride + x * 4;
|
|
offscreen_ptr += offset;
|
|
onscreen_ptr += offset;
|
|
|
|
while font_i < font_end {
|
|
let mut row_data = FONT[font_i];
|
|
let mut col = 8;
|
|
while col > 0 {
|
|
col -= 1;
|
|
if row_data & 1 == 1 {
|
|
unsafe {
|
|
*((offscreen_ptr + col * 4) as *mut u32) = color;
|
|
}
|
|
}
|
|
row_data = row_data >> 1;
|
|
}
|
|
|
|
unsafe {
|
|
fast_copy64(onscreen_ptr as *mut u64, offscreen_ptr as *const u64, 4);
|
|
}
|
|
|
|
offscreen_ptr += stride;
|
|
onscreen_ptr += stride;
|
|
font_i += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Scroll display
|
|
pub fn scroll(&mut self, rows: usize, color: u32) {
|
|
let data = (color as u64) << 32 | color as u64;
|
|
|
|
let width = self.width/2;
|
|
let height = self.height;
|
|
if rows > 0 && rows < height {
|
|
let off1 = rows * width;
|
|
let off2 = height * width - off1;
|
|
unsafe {
|
|
let data_ptr = self.offscreen.as_mut_ptr() as *mut u64;
|
|
fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2);
|
|
fast_set64(data_ptr.offset(off2 as isize), data, off1);
|
|
|
|
fast_copy64(self.onscreen.as_mut_ptr() as *mut u64, data_ptr, off1 + off2);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Handle ransid event
|
|
pub fn event(&mut self, event: Event) {
|
|
match event {
|
|
Event::Char { x, y, c, color, .. } => {
|
|
self.char(x * 8, y * 16, c, color.data);
|
|
},
|
|
Event::Rect { x, y, w, h, color } => {
|
|
self.rect(x * 8, y * 16, w * 8, h * 16, color.data);
|
|
},
|
|
Event::Scroll { rows, color } => {
|
|
self.scroll(rows * 16, color.data);
|
|
}
|
|
}
|
|
}
|
|
}
|