Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@ virtio-vsock = ["virtio"]
## This is only useful on PCs (x86-64).
vga = []

## Enables the _Bochs Graphics Adapter_ (BGA) driver.
##
## This provides a linear framebuffer for pixel graphics and is primarily useful in QEMU/Bochs environments (x86-64).
bga = ["pci"]
#! ### Performance Features

## Disables putting the CPU to sleep.
Expand Down
91 changes: 91 additions & 0 deletions src/arch/x86_64/kernel/bga.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use core::sync::atomic::{AtomicU64, Ordering};

use memory_addresses::{PhysAddr, VirtAddr};
use pci_types::{Bar, CommandRegister};
use x86_64::instructions::port::Port;

use crate::arch::x86_64::mm::paging;
use crate::arch::x86_64::mm::paging::{BasePageSize, PageTableEntryFlags, PageTableEntryFlagsExt};
use crate::drivers::pci::PciDevice;
use crate::kernel::pci::PciConfigRegion;

static FRAMEBUFFER_PHYS: AtomicU64 = AtomicU64::new(0);

const VBE_DISPI_IOPORT_INDEX: u16 = 0x01ce;
const VBE_DISPI_IOPORT_DATA: u16 = 0x01cf;

const VBE_DISPI_INDEX_ID: u16 = 0;
const VBE_DISPI_INDEX_XRES: u16 = 1;
const VBE_DISPI_INDEX_YRES: u16 = 2;
const VBE_DISPI_INDEX_BPP: u16 = 3;
const VBE_DISPI_INDEX_ENABLE: u16 = 4;

const VBE_DISPI_DISABLED: u16 = 0x00;
const VBE_DISPI_ENABLED: u16 = 0x01;
const VBE_DISPI_LFB_ENABLED: u16 = 0x40;
const VBE_DISPI_ID5: u16 = 0xb0c5;

pub fn init_device(adapter: &PciDevice<PciConfigRegion>) {
//To Do: Detect Resolution automatically
let width: u16 = 640;
let height: u16 = 400;
let bpp: u16 = 32;

unsafe {
let mut index_port: Port<u16> = Port::new(VBE_DISPI_IOPORT_INDEX);
let mut data_port: Port<u16> = Port::new(VBE_DISPI_IOPORT_DATA);

index_port.write(VBE_DISPI_INDEX_ID);
let bga_version = data_port.read();

if bga_version != VBE_DISPI_ID5 {
error!("Unsupported BGA version: {bga_version:#06x}");
return;
}

index_port.write(VBE_DISPI_INDEX_ENABLE);
data_port.write(VBE_DISPI_DISABLED);

index_port.write(VBE_DISPI_INDEX_XRES);
data_port.write(width);

index_port.write(VBE_DISPI_INDEX_YRES);
data_port.write(height);

index_port.write(VBE_DISPI_INDEX_BPP);
data_port.write(bpp);

index_port.write(VBE_DISPI_INDEX_ENABLE);
data_port.write(VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
}

adapter.set_command(CommandRegister::MEMORY_ENABLE);

let (phys_addr, size) = match adapter.get_bar(0) {
Some(Bar::Memory32 { address, size, .. }) => (u64::from(address), size as usize),
Some(Bar::Memory64 { address, size, .. }) => (address, size as usize),
_ => return,
};

FRAMEBUFFER_PHYS.store(phys_addr, Ordering::Release);

assert!(
size % 4096 == 0,
"Framebuffer size must be a multiple of 4096 bytes"
);
let page_count = size / 4096;

let mut flags = PageTableEntryFlags::empty();
flags.device().writable().execute_disable();
flags.insert(PageTableEntryFlags::USER_ACCESSIBLE);
paging::map::<BasePageSize>(
VirtAddr::new(phys_addr),
PhysAddr::new(phys_addr),
page_count,
flags,
);
}

pub fn get_framebuffer_address() -> u64 {
FRAMEBUFFER_PHYS.load(Ordering::Acquire)
}
2 changes: 2 additions & 0 deletions src/arch/x86_64/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use crate::env::{self, is_uhyve};
#[cfg(feature = "acpi")]
pub mod acpi;
pub mod apic;
#[cfg(feature = "bga")]
pub mod bga;
pub mod core_local;
pub mod gdt;
pub mod interrupts;
Expand Down
13 changes: 13 additions & 0 deletions src/drivers/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,19 @@ pub(crate) fn init(handlers: &mut InterruptHandlerMap) {
Err(err) => error!("Could not initialize rtl8139 device: {err}"),
}
}

#[cfg(all(target_arch = "x86_64", feature = "bga"))]
for adapter in PCI_DEVICES.finalize().iter().filter(|x| {
let (vendor_id, device_id) = x.id();
vendor_id == 0x1234 && device_id == 0x1111
}) {
info!(
"Found Bochs VGA device with device id {:#x}",
adapter.device_id()
);

crate::kernel::bga::init_device(adapter);
}
PCI_DRIVERS.finalize();
});
}
Expand Down
15 changes: 15 additions & 0 deletions src/syscalls/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,18 @@ use crate::arch::mm::paging::{BasePageSize, PageSize};
pub extern "C" fn sys_getpagesize() -> i32 {
BasePageSize::SIZE.try_into().unwrap()
}

/// Returns the address of the framebuffer, if available. Returns 0 if no framebuffer is available.
#[cfg(all(target_arch = "x86_64", feature = "bga"))]
#[hermit_macro::system]
#[unsafe(no_mangle)]
pub extern "C" fn sys_get_framebuffer() -> u64 {
crate::kernel::bga::get_framebuffer_address()
}

#[cfg(not(all(target_arch = "x86_64", feature = "bga")))]
#[hermit_macro::system]
#[unsafe(no_mangle)]
pub extern "C" fn sys_get_framebuffer() -> u64 {
0
}
Loading