video: x86_64 switch-over from boot fb to virtio-gpu if present
This commit is contained in:
parent
6bd3d387bf
commit
8c09e046e9
@ -4,6 +4,9 @@ use bytemuck::{Pod, Zeroable};
|
|||||||
|
|
||||||
use crate::{AvailableRegion, IterableMemoryMap, LoadProtocolHeader};
|
use crate::{AvailableRegion, IterableMemoryMap, LoadProtocolHeader};
|
||||||
|
|
||||||
|
pub const PIXEL_R8G8B8A8: u32 = 1;
|
||||||
|
pub const PIXEL_B8G8R8A8: u32 = 2;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct LoadProtocol {
|
pub struct LoadProtocol {
|
||||||
@ -46,6 +49,8 @@ pub struct FramebufferOption {
|
|||||||
pub res_stride: u64,
|
pub res_stride: u64,
|
||||||
pub res_address: u64,
|
pub res_address: u64,
|
||||||
pub res_size: u64,
|
pub res_size: u64,
|
||||||
|
pub res_format: u32,
|
||||||
|
pub _0: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AvailableRegion for AvailableMemoryRegion {
|
impl AvailableRegion for AvailableMemoryRegion {
|
||||||
|
@ -14,7 +14,9 @@ use log::{debug, error, info};
|
|||||||
use uefi::{
|
use uefi::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
proto::{
|
proto::{
|
||||||
console::gop::GraphicsOutput, device_path::DevicePath, loaded_image::LoadedImage,
|
console::gop::{GraphicsOutput, PixelFormat},
|
||||||
|
device_path::DevicePath,
|
||||||
|
loaded_image::LoadedImage,
|
||||||
media::fs::SimpleFileSystem,
|
media::fs::SimpleFileSystem,
|
||||||
},
|
},
|
||||||
table::{
|
table::{
|
||||||
@ -24,7 +26,7 @@ use uefi::{
|
|||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
use yboot_proto::{
|
use yboot_proto::{
|
||||||
v1::{AvailableMemoryRegion, FramebufferOption},
|
v1::{self, AvailableMemoryRegion, FramebufferOption},
|
||||||
LoadProtocolV1, LOADER_MAGIC,
|
LoadProtocolV1, LOADER_MAGIC,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -47,11 +49,18 @@ fn setup_framebuffer(bs: &BootServices, fb: &mut FramebufferOption) -> Result<()
|
|||||||
|
|
||||||
let mut result = gop.frame_buffer();
|
let mut result = gop.frame_buffer();
|
||||||
|
|
||||||
|
let format = match mode.info().pixel_format() {
|
||||||
|
PixelFormat::Bgr => v1::PIXEL_B8G8R8A8,
|
||||||
|
PixelFormat::Rgb => v1::PIXEL_R8G8B8A8,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
fb.res_width = fb.req_width;
|
fb.res_width = fb.req_width;
|
||||||
fb.res_height = fb.req_height;
|
fb.res_height = fb.req_height;
|
||||||
fb.res_address = result.as_mut_ptr() as _;
|
fb.res_address = result.as_mut_ptr() as _;
|
||||||
fb.res_stride = mode.info().stride() as u64 * 4;
|
fb.res_stride = mode.info().stride() as u64 * 4;
|
||||||
fb.res_size = result.size() as _;
|
fb.res_size = result.size() as _;
|
||||||
|
fb.res_format = format;
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Framebuffer: {}x{} @ {:#x}",
|
"Framebuffer: {}x{} @ {:#x}",
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
use core::{future::poll_fn, mem::size_of, ptr::null_mut, task::Poll};
|
use core::{future::poll_fn, mem::size_of, ptr::null_mut, task::Poll};
|
||||||
|
|
||||||
use alloc::{
|
use alloc::collections::{BTreeMap, BTreeSet};
|
||||||
collections::{BTreeMap, BTreeSet},
|
|
||||||
vec::Vec,
|
|
||||||
};
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use libk_mm::{
|
use libk_mm::{
|
||||||
address::{AsPhysicalAddress, PhysicalAddress},
|
address::{AsPhysicalAddress, PhysicalAddress},
|
||||||
@ -96,6 +93,7 @@ pub struct QueuePair {
|
|||||||
pub struct PrpList {
|
pub struct PrpList {
|
||||||
prp1: PhysicalRegionPage,
|
prp1: PhysicalRegionPage,
|
||||||
prp2: PhysicalRegionPage,
|
prp2: PhysicalRegionPage,
|
||||||
|
#[allow(unused)]
|
||||||
list: Option<PageBox<[PhysicalAddress]>>,
|
list: Option<PageBox<[PhysicalAddress]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
use alloc::{format, string::String};
|
use alloc::{format, string::String};
|
||||||
use libk::vfs::{block::BlockDevice, impls::MemoryDirectory, CharDevice, Node, NodeFlags, NodeRef};
|
use libk::vfs::{
|
||||||
|
block::BlockDevice,
|
||||||
|
impls::{fixed_symlink, MemoryDirectory},
|
||||||
|
AccessToken, CharDevice, Node, NodeFlags, NodeRef,
|
||||||
|
};
|
||||||
use libk_util::OneTimeInit;
|
use libk_util::OneTimeInit;
|
||||||
use yggdrasil_abi::error::Error;
|
use yggdrasil_abi::error::Error;
|
||||||
|
|
||||||
@ -39,6 +43,16 @@ pub fn root() -> &'static NodeRef {
|
|||||||
DEVFS_ROOT.get()
|
DEVFS_ROOT.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_node(name: &str, node: NodeRef) -> Result<(), Error> {
|
||||||
|
log::info!("Update node: {name}");
|
||||||
|
|
||||||
|
let root = DEVFS_ROOT.get();
|
||||||
|
root.remove_file(name, unsafe { AccessToken::authorized() })
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
root.add_child(name, fixed_symlink(node))
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a character device with a custom name
|
/// Adds a character device with a custom name
|
||||||
pub fn add_named_char_device(dev: &'static dyn CharDevice, name: String) -> Result<(), Error> {
|
pub fn add_named_char_device(dev: &'static dyn CharDevice, name: String) -> Result<(), Error> {
|
||||||
log::info!("Add char device: {}", name);
|
log::info!("Add char device: {}", name);
|
||||||
@ -52,16 +66,21 @@ pub fn add_named_char_device(dev: &'static dyn CharDevice, name: String) -> Resu
|
|||||||
pub fn add_named_block_device<S: Into<String>>(
|
pub fn add_named_block_device<S: Into<String>>(
|
||||||
dev: &'static dyn BlockDevice,
|
dev: &'static dyn BlockDevice,
|
||||||
name: S,
|
name: S,
|
||||||
) -> Result<(), Error> {
|
) -> Result<NodeRef, Error> {
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
log::info!("Add block device: {}", name);
|
log::info!("Add block device: {}", name);
|
||||||
|
|
||||||
let node = Node::block(dev, NodeFlags::IN_MEMORY_PROPS);
|
let node = Node::block(dev, NodeFlags::IN_MEMORY_PROPS);
|
||||||
|
|
||||||
DEVFS_ROOT.get().add_child(name, node)
|
DEVFS_ROOT.get().add_child(name, node.clone())?;
|
||||||
|
|
||||||
|
Ok(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_block_device(dev: &'static dyn BlockDevice, kind: BlockDeviceType) -> Result<(), Error> {
|
pub fn add_block_device(
|
||||||
|
dev: &'static dyn BlockDevice,
|
||||||
|
kind: BlockDeviceType,
|
||||||
|
) -> Result<NodeRef, Error> {
|
||||||
static FB_COUNT: AtomicUsize = AtomicUsize::new(0);
|
static FB_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
let (count, prefix) = match kind {
|
let (count, prefix) = match kind {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use alloc::vec::Vec;
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use libk::{device::display::PixelFormat, error::Error};
|
use libk::{device::display::PixelFormat, error::Error};
|
||||||
use libk_mm::{address::PhysicalAddress, PageBox};
|
use libk_mm::{address::PhysicalAddress, PageBox};
|
||||||
|
@ -5,16 +5,14 @@ extern crate alloc;
|
|||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
use alloc::{boxed::Box, vec::Vec};
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use command::{ControlLock, ScanoutInfo};
|
||||||
use command::{ControlLock, Rect, ScanoutInfo};
|
|
||||||
use device_api::Device;
|
use device_api::Device;
|
||||||
use libk::device::display::{
|
use libk::device::display::{
|
||||||
register_display_device, DisplayDevice, DisplayDeviceWrapper, DisplayMode, DisplayOwner,
|
register_display_device, DisplayDevice, DisplayDeviceWrapper, DisplayMode, DisplayOwner,
|
||||||
FramebufferInfo, PixelFormat,
|
DriverFlags, FramebufferInfo, PixelFormat,
|
||||||
};
|
};
|
||||||
use libk_mm::{
|
use libk_mm::{
|
||||||
address::{PhysicalAddress, Virtualize},
|
address::{PhysicalAddress, Virtualize},
|
||||||
device::RawDeviceMemoryMapping,
|
|
||||||
phys,
|
phys,
|
||||||
table::MapAttributes,
|
table::MapAttributes,
|
||||||
PageBox, PageProvider, L3_PAGE_SIZE,
|
PageBox, PageProvider, L3_PAGE_SIZE,
|
||||||
@ -59,6 +57,7 @@ struct Config {
|
|||||||
|
|
||||||
pub struct VirtioGpu<T: Transport> {
|
pub struct VirtioGpu<T: Transport> {
|
||||||
transport: IrqSafeSpinlock<T>,
|
transport: IrqSafeSpinlock<T>,
|
||||||
|
#[allow(unused)]
|
||||||
pci_device_info: Option<PciDeviceInfo>,
|
pci_device_info: Option<PciDeviceInfo>,
|
||||||
|
|
||||||
queues: OneTimeInit<Queues>,
|
queues: OneTimeInit<Queues>,
|
||||||
@ -296,19 +295,23 @@ impl<T: Transport + 'static> PageProvider for VirtioGpu<T> {
|
|||||||
|
|
||||||
fn clone_page(
|
fn clone_page(
|
||||||
&self,
|
&self,
|
||||||
offset: u64,
|
_offset: u64,
|
||||||
src_phys: PhysicalAddress,
|
_src_phys: PhysicalAddress,
|
||||||
src_attrs: MapAttributes,
|
_src_attrs: MapAttributes,
|
||||||
) -> Result<PhysicalAddress, Error> {
|
) -> Result<PhysicalAddress, Error> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release_page(&self, offset: u64, phys: PhysicalAddress) -> Result<(), Error> {
|
fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Transport + 'static> DisplayDevice for VirtioGpu<T> {
|
impl<T: Transport + 'static> DisplayDevice for VirtioGpu<T> {
|
||||||
|
fn driver_flags(&self) -> DriverFlags {
|
||||||
|
DriverFlags::REPLACES_BOOT_FRAMEBUFFER
|
||||||
|
}
|
||||||
|
|
||||||
fn lock(&self, owner: DisplayOwner) -> Result<(), Error> {
|
fn lock(&self, owner: DisplayOwner) -> Result<(), Error> {
|
||||||
let mut config = self.config.write();
|
let mut config = self.config.write();
|
||||||
if config.owner == owner {
|
if config.owner == owner {
|
||||||
@ -341,7 +344,7 @@ impl<T: Transport + 'static> DisplayDevice for VirtioGpu<T> {
|
|||||||
self.flush()
|
self.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_display_mode(&self, index: u32, double_buffer: bool) -> Result<(), Error> {
|
fn set_display_mode(&self, _index: u32, _double_buffer: bool) -> Result<(), Error> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,7 +386,7 @@ impl<T: Transport + 'static> DisplayDevice for VirtioGpu<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_display_modes(&self, modes: &mut [MaybeUninit<DisplayMode>]) -> Result<usize, Error> {
|
fn query_display_modes(&self, _modes: &mut [MaybeUninit<DisplayMode>]) -> Result<usize, Error> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ use device_api::Device;
|
|||||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider};
|
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider};
|
||||||
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
|
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
|
||||||
use yggdrasil_abi::{
|
use yggdrasil_abi::{
|
||||||
|
bitflags,
|
||||||
error::Error,
|
error::Error,
|
||||||
io::{DeviceRequest, Framebuffer},
|
io::{DeviceRequest, Framebuffer},
|
||||||
process::ProcessId,
|
process::ProcessId,
|
||||||
@ -17,6 +18,22 @@ use yggdrasil_abi::{
|
|||||||
|
|
||||||
use crate::{task::thread::Thread, vfs::block::BlockDevice};
|
use crate::{task::thread::Thread, vfs::block::BlockDevice};
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// Init-time display driver flags
|
||||||
|
pub struct DriverFlags: u32 {
|
||||||
|
/// If set, replaces a previosly present boot framebuffer if one was present
|
||||||
|
const REPLACES_BOOT_FRAMEBUFFER: bit 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct Color {
|
||||||
|
pub r: u8,
|
||||||
|
pub g: u8,
|
||||||
|
pub b: u8,
|
||||||
|
pub a: u8,
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents the current lock holder for a display device
|
/// Represents the current lock holder for a display device
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum DisplayOwner {
|
pub enum DisplayOwner {
|
||||||
@ -81,6 +98,9 @@ pub struct FramebufferInfo {
|
|||||||
|
|
||||||
/// Abstract display device interface
|
/// Abstract display device interface
|
||||||
pub trait DisplayDevice: Device + PageProvider {
|
pub trait DisplayDevice: Device + PageProvider {
|
||||||
|
/// Returns the init-time driver flags
|
||||||
|
fn driver_flags(&self) -> DriverFlags;
|
||||||
|
|
||||||
/// Returns the active display mode
|
/// Returns the active display mode
|
||||||
fn active_display_mode(&self) -> Option<DisplayMode>;
|
fn active_display_mode(&self) -> Option<DisplayMode>;
|
||||||
/// Returns the list of available display modes
|
/// Returns the list of available display modes
|
||||||
@ -221,3 +241,81 @@ impl Deref for DisplayDeviceWrapper {
|
|||||||
self.inner
|
self.inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _0: () = const {
|
||||||
|
let c1 = Color::from_rgba_u32(0x11223344);
|
||||||
|
let c2 = Color::from_rgb_u32(0x112233);
|
||||||
|
if c1.r != 0x11 || c1.g != 0x22 || c1.b != 0x33 || c1.a != 0x44 {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
if c2.r != 0x11 || c2.g != 0x22 || c2.b != 0x33 {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
// if color.to_le_rgba_u32() != 0x11223344 {
|
||||||
|
// panic!();
|
||||||
|
// }
|
||||||
|
// assert_eq!(color.to_rgba_u32(), 0x11223344);
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
pub const BLACK: Self = Self::from_rgb_u32(0x000000);
|
||||||
|
pub const WHITE: Self = Self::from_rgb_u32(0xFFFFFF);
|
||||||
|
pub const RED: Self = Self::from_rgb_u32(0xFF0000);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_rgba_u32(v: u32) -> Self {
|
||||||
|
// 0x11223344 -> [0x44, 0x33, 0x22, 0x11]
|
||||||
|
// a b g r
|
||||||
|
let x = v.to_le_bytes();
|
||||||
|
Self {
|
||||||
|
a: x[0],
|
||||||
|
b: x[1],
|
||||||
|
g: x[2],
|
||||||
|
r: x[3],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_rgb_u32(v: u32) -> Self {
|
||||||
|
let x = v.to_le_bytes();
|
||||||
|
Self {
|
||||||
|
a: u8::MAX,
|
||||||
|
b: x[0],
|
||||||
|
g: x[1],
|
||||||
|
r: x[2],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn to_rgba_u32(self) -> u32 {
|
||||||
|
u32::from_ne_bytes([self.r, self.g, self.b, self.a])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn to_bgra_u32(self) -> u32 {
|
||||||
|
u32::from_ne_bytes([self.b, self.g, self.r, self.a])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn to_pixel_u32(self, format: PixelFormat) -> u32 {
|
||||||
|
match format {
|
||||||
|
PixelFormat::B8G8R8A8 => self.to_bgra_u32(),
|
||||||
|
PixelFormat::R8G8B8A8 => self.to_rgba_u32(),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn rgb_mul(self, v: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
a: self.a,
|
||||||
|
r: self.r.saturating_mul(v),
|
||||||
|
g: self.g.saturating_mul(v),
|
||||||
|
b: self.b.saturating_mul(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// pub fn rgb_mul_assign(&mut self, v: u8) {
|
||||||
|
// self.r = self.r.saturating_mul(v);
|
||||||
|
// self.g = self.g.saturating_mul(v);
|
||||||
|
// self.b = self.b.saturating_mul(v);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
@ -282,7 +282,7 @@ impl<A: PhysicalMemoryAllocator<Address = PhysicalAddress>> BlockCache<A> {
|
|||||||
pub async fn try_with_mut<T, F: FnOnce(&mut [u8]) -> Result<T, Error>>(
|
pub async fn try_with_mut<T, F: FnOnce(&mut [u8]) -> Result<T, Error>>(
|
||||||
&self,
|
&self,
|
||||||
block_position: u64,
|
block_position: u64,
|
||||||
size: usize,
|
_size: usize,
|
||||||
mapper: F,
|
mapper: F,
|
||||||
) -> Result<T, Error> {
|
) -> Result<T, Error> {
|
||||||
let segment_position = block_position & !(self.segment_size as u64 - 1);
|
let segment_position = block_position & !(self.segment_size as u64 - 1);
|
||||||
|
@ -55,6 +55,8 @@ static YBOOT_DATA: LoadProtocolV1 = LoadProtocolV1 {
|
|||||||
res_stride: 0,
|
res_stride: 0,
|
||||||
res_address: 0,
|
res_address: 0,
|
||||||
res_size: 0,
|
res_size: 0,
|
||||||
|
res_format: 0,
|
||||||
|
_0: 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use core::{
|
|||||||
mem::size_of,
|
mem::size_of,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
ptr::null_mut,
|
ptr::null_mut,
|
||||||
sync::atomic::{AtomicU32, Ordering},
|
sync::atomic::Ordering,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ::acpi::{mcfg::Mcfg, AcpiTables, InterruptModel};
|
use ::acpi::{mcfg::Mcfg, AcpiTables, InterruptModel};
|
||||||
@ -29,6 +29,7 @@ use libk::{
|
|||||||
device::{
|
device::{
|
||||||
display::{
|
display::{
|
||||||
register_display_device, set_display_registration_callback, DisplayDeviceWrapper,
|
register_display_device, set_display_registration_callback, DisplayDeviceWrapper,
|
||||||
|
DriverFlags, PixelFormat,
|
||||||
},
|
},
|
||||||
register_external_interrupt_controller,
|
register_external_interrupt_controller,
|
||||||
},
|
},
|
||||||
@ -40,7 +41,10 @@ use libk_mm::{
|
|||||||
table::{EntryLevel, EntryLevelExt},
|
table::{EntryLevel, EntryLevelExt},
|
||||||
};
|
};
|
||||||
use libk_util::{sync::SpinFence, OneTimeInit};
|
use libk_util::{sync::SpinFence, OneTimeInit};
|
||||||
use yboot_proto::{v1::AvailableMemoryRegion, LoadProtocolV1};
|
use yboot_proto::{
|
||||||
|
v1::{self, AvailableMemoryRegion},
|
||||||
|
LoadProtocolV1,
|
||||||
|
};
|
||||||
use ygg_driver_pci::PciBusManager;
|
use ygg_driver_pci::PciBusManager;
|
||||||
|
|
||||||
mod acpi;
|
mod acpi;
|
||||||
@ -55,7 +59,7 @@ use crate::{
|
|||||||
debug::{self, LogLevel},
|
debug::{self, LogLevel},
|
||||||
device::{
|
device::{
|
||||||
self,
|
self,
|
||||||
display::{console, fb_console::FramebufferConsole, linear_fb::LinearFramebuffer},
|
display::{fb_console::FramebufferConsole, linear_fb::LinearFramebuffer},
|
||||||
},
|
},
|
||||||
fs::{Initrd, INITRD_DATA},
|
fs::{Initrd, INITRD_DATA},
|
||||||
};
|
};
|
||||||
@ -348,7 +352,26 @@ impl X86_64 {
|
|||||||
|
|
||||||
set_display_registration_callback(|device| {
|
set_display_registration_callback(|device| {
|
||||||
log::info!("Display registered: {:?}", device.display_name());
|
log::info!("Display registered: {:?}", device.display_name());
|
||||||
devfs::add_block_device(device, BlockDeviceType::Framebuffer).ok();
|
let node = devfs::add_block_device(device, BlockDeviceType::Framebuffer);
|
||||||
|
|
||||||
|
if device
|
||||||
|
.driver_flags()
|
||||||
|
.contains(DriverFlags::REPLACES_BOOT_FRAMEBUFFER)
|
||||||
|
{
|
||||||
|
// Switch fbconsole to the new framebuffer
|
||||||
|
if let Some(fbconsole) = PLATFORM.fbconsole.try_get()
|
||||||
|
&& fbconsole.uses_boot_framebuffer()
|
||||||
|
{
|
||||||
|
if let Err(error) = fbconsole.set_display(device.deref()) {
|
||||||
|
log::error!("Couldn't set fb console display: {error:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch /dev/fb0 to the new node
|
||||||
|
if let Ok(node) = node {
|
||||||
|
devfs::set_node("fb0", node).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
self.init_framebuffer()?;
|
self.init_framebuffer()?;
|
||||||
|
|
||||||
@ -425,53 +448,47 @@ impl X86_64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn init_framebuffer(&'static self) -> Result<(), Error> {
|
unsafe fn init_framebuffer(&'static self) -> Result<(), Error> {
|
||||||
// TODO use boot fb temporarily and then switch to whatever proper GPU is detected
|
let display = match self.boot_data.get() {
|
||||||
|
&BootData::YBoot(data) => {
|
||||||
|
let info = &data.opt_framebuffer;
|
||||||
|
let format = match info.res_format {
|
||||||
|
v1::PIXEL_B8G8R8A8 => PixelFormat::B8G8R8A8,
|
||||||
|
v1::PIXEL_R8G8B8A8 => PixelFormat::R8G8B8A8,
|
||||||
|
// Fallback
|
||||||
|
_ => PixelFormat::R8G8B8A8,
|
||||||
|
};
|
||||||
|
|
||||||
|
let framebuffer = LinearFramebuffer::from_physical_bits(
|
||||||
|
PhysicalAddress::from_u64(info.res_address),
|
||||||
|
info.res_size as usize,
|
||||||
|
info.res_stride as usize,
|
||||||
|
info.res_width,
|
||||||
|
info.res_height,
|
||||||
|
format,
|
||||||
|
)?;
|
||||||
|
let framebuffer = self.gop_framebuffer.init(framebuffer);
|
||||||
|
|
||||||
|
Some(framebuffer)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(display) = display else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Register boot display
|
||||||
|
let display = Box::leak(Box::new(DisplayDeviceWrapper::new(display)));
|
||||||
|
register_display_device(display);
|
||||||
|
|
||||||
|
let fbconsole = self.fbconsole.init(FramebufferConsole::from_framebuffer(
|
||||||
|
(*display).deref(),
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
)?);
|
||||||
|
|
||||||
|
debug::add_sink(fbconsole, LogLevel::Info);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
// let display = match self.boot_data.get() {
|
|
||||||
// &BootData::YBoot(data) => {
|
|
||||||
// let info = &data.opt_framebuffer;
|
|
||||||
|
|
||||||
// let framebuffer = LinearFramebuffer::from_physical_bits(
|
|
||||||
// PhysicalAddress::from_u64(info.res_address),
|
|
||||||
// info.res_size as usize,
|
|
||||||
// info.res_stride as usize,
|
|
||||||
// info.res_width,
|
|
||||||
// info.res_height,
|
|
||||||
// )?;
|
|
||||||
// let framebuffer = self.gop_framebuffer.init(framebuffer);
|
|
||||||
|
|
||||||
// Some(framebuffer)
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let Some(display) = display else {
|
|
||||||
// return Ok(());
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Register boot display
|
|
||||||
// let display = Box::leak(Box::new(DisplayDeviceWrapper::new(display)));
|
|
||||||
// register_display_device(display);
|
|
||||||
|
|
||||||
// let fbconsole = self.fbconsole.init(FramebufferConsole::from_framebuffer(
|
|
||||||
// (*display).deref(),
|
|
||||||
// None,
|
|
||||||
// )?);
|
|
||||||
|
|
||||||
// debug::add_sink(fbconsole, LogLevel::Info);
|
|
||||||
|
|
||||||
// // self.fbconsole.init(FramebufferConsole::from_framebuffer(
|
|
||||||
// // self.framebuffer.get(),
|
|
||||||
// // None,
|
|
||||||
// // )?);
|
|
||||||
// // debug::add_sink(self.fbconsole.get(), LogLevel::Info);
|
|
||||||
|
|
||||||
// // // self.tty.init(CombinedTerminal::new(self.fbconsole.get()));
|
|
||||||
|
|
||||||
// // devfs::add_named_block_device(self.framebuffer.get(), "fb0")?;
|
|
||||||
// // // devfs::add_char_device(self.tty.get(), CharDeviceType::TtyRegular)?;
|
|
||||||
// // console::add_console_autoflush(self.fbconsole.get());
|
|
||||||
|
|
||||||
// Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_initrd(initrd_start: PhysicalAddress, initrd_end: PhysicalAddress) {
|
fn init_initrd(initrd_start: PhysicalAddress, initrd_end: PhysicalAddress) {
|
||||||
|
@ -8,7 +8,10 @@ use abi::error::Error;
|
|||||||
use libk::task::{process::Process, thread::Thread};
|
use libk::task::{process::Process, thread::Thread};
|
||||||
use libk_util::{
|
use libk_util::{
|
||||||
ring::RingBuffer,
|
ring::RingBuffer,
|
||||||
sync::{IrqSafeSpinlock, IrqSafeSpinlockGuard},
|
sync::{
|
||||||
|
spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard},
|
||||||
|
IrqSafeSpinlock,
|
||||||
|
},
|
||||||
StaticVector,
|
StaticVector,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -20,7 +23,7 @@ static RING_AVAILABLE: AtomicBool = AtomicBool::new(false);
|
|||||||
struct KernelLoggerSink;
|
struct KernelLoggerSink;
|
||||||
/// Locking log sink for dumping panic info
|
/// Locking log sink for dumping panic info
|
||||||
pub struct PanicLoggerSink<'a> {
|
pub struct PanicLoggerSink<'a> {
|
||||||
lock: IrqSafeSpinlockGuard<'a, StaticVector<DebugSinkWrapper, MAX_DEBUG_SINKS>>,
|
lock: IrqSafeRwLockReadGuard<'a, StaticVector<DebugSinkWrapper, MAX_DEBUG_SINKS>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RingLoggerInner {
|
struct RingLoggerInner {
|
||||||
@ -152,7 +155,7 @@ impl log::Log for KernelLoggerSink {
|
|||||||
if RING_AVAILABLE.load(Ordering::Acquire) {
|
if RING_AVAILABLE.load(Ordering::Acquire) {
|
||||||
RING_LOGGER_SINK.log(record);
|
RING_LOGGER_SINK.log(record);
|
||||||
}
|
}
|
||||||
for sink in DEBUG_SINKS.lock().iter_mut() {
|
for sink in DEBUG_SINKS.read().iter() {
|
||||||
if sink.enabled(record.metadata()) {
|
if sink.enabled(record.metadata()) {
|
||||||
sink.log(record);
|
sink.log(record);
|
||||||
}
|
}
|
||||||
@ -231,7 +234,7 @@ impl PanicLoggerSink<'_> {
|
|||||||
/// interrupted
|
/// interrupted
|
||||||
pub fn lock() -> Self {
|
pub fn lock() -> Self {
|
||||||
Self {
|
Self {
|
||||||
lock: DEBUG_SINKS.lock(),
|
lock: DEBUG_SINKS.read(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,8 +275,8 @@ pub macro panic_log($sink:expr, $($args:tt)+) {
|
|||||||
|
|
||||||
static LOGGER: KernelLoggerSink = KernelLoggerSink;
|
static LOGGER: KernelLoggerSink = KernelLoggerSink;
|
||||||
|
|
||||||
static DEBUG_SINKS: IrqSafeSpinlock<StaticVector<DebugSinkWrapper, MAX_DEBUG_SINKS>> =
|
static DEBUG_SINKS: IrqSafeRwLock<StaticVector<DebugSinkWrapper, MAX_DEBUG_SINKS>> =
|
||||||
IrqSafeSpinlock::new(StaticVector::new());
|
IrqSafeRwLock::new(StaticVector::new());
|
||||||
|
|
||||||
/// See [RingLoggerSink]
|
/// See [RingLoggerSink]
|
||||||
pub static RING_LOGGER_SINK: RingLoggerSink = RingLoggerSink::new();
|
pub static RING_LOGGER_SINK: RingLoggerSink = RingLoggerSink::new();
|
||||||
@ -281,7 +284,7 @@ pub static RING_LOGGER_SINK: RingLoggerSink = RingLoggerSink::new();
|
|||||||
/// Adds a debugging output sink
|
/// Adds a debugging output sink
|
||||||
pub fn add_sink(sink: &'static dyn DebugSink, level: LogLevel) {
|
pub fn add_sink(sink: &'static dyn DebugSink, level: LogLevel) {
|
||||||
DEBUG_SINKS
|
DEBUG_SINKS
|
||||||
.lock()
|
.write()
|
||||||
.push(DebugSinkWrapper { inner: sink, level });
|
.push(DebugSinkWrapper { inner: sink, level });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use core::time::Duration;
|
|||||||
use abi::{error::Error, io::TerminalSize, primitive_enum};
|
use abi::{error::Error, io::TerminalSize, primitive_enum};
|
||||||
use alloc::{vec, vec::Vec};
|
use alloc::{vec, vec::Vec};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use libk::{task::runtime, vfs::TerminalOutput};
|
use libk::{device::display::Color, task::runtime, vfs::TerminalOutput};
|
||||||
use libk_util::{sync::IrqSafeSpinlock, StaticVector};
|
use libk_util::{sync::IrqSafeSpinlock, StaticVector};
|
||||||
|
|
||||||
use crate::debug::DebugSink;
|
use crate::debug::DebugSink;
|
||||||
@ -14,7 +14,8 @@ const CONSOLE_ROW_LEN: usize = 80;
|
|||||||
const MAX_CSI_ARGS: usize = 8;
|
const MAX_CSI_ARGS: usize = 8;
|
||||||
|
|
||||||
const DEFAULT_FG_COLOR: ColorAttribute = ColorAttribute::White;
|
const DEFAULT_FG_COLOR: ColorAttribute = ColorAttribute::White;
|
||||||
const DEFAULT_BG_COLOR: ColorAttribute = ColorAttribute::Blue;
|
/// Default console background color
|
||||||
|
pub const DEFAULT_BG_COLOR: ColorAttribute = ColorAttribute::Blue;
|
||||||
|
|
||||||
primitive_enum! {
|
primitive_enum! {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
@ -49,19 +50,22 @@ impl ColorAttribute {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Converts the attribute to RGBA representation
|
/// Converts the attribute to RGBA representation
|
||||||
pub fn as_rgba(&self, bold: bool) -> u32 {
|
pub fn as_rgba(&self, bold: bool) -> Color {
|
||||||
let color = match self {
|
const TABLE: &[Color] = &[
|
||||||
Self::Black => 0x000000,
|
Color::from_rgb_u32(0x000000),
|
||||||
Self::Red => 0x7F0000,
|
Color::from_rgb_u32(0x7F0000),
|
||||||
Self::Green => 0x007F00,
|
Color::from_rgb_u32(0x007F00),
|
||||||
Self::Yellow => 0x7F7F00,
|
Color::from_rgb_u32(0x7F7F00),
|
||||||
Self::Blue => 0x00007F,
|
Color::from_rgb_u32(0x00007F),
|
||||||
Self::Magenta => 0x7F007F,
|
Color::from_rgb_u32(0x7F007F),
|
||||||
Self::Cyan => 0x007F7F,
|
Color::from_rgb_u32(0x007F7F),
|
||||||
Self::White => 0x7F7F7F,
|
Color::from_rgb_u32(0x7F7F7F),
|
||||||
};
|
];
|
||||||
|
|
||||||
|
let color = TABLE[*self as usize];
|
||||||
|
|
||||||
if bold {
|
if bold {
|
||||||
color * 2
|
color.rgb_mul(2)
|
||||||
} else {
|
} else {
|
||||||
color
|
color
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,15 @@
|
|||||||
//! Display device structures and interfaces
|
//! Display device structures and interfaces
|
||||||
use core::{
|
use core::ops::{Deref, DerefMut};
|
||||||
mem::MaybeUninit,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
sync::atomic::{AtomicU32, Ordering},
|
|
||||||
};
|
|
||||||
|
|
||||||
use abi::{error::Error, io::DeviceRequest, process::ProcessId};
|
use abi::error::Error;
|
||||||
use alloc::{boxed::Box, collections::btree_map::BTreeMap, sync::Arc, vec::Vec};
|
use libk::device::display::{Color, DisplayDevice, DisplayOwner, PixelFormat};
|
||||||
use async_trait::async_trait;
|
|
||||||
use device_api::Device;
|
|
||||||
use libk::{
|
|
||||||
device::display::{DisplayDevice, DisplayOwner},
|
|
||||||
task::process::Process,
|
|
||||||
vfs::block::BlockDevice,
|
|
||||||
};
|
|
||||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider};
|
|
||||||
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
|
|
||||||
|
|
||||||
/// Convenience wrapper for accessing display framebuffers from the kernel side
|
/// Convenience wrapper for accessing display framebuffers from the kernel side
|
||||||
pub struct KernelFramebufferAccess<'a> {
|
pub struct KernelFramebufferAccess<'a> {
|
||||||
display: &'a dyn DisplayDevice,
|
display: &'a dyn DisplayDevice,
|
||||||
base: usize,
|
base: usize,
|
||||||
stride: usize,
|
stride: usize,
|
||||||
|
format: PixelFormat,
|
||||||
size: usize,
|
size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,30 +19,53 @@ impl<'a> KernelFramebufferAccess<'a> {
|
|||||||
// Lock the display by the kernel
|
// Lock the display by the kernel
|
||||||
display.lock(DisplayOwner::Kernel)?;
|
display.lock(DisplayOwner::Kernel)?;
|
||||||
|
|
||||||
match display.active_framebuffer() {
|
let Ok(framebuffer) = display.active_framebuffer() else {
|
||||||
Ok(info) if let Some(kernel_base) = info.kernel_base => Ok(Self {
|
display.unlock(DisplayOwner::Kernel).ok();
|
||||||
display,
|
return Err(Error::InvalidOperation);
|
||||||
base: kernel_base,
|
};
|
||||||
size: info.size / size_of::<u32>(),
|
let Some(kernel_base) = framebuffer.kernel_base else {
|
||||||
stride: info.stride / size_of::<u32>(),
|
display.unlock(DisplayOwner::Kernel).ok();
|
||||||
}),
|
return Err(Error::InvalidOperation);
|
||||||
_ => {
|
};
|
||||||
// Release the lock, couldn't get the framebuffer
|
let Some(mode) = display.active_display_mode() else {
|
||||||
display.unlock(DisplayOwner::Kernel).ok();
|
display.unlock(DisplayOwner::Kernel).ok();
|
||||||
Err(Error::InvalidOperation)
|
return Err(Error::InvalidOperation);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
Ok(Self {
|
||||||
|
display,
|
||||||
|
base: kernel_base,
|
||||||
|
size: framebuffer.size / size_of::<u32>(),
|
||||||
|
stride: framebuffer.stride / size_of::<u32>(),
|
||||||
|
format: mode.pixel_format,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the framebuffer pixel format
|
||||||
|
pub fn format(&self) -> PixelFormat {
|
||||||
|
self.format
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates a pixel in the framebuffer
|
/// Updates a pixel in the framebuffer
|
||||||
#[inline]
|
#[inline]
|
||||||
#[optimize(speed)]
|
#[optimize(speed)]
|
||||||
pub fn set_pixel(&mut self, x: u32, y: u32, pixel: u32) {
|
pub fn set_pixel(&mut self, x: u32, y: u32, v: u32) {
|
||||||
let p = y as usize * self.stride + x as usize;
|
let p = y as usize * self.stride + x as usize;
|
||||||
if p >= self.size {
|
if p >= self.size {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self[p] = pixel;
|
self[p] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fills a rectangle with pixels
|
||||||
|
#[optimize(speed)]
|
||||||
|
pub fn fill_rect(&mut self, sx: u32, sy: u32, w: u32, h: u32, c: Color) {
|
||||||
|
let v = c.to_pixel_u32(self.format);
|
||||||
|
for y in sy..sy + h {
|
||||||
|
let ry = y as usize * self.stride..;
|
||||||
|
let row = &mut self[ry];
|
||||||
|
row[sx as usize..sx as usize + w as usize].fill(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
//! Framebuffer console driver
|
//! Framebuffer console driver
|
||||||
|
|
||||||
use core::mem::MaybeUninit;
|
|
||||||
|
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
use libk::device::display::DisplayDevice;
|
use libk::device::display::{Color, DisplayDevice};
|
||||||
use libk_util::sync::IrqSafeSpinlock;
|
use libk_util::sync::IrqSafeSpinlock;
|
||||||
|
|
||||||
use crate::debug::DebugSink;
|
use crate::debug::DebugSink;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
console::{Attributes, ConsoleBuffer, ConsoleState, DisplayConsole},
|
console::{self, Attributes, ConsoleBuffer, ConsoleState, DisplayConsole},
|
||||||
device::KernelFramebufferAccess,
|
device::KernelFramebufferAccess,
|
||||||
font::PcScreenFont,
|
font::PcScreenFont,
|
||||||
linear_fb::LinearFramebuffer,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Inner {
|
struct Inner {
|
||||||
@ -24,14 +21,15 @@ struct Inner {
|
|||||||
height: u32,
|
height: u32,
|
||||||
cursor_row: u32,
|
cursor_row: u32,
|
||||||
cursor_col: u32,
|
cursor_col: u32,
|
||||||
|
boot_framebuffer: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DrawGlyph {
|
struct DrawGlyph {
|
||||||
sx: u32,
|
sx: u32,
|
||||||
sy: u32,
|
sy: u32,
|
||||||
c: u8,
|
c: u8,
|
||||||
fg: u32,
|
fg: Color,
|
||||||
bg: u32,
|
bg: Color,
|
||||||
bytes_per_line: usize,
|
bytes_per_line: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,13 +74,13 @@ impl DisplayConsole for FramebufferConsole {
|
|||||||
let cursor_col = state.cursor_col;
|
let cursor_col = state.cursor_col;
|
||||||
let cursor_row = state.cursor_row;
|
let cursor_row = state.cursor_row;
|
||||||
|
|
||||||
// inner.fill_rect(
|
framebuffer.fill_rect(
|
||||||
// old_cursor_col * cw,
|
old_cursor_col * cw,
|
||||||
// old_cursor_row * ch,
|
old_cursor_row * ch,
|
||||||
// cw,
|
cw,
|
||||||
// ch,
|
ch,
|
||||||
// state.bg_color.as_rgba(false),
|
state.bg_color.as_rgba(false),
|
||||||
// );
|
);
|
||||||
|
|
||||||
while let Some((row_idx, row)) = iter.next_dirty() {
|
while let Some((row_idx, row)) = iter.next_dirty() {
|
||||||
if row_idx >= inner.height {
|
if row_idx >= inner.height {
|
||||||
@ -112,14 +110,15 @@ impl DisplayConsole for FramebufferConsole {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Place cursor
|
// Place cursor
|
||||||
// inner.fill_rect(
|
framebuffer.fill_rect(
|
||||||
// cursor_col * cw,
|
cursor_col * cw,
|
||||||
// cursor_row * ch,
|
cursor_row * ch,
|
||||||
// cw,
|
cw,
|
||||||
// ch,
|
ch,
|
||||||
// state.fg_color.as_rgba(false),
|
state.fg_color.as_rgba(false),
|
||||||
// );
|
);
|
||||||
|
inner.display.synchronize().ok();
|
||||||
|
|
||||||
inner.cursor_col = cursor_col;
|
inner.cursor_col = cursor_col;
|
||||||
inner.cursor_row = cursor_row;
|
inner.cursor_row = cursor_row;
|
||||||
@ -132,14 +131,11 @@ impl FramebufferConsole {
|
|||||||
// framebuffer: &'static LinearFramebuffer,
|
// framebuffer: &'static LinearFramebuffer,
|
||||||
display: &'static dyn DisplayDevice,
|
display: &'static dyn DisplayDevice,
|
||||||
font: Option<PcScreenFont<'static>>,
|
font: Option<PcScreenFont<'static>>,
|
||||||
|
boot: bool,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut framebuffer = [MaybeUninit::uninit()];
|
|
||||||
let mode = display
|
let mode = display
|
||||||
.active_display_mode()
|
.active_display_mode()
|
||||||
.ok_or(Error::InvalidOperation)?;
|
.ok_or(Error::InvalidOperation)?;
|
||||||
display.active_framebuffers(&mut framebuffer).unwrap();
|
|
||||||
|
|
||||||
let framebuffer = unsafe { framebuffer[0].assume_init() };
|
|
||||||
|
|
||||||
let font = font.unwrap_or_default();
|
let font = font.unwrap_or_default();
|
||||||
let char_width = font.width();
|
let char_width = font.width();
|
||||||
@ -156,6 +152,7 @@ impl FramebufferConsole {
|
|||||||
char_height,
|
char_height,
|
||||||
cursor_row: 0,
|
cursor_row: 0,
|
||||||
cursor_col: 0,
|
cursor_col: 0,
|
||||||
|
boot_framebuffer: boot,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@ -163,6 +160,56 @@ impl FramebufferConsole {
|
|||||||
state: IrqSafeSpinlock::new(ConsoleState::new(buffer)),
|
state: IrqSafeSpinlock::new(ConsoleState::new(buffer)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Changes the display used for this console
|
||||||
|
pub fn set_display(&self, display: &'static dyn DisplayDevice) -> Result<(), Error> {
|
||||||
|
let mode = display
|
||||||
|
.active_display_mode()
|
||||||
|
.ok_or(Error::InvalidOperation)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut old_inner = self.inner.lock();
|
||||||
|
let mut old_state = self.state.lock();
|
||||||
|
|
||||||
|
let char_width = old_inner.char_width;
|
||||||
|
let char_height = old_inner.char_height;
|
||||||
|
|
||||||
|
let buffer = ConsoleBuffer::new(mode.height / char_height)?;
|
||||||
|
|
||||||
|
let inner = Inner {
|
||||||
|
display,
|
||||||
|
font: old_inner.font,
|
||||||
|
width: mode.width / char_width,
|
||||||
|
height: mode.height / char_height,
|
||||||
|
char_width,
|
||||||
|
char_height,
|
||||||
|
cursor_row: 0,
|
||||||
|
cursor_col: 0,
|
||||||
|
boot_framebuffer: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
*old_inner = inner;
|
||||||
|
*old_state = ConsoleState::new(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the display
|
||||||
|
if let Ok(mut framebuffer) = KernelFramebufferAccess::acquire(display) {
|
||||||
|
framebuffer.fill_rect(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
mode.width,
|
||||||
|
mode.height,
|
||||||
|
console::DEFAULT_BG_COLOR.as_rgba(false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the console is using a boot-time framebuffer
|
||||||
|
pub fn uses_boot_framebuffer(&self) -> bool {
|
||||||
|
self.inner.lock().boot_framebuffer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_glyph(
|
fn draw_glyph(
|
||||||
@ -175,6 +222,10 @@ fn draw_glyph(
|
|||||||
c = b'?' as u32;
|
c = b'?' as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let f = framebuffer.format();
|
||||||
|
let fg = g.fg.to_pixel_u32(f);
|
||||||
|
let bg = g.bg.to_pixel_u32(f);
|
||||||
|
|
||||||
let mut glyph = font.raw_glyph_data(c);
|
let mut glyph = font.raw_glyph_data(c);
|
||||||
|
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
@ -184,10 +235,8 @@ fn draw_glyph(
|
|||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
|
|
||||||
while x < font.width() {
|
while x < font.width() {
|
||||||
let v = if glyph[0] & mask != 0 { g.fg } else { g.bg };
|
let v = if glyph[0] & mask != 0 { fg } else { bg };
|
||||||
let v = v | 0xFF000000;
|
|
||||||
framebuffer.set_pixel(g.sx + x, g.sy + y, v);
|
framebuffer.set_pixel(g.sx + x, g.sy + y, v);
|
||||||
// framebuffer.set_pixel(g.sy + y, g.sx + x, v);
|
|
||||||
mask >>= 1;
|
mask >>= 1;
|
||||||
x += 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
@ -196,57 +245,3 @@ fn draw_glyph(
|
|||||||
y += 1;
|
y += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Inner {
|
|
||||||
// #[optimize(speed)]
|
|
||||||
// fn draw_glyph(&mut self, font: PcScreenFont<'static>, g: DrawGlyph) {
|
|
||||||
// let Ok(framebuffer) = KernelFramebufferAccess::acquire(self.display) else {
|
|
||||||
// return;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// // let Some(mut fb) = (unsafe { self.framebuffer.lock() }) else {
|
|
||||||
// // return;
|
|
||||||
// // };
|
|
||||||
//
|
|
||||||
// // let mut c = g.c as u32;
|
|
||||||
// // if c >= font.len() {
|
|
||||||
// // c = b'?' as u32;
|
|
||||||
// // }
|
|
||||||
//
|
|
||||||
// // let mut glyph = font.raw_glyph_data(c);
|
|
||||||
//
|
|
||||||
// // let mut y = 0;
|
|
||||||
//
|
|
||||||
// // while y < font.height() {
|
|
||||||
// // let mut mask = 1 << (font.width() - 1);
|
|
||||||
// // let mut x = 0;
|
|
||||||
//
|
|
||||||
// // while x < font.width() {
|
|
||||||
// // let v = if glyph[0] & mask != 0 { g.fg } else { g.bg };
|
|
||||||
// // let v = v | 0xFF000000;
|
|
||||||
// // fb[g.sy + y][(g.sx + x) as usize] = v;
|
|
||||||
// // mask >>= 1;
|
|
||||||
// // x += 1;
|
|
||||||
// // }
|
|
||||||
//
|
|
||||||
// // glyph = &glyph[g.bytes_per_line..];
|
|
||||||
// // y += 1;
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #[optimize(speed)]
|
|
||||||
// fn fill_rect(&mut self, x: u32, y: u32, w: u32, h: u32, val: u32) {
|
|
||||||
// if self.display.lock(DisplayOwner::Kernel).is_err() {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // let Some(mut fb) = (unsafe { self.framebuffer.lock() }) else {
|
|
||||||
// // return;
|
|
||||||
// // };
|
|
||||||
//
|
|
||||||
// // for i in 0..h {
|
|
||||||
// // let row = &mut fb[i + y];
|
|
||||||
// // row[x as usize..(x + w) as usize].fill(val);
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
@ -1,19 +1,11 @@
|
|||||||
//! Abstract linear framebuffer device implementation
|
//! Abstract linear framebuffer device implementation
|
||||||
|
|
||||||
use core::{
|
use core::mem::MaybeUninit;
|
||||||
mem::MaybeUninit,
|
|
||||||
ops::{Index, IndexMut},
|
|
||||||
};
|
|
||||||
|
|
||||||
use abi::{error::Error, io::DeviceRequest, process::ProcessId};
|
use abi::error::Error;
|
||||||
use alloc::sync::Arc;
|
|
||||||
use device_api::Device;
|
use device_api::Device;
|
||||||
use libk::{
|
use libk::device::display::{
|
||||||
device::display::{
|
DisplayDevice, DisplayMode, DisplayOwner, DriverFlags, FramebufferInfo, PixelFormat,
|
||||||
DisplayDevice, DisplayDimensions, DisplayMode, DisplayOwner, FramebufferInfo, PixelFormat,
|
|
||||||
},
|
|
||||||
task::{process::Process, thread::Thread},
|
|
||||||
vfs::block::BlockDevice,
|
|
||||||
};
|
};
|
||||||
use libk_mm::{
|
use libk_mm::{
|
||||||
address::PhysicalAddress,
|
address::PhysicalAddress,
|
||||||
@ -42,7 +34,6 @@ struct Inner {
|
|||||||
pub struct LinearFramebuffer {
|
pub struct LinearFramebuffer {
|
||||||
inner: IrqSafeSpinlock<Inner>,
|
inner: IrqSafeSpinlock<Inner>,
|
||||||
phys_base: PhysicalAddress,
|
phys_base: PhysicalAddress,
|
||||||
dimensions: DisplayDimensions,
|
|
||||||
mode: DisplayMode,
|
mode: DisplayMode,
|
||||||
size: usize,
|
size: usize,
|
||||||
}
|
}
|
||||||
@ -59,6 +50,7 @@ impl LinearFramebuffer {
|
|||||||
stride: usize,
|
stride: usize,
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
|
pixel_format: PixelFormat,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mapping = unsafe {
|
let mapping = unsafe {
|
||||||
RawDeviceMemoryMapping::map(
|
RawDeviceMemoryMapping::map(
|
||||||
@ -80,12 +72,11 @@ impl LinearFramebuffer {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
frames_per_second: u32::MAX,
|
frames_per_second: u32::MAX,
|
||||||
pixel_format: PixelFormat::R8G8B8A8,
|
pixel_format,
|
||||||
};
|
};
|
||||||
|
|
||||||
let res = Self {
|
let res = Self {
|
||||||
inner: IrqSafeSpinlock::new(inner),
|
inner: IrqSafeSpinlock::new(inner),
|
||||||
dimensions: DisplayDimensions { width, height },
|
|
||||||
phys_base,
|
phys_base,
|
||||||
size,
|
size,
|
||||||
mode,
|
mode,
|
||||||
@ -134,6 +125,10 @@ impl Device for LinearFramebuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayDevice for LinearFramebuffer {
|
impl DisplayDevice for LinearFramebuffer {
|
||||||
|
fn driver_flags(&self) -> DriverFlags {
|
||||||
|
DriverFlags::empty()
|
||||||
|
}
|
||||||
|
|
||||||
fn synchronize(&self) -> Result<(), Error> {
|
fn synchronize(&self) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,5 @@
|
|||||||
//! Display device interfaces
|
//! Display device interfaces
|
||||||
|
|
||||||
use core::{mem::MaybeUninit, ops::Deref};
|
|
||||||
|
|
||||||
use abi::error::Error;
|
|
||||||
use alloc::{boxed::Box, sync::Arc};
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use libk::{task::process::Process, vfs::block::BlockDevice};
|
|
||||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider};
|
|
||||||
|
|
||||||
use super::Device;
|
|
||||||
|
|
||||||
pub mod console;
|
pub mod console;
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub mod font;
|
pub mod font;
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
/sbin/service start /bin/colors
|
/sbin/service start /bin/colors /dev/fb0
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
/sbin/service start /bin/colors
|
/sbin/service start /bin/colors /dev/fb0
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fs::{File, OpenOptions},
|
fs::OpenOptions,
|
||||||
mem::MaybeUninit,
|
mem::MaybeUninit,
|
||||||
os::yggdrasil::io::{
|
os::yggdrasil::io::{
|
||||||
device::{DeviceRequest, FdDeviceRequest},
|
device::{DeviceRequest, FdDeviceRequest},
|
||||||
mapping::FileMapping,
|
mapping::FileMapping,
|
||||||
},
|
},
|
||||||
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
@ -16,15 +17,16 @@ pub struct Display<'a> {
|
|||||||
|
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
stride: usize,
|
// TODO use those
|
||||||
size: usize,
|
_stride: usize,
|
||||||
|
_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Point<T>(pub T, pub T);
|
pub struct Point<T>(pub T, pub T);
|
||||||
|
|
||||||
impl Display<'_> {
|
impl Display<'_> {
|
||||||
pub fn open() -> Result<Self, Error> {
|
pub fn open(framebuffer: impl AsRef<Path>) -> Result<Self, Error> {
|
||||||
let file = OpenOptions::new().open("/dev/fb0")?;
|
let file = OpenOptions::new().open(framebuffer)?;
|
||||||
|
|
||||||
let framebuffer = unsafe {
|
let framebuffer = unsafe {
|
||||||
file.device_request(&mut DeviceRequest::AcquireDevice)?;
|
file.device_request(&mut DeviceRequest::AcquireDevice)?;
|
||||||
@ -51,8 +53,8 @@ impl Display<'_> {
|
|||||||
|
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
stride: framebuffer.stride / size_of::<u32>(),
|
_stride: framebuffer.stride / size_of::<u32>(),
|
||||||
size: framebuffer.size / size_of::<u32>(),
|
_size: framebuffer.size / size_of::<u32>(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,15 +3,13 @@
|
|||||||
// TODO rewrite and split this into meaningful components
|
// TODO rewrite and split this into meaningful components
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, HashMap},
|
collections::{BTreeMap, HashMap}, env, os::{
|
||||||
os::{
|
|
||||||
fd::{AsRawFd, RawFd},
|
fd::{AsRawFd, RawFd},
|
||||||
yggdrasil::io::{
|
yggdrasil::io::{
|
||||||
mapping::FileMapping, poll::PollChannel,
|
mapping::FileMapping, poll::PollChannel,
|
||||||
shared_memory::SharedMemory,
|
shared_memory::SharedMemory,
|
||||||
},
|
},
|
||||||
},
|
}, process::{Command, ExitCode}
|
||||||
process::{Command, ExitCode},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use display::Display;
|
use display::Display;
|
||||||
@ -142,10 +140,10 @@ impl Row {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Server<'a, '_> {
|
impl<'a> Server<'a, '_> {
|
||||||
pub fn new() -> Result<Self, Error> {
|
pub fn new(framebuffer: &str) -> Result<Self, Error> {
|
||||||
let mut poll = PollChannel::new()?;
|
let mut poll = PollChannel::new()?;
|
||||||
|
|
||||||
let mut display = Display::open()?;
|
let mut display = Display::open(framebuffer)?;
|
||||||
let input = KeyboardInput::open()?;
|
let input = KeyboardInput::open()?;
|
||||||
|
|
||||||
let (sender, receiver) = serde_ipc::listen(libcolors::CHANNEL_NAME)?;
|
let (sender, receiver) = serde_ipc::listen(libcolors::CHANNEL_NAME)?;
|
||||||
@ -156,6 +154,7 @@ impl<'a> Server<'a, '_> {
|
|||||||
|
|
||||||
let background = 0xFFCCCCCC;
|
let background = 0xFFCCCCCC;
|
||||||
display.fill(background);
|
display.fill(background);
|
||||||
|
display.flush();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
display,
|
display,
|
||||||
@ -587,7 +586,10 @@ impl ServerSender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
let server = Server::new().unwrap();
|
let args = env::args().skip(1).collect::<Vec<_>>();
|
||||||
|
let framebuffer = args.get(0).map_or("/dev/fb0", |s| s.as_str());
|
||||||
|
|
||||||
|
let server = Server::new(framebuffer).unwrap();
|
||||||
|
|
||||||
server.run()
|
server.run()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user