Newer
Older
#[macro_use]
extern crate alloc;
use alloc::vec::Vec;
fmt::{self, Write},
use linked_list_allocator::LockedHeap;
use self::disk::DiskBios;
use self::logger::LOGGER;
use self::thunk::ThunkData;
use self::vbe::{VbeCardInfo, VbeModeInfo};
use self::vga::{VgaTextBlock, VgaTextColor, Vga};
mod panic;
mod thunk;
mod vbe;
mod vga;
// Real mode memory allocation, for use with thunk
// 0x500 to 0x7BFF is free
const VBE_CARD_INFO_ADDR: usize = 0x500; // 512 bytes, ends at 0x6FF
const VBE_MODE_INFO_ADDR: usize = 0x700; // 256 bytes, ends at 0x7FF
const DISK_ADDRESS_PACKET_ADDR: usize = 0x0FF0; // 16 bytes, ends at 0x0FFF
const DISK_BIOS_ADDR: usize = 0x1000; // 4096 bytes, ends at 0x1FFF
const THUNK_STACK_ADDR: usize = 0x7C00; // Grows downwards
#[global_allocator]
static ALLOCATOR: LockedHeap = LockedHeap::empty();
static mut VGA: Vga = unsafe { Vga::new(VGA_ADDR as *mut VgaTextBlock, 80, 25) };
thunk10: extern "C" fn(),
thunk13: extern "C" fn(),
thunk15: extern "C" fn(),
thunk16: extern "C" fn(),
let mut data = ThunkData::new();
data.ax = 0x03;
data.with(thunk10);
}
{
// Disable cursor
let mut data = ThunkData::new();
data.ax = 0x0100;
data.cx = 0x3F00;
data.with(thunk10);
}
{
// Clear VGA console
let blocks = VGA.blocks();
for i in 0..blocks.len() {
blocks[i] = VgaTextBlock {
char: 0,
color: ((VGA.bg as u8) << 4) | (VGA.fg 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);
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Set logger
LOGGER.init();
// Locate RedoxFS
{
//TODO: ensure boot_disk is 8-bit
info!("DISK {:02X}", boot_disk);
let disk = DiskBios::new(boot_disk as u8, thunk13);
//TODO: get block from partition table
let block = 1024 * 1024 / redoxfs::BLOCK_SIZE;
match redoxfs::FileSystem::open(disk, Some(block), false) {
Ok(mut fs) => {
info!("RedoxFS {} MiB", fs.header.size() / 1024 / 1024);
match fs.tx(|tx| tx.find_node(redoxfs::TreePtr::root(), "kernel")) {
Ok(node) => {
info!("Kernel {} MiB", node.data().size() / 1024 / 1024);
},
Err(err) => {
error!("Failed to find kernel file: {:?}", err);
}
}
},
Err(err) => {
error!("Failed to open RedoxFS: {:?}", err);
}
}
}
{
// Get card info
let mut data = ThunkData::new();
data.ax = 0x4F00;
data.with(thunk10);
if data.ax == 0x004F {
let card_info = ptr::read(VBE_CARD_INFO_ADDR as *const VbeCardInfo);
let mut mode_ptr = card_info.videomodeptr as *const u16;
// Ask for linear frame buffer with mode
let mode = *mode_ptr | (1 << 14);
// Get mode info
let mut data = ThunkData::new();
data.ax = 0x4F01;
data.with(thunk10);
if data.ax == 0x004F {
let mode_info = ptr::read(VBE_MODE_INFO_ADDR as *const VbeModeInfo);
// We only support 32-bits per pixel modes
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,
mode_info.physbaseptr,
format!("{:>4}x{:<4} {:>3}:{:<3}", w, h, aspect_w, aspect_h)
));
error!("Failed to read VBE mode 0x{:04X} info: 0x{:04X}", mode, data.ax);
error!("Failed to read VBE card info: 0x{:04X}", data.ax);
// 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 enter select mode").unwrap();
//TODO 0x4F03 VBE function to get current mode
let off_x = VGA.x;
let off_y = VGA.y;
let rows = 12;
let mut selected = modes.get(0).map_or(0, |x| x.0);
let mut row = 0;
let mut col = 0;
if row >= rows {
col += 1;
row = 0;
}
VGA.x = off_x + col * 20;
VGA.y = off_y + row;
VGA.bg = VgaTextColor::White;
VGA.fg = VgaTextColor::Black;
VGA.bg = VgaTextColor::DarkGray;
VGA.fg = VgaTextColor::White;
write!(VGA, "{}", text).unwrap();
let mut data = ThunkData::new();
data.with(thunk16);
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
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);
},
_ => (),
}