Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic x112virtgpu support #72

Merged
merged 3 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion crates/muvm/src/bin/muvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ fn main() -> Result<()> {

// Forward the native X11 display into the guest as a socket
if let Ok(x11_display) = env::var("DISPLAY") {
if let Some(x11_display) = x11_display.strip_prefix(":") {
if let Some(x11_display) = x11_display.strip_prefix(':') {
let socket_path = Path::new("/tmp/.X11-unix/").join(format!("X{}", x11_display));
if socket_path.exists() {
let socket_path = CString::new(
Expand Down Expand Up @@ -361,6 +361,18 @@ fn main() -> Result<()> {
options.server_port.to_string(),
);

if options.direct_x11 {
let display =
env::var("DISPLAY").context("X11 forwarding requested but DISPLAY is unset")?;
env.insert("HOST_DISPLAY".to_string(), display);

// And forward XAUTHORITY. This will be modified to fix the
// display name in muvm-guest.
if let Ok(xauthority) = env::var("XAUTHORITY") {
env.insert("XAUTHORITY".to_string(), xauthority);
}
}

let mut krun_config = KrunConfig {
args: Vec::new(),
envs: Vec::new(),
Expand Down
7 changes: 7 additions & 0 deletions crates/muvm/src/cli_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub struct Options {
pub passt_socket: Option<PathBuf>,
pub server_port: u32,
pub fex_images: Vec<String>,
pub direct_x11: bool,
pub command: PathBuf,
pub command_args: Vec<String>,
}
Expand Down Expand Up @@ -98,6 +99,11 @@ pub fn options() -> OptionParser<Options> {
.argument("SERVER_PORT")
.fallback(3334)
.display_fallback();
let direct_x11 = long("direct-x11")
.short('x')
.help("Use direct X11 forwarding instead of sommelier + XWayland")
.switch();

let command = positional("COMMAND").help("the command you want to execute in the vm");
let command_args = any::<String, _, _>("COMMAND_ARGS", |arg| {
(!["--help", "-h"].contains(&&*arg)).then_some(arg)
Expand All @@ -113,6 +119,7 @@ pub fn options() -> OptionParser<Options> {
passt_socket,
server_port,
fex_images,
direct_x11,
// positionals
command,
command_args,
Expand Down
13 changes: 0 additions & 13 deletions crates/muvm/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,6 @@ pub fn prepare_env_vars(env: Vec<(String, Option<String>)>) -> Result<HashMap<St
env_map.insert(key, value);
}

// If we have an X11 display in the host, set HOST_DISPLAY in the guest.
// muvm-guest will then use this to set up xauth and replace it with :1
// (which is forwarded to the host display).
if let Ok(display) = env::var("DISPLAY") {
env_map.insert("HOST_DISPLAY".to_string(), display);

// And forward XAUTHORITY. This will be modified to fix the
// display name in muvm-guest.
if let Ok(xauthority) = env::var("XAUTHORITY") {
env_map.insert("XAUTHORITY".to_string(), xauthority);
}
}

debug!(env:? = env_map; "env vars");

Ok(env_map)
Expand Down
12 changes: 6 additions & 6 deletions crates/muvm/src/guest/bin/muvm-guest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ fn main() -> Result<()> {
let pulse_path = pulse_path.join("native");
setup_socket_proxy(pulse_path, 3333)?;

setup_x11_forwarding(run_path)?;

// Will not return if successful.
exec_sommelier(&options.command, &options.command_args)
.context("Failed to execute sommelier")?;
if !setup_x11_forwarding(run_path)? {
// Will not return if successful.
exec_sommelier(&options.command, &options.command_args)
.context("Failed to execute sommelier")?;
}

// Fallback option if sommelier is not present.
// Fallback option if sommelier is not present or for direct X11 mode.
debug!(command:? = options.command, command_args:? = options.command_args; "exec");
let err = Command::new(&options.command)
.args(options.command_args)
Expand Down
29 changes: 21 additions & 8 deletions crates/muvm/src/guest/x11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,47 @@ use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
use std::process::Command;

use anyhow::{anyhow, Context, Result};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use super::socket::setup_socket_proxy;

pub fn setup_x11_forwarding<P>(run_path: P) -> Result<()>
use crate::utils::env::find_in_path;

pub fn setup_x11_forwarding<P>(run_path: P) -> Result<bool>
where
P: AsRef<Path>,
{
// Set by muvm if DISPLAY was provided from the host.
let host_display = match env::var("HOST_DISPLAY") {
Ok(d) => d,
Err(_) => return Ok(()),
Err(_) => return Ok(false),
};

if !host_display.starts_with(":") {
if !host_display.starts_with(':') {
return Err(anyhow!("Invalid host DISPLAY"));
}
let host_display = &host_display[1..];

setup_socket_proxy(Path::new("/tmp/.X11-unix/X1"), 6000)?;
let x112virtgpu_path =
find_in_path("x112virtgpu").context("Failed to check existence of `x112virtgpu`")?;

if x112virtgpu_path.is_some() {
let mut cmd = Command::new(x112virtgpu_path.unwrap());
cmd.args(["--listen-display", ":1"]);

cmd.spawn().context("Failed to spawn `x112virtgpu`")?;
} else {
log::error!("x112virtgpu not available, X11 forwarding will operate in socket forwarding mode. This is probably not what you want.");
setup_socket_proxy(Path::new("/tmp/.X11-unix/X1"), 6000)?;
}

// Set HOST_DISPLAY to :1, which is the display number within the guest
// at which the actual host display is accessible.
// SAFETY: Safe if and only if `muvm-guest` program is not multithreaded.
// See https://doc.rust-lang.org/std/env/fn.set_var.html#safety
env::set_var("HOST_DISPLAY", ":1");
env::set_var("DISPLAY", ":1");
env::set_var("XSHMFENCE_NO_MEMFD", "1");

if let Ok(xauthority) = std::env::var("XAUTHORITY") {
let src_path = format!("/run/muvm-host/{}", xauthority);
Expand Down Expand Up @@ -87,5 +100,5 @@ where
env::set_var("XAUTHORITY", dst_path);
}

Ok(())
Ok(true)
}
Loading