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(),
{
// Disable cursor
let mut data = ThunkData::new();
data.eax = 0x0100;
data.ecx = 0x3F00;
{
// 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, which we can be pretty
// sure will be available.
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);
// 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;
info!("RedoxFS {} MiB", fs.header.1.size / 1024 / 1024);
match fs.find_node("kernel", fs.header.1.root) {
Ok(node) => match fs.node_len(node.0) {
Ok(len) => {
info!("Kernel {} MiB", len / 1024 / 1024);
},
Err(err) => {
error!("Failed to read kernel file length: {:?}", err);
}
},
Err(err) => {
error!("Failed to find kernel file: {:?}", err);
}
}
},
Err(err) => {
error!("Failed to open RedoxFS: {:?}", err);
}
}
}
//let page_phys = paging::paging_create(KERNEL_PHYS);
{
// Get card info
let mut data = ThunkData::new();
data.eax = 0x4F00;
data.edi = VBE_CARD_INFO_ADDR as u32;
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.eax = 0x4F01;
data.ecx = mode as u32;
data.edi = VBE_MODE_INFO_ADDR as u32;
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.eax);
error!("Failed to read VBE card info: 0x{:04X}", data.eax);
// 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);
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
281
282
283
284
285
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.eax = 0x4F02;
data.ebx = selected as u32;
data.with(thunk10);
},
_ => (),
}