Add allocator and set mode using VBE

This commit is contained in:
Jeremy Soller
2022-02-02 14:34:56 -07:00
parent 50b42eda0d
commit 14993ed497
3 changed files with 183 additions and 12 deletions
Generated
+36
View File
@@ -2,6 +2,42 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "linked_list_allocator"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a"
dependencies = [
"spinning_top",
]
[[package]]
name = "lock_api"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
dependencies = [
"scopeguard",
]
[[package]]
name = "redox_bootloader"
version = "0.1.0"
dependencies = [
"linked_list_allocator",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "spinning_top"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c"
dependencies = [
"lock_api",
]
+2
View File
@@ -8,4 +8,6 @@ name = "bootloader"
path = "src/lib.rs"
crate-type = ["staticlib"]
[dependencies]
linked_list_allocator = "0.9.0"
+145 -12
View File
@@ -3,14 +3,23 @@
#![feature(lang_items)]
#![feature(llvm_asm)]
#[macro_use]
extern crate alloc;
use alloc::vec::Vec;
use core::{
cmp,
fmt::{self, Write},
ptr,
slice,
};
use linked_list_allocator::LockedHeap;
mod panic;
#[global_allocator]
static ALLOCATOR: LockedHeap = LockedHeap::empty();
#[derive(Clone, Copy)]
#[repr(packed)]
pub struct ThunkData {
@@ -117,6 +126,7 @@ pub struct VgaTextBlock {
color: u8,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum VgaTextColor {
Black = 0,
@@ -143,6 +153,8 @@ pub struct Vga {
height: usize,
x: usize,
y: usize,
bg: VgaTextColor,
fg: VgaTextColor,
}
impl Vga {
@@ -156,6 +168,8 @@ impl Vga {
height,
x: 0,
y: 0,
bg: VgaTextColor::DarkGray,
fg: VgaTextColor::White,
}
}
}
@@ -192,6 +206,9 @@ impl fmt::Write for Vga {
let i = self.y * self.width + self.x;
if let Some(block) = self.blocks.get_mut(i) {
block.char = c as u8;
block.color =
((self.bg as u8) << 4) |
(self.fg as u8);
}
}
}
@@ -233,6 +250,15 @@ pub unsafe extern "C" fn kstart(
(VgaTextColor::White as u8);
}
// Initialize allocator at the end of stage 3 with a meager 1 MiB
extern "C" {
static mut __end: u8;
}
let heap_start = &__end as *const _ as usize;
let heap_size = 1024 * 1024;
ALLOCATOR.lock().init(heap_start, heap_size);
let mut modes = Vec::new();
{
// Get card info
let mut data = ThunkData::new();
@@ -242,33 +268,47 @@ pub unsafe extern "C" fn kstart(
if data.ax == 0x004F {
let card_info = ptr::read(0x1000 as *const VbeCardInfo);
let mut modes = card_info.videomodeptr as *const u16;
let mut mode_ptr = card_info.videomodeptr as *const u16;
loop {
let mode = *modes;
// Ask for linear frame buffer with mode
let mode = *mode_ptr | (1 << 14);
if mode == 0xFFFF {
break;
}
modes = modes.add(1);
mode_ptr = mode_ptr.add(1);
// Get mode info
let mut data = ThunkData::new();
data.ax = 0x4F01;
// Ask for linear frame buffer with mode
data.cx = mode | (1 << 14);
data.cx = mode;
data.di = 0x2000;
data.with(thunk10);
if data.ax == 0x004F {
let mode_info = ptr::read(0x2000 as *const VbeModeInfo);
// We only support 32-bits per pixel modes
if mode_info.bitsperpixel == 32 {
writeln!(
vga,
"{}x{}",
mode_info.xresolution,
mode_info.yresolution
);
if mode_info.bitsperpixel != 32 {
continue;
}
let w = mode_info.xresolution as u32;
let h = mode_info.yresolution as u32;
let mut aspect_w = w;
let mut aspect_h = h;
for i in 2..cmp::min(aspect_w / 2, aspect_h / 2) {
while aspect_w % i == 0 && aspect_h % i == 0 {
aspect_w /= i;
aspect_h /= i;
}
}
//TODO: support resolutions that are not perfect multiples of 4
if w % 4 != 0 {
continue;
}
modes.push((mode, w, h, format!("{:>4}x{:<4} {:>3}:{:<3}", w, h, aspect_w, aspect_h)));
} else {
writeln!(vga, "Failed to read VBE mode 0x{:04X} info: 0x{:04X}", mode, data.ax);
}
@@ -278,8 +318,39 @@ pub unsafe extern "C" fn kstart(
}
}
// Sort modes by pixel area, reversed
modes.sort_by(|a, b| (b.1 * b.2).cmp(&(a.1 * a.2)));
writeln!(vga, "Arrow keys and space select mode, enter to continue");
//TODO 0x4F03 VBE function to get current mode
let rows = 12;
let mut selected = modes.get(0).map_or(0, |x| x.0);
loop {
let mut row = 0;
let mut col = 0;
for (mode, w, h, text) in modes.iter() {
if row >= rows {
col += 1;
row = 0;
}
vga.x = 1 + col * 20;
vga.y = 1 + row;
if *mode == selected {
vga.bg = VgaTextColor::White;
vga.fg = VgaTextColor::Black;
} else {
vga.bg = VgaTextColor::DarkGray;
vga.fg = VgaTextColor::White;
}
write!(vga, "{}", text);
row += 1;
}
// Read keypress
let mut data = ThunkData::new();
data.with(thunk16);
@@ -289,5 +360,67 @@ pub unsafe extern "C" fn kstart(
(data.ax as u8) as char,
(data.ax >> 8) as u8
);
match (data.ax >> 8) as u8 {
0x4B /* Left */ => {
if let Some(mut mode_i) = modes.iter().position(|x| x.0 == selected) {
if mode_i < rows {
while mode_i < modes.len() {
mode_i += rows;
}
}
mode_i -= rows;
if let Some(new) = modes.get(mode_i) {
selected = new.0;
}
}
},
0x4D /* Right */ => {
if let Some(mut mode_i) = modes.iter().position(|x| x.0 == selected) {
mode_i += rows;
if mode_i >= modes.len() {
mode_i = mode_i % rows;
}
if let Some(new) = modes.get(mode_i) {
selected = new.0;
}
}
},
0x48 /* Up */ => {
if let Some(mut mode_i) = modes.iter().position(|x| x.0 == selected) {
if mode_i % rows == 0 {
mode_i += rows;
if mode_i > modes.len() {
mode_i = modes.len();
}
}
mode_i -= 1;
if let Some(new) = modes.get(mode_i) {
selected = new.0;
}
}
},
0x50 /* Down */ => {
if let Some(mut mode_i) = modes.iter().position(|x| x.0 == selected) {
mode_i += 1;
if mode_i % rows == 0 {
mode_i -= rows;
}
if mode_i >= modes.len() {
mode_i = mode_i - mode_i % rows;
}
if let Some(new) = modes.get(mode_i) {
selected = new.0;
}
}
},
0x1C /* Enter */ => {
let mut data = ThunkData::new();
data.ax = 0x4F02;
data.bx = selected;
data.with(thunk10);
},
_ => (),
}
}
}