1# Design
2
3## Objectives
4
5- Provide a set of traits for accessing and configuring the physical memory of
6  a virtual machine.
7- Provide a clean abstraction of the VM memory such that rust-vmm components
8  can use it without depending on the implementation details specific to
9  different VMMs.
10
11## API Principles
12
13- Define consumer side interfaces to access VM's physical memory.
14- Do not define provider side interfaces to supply VM physical memory.
15
16The `vm-memory` crate focuses on defining consumer side interfaces to access
17the physical memory of the VM. It does not define how the underlying VM memory
18provider is implemented. Lightweight VMMs like
19[CrosVM](https://chromium.googlesource.com/chromiumos/platform/crosvm/) and
20[Firecracker](https://github.com/firecracker-microvm/firecracker) can make
21assumptions about the structure of VM's physical memory and implement a
22lightweight backend to access it. For VMMs like [Qemu](https://www.qemu.org/),
23a high performance and full functionality backend may be implemented with less
24assumptions.
25
26## Architecture
27
28The `vm-memory` is derived from two upstream projects:
29
30- [CrosVM](https://chromium.googlesource.com/chromiumos/platform/crosvm/)
31  commit 186eb8b0db644892e8ffba8344efe3492bb2b823
32- [Firecracker](https://github.com/firecracker-microvm/firecracker) commit
33  80128ea61b305a27df1f751d70415b04b503eae7
34
35The high level abstraction of the VM memory has been heavily refactored to
36provide a VMM agnostic interface.
37
38The `vm-memory` crate could be divided into four logic parts as:
39
40- [Abstraction of Address Space](#abstraction-of-address-space)
41- [Specialization for Virtual Machine Physical Address Space](#specialization-for-virtual-machine-physical-address-space)
42- [Backend Implementation Based on `mmap`](#backend-implementation-based-on-`mmap`)
43- [Utilities and helpers](#utilities-and-helpers)
44
45### Address Space Abstraction
46
47The address space abstraction contains traits and implementations for working
48with addresses as follows:
49
50- `AddressValue`: stores the raw value of an address. Typically `u32`, `u64` or
51   `usize` are used to store the raw value. Pointers such as `*u8`, can not be
52   used as an implementation of `AddressValue` because the `Add` and `Sub`
53   traits are not implemented for that type.
54- `Address`: implementation of `AddressValue`.
55- `Bytes`: trait for volatile access to memory. The `Bytes` trait can be
56  parameterized with types that represent addresses, in order to enforce that
57  addresses are used with the right "kind" of volatile memory.
58- `VolatileMemory`: basic implementation of volatile access to memory.
59  Implements `Bytes<usize>`.
60
61To make the abstraction as generic as possible, all of above traits only define
62methods to access the address space, and they never define methods to manage
63(create, delete, insert, remove etc) address spaces. This way, the address
64space consumers may be decoupled from the address space provider
65(typically a VMM).
66
67### Specialization for Virtual Machine Physical Address Space
68
69The generic address space crates are specialized to access the physical memory
70of the VM using the following traits:
71
72- `GuestAddress`: represents a guest physical address (GPA). On ARM64, a
73  32-bit VMM/hypervisor can be used to support a 64-bit VM. For simplicity,
74  `u64` is used to store the the raw value no matter if it is a 32-bit or
75  a 64-bit virtual machine.
76- `GuestMemoryRegion`: represents a continuous region of the VM memory.
77- `GuestMemory`: represents a collection of `GuestMemoryRegion` objects. The
78  main responsibilities of the `GuestMemory` trait are:
79  - hide the detail of accessing physical addresses (for example complex
80    hierarchical structures).
81  - map an address request to a `GuestMemoryRegion` object and relay the
82    request to it.
83  - handle cases where an access request is spanning two or more
84    `GuestMemoryRegion` objects.
85
86The VM memory consumers should only rely on traits and structs defined here to
87access VM's physical memory and not on the implementation of the traits.
88
89### Backend Implementation Based on `mmap`
90
91Provides an implementation of the `GuestMemory` trait by mmapping the VM's physical
92memory into the current process.
93
94- `MmapRegion`: implementation of mmap a continuous range of physical memory
95  with methods for accessing the mapped memory.
96- `GuestRegionMmap`: implementation of `GuestMemoryRegion` providing a wrapper
97  used to map VM's physical address into a `(mmap_region, offset)` tuple.
98- `GuestMemoryMmap`: implementation of `GuestMemory` that manages a collection
99  of `GuestRegionMmap` objects for a VM.
100
101One of the main responsibilities of `GuestMemoryMmap` is to handle the use
102cases where an access request crosses the memory region boundary. This scenario
103may be triggered when memory hotplug is supported. There is a trade-off between
104simplicity and code complexity:
105
106- The following pattern currently used in both CrosVM and Firecracker is
107  simple, but fails when the request crosses region boundary.
108
109```rust
110let guest_memory_mmap: GuestMemoryMmap = ...
111let addr: GuestAddress = ...
112let buf = &mut [0u8; 5];
113let result = guest_memory_mmap.find_region(addr).unwrap().write(buf, addr);
114```
115
116- To support requests crossing region boundary, the following update is needed:
117
118```rust
119let guest_memory_mmap: GuestMemoryMmap = ...
120let addr: GuestAddress = ...
121let buf = &mut [0u8; 5];
122let result = guest_memory_mmap.write(buf, addr);
123```
124
125### Utilities and Helpers
126
127The following utilities and helper traits/macros are imported from the
128[crosvm project](https://chromium.googlesource.com/chromiumos/platform/crosvm/)
129with minor changes:
130
131- `ByteValued` (originally `DataInit`): types which are safe to be initialized
132  from raw data. A type `T` is `ByteValued` if and only if it can be
133  initialized by reading its contents from a byte array. This is generally true
134  for all plain-old-data structs.  It is notably not true for any type that
135  includes a reference.
136- `{Le,Be}_{16,32,64}`: explicit endian types useful for embedding in structs
137  or reinterpreting data.
138
139## Relationships between Traits, Structs and Types
140
141**Traits**:
142
143- `Address` inherits `AddressValue`
144- `GuestMemoryRegion` inherits `Bytes<MemoryRegionAddress, E = Error>`. The
145  `Bytes` trait must be implemented.
146- `GuestMemory` has a generic implementation of `Bytes<GuestAddress>`.
147
148**Types**:
149
150- `GuestAddress`: `Address<u64>`
151- `MemoryRegionAddress`: `Address<u64>`
152
153**Structs**:
154
155- `MmapRegion` implements `VolatileMemory`
156- `GuestRegionMmap` implements `Bytes<MemoryRegionAddress> + GuestMemoryRegion`
157- `GuestMemoryMmap` implements `GuestMemory`
158- `VolatileSlice` implements
159  `Bytes<usize, E = volatile_memory::Error> + VolatileMemory`
160