1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::fs::File;
6 use std::fs::OpenOptions;
7 use std::os::windows::fs::OpenOptionsExt;
8
9 use anyhow::bail;
10 use anyhow::Context;
11 use argh::FromArgs;
12 use base::enable_high_res_timers;
13 use base::info;
14 use base::Event;
15 use base::RawDescriptor;
16 use broker_ipc::common_child_setup;
17 use broker_ipc::CommonChildStartupArgs;
18 use cros_async::sys::windows::ExecutorKindSys;
19 use cros_async::Executor;
20 use crosvm_cli::sys::windows::exit::Exit;
21 use crosvm_cli::sys::windows::exit::ExitContext;
22 use crosvm_cli::sys::windows::exit::ExitContextAnyhow;
23 use hypervisor::ProtectionType;
24 use tube_transporter::TubeToken;
25
26 use crate::virtio::base_features;
27 use crate::virtio::block::DiskOption;
28 use crate::virtio::vhost::user::device::block::BlockBackend;
29 use crate::virtio::vhost::user::device::handler::sys::windows::read_from_tube_transporter;
30 use crate::virtio::vhost::user::device::handler::sys::windows::run_handler;
31 use crate::virtio::vhost::user::device::VhostUserDevice;
32 use crate::virtio::vhost::user::VhostUserDeviceBuilder;
33 use crate::virtio::BlockAsync;
34
35 #[derive(FromArgs, Debug)]
36 #[argh(subcommand, name = "block", description = "")]
37 pub struct Options {
38 #[argh(
39 option,
40 description = "pipe handle end for Tube Transporter",
41 arg_name = "HANDLE"
42 )]
43 bootstrap: usize,
44 }
45
start_device(opts: Options) -> anyhow::Result<()>46 pub fn start_device(opts: Options) -> anyhow::Result<()> {
47 cros_tracing::init();
48
49 let raw_transport_tube = opts.bootstrap as RawDescriptor;
50
51 let mut tubes = read_from_tube_transporter(raw_transport_tube)?;
52
53 let vhost_user_tube = tubes.get_tube(TubeToken::VhostUser)?;
54 let _control_tube = tubes.get_tube(TubeToken::Control)?;
55 let bootstrap_tube = tubes.get_tube(TubeToken::Bootstrap)?;
56
57 let startup_args: CommonChildStartupArgs = bootstrap_tube.recv::<CommonChildStartupArgs>()?;
58 let _child_cleanup = common_child_setup(startup_args)?;
59
60 let disk_option: DiskOption = bootstrap_tube.recv::<DiskOption>()?;
61 let exit_event = bootstrap_tube.recv::<Event>()?;
62
63 // TODO(b/213146388): Replace below with `broker_ipc::common_child_setup`
64 // once `src` directory is upstreamed.
65 let _raise_timer_resolution =
66 enable_high_res_timers().context("failed to set timer resolution")?;
67
68 info!("using {:?} executor.", disk_option.async_executor);
69
70 let kind = disk_option.async_executor.unwrap_or_default();
71 let ex = Executor::with_executor_kind(kind).context("failed to create executor")?;
72
73 let block = Box::new(BlockAsync::new(
74 base_features(ProtectionType::Unprotected),
75 disk_option
76 .open()
77 .exit_context(Exit::OpenDiskImage, "failed to open disk image")?,
78 &disk_option,
79 None,
80 None,
81 None,
82 )?);
83
84 // TODO(b/213170185): Uncomment once sandbox is upstreamed.
85 // if sandbox::is_sandbox_target() {
86 // sandbox::TargetServices::get()
87 // .expect("failed to get target services")
88 // .unwrap()
89 // .lower_token();
90 // }
91
92 // This is basically the event loop.
93 let handler = block.build(&ex)?;
94
95 info!("vhost-user disk device ready, starting run loop...");
96 ex.run_until(run_handler(handler, vhost_user_tube, exit_event, &ex))
97 .context("run_until error")?
98 .context("run_handler error")
99 }
100