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
71 .async_executor
72 .unwrap_or(ExecutorKindSys::Handle.into());
73 let ex = Executor::with_executor_kind(kind).context("failed to create executor")?;
74
75 let block = Box::new(BlockAsync::new(
76 base_features(ProtectionType::Unprotected),
77 disk_option
78 .open()
79 .exit_context(Exit::OpenDiskImage, "failed to open disk image")?,
80 &disk_option,
81 None,
82 None,
83 None,
84 )?);
85
86 // TODO(b/213170185): Uncomment once sandbox is upstreamed.
87 // if sandbox::is_sandbox_target() {
88 // sandbox::TargetServices::get()
89 // .expect("failed to get target services")
90 // .unwrap()
91 // .lower_token();
92 // }
93
94 // This is basically the event loop.
95 let handler = block.build(&ex)?;
96
97 info!("vhost-user disk device ready, starting run loop...");
98 if let Err(e) = ex.run_until(run_handler(handler, vhost_user_tube, exit_event, &ex)) {
99 bail!("error occurred: {}", e);
100 }
101
102 Ok(())
103 }
104