diff --git a/vboxd/src/bga.rs b/vboxd/src/bga.rs new file mode 100644 index 0000000000..21599f7fd0 --- /dev/null +++ b/vboxd/src/bga.rs @@ -0,0 +1,46 @@ +use syscall::io::{Io, Pio}; + +const BGA_INDEX_XRES: u16 = 1; +const BGA_INDEX_YRES: u16 = 2; +const BGA_INDEX_BPP: u16 = 3; +const BGA_INDEX_ENABLE: u16 = 4; + +pub struct Bga { + index: Pio, + data: Pio, +} + +impl Bga { + pub fn new() -> Bga { + Bga { + index: Pio::new(0x1CE), + data: Pio::new(0x1CF), + } + } + + fn read(&mut self, index: u16) -> u16 { + self.index.write(index); + self.data.read() + } + + fn write(&mut self, index: u16, data: u16) { + self.index.write(index); + self.data.write(data); + } + + pub fn width(&mut self) -> u16 { + self.read(BGA_INDEX_XRES) + } + + pub fn height(&mut self) -> u16 { + self.read(BGA_INDEX_YRES) + } + + pub fn set_size(&mut self, width: u16, height: u16) { + self.write(BGA_INDEX_ENABLE, 0); + self.write(BGA_INDEX_XRES, width); + self.write(BGA_INDEX_YRES, height); + self.write(BGA_INDEX_BPP, 32); + self.write(BGA_INDEX_ENABLE, 0x41); + } +} \ No newline at end of file diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 5c2af742a3..d84342a41c 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -13,6 +13,10 @@ use syscall::flag::MAP_WRITE; use syscall::io::{Dma, Io, Mmio, Pio}; use syscall::iopl; +use bga::Bga; + +mod bga; + const VBOX_REQUEST_HEADER_VERSION: u32 = 0x10001; const VBOX_VMMDEV_VERSION: u32 = 0x00010003; @@ -234,6 +238,7 @@ fn main() { let mut event_queue = EventQueue::<()>::new().expect("vboxd: failed to create event queue"); + let mut bga = Bga::new(); let get_mouse = VboxGetMouse::new().expect("vboxd: failed to map GetMouse"); let display_change = VboxDisplayChange::new().expect("vboxd: failed to map DisplayChange"); let ack_events = VboxAckEvents::new().expect("vboxd: failed to map AckEvents"); @@ -247,14 +252,27 @@ fn main() { if host_events & VBOX_EVENT_DISPLAY == VBOX_EVENT_DISPLAY { port.write(display_change.physical() as u32); - println!("Display {}, {}", display_change.xres.read(), display_change.yres.read()); + if let Some(ref mut display) = display_opt { + let new_width = display_change.xres.read(); + let new_height = display_change.yres.read(); + if width != new_width || height != new_height { + width = new_width; + height = new_height; + println!("Display {}, {}", width, height); + bga.set_size(width as u16, height as u16); + let _ = display.write(&orbclient::ResizeEvent { + width: width, + height: height, + }.to_event()); + } + } } if host_events & VBOX_EVENT_MOUSE == VBOX_EVENT_MOUSE { port.write(get_mouse.physical() as u32); - let x = get_mouse.x.read() * width / 0x10000; - let y = get_mouse.y.read() * height / 0x10000; if let Some(ref mut display) = display_opt { + let x = get_mouse.x.read() * width / 0x10000; + let y = get_mouse.y.read() * height / 0x10000; let _ = display.write(&orbclient::MouseEvent { x: x as i32, y: y as i32, diff --git a/vesad/src/display.rs b/vesad/src/display.rs index e8b7eb0e84..f6c37c417c 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -68,6 +68,36 @@ impl Display { } } + pub fn resize(&mut self, width: usize, height: usize) { + println!("Resize display to {}, {}", width, height); + + let size = width * height; + let offscreen = unsafe { heap::allocate(size * 4, 4096) }; + + { + let mut old_ptr = self.offscreen.as_ptr(); + let mut new_ptr = offscreen as *mut u32; + for _y in 0..cmp::min(height, self.height) { + unsafe { + fast_copy(new_ptr as *mut u8, old_ptr as *const u8, cmp::min(width, self.width) * 4); + old_ptr = old_ptr.offset(self.width as isize); + new_ptr = new_ptr.offset(width as isize); + } + } + } + + self.width = width; + self.height = height; + + let onscreen = self.onscreen.as_mut_ptr(); + self.onscreen = unsafe { slice::from_raw_parts_mut(onscreen, size) }; + + unsafe { heap::deallocate(self.offscreen.as_mut_ptr() as *mut u8, self.offscreen.len() * 4, 4096) }; + self.offscreen = unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }; + + self.sync(0, 0, width, height); + } + /// Draw a rectangle pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) { let start_y = cmp::min(self.height - 1, y); @@ -244,3 +274,9 @@ impl Display { } } } + +impl Drop for Display { + fn drop(&mut self) { + unsafe { heap::deallocate(self.offscreen.as_mut_ptr() as *mut u8, self.offscreen.len() * 4, 4096) }; + } +} diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 337f6a560b..211058cea5 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -55,8 +55,9 @@ fn main() { let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); let size = width * height; - - let onscreen = unsafe { physmap(physbaseptr, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; + //TODO: Remap on resize + let largest_size = 8 * 1024 * 1024; + let onscreen = unsafe { physmap(physbaseptr, largest_size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; unsafe { fast_set64(onscreen as *mut u64, 0, size/2) }; let mut scheme = DisplayScheme::new(width, height, onscreen, &spec); diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 495dc44810..21fae86c2f 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -142,21 +142,27 @@ impl SchemeMut for DisplayScheme { let events = unsafe { slice::from_raw_parts(buf.as_ptr() as *const Event, buf.len()/mem::size_of::()) }; for event in events.iter() { - let new_active_opt = if let EventOption::Key(key_event) = event.to_option() { - match key_event.scancode { + let mut new_active_opt = None; + match event.to_option() { + EventOption::Key(key_event) => match key_event.scancode { f @ 0x3B ... 0x44 => { // F1 through F10 - Some((f - 0x3A) as usize) + new_active_opt = Some((f - 0x3A) as usize); }, 0x57 => { // F11 - Some(11) + new_active_opt = Some(11); }, 0x58 => { // F12 - Some(12) + new_active_opt = Some(12); }, - _ => None - } - } else { - None + _ => () + }, + EventOption::Resize(resize_event) => { + println!("Resizing to {}, {}", resize_event.width, resize_event.height); + for (_screen_id, screen) in self.screens.iter_mut() { + screen.resize(resize_event.width as usize, resize_event.height as usize); + } + }, + _ => () }; if let Some(new_active) = new_active_opt { diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 12a26a0a52..089787a81a 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use std::{cmp, mem, slice}; -use orbclient::Event; +use orbclient::{Event, ResizeEvent}; use syscall::error::*; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; @@ -36,6 +36,15 @@ impl Screen for GraphicScreen { self.display.height } + fn resize(&mut self, width: usize, height: usize) { + //TODO: Fix issue with mapped screens + self.display.resize(width, height); + self.input.push_back(ResizeEvent { + width: width as u32, + height: height as u32, + }.to_event()); + } + fn event(&mut self, flags: usize) -> Result { self.requested = flags; Ok(0) diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs index 9909694a99..4558546412 100644 --- a/vesad/src/screen/mod.rs +++ b/vesad/src/screen/mod.rs @@ -12,6 +12,8 @@ pub trait Screen { fn height(&self) -> usize; + fn resize(&mut self, width: usize, height: usize); + fn event(&mut self, flags: usize) -> Result; fn map(&self, offset: usize, size: usize) -> Result; diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index d7f226aaff..d9fd609219 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -43,6 +43,10 @@ impl Screen for TextScreen { self.console.h } + fn resize(&mut self, width: usize, height: usize) { + self.display.resize(width, height); + } + fn event(&mut self, flags: usize) -> Result { self.requested = flags; Ok(0)