Skip to content

Commit 62fa495

Browse files
committed
x11: add x86_64 support
Signed-off-by: Val Packett <[email protected]>
1 parent 4077aea commit 62fa495

File tree

1 file changed

+70
-15
lines changed
  • crates/muvm/src/guest/bridge

1 file changed

+70
-15
lines changed

crates/muvm/src/guest/bridge/x11.rs

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,71 @@ const DRI3_OPCODE_PIXMAP_FROM_BUFFERS: u8 = 7;
5151
const PRESENT_OPCODE_PRESENT_PIXMAP: u8 = 1;
5252
pub const SHM_TEMPLATE: &str = "/dev/shm/krshm-XXXXXX";
5353
pub const SHM_DIR: &str = "/dev/shm/";
54-
const SYSCALL_INSTR: u32 = 0xd4000001;
5554
static SYSCALL_OFFSET: OnceLock<usize> = OnceLock::new();
5655
const CROSS_DOMAIN_CHANNEL_TYPE_X11: u32 = 0x11;
5756
const CROSS_DOMAIN_ID_TYPE_SHM: u32 = 5;
5857
const CROSS_DOMAIN_CMD_FUTEX_NEW: u8 = 8;
5958
const CROSS_DOMAIN_CMD_FUTEX_SIGNAL: u8 = 9;
6059
const CROSS_DOMAIN_CMD_FUTEX_DESTROY: u8 = 10;
6160

61+
#[cfg(target_arch = "aarch64")]
62+
mod arch {
63+
use nix::libc::{c_long, c_ulonglong, user_regs_struct};
64+
pub type SyscallInstr = u32;
65+
pub const SYSCALL_INSTR: SyscallInstr = 0xd4000001;
66+
67+
pub fn set_syscall_addr(regs: &mut user_regs_struct, syscall_addr: usize) {
68+
regs.pc = syscall_addr as u64;
69+
}
70+
71+
pub fn fill_syscall_args(
72+
regs: &mut user_regs_struct,
73+
syscall_no: c_long,
74+
args: &[c_ulonglong; 6],
75+
) {
76+
regs.regs[..6].copy_from_slice(args);
77+
regs.regs[8] = syscall_no as c_ulonglong;
78+
}
79+
80+
pub fn get_syscall_result(regs: &user_regs_struct) -> c_ulonglong {
81+
regs.regs[0]
82+
}
83+
}
84+
85+
#[cfg(target_arch = "x86_64")]
86+
mod arch {
87+
use nix::libc::{c_long, c_ulonglong, user_regs_struct};
88+
pub type SyscallInstr = u16;
89+
pub const SYSCALL_INSTR: SyscallInstr = 0x05_0f;
90+
91+
pub fn set_syscall_addr(regs: &mut user_regs_struct, syscall_addr: usize) {
92+
regs.rip = syscall_addr as u64;
93+
}
94+
95+
pub fn fill_syscall_args(
96+
regs: &mut user_regs_struct,
97+
syscall_no: c_long,
98+
args: &[c_ulonglong; 6],
99+
) {
100+
regs.rdi = args[0];
101+
regs.rsi = args[1];
102+
regs.rdx = args[2];
103+
regs.r10 = args[3];
104+
regs.r8 = args[4];
105+
regs.r9 = args[5];
106+
regs.rax = syscall_no as c_ulonglong;
107+
}
108+
109+
pub fn get_syscall_result(regs: &user_regs_struct) -> c_ulonglong {
110+
regs.rax
111+
}
112+
}
113+
114+
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
115+
mod arch {
116+
pub const SYSCALL_INSTR: u32 = 0xffffffff;
117+
}
118+
62119
#[repr(C)]
63120
#[derive(Debug, Default)]
64121
struct ExportedHandle {
@@ -458,7 +515,7 @@ impl X11ProtocolHandler {
458515
// Allow everything in /dev/shm (including paths with trailing '(deleted)')
459516
let shmem_file = if filename.starts_with(SHM_DIR) {
460517
File::from(memfd)
461-
} else if cfg!(not(target_arch = "aarch64")) {
518+
} else if cfg!(not(any(target_arch = "aarch64", target_arch = "x86_64"))) {
462519
return Err(Errno::EOPNOTSUPP.into());
463520
} else {
464521
let (fd, shmem_path) = mkstemp(SHM_TEMPLATE)?;
@@ -638,8 +695,7 @@ struct RemoteCaller {
638695
}
639696

640697
impl RemoteCaller {
641-
// This is arch-specific, so gate it off of x86_64 builds done for CI purposes
642-
#[cfg(target_arch = "aarch64")]
698+
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
643699
fn with<R, F>(pid: Pid, f: F) -> Result<R>
644700
where
645701
F: FnOnce(&RemoteCaller) -> Result<R>,
@@ -651,7 +707,7 @@ impl RemoteCaller {
651707
let syscall_addr = vdso_start + SYSCALL_OFFSET.get().unwrap();
652708

653709
let mut regs = old_regs;
654-
regs.pc = syscall_addr as u64;
710+
arch::set_syscall_addr(&mut regs, syscall_addr);
655711
ptrace::setregs(pid, regs)?;
656712
let res = f(&RemoteCaller { regs, pid })?;
657713
ptrace::setregs(pid, old_regs)?;
@@ -711,30 +767,29 @@ impl RemoteCaller {
711767
.map(|x| x as i32)
712768
}
713769

714-
// This is arch-specific, so gate it off of x86_64 builds done for CI purposes
715-
#[cfg(target_arch = "aarch64")]
770+
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
716771
fn syscall(&self, syscall_no: c_long, args: [c_ulonglong; 6]) -> Result<c_ulonglong> {
717772
let mut regs = self.regs;
718-
regs.regs[..6].copy_from_slice(&args);
719-
regs.regs[8] = syscall_no as c_ulonglong;
773+
arch::fill_syscall_args(&mut regs, syscall_no, &args);
720774
ptrace::setregs(self.pid, regs)?;
721775
ptrace::step(self.pid, None)?;
722776
let evt = waitpid(self.pid, Some(WaitPidFlag::__WALL))?;
723777
if !matches!(evt, WaitStatus::Stopped(_, _)) {
724778
unimplemented!();
725779
}
726780
regs = ptrace::getregs(self.pid)?;
727-
Ok(regs.regs[0])
781+
Ok(arch::get_syscall_result(&regs))
728782
}
729783

730-
#[cfg(not(target_arch = "aarch64"))]
784+
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
731785
fn with<R, F>(_pid: Pid, _f: F) -> Result<R>
732786
where
733787
F: FnOnce(&RemoteCaller) -> Result<R>,
734788
{
735789
Err(Errno::EOPNOTSUPP.into())
736790
}
737-
#[cfg(not(target_arch = "aarch64"))]
791+
792+
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
738793
fn syscall(&self, _syscall_no: c_long, _args: [c_ulonglong; 6]) -> Result<c_ulonglong> {
739794
Err(Errno::EOPNOTSUPP.into())
740795
}
@@ -799,10 +854,10 @@ pub fn start_x11bridge(display: u32) {
799854
// the same vDSO (which should be true if they are running under the same
800855
// kernel!)
801856
let (vdso_start, vdso_end) = find_vdso(None).unwrap();
802-
for off in (0..(vdso_end - vdso_start)).step_by(4) {
857+
for off in (0..(vdso_end - vdso_start)).step_by(mem::size_of::<arch::SyscallInstr>()) {
803858
let addr = vdso_start + off;
804-
let val = unsafe { std::ptr::read(addr as *const u32) };
805-
if val == SYSCALL_INSTR {
859+
let val = unsafe { std::ptr::read(addr as *const arch::SyscallInstr) };
860+
if val == arch::SYSCALL_INSTR {
806861
SYSCALL_OFFSET.set(off).unwrap();
807862
break;
808863
}

0 commit comments

Comments
 (0)