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"]
|
default = ["acpi"]
|
||||||
acpi = []
|
acpi = []
|
||||||
doc = []
|
doc = []
|
||||||
|
graphical_debug = []
|
||||||
live = []
|
live = []
|
||||||
multi_core = []
|
multi_core = []
|
||||||
pti = []
|
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 {
|
macro_rules! print {
|
||||||
($($arg:tt)*) => ({
|
($($arg:tt)*) => ({
|
||||||
use core::fmt::Write;
|
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]
|
#[macro_use]
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
||||||
|
/// Debugging support
|
||||||
|
pub mod debug;
|
||||||
|
|
||||||
/// Devices
|
/// Devices
|
||||||
pub mod device;
|
pub mod device;
|
||||||
|
|
||||||
/// Global descriptor table
|
/// Global descriptor table
|
||||||
pub mod gdt;
|
pub mod gdt;
|
||||||
|
|
||||||
|
/// Graphical debug
|
||||||
|
#[cfg(feature = "graphical_debug")]
|
||||||
|
mod graphical_debug;
|
||||||
|
|
||||||
/// Interrupt descriptor table
|
/// Interrupt descriptor table
|
||||||
pub mod idt;
|
pub mod idt;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, AtomicUsize, ATOMIC_USIZE
|
||||||
use allocator;
|
use allocator;
|
||||||
#[cfg(feature = "acpi")]
|
#[cfg(feature = "acpi")]
|
||||||
use acpi;
|
use acpi;
|
||||||
|
#[cfg(feature = "graphical_debug")]
|
||||||
|
use arch::x86_64::graphical_debug;
|
||||||
use arch::x86_64::pti;
|
use arch::x86_64::pti;
|
||||||
use device;
|
use device;
|
||||||
use gdt;
|
use gdt;
|
||||||
|
@ -100,6 +102,10 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||||
// Setup kernel heap
|
// Setup kernel heap
|
||||||
allocator::init(&mut active_table);
|
allocator::init(&mut active_table);
|
||||||
|
|
||||||
|
// Use graphical debug
|
||||||
|
#[cfg(feature="graphical_debug")]
|
||||||
|
graphical_debug::init(&mut active_table);
|
||||||
|
|
||||||
// Initialize devices
|
// Initialize devices
|
||||||
device::init(&mut active_table);
|
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
|
// Initialize memory functions after core has loaded
|
||||||
memory::init_noncore();
|
memory::init_noncore();
|
||||||
|
|
||||||
|
// Stop graphical debug
|
||||||
|
#[cfg(feature="graphical_debug")]
|
||||||
|
graphical_debug::fini(&mut active_table);
|
||||||
|
|
||||||
BSP_READY.store(true, Ordering::SeqCst);
|
BSP_READY.store(true, Ordering::SeqCst);
|
||||||
|
|
||||||
slice::from_raw_parts(env_base as *const u8, env_size)
|
slice::from_raw_parts(env_base as *const u8, env_size)
|
||||||
|
|
Loading…
Reference in New Issue