-
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
4
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
4 commits
Select commit
Hold shift + click to select a range
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,161 @@ | ||
| //! 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::OnceCell; | ||
| 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)] | ||
| pub struct BgaInfo { | ||
| pub framebuffer: usize, | ||
| pub width: u16, | ||
| pub height: u16, | ||
| pub bpp: u16, | ||
| } | ||
|
|
||
| static BGA_INFO: OnceCell<BgaInfo> = OnceCell::new(); | ||
|
|
||
| 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>) { | ||
| //To Do: Add support for different resolutions and BPP 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; | ||
| } | ||
|
|
||
| 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, | ||
| ); | ||
|
|
||
| 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 | ||
|
GloriousAlpaca marked this conversation as resolved.
|
||
| .set(BgaInfo { | ||
| framebuffer: phys_addr as usize, | ||
| width, | ||
| height, | ||
| bpp, | ||
| }) | ||
| .unwrap(); | ||
|
|
||
| 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 get_framebuffer_info() -> Option<&'static BgaInfo> { | ||
| BGA_INFO.get() | ||
| } | ||
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
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.