Add support for graphical debug, to be used during ACPI phase
This commit is contained in:
parent
133c433f60
commit
819f77daf3
|
@ -30,6 +30,7 @@ default-features = false
|
|||
default = ["acpi"]
|
||||
acpi = []
|
||||
doc = []
|
||||
graphical_debug = []
|
||||
live = []
|
||||
multi_core = []
|
||||
pti = []
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,41 @@
|
|||
use core::fmt;
|
||||
use spin::MutexGuard;
|
||||
|
||||
use devices::uart_16550::SerialPort;
|
||||
use syscall::io::Pio;
|
||||
|
||||
use super::device::serial::COM1;
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
use super::graphical_debug::{DEBUG_DISPLAY, DebugDisplay};
|
||||
|
||||
pub struct Writer<'a> {
|
||||
serial: MutexGuard<'a, SerialPort<Pio<u8>>>,
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
display: MutexGuard<'a, Option<DebugDisplay>>
|
||||
}
|
||||
|
||||
impl<'a> Writer<'a> {
|
||||
pub fn new() -> Writer<'a> {
|
||||
Writer {
|
||||
serial: COM1.lock(),
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
display: DEBUG_DISPLAY.lock(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Write for Writer<'a> {
|
||||
#[cfg(not(feature = "graphical_debug"))]
|
||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||
self.serial.write_str(s)
|
||||
}
|
||||
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||
if let Some(ref mut display) = *self.display {
|
||||
display.write_str(s)
|
||||
} else {
|
||||
self.serial.write_str(s)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
use core::fmt;
|
||||
|
||||
use super::Display;
|
||||
|
||||
pub struct DebugDisplay {
|
||||
display: Display,
|
||||
x: usize,
|
||||
y: usize,
|
||||
w: usize,
|
||||
h: usize,
|
||||
}
|
||||
|
||||
impl DebugDisplay {
|
||||
pub fn new(display: Display) -> DebugDisplay {
|
||||
let w = display.width/8;
|
||||
let h = display.height/16;
|
||||
DebugDisplay {
|
||||
display,
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: w,
|
||||
h: h,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&mut self, c: char) {
|
||||
if self.x >= self.w || c == '\n' {
|
||||
self.x = 0;
|
||||
self.y += 1;
|
||||
}
|
||||
|
||||
if self.y >= self.h {
|
||||
let new_y = self.h - 1;
|
||||
let d_y = self.y - new_y;
|
||||
|
||||
self.display.scroll(d_y * 16);
|
||||
|
||||
self.display.rect(
|
||||
0, (self.h - d_y) * 16,
|
||||
self.w * 8, d_y * 16,
|
||||
0x000000
|
||||
);
|
||||
|
||||
self.display.sync(
|
||||
0, 0,
|
||||
self.w * 8, self.h * 16
|
||||
);
|
||||
|
||||
self.y = new_y;
|
||||
}
|
||||
|
||||
if c != '\n' {
|
||||
self.display.rect(
|
||||
self.x * 8, self.y * 16,
|
||||
8, 16,
|
||||
0x000000
|
||||
);
|
||||
|
||||
self.display.char(
|
||||
self.x * 8, self.y * 16,
|
||||
c,
|
||||
0xFFFFFF
|
||||
);
|
||||
|
||||
self.display.sync(
|
||||
self.x, self.y,
|
||||
8, 16
|
||||
);
|
||||
|
||||
self.x += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for DebugDisplay {
|
||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||
for c in s.chars() {
|
||||
self.write(c);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
use alloc::allocator::{Alloc, Layout};
|
||||
use alloc::heap::Heap;
|
||||
use core::{cmp, slice};
|
||||
|
||||
use super::FONT;
|
||||
use super::primitive::{fast_set32, fast_set64, fast_copy};
|
||||
|
||||
/// 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: usize) -> Display {
|
||||
let size = width * height;
|
||||
let offscreen = unsafe { Heap.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap() };
|
||||
unsafe { fast_set64(offscreen as *mut u64, 0, size/2) };
|
||||
Display {
|
||||
width: width,
|
||||
height: height,
|
||||
onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) },
|
||||
offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }
|
||||
}
|
||||
}
|
||||
|
||||
/// 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, y);
|
||||
let end_y = cmp::min(self.height, y + h);
|
||||
|
||||
let start_x = cmp::min(self.width, x);
|
||||
let len = cmp::min(self.width, x + w) - start_x;
|
||||
|
||||
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
|
||||
|
||||
let stride = self.width * 4;
|
||||
|
||||
let offset = y * stride + start_x * 4;
|
||||
offscreen_ptr += offset;
|
||||
|
||||
let mut rows = end_y - start_y;
|
||||
while rows > 0 {
|
||||
unsafe {
|
||||
fast_set32(offscreen_ptr as *mut u32, color, len);
|
||||
}
|
||||
offscreen_ptr += stride;
|
||||
rows -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Invert a rectangle
|
||||
pub fn invert(&mut self, x: usize, y: usize, w: usize, h: usize) {
|
||||
let start_y = cmp::min(self.height, y);
|
||||
let end_y = cmp::min(self.height, y + h);
|
||||
|
||||
let start_x = cmp::min(self.width, x);
|
||||
let len = cmp::min(self.width, x + w) - start_x;
|
||||
|
||||
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
|
||||
|
||||
let stride = self.width * 4;
|
||||
|
||||
let offset = y * stride + start_x * 4;
|
||||
offscreen_ptr += offset;
|
||||
|
||||
let mut rows = end_y - start_y;
|
||||
while rows > 0 {
|
||||
let mut row_ptr = offscreen_ptr;
|
||||
let mut cols = len;
|
||||
while cols > 0 {
|
||||
unsafe {
|
||||
let color = *(row_ptr as *mut u32);
|
||||
*(row_ptr as *mut u32) = !color;
|
||||
}
|
||||
row_ptr += 4;
|
||||
cols -= 1;
|
||||
}
|
||||
offscreen_ptr += stride;
|
||||
rows -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a character
|
||||
pub fn char(&mut self, x: usize, y: usize, character: char, color: u32) {
|
||||
if x + 8 <= self.width && y + 16 <= self.height {
|
||||
let mut dst = self.offscreen.as_mut_ptr() as usize + (y * self.width + x) * 4;
|
||||
|
||||
let font_i = 16 * (character as usize);
|
||||
if font_i + 16 <= FONT.len() {
|
||||
for row in 0..16 {
|
||||
let row_data = FONT[font_i + row];
|
||||
for col in 0..8 {
|
||||
if (row_data >> (7 - col)) & 1 == 1 {
|
||||
unsafe { *((dst + col * 4) as *mut u32) = color; }
|
||||
}
|
||||
}
|
||||
dst += self.width * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll the screen
|
||||
pub fn scroll(&mut self, lines: usize) {
|
||||
let offset = cmp::min(self.height, lines) * self.width;
|
||||
let size = self.offscreen.len() - offset;
|
||||
unsafe {
|
||||
let to = self.offscreen.as_mut_ptr();
|
||||
let from = to.offset(offset as isize);
|
||||
fast_copy(to as *mut u8, from as *const u8, size * 4);
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy from offscreen to onscreen
|
||||
pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize) {
|
||||
let start_y = cmp::min(self.height, y);
|
||||
let end_y = cmp::min(self.height, y + h);
|
||||
|
||||
let start_x = cmp::min(self.width, x);
|
||||
let len = (cmp::min(self.width, x + w) - start_x) * 4;
|
||||
|
||||
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_copy(onscreen_ptr as *mut u8, offscreen_ptr as *const u8, len);
|
||||
}
|
||||
offscreen_ptr += stride;
|
||||
onscreen_ptr += stride;
|
||||
rows -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Display {
|
||||
fn drop(&mut self) {
|
||||
unsafe { Heap.dealloc(self.offscreen.as_mut_ptr() as *mut u8, Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) };
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
use spin::Mutex;
|
||||
|
||||
use memory::Frame;
|
||||
use paging::{ActivePageTable, Page, PhysicalAddress, VirtualAddress};
|
||||
use paging::entry::EntryFlags;
|
||||
|
||||
pub use self::debug::DebugDisplay;
|
||||
use self::display::Display;
|
||||
use self::mode_info::VBEModeInfo;
|
||||
use self::primitive::fast_set64;
|
||||
|
||||
pub mod debug;
|
||||
pub mod display;
|
||||
pub mod mode_info;
|
||||
pub mod primitive;
|
||||
|
||||
pub static FONT: &'static [u8] = include_bytes!("../../../../res/unifont.font");
|
||||
|
||||
pub static DEBUG_DISPLAY: Mutex<Option<DebugDisplay>> = Mutex::new(None);
|
||||
|
||||
pub fn init(active_table: &mut ActivePageTable) {
|
||||
//TODO: Unmap mode_info and map physbaseptr in kernel space
|
||||
|
||||
println!("Starting graphical debug");
|
||||
|
||||
let width;
|
||||
let height;
|
||||
let physbaseptr;
|
||||
|
||||
{
|
||||
let mode_info_addr = 0x5200;
|
||||
|
||||
{
|
||||
let page = Page::containing_address(VirtualAddress::new(mode_info_addr));
|
||||
let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get()));
|
||||
let result = active_table.map_to(page, frame, EntryFlags::PRESENT | EntryFlags::NO_EXECUTE);
|
||||
result.flush(active_table);
|
||||
}
|
||||
|
||||
let mode_info = unsafe { &*(mode_info_addr as *const VBEModeInfo) };
|
||||
|
||||
width = mode_info.xresolution as usize;
|
||||
height = mode_info.yresolution as usize;
|
||||
physbaseptr = mode_info.physbaseptr as usize;
|
||||
}
|
||||
|
||||
{
|
||||
let size = width * height;
|
||||
|
||||
{
|
||||
let start_page = Page::containing_address(VirtualAddress::new(physbaseptr));
|
||||
let end_page = Page::containing_address(VirtualAddress::new(physbaseptr + size * 4));
|
||||
for page in Page::range_inclusive(start_page, end_page) {
|
||||
let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get()));
|
||||
let result = active_table.map_to(page, frame, EntryFlags::PRESENT | EntryFlags::NO_EXECUTE | EntryFlags::WRITABLE | EntryFlags::HUGE_PAGE);
|
||||
result.flush(active_table);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { fast_set64(physbaseptr as *mut u64, 0, size/2) };
|
||||
|
||||
*DEBUG_DISPLAY.lock() = Some(DebugDisplay::new(Display::new(width, height, physbaseptr)));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fini(_active_table: &mut ActivePageTable) {
|
||||
//TODO: Unmap physbaseptr
|
||||
*DEBUG_DISPLAY.lock() = None;
|
||||
|
||||
println!("Finished graphical debug");
|
||||
}
|
|
@ -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,
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#[cfg(target_arch = "x86_64")]
|
||||
#[inline(always)]
|
||||
#[cold]
|
||||
pub unsafe fn fast_copy(dst: *mut u8, src: *const u8, len: usize) {
|
||||
asm!("cld
|
||||
rep movsb"
|
||||
:
|
||||
: "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
|
||||
: "cc", "memory", "rdi", "rsi", "rcx"
|
||||
: "intel", "volatile");
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[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", "rdi", "rsi", "rcx"
|
||||
: "intel", "volatile");
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[inline(always)]
|
||||
#[cold]
|
||||
pub unsafe fn fast_set32(dst: *mut u32, src: u32, len: usize) {
|
||||
asm!("cld
|
||||
rep stosd"
|
||||
:
|
||||
: "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len)
|
||||
: "cc", "memory", "rdi", "rcx"
|
||||
: "intel", "volatile");
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[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", "rdi", "rcx"
|
||||
: "intel", "volatile");
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
macro_rules! print {
|
||||
($($arg:tt)*) => ({
|
||||
use core::fmt::Write;
|
||||
let _ = write!($crate::arch::device::serial::COM1.lock(), $($arg)*);
|
||||
let _ = write!($crate::arch::debug::Writer::new(), $($arg)*);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
#[macro_use]
|
||||
pub mod macros;
|
||||
|
||||
/// Debugging support
|
||||
pub mod debug;
|
||||
|
||||
/// Devices
|
||||
pub mod device;
|
||||
|
||||
/// Global descriptor table
|
||||
pub mod gdt;
|
||||
|
||||
/// Graphical debug
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
mod graphical_debug;
|
||||
|
||||
/// Interrupt descriptor table
|
||||
pub mod idt;
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, AtomicUsize, ATOMIC_USIZE
|
|||
use allocator;
|
||||
#[cfg(feature = "acpi")]
|
||||
use acpi;
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
use arch::x86_64::graphical_debug;
|
||||
use arch::x86_64::pti;
|
||||
use device;
|
||||
use gdt;
|
||||
|
@ -100,6 +102,10 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
|||
// Setup kernel heap
|
||||
allocator::init(&mut active_table);
|
||||
|
||||
// Use graphical debug
|
||||
#[cfg(feature="graphical_debug")]
|
||||
graphical_debug::init(&mut active_table);
|
||||
|
||||
// Initialize devices
|
||||
device::init(&mut active_table);
|
||||
|
||||
|
@ -113,6 +119,10 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
|||
// Initialize memory functions after core has loaded
|
||||
memory::init_noncore();
|
||||
|
||||
// Stop graphical debug
|
||||
#[cfg(feature="graphical_debug")]
|
||||
graphical_debug::fini(&mut active_table);
|
||||
|
||||
BSP_READY.store(true, Ordering::SeqCst);
|
||||
|
||||
slice::from_raw_parts(env_base as *const u8, env_size)
|
||||
|
|
Loading…
Reference in New Issue