Added VGA graphics
This commit is contained in:
parent
fa2ff36610
commit
59df532105
@ -1,7 +1,7 @@
|
||||
use linked_list_allocator::LockedHeap;
|
||||
use spin::Mutex;
|
||||
|
||||
use crate::serial_println;
|
||||
use tetris::TetrisBoard;
|
||||
use vga::Vga13h;
|
||||
|
||||
use self::memory_map::memory_map;
|
||||
use self::thunk::ThunkData;
|
||||
@ -10,6 +10,7 @@ use crate::println;
|
||||
|
||||
mod memory_map;
|
||||
mod panic;
|
||||
mod tetris;
|
||||
mod thunk;
|
||||
mod vga;
|
||||
|
||||
@ -17,12 +18,11 @@ mod vga;
|
||||
// 0x500 to 0x7BFF is free
|
||||
const MEMORY_MAP_ADDR: usize = 0x1380; // 24 bytes, ends at 0x1397
|
||||
const THUNK_STACK_ADDR: usize = 0x7C00; // Grows downwards
|
||||
const VGA_ADDR: usize = 0xB8000;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: LockedHeap = LockedHeap::empty();
|
||||
|
||||
pub(crate) static VGA: Mutex<Vga> = Mutex::new(unsafe { Vga::new(VGA_ADDR, 80, 25) });
|
||||
pub(crate) static VGA: Mutex<Vga13h> = Mutex::new(unsafe { Vga13h::new() });
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn start(
|
||||
@ -35,9 +35,9 @@ pub unsafe extern "C" fn start(
|
||||
println!("Entered Rust, serial ready.");
|
||||
|
||||
{
|
||||
// Make sure we are in mode 3 (80x25 text mode)
|
||||
// Set vga mode
|
||||
let mut data = ThunkData::new();
|
||||
data.eax = 0x03;
|
||||
data.eax = 0x13;
|
||||
data.with(thunk10);
|
||||
}
|
||||
|
||||
@ -50,7 +50,19 @@ pub unsafe extern "C" fn start(
|
||||
}
|
||||
|
||||
// Clear screen
|
||||
VGA.lock().clear();
|
||||
let mut v = VGA.lock();
|
||||
|
||||
/*
|
||||
let fb = v.get_fb();
|
||||
let mut c: u8 = 0;
|
||||
for x in 0..128 {
|
||||
for y in 0..128 {
|
||||
let idx = Vga13h::pix_idx(x, y);
|
||||
fb[idx] = c;
|
||||
c = c.wrapping_add(1);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
let (heap_start, heap_size) = memory_map(thunk15).expect("No memory for heap");
|
||||
|
||||
|
119
bootloader/bootloader/src/os/bios/vga-copy.rs
Normal file
119
bootloader/bootloader/src/os/bios/vga-copy.rs
Normal file
@ -0,0 +1,119 @@
|
||||
use core::{fmt, slice};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
pub struct VgaTextBlock {
|
||||
pub char: u8,
|
||||
pub color: u8,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
pub enum VgaTextColor {
|
||||
Black = 0,
|
||||
Blue = 1,
|
||||
Green = 2,
|
||||
Cyan = 3,
|
||||
Red = 4,
|
||||
Purple = 5,
|
||||
Brown = 6,
|
||||
Gray = 7,
|
||||
DarkGray = 8,
|
||||
LightBlue = 9,
|
||||
LightGreen = 10,
|
||||
LightCyan = 11,
|
||||
LightRed = 12,
|
||||
LightPurple = 13,
|
||||
Yellow = 14,
|
||||
White = 15,
|
||||
}
|
||||
|
||||
pub struct Vga {
|
||||
pub base: usize,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub x: usize,
|
||||
pub y: usize,
|
||||
pub bg: VgaTextColor,
|
||||
pub fg: VgaTextColor,
|
||||
}
|
||||
|
||||
impl Vga {
|
||||
pub const unsafe fn new(base: usize, width: usize, height: usize) -> Self {
|
||||
Self {
|
||||
base,
|
||||
width,
|
||||
height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
bg: VgaTextColor::Black,
|
||||
fg: VgaTextColor::Gray,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn blocks(&mut self) -> &'static mut [VgaTextBlock] {
|
||||
slice::from_raw_parts_mut(self.base as *mut VgaTextBlock, self.width * self.height)
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.x = 0;
|
||||
self.y = 0;
|
||||
let blocks = unsafe { self.blocks() };
|
||||
for i in 0..blocks.len() {
|
||||
blocks[i] = VgaTextBlock {
|
||||
char: 0,
|
||||
color: ((self.bg as u8) << 4) | (self.fg as u8),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for Vga {
|
||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||
let blocks = unsafe { self.blocks() };
|
||||
for c in s.chars() {
|
||||
if self.x >= self.width {
|
||||
self.x = 0;
|
||||
self.y += 1;
|
||||
}
|
||||
while self.y >= self.height {
|
||||
for y in 1..self.height {
|
||||
for x in 0..self.width {
|
||||
let i = y * self.width + x;
|
||||
let j = i - self.width;
|
||||
blocks[j] = blocks[i];
|
||||
if y + 1 == self.height {
|
||||
blocks[i].char = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.y -= 1;
|
||||
}
|
||||
match c {
|
||||
'\x08' => {
|
||||
if self.x > 0 {
|
||||
self.x -= 1;
|
||||
}
|
||||
}
|
||||
'\r' => {
|
||||
self.x = 0;
|
||||
}
|
||||
'\n' => {
|
||||
self.x = 0;
|
||||
self.y += 1;
|
||||
}
|
||||
_ => {
|
||||
let i = self.y * self.width + self.x;
|
||||
if let Some(block) = blocks.get_mut(i) {
|
||||
block.char = c as u8;
|
||||
block.color = ((self.bg as u8) << 4) | (self.fg as u8);
|
||||
}
|
||||
self.x += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,119 +1,67 @@
|
||||
use core::{fmt, slice};
|
||||
use core::slice;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
pub struct VgaTextBlock {
|
||||
pub char: u8,
|
||||
pub color: u8,
|
||||
/// VGA driver for mode 0x13:
|
||||
///
|
||||
/// - mode: graphics
|
||||
/// - text res: 40x25
|
||||
/// - pixel box: 8x8
|
||||
/// - pixel res: 320x200
|
||||
/// - colors: 256/256k
|
||||
/// - addr: A000
|
||||
/// - pixel format: RRRGGGBB
|
||||
pub struct Vga13h {
|
||||
// Double frame buffers
|
||||
fb_a: [u8; Vga13h::WIDTH * Vga13h::HEIGHT],
|
||||
fb_b: [u8; Vga13h::WIDTH * Vga13h::HEIGHT],
|
||||
|
||||
/// If true, show fb_a (and write to fb_b).
|
||||
/// if false, show fb_b.
|
||||
show_fb_a: bool,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
pub enum VgaTextColor {
|
||||
Black = 0,
|
||||
Blue = 1,
|
||||
Green = 2,
|
||||
Cyan = 3,
|
||||
Red = 4,
|
||||
Purple = 5,
|
||||
Brown = 6,
|
||||
Gray = 7,
|
||||
DarkGray = 8,
|
||||
LightBlue = 9,
|
||||
LightGreen = 10,
|
||||
LightCyan = 11,
|
||||
LightRed = 12,
|
||||
LightPurple = 13,
|
||||
Yellow = 14,
|
||||
White = 15,
|
||||
}
|
||||
impl Vga13h {
|
||||
pub const WIDTH: usize = 320;
|
||||
pub const HEIGHT: usize = 200;
|
||||
pub const ADDR: usize = 0xA0000;
|
||||
|
||||
pub struct Vga {
|
||||
pub base: usize,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub x: usize,
|
||||
pub y: usize,
|
||||
pub bg: VgaTextColor,
|
||||
pub fg: VgaTextColor,
|
||||
}
|
||||
|
||||
impl Vga {
|
||||
pub const unsafe fn new(base: usize, width: usize, height: usize) -> Self {
|
||||
pub const unsafe fn new() -> Self {
|
||||
Self {
|
||||
base,
|
||||
width,
|
||||
height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
bg: VgaTextColor::Black,
|
||||
fg: VgaTextColor::Gray,
|
||||
fb_a: [0; Vga13h::WIDTH * Vga13h::HEIGHT],
|
||||
fb_b: [0; Vga13h::WIDTH * Vga13h::HEIGHT],
|
||||
show_fb_a: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn blocks(&mut self) -> &'static mut [VgaTextBlock] {
|
||||
slice::from_raw_parts_mut(self.base as *mut VgaTextBlock, self.width * self.height)
|
||||
unsafe fn segment(&mut self) -> &'static mut [u8] {
|
||||
slice::from_raw_parts_mut(Vga13h::ADDR as *mut u8, Vga13h::WIDTH * Vga13h::HEIGHT)
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.x = 0;
|
||||
self.y = 0;
|
||||
let blocks = unsafe { self.blocks() };
|
||||
for i in 0..blocks.len() {
|
||||
blocks[i] = VgaTextBlock {
|
||||
char: 0,
|
||||
color: ((self.bg as u8) << 4) | (self.fg as u8),
|
||||
};
|
||||
pub fn swap(&mut self) {
|
||||
let seg = unsafe { self.segment() };
|
||||
if self.show_fb_a {
|
||||
seg.copy_from_slice(&self.fb_b);
|
||||
self.show_fb_a = false
|
||||
} else {
|
||||
seg.copy_from_slice(&self.fb_a);
|
||||
self.show_fb_a = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for Vga {
|
||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||
let blocks = unsafe { self.blocks() };
|
||||
for c in s.chars() {
|
||||
if self.x >= self.width {
|
||||
self.x = 0;
|
||||
self.y += 1;
|
||||
}
|
||||
while self.y >= self.height {
|
||||
for y in 1..self.height {
|
||||
for x in 0..self.width {
|
||||
let i = y * self.width + x;
|
||||
let j = i - self.width;
|
||||
blocks[j] = blocks[i];
|
||||
if y + 1 == self.height {
|
||||
blocks[i].char = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.y -= 1;
|
||||
}
|
||||
match c {
|
||||
'\x08' => {
|
||||
if self.x > 0 {
|
||||
self.x -= 1;
|
||||
}
|
||||
}
|
||||
'\r' => {
|
||||
self.x = 0;
|
||||
}
|
||||
'\n' => {
|
||||
self.x = 0;
|
||||
self.y += 1;
|
||||
}
|
||||
_ => {
|
||||
let i = self.y * self.width + self.x;
|
||||
if let Some(block) = blocks.get_mut(i) {
|
||||
block.char = c as u8;
|
||||
block.color = ((self.bg as u8) << 4) | (self.fg as u8);
|
||||
}
|
||||
self.x += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_fb(&mut self) -> &mut [u8; Vga13h::WIDTH * Vga13h::HEIGHT] {
|
||||
unsafe { self.segment().try_into().unwrap() }
|
||||
|
||||
/*
|
||||
if self.show_fb_a {
|
||||
&mut self.fb_b
|
||||
} else {
|
||||
&mut self.fb_a
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
pub fn pix_idx(x: usize, y: usize) -> usize {
|
||||
debug_assert!(x < Vga13h::WIDTH);
|
||||
debug_assert!(y < Vga13h::HEIGHT);
|
||||
return y * Vga13h::WIDTH + x;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user