diff --git a/kernel/src/driver/video/fbdev/base/mod.rs b/kernel/src/driver/video/fbdev/base/mod.rs index fb9921a6..0f3b6081 100644 --- a/kernel/src/driver/video/fbdev/base/mod.rs +++ b/kernel/src/driver/video/fbdev/base/mod.rs @@ -1,4 +1,5 @@ use alloc::{string::String, sync::Arc, vec::Vec}; +use render_helper::{FrameP, FramePointerStatus}; use system_error::SystemError; use crate::{ @@ -69,22 +70,20 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { let bit_per_pixel = self.current_fb_var().bits_per_pixel; // 计算图像在帧缓冲中的起始位 - let mut bitstart = (y * self.current_fb_fix().line_length * 8) + (x * bit_per_pixel); + let bitstart = (y * self.current_fb_fix().line_length * 8) + (x * bit_per_pixel); let start_index = bitstart & (32 - 1); let pitch_index = (self.current_fb_fix().line_length & (byte_per_pixel - 1)) * 8; - // 位转字节 - bitstart /= 8; - - // 对齐到像素字节大小 - bitstart &= !(byte_per_pixel - 1); - - let dst1 = boot_param.screen_info.lfb_virt_base; - if dst1.is_none() { + let dst2 = boot_param.screen_info.lfb_virt_base; + if dst2.is_none() { return; } - let mut dst1 = dst1.unwrap(); - dst1 += VirtAddr::new(bitstart as usize); - + let mut safe_pointer = FrameP::new( + self.current_fb_var().yres as usize, + self.current_fb_var().xres as usize, + self.current_fb_var().bits_per_pixel as usize, + dst2.unwrap(), + image, + ); let _ = self.fb_sync(); if image.depth == 1 { @@ -107,16 +106,9 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { && image.width & (32 / bit_per_pixel - 1) == 0 && (8..=32).contains(&bit_per_pixel) { - unsafe { self.fast_imageblit(image, dst1, fg, bg) } + unsafe { self.fast_imageblit(image, &mut safe_pointer, fg, bg) } } else { - self.slow_imageblit( - image, - dst1, - fg, - bg, - bitstart / 4, - self.current_fb_fix().line_length, - ) + self.slow_imageblit(image, &mut safe_pointer, fg, bg) } } else { todo!("color image blit todo"); @@ -129,7 +121,7 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { /// 要求 image->width 可以被像素或 dword (ppw) 整除。 /// 要求 fix->line_length 可以被 4 整除。 /// 扫描线的开始和结束都是 dword 对齐的。 - unsafe fn fast_imageblit(&self, image: &FbImage, mut dst1: VirtAddr, fg: u32, bg: u32) { + unsafe fn fast_imageblit(&self, image: &FbImage, dst1: &mut FrameP, fg: u32, bg: u32) { let bpp = self.current_fb_var().bits_per_pixel; let mut fgx = fg; let mut bgx = bg; @@ -161,13 +153,12 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { color_tab[idx] = (*val & eorx) ^ bgx; } - let mut dst; let mut shift; let mut src; let mut offset = 0; let mut j = 0; + let mut count = 0; for _ in (0..image.height).rev() { - dst = dst1.as_ptr::(); shift = 8; src = offset; match ppw { @@ -175,10 +166,8 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { // 8bpp j = k; while j >= 2 { - *dst = color_tab[(image.data[src] as usize >> 4) & bitmask]; - dst = dst.add(1); - *dst = color_tab[(image.data[src] as usize) & bitmask]; - dst = dst.add(1); + dst1.write(color_tab[(image.data[src] as usize >> 4) & bitmask]); + dst1.write(color_tab[(image.data[src] as usize) & bitmask]); j -= 2; src += 1; } @@ -187,14 +176,10 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { // 16bpp j = k; while j >= 4 { - *dst = color_tab[(image.data[src] as usize >> 6) & bitmask]; - dst = dst.add(1); - *dst = color_tab[(image.data[src] as usize >> 4) & bitmask]; - dst = dst.add(1); - *dst = color_tab[(image.data[src] as usize >> 2) & bitmask]; - dst = dst.add(1); - *dst = color_tab[(image.data[src] as usize) & bitmask]; - dst = dst.add(1); + dst1.write(color_tab[(image.data[src] as usize >> 6) & bitmask]); + dst1.write(color_tab[(image.data[src] as usize >> 4) & bitmask]); + dst1.write(color_tab[(image.data[src] as usize >> 2) & bitmask]); + dst1.write(color_tab[(image.data[src] as usize) & bitmask]); src += 1; j -= 4; } @@ -203,22 +188,14 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { // 32 bpp j = k; while j >= 8 { - *dst = color_tab[(image.data[src] as usize >> 7) & bitmask]; - dst = dst.add(1); - *dst = color_tab[(image.data[src] as usize >> 6) & bitmask]; - dst = dst.add(1); - *dst = color_tab[(image.data[src] as usize >> 5) & bitmask]; - dst = dst.add(1); - *dst = color_tab[(image.data[src] as usize >> 4) & bitmask]; - dst = dst.add(1); - *dst = color_tab[(image.data[src] as usize >> 3) & bitmask]; - dst = dst.add(1); - *dst = color_tab[(image.data[src] as usize >> 2) & bitmask]; - dst = dst.add(1); - *dst = color_tab[(image.data[src] as usize >> 1) & bitmask]; - dst = dst.add(1); - *dst = color_tab[(image.data[src] as usize) & bitmask]; - dst = dst.add(1); + dst1.write(color_tab[(image.data[src] as usize >> 7) & bitmask]); + dst1.write(color_tab[(image.data[src] as usize >> 6) & bitmask]); + dst1.write(color_tab[(image.data[src] as usize >> 5) & bitmask]); + dst1.write(color_tab[(image.data[src] as usize >> 4) & bitmask]); + dst1.write(color_tab[(image.data[src] as usize >> 3) & bitmask]); + dst1.write(color_tab[(image.data[src] as usize >> 2) & bitmask]); + dst1.write(color_tab[(image.data[src] as usize >> 1) & bitmask]); + dst1.write(color_tab[(image.data[src] as usize) & bitmask]); src += 1; j -= 8; } @@ -233,8 +210,7 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { */ while j != 0 { shift -= ppw; - *dst = color_tab[(image.data[src] as usize >> shift) & bitmask]; - dst = dst.add(1); + dst1.write(color_tab[(image.data[src] as usize >> shift) & bitmask]); if shift == 0 { shift = 8; src += 1; @@ -242,22 +218,15 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { j -= 1; } - dst1 += VirtAddr::new(self.current_fb_fix().line_length as usize); + count += 1; + dst1.move_with_offset(self.current_fb_fix().line_length * count); offset += spitch as usize; } } - fn slow_imageblit( - &self, - _image: &FbImage, - _dst1: VirtAddr, - _fg: u32, - _bg: u32, - _start_index: u32, - _pitch_index: u32, - ) { - let mut dst = _dst1.as_ptr::(); + fn slow_imageblit(&self, _image: &FbImage, safe_dst: &mut FrameP, _fg: u32, _bg: u32) { let mut count = 0; + let mut pt_status = FramePointerStatus::Normal; let iter = BitIter::new( _fg, _bg, @@ -268,17 +237,19 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { _image.width, ); for (content, full) in iter { - unsafe { - *dst = content; - - dst = dst.add(1); + match pt_status { + FramePointerStatus::OutOfBuffer => { + return; + } + FramePointerStatus::OutOfScreen => {} + FramePointerStatus::Normal => { + pt_status = safe_dst.write(content); + } } - if full { count += 1; - dst = unsafe { - _dst1.as_ptr::().add((_pitch_index * count) as usize) as *mut u32 - }; + safe_dst.move_with_offset(self.current_fb_fix().line_length * count); + pt_status = FramePointerStatus::Normal; } } } diff --git a/kernel/src/driver/video/fbdev/base/render_helper.rs b/kernel/src/driver/video/fbdev/base/render_helper.rs index 0ce9f80a..25b2d5cb 100644 --- a/kernel/src/driver/video/fbdev/base/render_helper.rs +++ b/kernel/src/driver/video/fbdev/base/render_helper.rs @@ -1,4 +1,8 @@ -use core::slice::Iter; +use core::{ops::Add, slice::Iter}; + +use crate::mm::VirtAddr; + +use super::FbImage; pub struct BitIter<'a> { fgcolor: u32, @@ -170,3 +174,125 @@ impl PixelLineStatus { } } } + +/// # 结构功能 +/// 安全的FrameBufferPointer +/// 使用该结构体访问FrameBuffer可以防止超出FrameBuffer区域的访问 +/// 需要注意,使用该指针写入时,任何超出屏幕的写入都是无效的!即使仍然可以写入显存。 +/// 此外由于FbImage中的x和y变量采用u32类型,所以并未考虑左越界和上越界的安全性(即Image.x<0或Image.y<0的情况) +/// ## 成员 +/// +/// - "dst" : 显存base address,通常是0xffffa1003ff00000 +/// - "limit" : 显存区域上界,可以通过公式计算:limit = dst + 分辨率高*分辨率宽*每个像素的**字节**数。也就是说任何对于显存的访问应该限制在[dst,limit)中 +/// - "current" : 当前相对于start_offset的位移 +/// - "start_offset" : 如果你要渲染某个Image,你可能不是总是从屏幕左上角(0,0)开始渲染,你可能从某个offset开始 +/// - "start_xpos" : 表示你要渲染的Image的x位置的字节位置 +/// - "current_xpos" : 当前渲染的x位置的字节位置 +/// - "limit_xpos" : 最大的渲染x位置的字节位置。 例:假设系统的分辨率为640,位深为24,你需要渲染的Image的x坐标为200,那么start_xpos=200*3=600,current_xpos=200*3+当前行已经渲染像素数*3,limit_xpos=640*3 +#[derive(Debug)] +pub struct FrameP { + dst: VirtAddr, + limit: VirtAddr, + current: usize, + start_offset: usize, + start_xpos: usize, + current_xpos: usize, + limit_xpos: usize, +} + +impl FrameP { + pub fn new( + frame_height: usize, + frame_width: usize, + bitdepth: usize, + dst: VirtAddr, + image: &FbImage, + ) -> Self { + let byte_per_pixel = bitdepth / 8; + let limit = VirtAddr::new(frame_height * frame_width * byte_per_pixel) + dst; + Self { + dst, + limit, + current: 0, + start_offset: start_offset(image, bitdepth as u32, (frame_width * bitdepth / 8) as u32) + as usize, + start_xpos: image.x as usize * byte_per_pixel, + current_xpos: image.x as usize * byte_per_pixel, + limit_xpos: frame_width * byte_per_pixel, + } + } + + /// # 函数功能 + /// 写入某个数据并将指针增大 + pub fn write(&mut self, data: T) -> FramePointerStatus { + // 首先获取数据大小 + let size = size_of::(); + // 复制显存指针防止改变self的dst + let mut dst = self.dst; + + // 你最终要写入的位置实际上是[dst+start_offset+current,dst+start_offset+current+size),所以我们要确定你写入的位置是否超过limit + if self.dst.data() + self.current + self.start_offset + size > self.limit.data() { + return FramePointerStatus::OutOfBuffer; + } + // 我们也不希望你的x超出屏幕右边,超出屏幕右边的部分会被忽略掉,因为如果写入显存会导致内存风险 + else if self.current_xpos + size > self.limit_xpos { + return FramePointerStatus::OutOfScreen; + } + // 如果上面两个检查都通过了,我们就可以写入显存了 + else { + // 这里是写入位置的实际虚拟地址 + dst = dst.add(self.current + self.start_offset); + } + // 写入操作 + unsafe { + *dst.as_ptr::() = data; + } + // 写入后更新current和xpos + self.current += size; + self.current_xpos += size; + // 由于写入正常,我们返回正常的状态 + return FramePointerStatus::Normal; + } + + /// # 函数功能 + /// 移动指针**至**某个offset + /// todo: 当前函数应当只用于换行,否则可能会导致安全性问题,即offset应该是每行像素的开头 + pub fn move_with_offset(&mut self, offset: u32) { + self.current = offset as usize; + // let x_pos=self.current%self.limit_xpos; + // match x_pos{ + // n if n{ + // // send_to_default_serial8250_port(format!("Sended by function move_with_offset: Check if there is misusage of offset,the image.x is:{:?} while the xpos indicated by the offset is:{:?},current FP:{:?}\n",self.start_offset,x_pos,self).as_bytes()); + // } + // n if n>=self.limit_xpos=>{ + // // send_to_default_serial8250_port(format!("Sended by function move_with_offset: Check if there is misusage of offset,The offset:{:?} is so large that it would exceed the limit of frame buffer\n",offset).as_bytes()); + // } + // _=>{ + + // } + // } + self.current_xpos = self.start_xpos; + } +} + +pub enum FramePointerStatus { + /// 表示状态正常 + Normal, + /// 超出屏幕,一直到换行时才应该恢复到正常状态 + OutOfScreen, + /// 超出缓存,此时应当立即停止渲染 + OutOfBuffer, +} + +pub fn start_offset(image: &FbImage, bitdepth: u32, line_length: u32) -> u32 { + let x = image.x; + let y = image.y; + let mut bitstart = (y * line_length * 8) + (x * bitdepth); + let byte_per_pixel = core::mem::size_of::() as u32; + // 位转字节 + bitstart /= 8; + + // 对齐到像素字节大小 + bitstart &= !(byte_per_pixel - 1); + return bitstart; +}