1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! A client for trusty security VMs during early boot.
16
17 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
18 CpuTopology::CpuTopology, IVirtualizationService::IVirtualizationService,
19 VirtualMachineConfig::VirtualMachineConfig, VirtualMachineRawConfig::VirtualMachineRawConfig,
20 };
21 use android_system_virtualizationservice::binder::{ParcelFileDescriptor, Strong};
22 use anyhow::{Context, Result};
23 use clap::Parser;
24 use std::fs::File;
25 use std::path::PathBuf;
26 use vmclient::VmInstance;
27
28 #[derive(Parser)]
29 /// Collection of CLI for trusty_security_vm_launcher
30 pub struct Args {
31 /// Path to the trusty kernel image.
32 #[arg(long)]
33 kernel: PathBuf,
34
35 /// Whether the VM is protected or not.
36 #[arg(long)]
37 protected: bool,
38
39 /// Name of the VM. Used to pull correct config from early_vms.xml
40 #[arg(long, default_value = "trusty_security_vm_launcher")]
41 name: String,
42
43 /// Memory size of the VM in MiB
44 #[arg(long, default_value_t = 128)]
45 memory_size_mib: i32,
46
47 /// CPU Topology exposed to the VM <one-cpu|match-host>
48 #[arg(long, default_value = "one-cpu", value_parser = parse_cpu_topology)]
49 cpu_topology: CpuTopology,
50 }
51
get_service() -> Result<Strong<dyn IVirtualizationService>>52 fn get_service() -> Result<Strong<dyn IVirtualizationService>> {
53 let virtmgr = vmclient::VirtualizationService::new_early()
54 .context("Failed to spawn VirtualizationService")?;
55 virtmgr.connect().context("Failed to connect to VirtualizationService")
56 }
57
parse_cpu_topology(s: &str) -> Result<CpuTopology, String>58 fn parse_cpu_topology(s: &str) -> Result<CpuTopology, String> {
59 match s {
60 "one-cpu" => Ok(CpuTopology::ONE_CPU),
61 "match-host" => Ok(CpuTopology::MATCH_HOST),
62 _ => Err(format!("Invalid cpu topology {}", s)),
63 }
64 }
65
main() -> Result<()>66 fn main() -> Result<()> {
67 let args = Args::parse();
68
69 let service = get_service()?;
70
71 let kernel =
72 File::open(&args.kernel).with_context(|| format!("Failed to open {:?}", &args.kernel))?;
73
74 let vm_config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
75 name: args.name.to_owned(),
76 kernel: Some(ParcelFileDescriptor::new(kernel)),
77 protectedVm: args.protected,
78 memoryMib: args.memory_size_mib,
79 cpuTopology: args.cpu_topology,
80 platformVersion: "~1.0".to_owned(),
81 // TODO: add instanceId
82 ..Default::default()
83 });
84
85 println!("creating VM");
86 let vm = VmInstance::create(
87 service.as_ref(),
88 &vm_config,
89 // console_in, console_out, and log will be redirected to the kernel log by virtmgr
90 None, // console_in
91 None, // console_out
92 None, // log
93 None, // dump_dt
94 None, // callback
95 )
96 .context("Failed to create VM")?;
97 vm.start().context("Failed to start VM")?;
98
99 println!("started trusty_security_vm_launcher VM");
100 let death_reason = vm.wait_for_death();
101 eprintln!("trusty_security_vm_launcher ended: {:?}", death_reason);
102
103 // TODO(b/331320802): we may want to use android logger instead of stdio_to_kmsg?
104
105 Ok(())
106 }
107