mirror of https://github.com/vinc/moros.git
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:
parent
d541ed949a
commit
71303cd455
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
113
src/sys/vga.rs
113
src/sys/vga.rs
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue