1 // Copyright 2021, 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 //! Function and types for VM configuration.
16 
17 use anyhow::{bail, Error};
18 use serde::{Deserialize, Serialize};
19 use std::fs::File;
20 use std::io::BufReader;
21 
22 /// Configuration for a particular VM to be started.
23 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
24 pub struct VmConfig {
25     /// The filename of the kernel image, if any.
26     pub kernel: Option<String>,
27     /// The filename of the initial ramdisk for the kernel, if any.
28     pub initrd: Option<String>,
29     /// Parameters to pass to the kernel. As far as the VMM and boot protocol are concerned this is
30     /// just a string, but typically it will contain multiple parameters separated by spaces.
31     pub params: Option<String>,
32     /// The bootloader to use. If this is supplied then the kernel and initrd must not be supplied;
33     /// the bootloader is instead responsibly for loading the kernel from one of the disks.
34     pub bootloader: Option<String>,
35     /// Disk images to be made available to the VM.
36     #[serde(default)]
37     pub disks: Vec<DiskImage>,
38 }
39 
40 impl VmConfig {
41     /// Ensure that the configuration has a valid combination of fields set, or return an error if
42     /// not.
43     pub fn validate(&self) -> Result<(), Error> {
44         if self.bootloader.is_none() && self.kernel.is_none() {
45             bail!("VM must have either a bootloader or a kernel image.");
46         }
47         if self.bootloader.is_some() && (self.kernel.is_some() || self.initrd.is_some()) {
48             bail!("Can't have both bootloader and kernel/initrd image.");
49         }
50         Ok(())
51     }
52 
53     /// Load the configuration for a VM from the given JSON file.
54     pub fn load(file: &File) -> Result<VmConfig, Error> {
55         let buffered = BufReader::new(file);
56         Ok(serde_json::from_reader(buffered)?)
57     }
58 }
59 
60 /// A disk image to be made available to the VM.
61 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
62 pub struct DiskImage {
63     /// The filename of the disk image.
64     pub image: String,
65     /// Whether this disk should be writable by the VM.
66     pub writable: bool,
67 }
68