From bc7469f7cd177d91b5414f395b40109da3338203 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 12 Jan 2024 18:28:17 +0100 Subject: [PATCH 1/3] Switch vmmouse global_asm block back to inline asm There seems to be a bug somewhere in the global_asm block which causes a SIGSEGV when making unrelated code changes to ps2d. Using an inline asm block is easier to follow and less error prone around following the calling convention. --- ps2d/src/vm.rs | 59 +++++++++++++++++--------------------------------- 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index 3445015091..3f3ae50b50 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -4,7 +4,7 @@ // As well as the Linux implementation here: // http://elixir.free-electrons.com/linux/v4.1/source/drivers/input/mouse/vmmouse.c -use core::arch::global_asm; +use core::arch::asm; const MAGIC: u32 = 0x564D5868; const PORT: u16 = 0x5658; @@ -27,49 +27,30 @@ pub const LEFT_BUTTON: u32 = 0x20; pub const RIGHT_BUTTON: u32 = 0x10; pub const MIDDLE_BUTTON: u32 = 0x08; -#[cfg(target_arch = "x86_64")] -global_asm!(" - .globl cmd_inner -cmd_inner: - mov r8, rdi - - // 2nd argument `cmd` as per sysv64. - mov ecx, esi - // 3rd argument `arg` as per sysv64. - mov ebx, edx - - mov eax, {MAGIC} - mov dx, {PORT} - - in eax, dx - - xchg rdi, r8 - - mov DWORD PTR [rdi + 0x00], eax - mov DWORD PTR [rdi + 0x04], ebx - mov DWORD PTR [rdi + 0x08], ecx - mov DWORD PTR [rdi + 0x0C], edx - mov DWORD PTR [rdi + 0x10], esi - mov DWORD PTR [rdi + 0x14], r8d - - ret -", - MAGIC = const MAGIC, - PORT = const PORT, -); - #[cfg(target_arch = "x86_64")] pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32, u32, u32) { - extern "sysv64" { - fn cmd_inner(array_ptr: *mut u32, cmd: u32, arg: u32); - } + let a: u32; + let b: u32; + let c: u32; + let d: u32; + let si: u32; + let di: u32; - let mut array = [0_u32; 6]; + // ebx can't be used as input or output constraint in rust as LLVM reserves it. + // Use xchg to pass it through r9 instead while restoring the original value in + // rbx when leaving the inline asm block. + asm!( + "xchg r9, rbx; in eax, dx; xchg r9, rbx", + inout("eax") MAGIC => a, + inout("r9") arg => b, + inout("ecx") cmd => c, + inout("edx") PORT as u32 => d, + out("esi") si, + out("edi") di, + ); - cmd_inner(array.as_mut_ptr(), cmd, arg); + (a, b, c, d, si, di) - let [a, b, c, d, e, f] = array; - (a, b, c, d, e, f) } //TODO: is it possible to enable this on non-x86_64? From c2fd9125a7be67b881967046ef2eb007728913ac Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 12 Jan 2024 18:31:08 +0100 Subject: [PATCH 2/3] Fix absolute mouse events with vmmouse It is no longer possible to query the display size from inputd, so defer conversion to display pixel coordinates to orbital instead. This also avoids a lot of work every mouse event to query the display size as orbital saves this information already. --- ps2d/src/state.rs | 58 +++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index b556897645..2496ec2e64 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -26,8 +26,6 @@ pub struct Ps2d char> { vmmouse: bool, vmmouse_relative: bool, input: File, - width: u32, - height: u32, extended: bool, lshift: bool, rshift: bool, @@ -51,13 +49,11 @@ impl char> Ps2d { let vmmouse_relative = true; let vmmouse = vm::enable(vmmouse_relative); - let mut ps2d = Ps2d { + Ps2d { ps2, vmmouse, vmmouse_relative, input, - width: 0, - height: 0, extended: false, lshift: false, rshift: false, @@ -70,20 +66,6 @@ impl char> Ps2d { packet_i: 0, extra_packet, get_char: keymap - }; - - ps2d.resize(); - - ps2d - } - - pub fn resize(&mut self) { - let mut buf: [u8; 4096] = [0; 4096]; - if let Ok(count) = syscall::fpath(self.input.as_raw_fd() as usize, &mut buf) { - let path = unsafe { str::from_utf8_unchecked(&buf[..count]) }; - let res = path.split(":").nth(1).unwrap_or(""); - self.width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); - self.height = res.split("/").nth(2).unwrap_or("").parse::().unwrap_or(0); } } @@ -253,20 +235,20 @@ impl char> Ps2d { } } else if self.vmmouse { for _i in 0..256 { - let (status, _, _, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) }; - //TODO if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) + let (status, _, _, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) }; + //TODO if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) - let queue_length = status & 0xffff; - if queue_length == 0 { - break; + let queue_length = status & 0xffff; + if queue_length == 0 { + break; } - if queue_length % 4 != 0 { - eprintln!("ps2d: queue length not a multiple of 4: {}", queue_length); - break; - } + if queue_length % 4 != 0 { + eprintln!("ps2d: queue length not a multiple of 4: {}", queue_length); + break; + } - let (status, dx, dy, dz, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; + let (status, dx, dy, dz, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; if self.vmmouse_relative { if dx != 0 || dy != 0 { @@ -275,21 +257,17 @@ impl char> Ps2d { dy: dy as i32, }.to_event()).expect("ps2d: failed to write mouse event"); } - } else { - // TODO: Improve efficiency - self.resize(); - - let x = dx as i32 * self.width as i32 / 0xFFFF; - let y = dy as i32 * self.height as i32 / 0xFFFF; + } else { + let x = dx as i32; + let y = dy as i32; if x != self.mouse_x || y != self.mouse_y { self.mouse_x = x; self.mouse_y = y; - self.input.write(&MouseEvent { - x: x, - y: y, - }.to_event()).expect("ps2d: failed to write mouse event"); + self.input + .write(&MouseEvent { x, y }.to_event()) + .expect("ps2d: failed to write mouse event"); } - }; + }; if dz != 0 { self.input.write(&ScrollEvent { From 7a21573ebde3d90128b178ca648b5ce460e51781 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 12 Jan 2024 18:33:29 +0100 Subject: [PATCH 3/3] Switch to absolute mouse events by default when running in a VM This will transparently release the mouse grab of the VM when leaving the screen edge, making it much easier to quickly switch between the VM and other apps running on the host. --- ps2d/src/state.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 2496ec2e64..9891cc8e7e 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -46,7 +46,8 @@ impl char> Ps2d { let mut ps2 = Ps2::new(); let extra_packet = ps2.init().expect("ps2d: failed to initialize"); - let vmmouse_relative = true; + // FIXME add an option for orbital to disable this when an app captures the mouse. + let vmmouse_relative = false; let vmmouse = vm::enable(vmmouse_relative); Ps2d {