mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
fix(video): 增加了对frame buffer操作的安全检查 (#1034)
fix(video): 增加了对frame buffer操作的安全检查
This commit is contained in:
parent
5d54e74768
commit
f5c732d8dc
@ -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::<u32>();
|
||||
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::<u32>();
|
||||
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::<u8>().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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<T>(&mut self, data: T) -> FramePointerStatus {
|
||||
// 首先获取数据大小
|
||||
let size = size_of::<T>();
|
||||
// 复制显存指针防止改变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::<T>() = 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<self.start_xpos=>{
|
||||
// // 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::<u32>() as u32;
|
||||
// 位转字节
|
||||
bitstart /= 8;
|
||||
|
||||
// 对齐到像素字节大小
|
||||
bitstart &= !(byte_per_pixel - 1);
|
||||
return bitstart;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user