diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml new file mode 100644 index 0000000000..eb9335bef5 --- /dev/null +++ b/vesad/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "vesad" +version = "0.1.0" + +[dependencies] +syscall = { path = "../../syscall/" } diff --git a/vesad/src/display.rs b/vesad/src/display.rs new file mode 100644 index 0000000000..f1befd36db --- /dev/null +++ b/vesad/src/display.rs @@ -0,0 +1,112 @@ +use std::cmp; + +use primitive::{fast_set, fast_set64, fast_copy64}; + +static FONT: &'static [u8] = include_bytes!("../../../res/unifont.font"); + +/// A display +pub struct Display { + pub width: usize, + pub height: usize, + pub onscreen: &'static mut [u32], + pub offscreen: &'static mut [u32], +} + +impl Display { + pub 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 + pub 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); + } + } + } +} diff --git a/vesad/src/main.rs b/vesad/src/main.rs new file mode 100644 index 0000000000..c85b3df466 --- /dev/null +++ b/vesad/src/main.rs @@ -0,0 +1,54 @@ +#![feature(alloc)] +#![feature(asm)] +#![feature(heap_api)] + +extern crate alloc; +extern crate syscall; + +use std::fs::File; +use std::{slice, thread}; +use syscall::{physmap, physunmap, MAP_WRITE, MAP_WRITE_COMBINE}; + +use display::Display; +use mode_info::VBEModeInfo; +use primitive::fast_set64; + +pub mod display; +pub mod mode_info; +pub mod primitive; + +fn main() { + let width; + let height; + let physbaseptr; + + { + let mode_info = unsafe { &*(physmap(0x5200, 4096, 0).expect("vesad: failed to map VBE info") as *const VBEModeInfo) }; + + width = mode_info.xresolution as usize; + height = mode_info.yresolution as usize; + physbaseptr = mode_info.physbaseptr as usize; + + unsafe { let _ = physunmap(mode_info as *const _ as usize); } + } + + if physbaseptr > 0 { + let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); + thread::spawn(move || { + let size = width * height; + + let onscreen = unsafe { physmap(physbaseptr as usize, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; + unsafe { fast_set64(onscreen as *mut u64, 0, size/2) }; + + let offscreen = unsafe { alloc::heap::allocate(size * 4, 4096) }; + unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; + + let mut display = Display::new(width, height, + unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, + unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } + ); + + display.rect(100, 100, 100, 100, 0xFF0000); + }); + } +} diff --git a/vesad/src/mode_info.rs b/vesad/src/mode_info.rs new file mode 100644 index 0000000000..7d59af6452 --- /dev/null +++ b/vesad/src/mode_info.rs @@ -0,0 +1,37 @@ +/// 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, + pub physbaseptr: u32, + offscreenmemoryoffset: u32, + offscreenmemsize: u16, +} diff --git a/vesad/src/primitive.rs b/vesad/src/primitive.rs new file mode 100644 index 0000000000..e3bdc25258 --- /dev/null +++ b/vesad/src/primitive.rs @@ -0,0 +1,38 @@ +#[cfg(target_arch = "x86_64")] +#[allow(unused_assignments)] +#[inline(always)] +#[cold] +pub 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] +pub 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] +pub 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"); +}