Files
RedBear-OS/src/os/bios/vbe.rs
T
2022-02-08 16:32:12 -07:00

138 lines
3.7 KiB
Rust

use core::ptr;
use log::error;
use crate::os::OsVideoMode;
use super::{ThunkData, VBE_CARD_INFO_ADDR, VBE_MODE_INFO_ADDR};
#[derive(Clone, Copy, Debug)]
#[repr(packed)]
pub struct VbeCardInfo {
pub signature: [u8; 4],
pub version: u16,
pub oemstring: u32,
pub capabilities: u32,
pub videomodeptr: u32,
pub totalmemory: u16,
pub oemsoftwarerev: u16,
pub oemvendornameptr: u32,
pub oemproductnameptr: u32,
pub oemproductrevptr: u32,
pub reserved: [u8; 222],
pub oemdata: [u8; 256],
}
#[derive(Clone, Copy, Debug)]
#[repr(packed)]
pub struct VbeModeInfo {
pub attributes: u16,
pub win_a: u8,
pub win_b: u8,
pub granularity: u16,
pub winsize: u16,
pub segment_a: u16,
pub segment_b: u16,
pub winfuncptr: u32,
pub bytesperscanline: u16,
pub xresolution: u16,
pub yresolution: u16,
pub xcharsize: u8,
pub ycharsize: u8,
pub numberofplanes: u8,
pub bitsperpixel: u8,
pub numberofbanks: u8,
pub memorymodel: u8,
pub banksize: u8,
pub numberofimagepages: u8,
pub unused: u8,
pub redmasksize: u8,
pub redfieldposition: u8,
pub greenmasksize: u8,
pub greenfieldposition: u8,
pub bluemasksize: u8,
pub bluefieldposition: u8,
pub rsvdmasksize: u8,
pub rsvdfieldposition: u8,
pub directcolormodeinfo: u8,
pub physbaseptr: u32,
pub offscreenmemoryoffset: u32,
pub offscreenmemsize: u16,
pub reserved: [u8; 206],
}
pub struct VideoModeIter {
thunk10: extern "C" fn(),
mode_ptr: *const u16,
}
impl VideoModeIter {
pub fn new(thunk10: extern "C" fn()) -> Self {
// Get card info
let mut data = ThunkData::new();
data.eax = 0x4F00;
data.edi = VBE_CARD_INFO_ADDR as u32;
unsafe { data.with(thunk10); }
let mode_ptr = if data.eax == 0x004F {
let card_info = unsafe { ptr::read(VBE_CARD_INFO_ADDR as *const VbeCardInfo) };
card_info.videomodeptr as *const u16
} else {
error!("Failed to read VBE card info: 0x{:04X}", { data.eax });
ptr::null()
};
Self {
thunk10,
mode_ptr
}
}
}
impl Iterator for VideoModeIter {
type Item = OsVideoMode;
fn next(&mut self) -> Option<Self::Item> {
if self.mode_ptr.is_null() {
return None;
}
loop {
// Set bit 14 to get linear frame buffer
let mode = unsafe { *self.mode_ptr } | (1 << 14);
if mode == 0xFFFF {
return None;
}
self.mode_ptr = unsafe { self.mode_ptr.add(1) };
// Get mode info
let mut data = ThunkData::new();
data.eax = 0x4F01;
data.ecx = mode as u32;
data.edi = VBE_MODE_INFO_ADDR as u32;
unsafe { data.with(self.thunk10); }
if data.eax == 0x004F {
let mode_info = unsafe { ptr::read(VBE_MODE_INFO_ADDR as *const VbeModeInfo) };
// We only support 32-bits per pixel modes
if mode_info.bitsperpixel != 32 {
continue;
}
let width = mode_info.xresolution as u32;
let height = mode_info.yresolution as u32;
//TODO: support resolutions that are not perfect multiples of 4
if width % 4 != 0 {
continue;
}
return Some(OsVideoMode {
id: mode as u32,
width,
height,
base: mode_info.physbaseptr as u64,
});
} else {
error!("Failed to read VBE mode 0x{:04X} info: 0x{:04X}", mode, { data.eax });
}
}
}
}