-
Notifications
You must be signed in to change notification settings - Fork 129
feat: Bochs VBE linear framebuffer support #2523
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
GloriousAlpaca
wants to merge
6
commits into
hermit-os:main
Choose a base branch
from
GloriousAlpaca:pr-bga-clean
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
61298f8
add Bochs VBE linear framebuffer support
bd25b82
style: use variable in format string
b28912e
Refactor BGA based on review feedback
8ea3de4
refactor: implement latest feedback, change structs to enums
d81bf61
make resolution of bga changeable via a systemcall, rename systemcalls
ff8a16b
refactor: change framebuffer address type to PhysAddr
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| //! This module contains the implementation of the Bochs Graphics Adapter (BGA) driver. | ||
| //! | ||
| //! The driver uses the Bochs VBE Extensions, which use two I/O ports to communicate with the | ||
| //! emulated VGA card instead of relying on a 16-bit VBE BIOS. The driver initializes the BGA | ||
| //! device, sets the desired resolution and bits per pixel (BPP), and maps the framebuffer | ||
| //! into the virtual address space. It also provides a function to retrieve the physical | ||
| //! address of the framebuffer. | ||
|
|
||
| use hermit_sync::{Lazy, TicketMutex}; | ||
| use memory_addresses::{PhysAddr, VirtAddr}; | ||
| use pci_types::{Bar, CommandRegister}; | ||
| use x86_64::instructions::port::{Port, PortWriteOnly}; | ||
|
|
||
| use crate::arch::kernel::pci::PciConfigRegion; | ||
| use crate::arch::x86_64::mm::paging::{ | ||
| self, BasePageSize, PageTableEntryFlags, PageTableEntryFlagsExt, | ||
| }; | ||
| use crate::drivers::pci::PciDevice; | ||
|
|
||
| #[derive(Debug, Clone, Copy)] | ||
| pub struct BgaInfo { | ||
| pub framebuffer: PhysAddr, | ||
| pub width: u16, | ||
| pub height: u16, | ||
| pub bpp: u16, | ||
| } | ||
|
|
||
| static BGA_INFO: Lazy<TicketMutex<Option<BgaInfo>>> = Lazy::new(|| TicketMutex::new(None)); | ||
|
|
||
| const VBE_DISPI_IOPORT_INDEX: u16 = 0x01ce; | ||
| const VBE_DISPI_IOPORT_DATA: u16 = 0x01cf; | ||
|
|
||
| #[allow(dead_code)] | ||
| #[repr(u16)] | ||
| pub enum VbeDispiIndex { | ||
| #[doc(alias = "VBE_DISPI_INDEX_ID")] | ||
| Id = 0, | ||
| #[doc(alias = "VBE_DISPI_INDEX_XRES")] | ||
| Xres = 1, | ||
| #[doc(alias = "VBE_DISPI_INDEX_YRES")] | ||
| Yres = 2, | ||
| #[doc(alias = "VBE_DISPI_INDEX_BPP")] | ||
| Bpp = 3, | ||
| #[doc(alias = "VBE_DISPI_INDEX_ENABLE")] | ||
| Enable = 4, | ||
| #[doc(alias = "VBE_DISPI_INDEX_BANK")] | ||
| Bank = 5, | ||
| #[doc(alias = "VBE_DISPI_INDEX_VIRT_WIDTH")] | ||
| VirtWidth = 6, | ||
| #[doc(alias = "VBE_DISPI_INDEX_VIRT_HEIGHT")] | ||
| VirtHeight = 7, | ||
| #[doc(alias = "VBE_DISPI_INDEX_X_OFFSET")] | ||
| XOffset = 8, | ||
| #[doc(alias = "VBE_DISPI_INDEX_Y_OFFSET")] | ||
| YOffset = 9, | ||
| } | ||
|
|
||
| const VBE_DISPI_DISABLED: u16 = 0x00; | ||
| const VBE_DISPI_ENABLED: u16 = 0x01; | ||
| const VBE_DISPI_LFB_ENABLED: u16 = 0x40; | ||
|
GloriousAlpaca marked this conversation as resolved.
|
||
|
|
||
| #[allow(dead_code)] | ||
| const VBE_DISPI_NOCLEARMEM: u16 = 0x80; | ||
|
|
||
| #[allow(dead_code)] | ||
| #[repr(u16)] | ||
| pub enum VbeDispiId { | ||
| #[doc(alias = "VBE_DISPI_ID0")] | ||
| Id0 = 0xb0c0, | ||
| #[doc(alias = "VBE_DISPI_ID1")] | ||
| Id1 = 0xb0c1, | ||
| #[doc(alias = "VBE_DISPI_ID2")] | ||
| Id2 = 0xb0c2, | ||
| #[doc(alias = "VBE_DISPI_ID3")] | ||
| Id3 = 0xb0c3, | ||
| #[doc(alias = "VBE_DISPI_ID4")] | ||
| Id4 = 0xb0c4, | ||
| #[doc(alias = "VBE_DISPI_ID5")] | ||
| Id5 = 0xb0c5, | ||
| } | ||
|
|
||
| struct BgaRegisters; | ||
|
|
||
| impl BgaRegisters { | ||
| pub fn read(index: VbeDispiIndex) -> u16 { | ||
| let mut index_port: PortWriteOnly<u16> = PortWriteOnly::new(VBE_DISPI_IOPORT_INDEX); | ||
| let mut data_port: Port<u16> = Port::new(VBE_DISPI_IOPORT_DATA); | ||
| unsafe { | ||
| index_port.write(index as u16); | ||
| data_port.read() | ||
| } | ||
| } | ||
|
|
||
| pub fn write(index: VbeDispiIndex, value: u16) { | ||
| let mut index_port: PortWriteOnly<u16> = PortWriteOnly::new(VBE_DISPI_IOPORT_INDEX); | ||
| let mut data_port: Port<u16> = Port::new(VBE_DISPI_IOPORT_DATA); | ||
| unsafe { | ||
| index_port.write(index as u16); | ||
| data_port.write(value); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| pub fn init_device(adapter: &PciDevice<PciConfigRegion>) { | ||
| // Hardcoded standard values | ||
| let width: u16 = 640; | ||
| let height: u16 = 400; | ||
| let bpp: u16 = 32; | ||
|
|
||
| let bga_version = BgaRegisters::read(VbeDispiIndex::Id); | ||
|
|
||
| if bga_version != VbeDispiId::Id5 as u16 { | ||
| error!("Unsupported BGA version: {bga_version:#06x}"); | ||
| return; | ||
| } | ||
|
|
||
| adapter.set_command(CommandRegister::MEMORY_ENABLE); | ||
|
|
||
| let (phys_addr, size) = match adapter.get_bar(0) { | ||
|
jounathaen marked this conversation as resolved.
|
||
| Some(Bar::Memory32 { address, size, .. }) => (u64::from(address), size as usize), | ||
| Some(Bar::Memory64 { address, size, .. }) => (address, size as usize), | ||
| _ => return, | ||
| }; | ||
|
|
||
| *BGA_INFO.lock() = Some(BgaInfo { | ||
| framebuffer: PhysAddr::from(phys_addr), | ||
| width: 0, | ||
| height: 0, | ||
| bpp: 0, | ||
| }); | ||
|
|
||
| set_resolution(width, height, bpp); | ||
|
|
||
| assert!( | ||
|
jounathaen marked this conversation as resolved.
|
||
| size.is_multiple_of(4096), | ||
| "Framebuffer size must be a multiple of 4096 bytes" | ||
| ); | ||
| let page_count = size / 4096; | ||
|
|
||
| let mut flags = PageTableEntryFlags::empty(); | ||
|
jounathaen marked this conversation as resolved.
|
||
| flags.device().writable().execute_disable(); | ||
| paging::map::<BasePageSize>( | ||
| VirtAddr::new(phys_addr), | ||
| PhysAddr::new(phys_addr), | ||
| page_count, | ||
| flags, | ||
| ); | ||
| } | ||
|
|
||
| pub fn set_resolution(width: u16, height: u16, bpp: u16) { | ||
| BgaRegisters::write(VbeDispiIndex::Enable, VBE_DISPI_DISABLED); | ||
| BgaRegisters::write(VbeDispiIndex::Xres, width); | ||
| BgaRegisters::write(VbeDispiIndex::Yres, height); | ||
| BgaRegisters::write(VbeDispiIndex::Bpp, bpp); | ||
| BgaRegisters::write( | ||
| VbeDispiIndex::Enable, | ||
| VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED, | ||
| ); | ||
| if let Some(ref mut info) = *BGA_INFO.lock() { | ||
| info.width = width; | ||
| info.height = height; | ||
| info.bpp = bpp; | ||
| } else { | ||
| error!("BGA is not initialized"); | ||
| } | ||
| } | ||
|
|
||
| pub fn get_framebuffer_info() -> Option<BgaInfo> { | ||
| *BGA_INFO.lock() | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,3 +1,6 @@ | ||||||||||||||||||||||||||
| #[cfg(all(target_arch = "x86_64", feature = "bga"))] | ||||||||||||||||||||||||||
| use core::ffi::c_int; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| use crate::arch::mm::paging::{BasePageSize, PageSize}; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /// Returns the base page size, in bytes, of the current system. | ||||||||||||||||||||||||||
|
|
@@ -6,3 +9,50 @@ use crate::arch::mm::paging::{BasePageSize, PageSize}; | |||||||||||||||||||||||||
| pub extern "C" fn sys_getpagesize() -> i32 { | ||||||||||||||||||||||||||
| BasePageSize::SIZE.try_into().unwrap() | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| #[cfg(all(target_arch = "x86_64", feature = "bga"))] | ||||||||||||||||||||||||||
| #[repr(C)] | ||||||||||||||||||||||||||
| pub struct FramebufferInfo { | ||||||||||||||||||||||||||
| pub framebuffer: *mut u8, | ||||||||||||||||||||||||||
| pub width: u32, | ||||||||||||||||||||||||||
| pub height: u32, | ||||||||||||||||||||||||||
| pub bpp: u32, | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /// Returns the framebuffer information for the BGA device, if it has been initialized. Returns 0 | ||||||||||||||||||||||||||
| /// on success, or -1 if the BGA device has not been initialized. | ||||||||||||||||||||||||||
| #[cfg(all(target_arch = "x86_64", feature = "bga"))] | ||||||||||||||||||||||||||
| #[hermit_macro::system] | ||||||||||||||||||||||||||
| #[unsafe(no_mangle)] | ||||||||||||||||||||||||||
| pub unsafe extern "C" fn sys_get_bga_info(info: *mut FramebufferInfo) -> c_int { | ||||||||||||||||||||||||||
|
Comment on lines
+22
to
+27
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||
| if info.is_null() { | ||||||||||||||||||||||||||
| return -1; | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| let bga_info = crate::arch::kernel::bga::get_framebuffer_info(); | ||||||||||||||||||||||||||
| match bga_info { | ||||||||||||||||||||||||||
| Some(bga_info) => { | ||||||||||||||||||||||||||
| let info_c = FramebufferInfo { | ||||||||||||||||||||||||||
| framebuffer: core::ptr::with_exposed_provenance_mut( | ||||||||||||||||||||||||||
| bga_info.framebuffer.as_usize(), | ||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||
| width: u32::from(bga_info.width), | ||||||||||||||||||||||||||
| height: u32::from(bga_info.height), | ||||||||||||||||||||||||||
| bpp: u32::from(bga_info.bpp), | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
| unsafe { | ||||||||||||||||||||||||||
| info.write(info_c); | ||||||||||||||||||||||||||
|
jounathaen marked this conversation as resolved.
|
||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| 0 | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| None => -1, | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| #[cfg(all(target_arch = "x86_64", feature = "bga"))] | ||||||||||||||||||||||||||
| #[hermit_macro::system] | ||||||||||||||||||||||||||
| #[unsafe(no_mangle)] | ||||||||||||||||||||||||||
| pub unsafe extern "C" fn sys_set_bga_resolution(width: u16, height: u16, bpp: u16) -> c_int { | ||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||
| crate::arch::kernel::bga::set_resolution(width, height, bpp); | ||||||||||||||||||||||||||
| 0 | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.