Fix VGA issues with real hardware (#258)

* Enable cursor after boot

* Remove unused time attribute on file

* Fix compilation warning

* Clear screen after vga init

* Add disable_blinking function

* Set palette registers at boot

* Set default palette

* Fix attribute control registers initialization

* Clear palette address source bit when setting palette

* Refactor code

* Remove index from palette

* Update comment

* Update changelog
This commit is contained in:
Vincent Ollivier 2021-10-24 18:23:01 +02:00 committed by GitHub
parent d541ed949a
commit 71303cd455
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 144 additions and 49 deletions

View File

@ -1,6 +1,7 @@
# Changelog
## Unreleased
- Fix VGA issues with real hardware (#258)
- Add rust binaries support (#255)
- Add dynamical disk information (#252)
- Add spawn syscall (#251)

View File

@ -1,18 +1,18 @@
# VGA Palette File (Index, Red, Green, Blue)
# VGA Palette File (Red, Green, Blue)
# Dark Gruvbox color palette
0x00, 0x28, 0x28, 0x28 # Black
0x01, 0x45, 0x85, 0x88 # Blue
0x02, 0x98, 0x97, 0x1A # Green
0x03, 0x68, 0x9D, 0x6A # Cyan
0x04, 0xCC, 0x24, 0x1D # Red
0x05, 0xB1, 0x62, 0x86 # Magenta
0x06, 0xD7, 0x99, 0x21 # Brown (Dark Yellow)
0x07, 0xEB, 0xDB, 0xB2 # Light Gray
0x08, 0xA8, 0x99, 0x84 # Dark Gray (Gray)
0x09, 0x83, 0xa5, 0x98 # Light Blue
0x0A, 0xB8, 0xBB, 0x26 # Light Green
0x0B, 0x8E, 0xC0, 0x7C # Light Cyan
0x0C, 0xFB, 0x49, 0x34 # Light Red
0x0D, 0xD3, 0x86, 0x9B # Pink (Light Magenta)
0x0E, 0xFA, 0xBD, 0x2F # Yellow (Light Yellow)
0x0F, 0xFB, 0xF1, 0xF7 # White
0x28, 0x28, 0x28 # Black
0x45, 0x85, 0x88 # Blue
0x98, 0x97, 0x1A # Green
0x68, 0x9D, 0x6A # Cyan
0xCC, 0x24, 0x1D # Red
0xB1, 0x62, 0x86 # Magenta
0xD7, 0x99, 0x21 # Brown (Dark Yellow)
0xEB, 0xDB, 0xB2 # Light Gray
0xA8, 0x99, 0x84 # Dark Gray (Gray)
0x83, 0xa5, 0x98 # Light Blue
0xB8, 0xBB, 0x26 # Light Green
0x8E, 0xC0, 0x7C # Light Cyan
0xFB, 0x49, 0x34 # Light Red
0xD3, 0x86, 0x9B # Pink (Light Magenta)
0xFA, 0xBD, 0x2F # Yellow (Light Yellow)
0xFB, 0xF1, 0xF7 # White

1 # VGA Palette File (Index, Red, Green, Blue) # VGA Palette File (Red, Green, Blue)
2 # Dark Gruvbox color palette # Dark Gruvbox color palette
3 0x00, 0x28, 0x28, 0x28 # Black 0x28, 0x28, 0x28 # Black
4 0x01, 0x45, 0x85, 0x88 # Blue 0x45, 0x85, 0x88 # Blue
5 0x02, 0x98, 0x97, 0x1A # Green 0x98, 0x97, 0x1A # Green
6 0x03, 0x68, 0x9D, 0x6A # Cyan 0x68, 0x9D, 0x6A # Cyan
7 0x04, 0xCC, 0x24, 0x1D # Red 0xCC, 0x24, 0x1D # Red
8 0x05, 0xB1, 0x62, 0x86 # Magenta 0xB1, 0x62, 0x86 # Magenta
9 0x06, 0xD7, 0x99, 0x21 # Brown (Dark Yellow) 0xD7, 0x99, 0x21 # Brown (Dark Yellow)
10 0x07, 0xEB, 0xDB, 0xB2 # Light Gray 0xEB, 0xDB, 0xB2 # Light Gray
11 0x08, 0xA8, 0x99, 0x84 # Dark Gray (Gray) 0xA8, 0x99, 0x84 # Dark Gray (Gray)
12 0x09, 0x83, 0xa5, 0x98 # Light Blue 0x83, 0xa5, 0x98 # Light Blue
13 0x0A, 0xB8, 0xBB, 0x26 # Light Green 0xB8, 0xBB, 0x26 # Light Green
14 0x0B, 0x8E, 0xC0, 0x7C # Light Cyan 0x8E, 0xC0, 0x7C # Light Cyan
15 0x0C, 0xFB, 0x49, 0x34 # Light Red 0xFB, 0x49, 0x34 # Light Red
16 0x0D, 0xD3, 0x86, 0x9B # Pink (Light Magenta) 0xD3, 0x86, 0x9B # Pink (Light Magenta)
17 0x0E, 0xFA, 0xBD, 0x2F # Yellow (Light Yellow) 0xFA, 0xBD, 0x2F # Yellow (Light Yellow)
18 0x0F, 0xFB, 0xF1, 0xF7 # White 0xFB, 0xF1, 0xF7 # White

View File

@ -71,7 +71,7 @@ pub fn from_ansi(code: u8) -> Color {
}
impl Color {
pub fn to_palette_code(&self) -> u8 {
pub fn to_vga_reg(&self) -> u8 {
match self {
Color::Black => 0x00,
Color::Blue => 0x01,
@ -79,8 +79,8 @@ impl Color {
Color::Cyan => 0x03,
Color::Red => 0x04,
Color::Magenta => 0x05,
Color::LightGray => 0x07,
Color::Brown => 0x14,
Color::LightGray => 0x07,
Color::DarkGray => 0x38,
Color::LightBlue => 0x39,
Color::LightGreen => 0x3A,

View File

@ -2,7 +2,32 @@ use alloc::vec::Vec;
use core::convert::TryInto;
pub struct Palette {
pub colors: [(u8, u8, u8, u8); 16]
pub colors: [(u8, u8, u8); 16]
}
impl Palette {
pub fn default() -> Palette {
Palette {
colors: [
(0x00, 0x00, 0x00), // Black
(0x00, 0x00, 0x80), // Blue
(0x00, 0x80, 0x00), // Green
(0x00, 0x80, 0x80), // Cyan
(0x80, 0x00, 0x00), // Red
(0x80, 0x00, 0x80), // Magenta
(0x80, 0x80, 0x00), // Brown (Dark Yellow)
(0xC0, 0xC0, 0xC0), // Light Gray
(0x80, 0x80, 0x80), // Dark Gray (Gray)
(0x00, 0x00, 0xFF), // Light Blue
(0x00, 0xFF, 0x00), // Light Green
(0x00, 0xFF, 0xFF), // Light Cyan
(0xFF, 0x00, 0x00), // Light Red
(0xFF, 0x00, 0xFF), // Pink (Light Magenta)
(0xFF, 0xFF, 0x00), // Yellow (Light Yellow)
(0xFF, 0xFF, 0xFF), // White
]
}
}
}
pub fn from_csv(s: &str) -> Result<Palette, ()> {
@ -13,8 +38,8 @@ pub fn from_csv(s: &str) -> Result<Palette, ()> {
let value = value.trim().trim_start_matches("0x");
u8::from_str_radix(value, radix).ok()
}).collect();
if color.len() == 4 { // Color index + rgb values
Some((color[0], color[1], color[2], color[3]))
if color.len() == 3 { // RGB values
Some((color[0], color[1], color[2]))
} else {
None
}
@ -33,6 +58,6 @@ fn parse_palette_csv() {
let s = include_str!("../../../dsk/ini/palette.csv");
let palette = from_csv(s).unwrap();
assert_eq!(palette.colors[0x03].0, 0x03);
assert_eq!(palette.colors[0x0D].2, 0x86);
assert_eq!(palette.colors[0x03].0, 0x68);
assert_eq!(palette.colors[0x0D].1, 0x86);
}

View File

@ -2,7 +2,6 @@
#![cfg_attr(test, no_main)]
#![feature(abi_x86_interrupt)]
#![feature(alloc_error_handler)]
#![feature(array_map)]
#![feature(asm)]
#![feature(naked_functions)]
#![feature(custom_test_frameworks)]

View File

@ -11,6 +11,7 @@ entry_point!(main);
fn main(boot_info: &'static BootInfo) -> ! {
moros::init(boot_info);
print!("\x1b[?25h"); // Enable cursor
loop {
let bootrc = "/ini/boot.sh";
if sys::fs::File::open(bootrc).is_some() {

View File

@ -17,7 +17,7 @@ pub const HEAP_START: usize = 0x4444_4444_0000;
static ALLOCATOR: LockedHeap = LockedHeap::empty();
pub fn init_heap(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut impl FrameAllocator<Size4KiB>) -> Result<(), MapToError<Size4KiB>> {
// Use half of the memory for the heap, caped to 16 GB because the allocator is too slow
// Use half of the memory for the heap, caped to 16 MB because the allocator is too slow
let heap_size = cmp::min(sys::mem::memory_size() / 2, 16 << 20);
let pages = {

View File

@ -18,7 +18,6 @@ pub struct File {
name: String,
addr: u32,
size: u32,
time: u64,
dir: Dir, // TODO: Replace with `parent: Some(Dir)` and also add it to `Dir`
offset: u32,
}
@ -29,7 +28,6 @@ impl From<DirEntry> for File {
name: entry.name(),
addr: entry.addr(),
size: entry.size(),
time: entry.time(),
dir: entry.dir(),
offset: 0,
}

View File

@ -10,7 +10,8 @@ use vte::{Params, Parser, Perform};
use x86_64::instructions::interrupts;
use x86_64::instructions::port::Port;
// See: https://web.stanford.edu/class/cs140/projects/pintos/specs/freevga/vga/vga.htm
// See https://web.stanford.edu/class/cs140/projects/pintos/specs/freevga/vga/vga.htm
// And https://01.org/sites/default/files/documentation/snb_ihd_os_vol3_part1_0.pdf
const ATTR_ADDR_DATA_REG: u16 = 0x3C0;
const ATTR_DATA_READ_REG: u16 = 0x3C1;
@ -192,6 +193,12 @@ impl Writer {
}
}
fn clear_screen(&mut self) {
for y in 0..BUFFER_HEIGHT {
self.clear_row_after(0, y);
}
}
pub fn set_color(&mut self, foreground: Color, background: Color) {
self.color_code = ColorCode::new(foreground, background);
}
@ -239,20 +246,25 @@ impl Writer {
pub fn set_palette(&mut self, palette: Palette) {
let mut addr: Port<u8> = Port::new(DAC_ADDR_WRITE_MODE_REG);
let mut data: Port<u8> = Port::new(DAC_DATA_REG);
for (i, r, g, b) in palette.colors {
for (i, (r, g, b)) in palette.colors.iter().enumerate() {
if i < 16 {
let code = color::from_index(i as usize).to_palette_code();
let reg = color::from_index(i as usize).to_vga_reg();
unsafe {
addr.write(code);
data.write(r >> 2); // Convert 8-bit color to 6-bit color
data.write(g >> 2);
data.write(b >> 2);
addr.write(reg);
data.write(vga_color(*r));
data.write(vga_color(*g));
data.write(vga_color(*b));
}
}
}
}
}
// Convert 8-bit to 6-bit color
fn vga_color(color: u8) -> u8 {
color >> 2
}
/// See https://vt100.net/emu/dec_ansi_parser
impl Perform for Writer {
fn print(&mut self, c: char) {
@ -356,11 +368,7 @@ impl Perform for Writer {
}
match n {
// TODO: 0 and 1, from cursor to begining or to end of screen
2 => {
for y in 0..BUFFER_HEIGHT {
self.clear_row_after(0, y);
}
}
2 => self.clear_screen(),
_ => return,
}
self.set_writer_position(0, 0);
@ -462,16 +470,79 @@ pub fn set_palette(palette: Palette) {
})
}
// 0x00 -> top
// 0x0F -> bottom
// 0x1F -> max (invisible)
fn set_underline_location(location: u8) {
interrupts::without_interrupts(|| {
let mut addr: Port<u8> = Port::new(CRTC_ADDR_REG);
let mut data: Port<u8> = Port::new(CRTC_DATA_REG);
unsafe {
addr.write(0x14); // Underline Location Register
data.write(location);
}
})
}
fn set_attr_ctrl_reg(index: u8, value: u8) {
interrupts::without_interrupts(|| {
let mut isr: Port<u8> = Port::new(INPUT_STATUS_REG);
let mut addr: Port<u8> = Port::new(ATTR_ADDR_DATA_REG);
unsafe {
isr.read(); // Reset to address mode
let tmp = addr.read();
addr.write(index);
addr.write(value);
addr.write(tmp);
}
})
}
fn get_attr_ctrl_reg(index: u8) -> u8 {
interrupts::without_interrupts(|| {
let mut isr: Port<u8> = Port::new(INPUT_STATUS_REG);
let mut addr: Port<u8> = Port::new(ATTR_ADDR_DATA_REG);
let mut data: Port<u8> = Port::new(ATTR_DATA_READ_REG);
let index = index | 0x20; // Set "Palette Address Source" bit
unsafe {
isr.read(); // Reset to address mode
let tmp = addr.read();
addr.write(index);
let res = data.read();
addr.write(tmp);
res
}
})
}
pub fn init() {
let mut isr: Port<u8> = Port::new(INPUT_STATUS_REG);
let mut aadr: Port<u8> = Port::new(ATTR_ADDR_DATA_REG);
let mut adrr: Port<u8> = Port::new(ATTR_DATA_READ_REG);
// Map palette registers to color registers
set_attr_ctrl_reg(0x0, 0x00);
set_attr_ctrl_reg(0x1, 0x01);
set_attr_ctrl_reg(0x2, 0x02);
set_attr_ctrl_reg(0x3, 0x03);
set_attr_ctrl_reg(0x4, 0x04);
set_attr_ctrl_reg(0x5, 0x05);
set_attr_ctrl_reg(0x6, 0x14);
set_attr_ctrl_reg(0x7, 0x07);
set_attr_ctrl_reg(0x8, 0x38);
set_attr_ctrl_reg(0x9, 0x39);
set_attr_ctrl_reg(0xA, 0x3A);
set_attr_ctrl_reg(0xB, 0x3B);
set_attr_ctrl_reg(0xC, 0x3C);
set_attr_ctrl_reg(0xD, 0x3D);
set_attr_ctrl_reg(0xE, 0x3E);
set_attr_ctrl_reg(0xF, 0x3F);
set_palette(Palette::default());
// Disable blinking
unsafe {
isr.read(); // Reset to address mode
aadr.write(0x30); // Select attribute mode control register
let value = adrr.read(); // Read attribute mode control register
aadr.write(value & !0x08); // Use `value | 0x08` to enable and `value ^ 0x08` to toggle
}
let reg = 0x10; // Attribute Mode Control Register
let mut attr = get_attr_ctrl_reg(reg);
attr.set_bit(3, false); // Clear "Blinking Enable" bit
set_attr_ctrl_reg(reg, attr);
set_underline_location(0x1F); // Disable underline
WRITER.lock().clear_screen();
}