1 /*
2  * Copyright (c) 2024 Google Inc. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #![deny(unsafe_op_in_unsafe_fn)]
25 use core::ffi::c_int;
26 use core::ptr;
27 
28 use alloc::sync::Arc;
29 
30 use log::{debug, error};
31 
32 use virtio_drivers::device::socket::VirtIOSocket;
33 use virtio_drivers::device::socket::VsockConnectionManager;
34 use virtio_drivers::transport::pci::bus::Cam;
35 use virtio_drivers::transport::pci::bus::Command;
36 use virtio_drivers::transport::pci::bus::DeviceFunction;
37 use virtio_drivers::transport::pci::bus::PciRoot;
38 use virtio_drivers::transport::pci::virtio_device_type;
39 use virtio_drivers::transport::pci::PciTransport;
40 use virtio_drivers::transport::DeviceType;
41 
42 use rust_support::mmu::ARCH_MMU_FLAG_PERM_NO_EXECUTE;
43 use rust_support::mmu::ARCH_MMU_FLAG_UNCACHED_DEVICE;
44 use rust_support::paddr_t;
45 use rust_support::thread::Builder;
46 use rust_support::thread::Priority;
47 use rust_support::vmm::vmm_alloc_physical;
48 use rust_support::vmm::vmm_get_kernel_aspace;
49 use rust_support::Error as LkError;
50 
51 use crate::err::Error;
52 use crate::vsock::VsockDevice;
53 use hal::TrustyHal;
54 
55 mod arch;
56 mod hal;
57 
58 impl TrustyHal {
init_vsock(pci_root: &mut PciRoot, device_function: DeviceFunction) -> Result<(), Error>59     fn init_vsock(pci_root: &mut PciRoot, device_function: DeviceFunction) -> Result<(), Error> {
60         let transport = PciTransport::new::<Self>(pci_root, device_function)?;
61         let driver: VirtIOSocket<TrustyHal, PciTransport, 4096> = VirtIOSocket::new(transport)?;
62         let manager = VsockConnectionManager::new_with_capacity(driver, 4096);
63 
64         let device_for_rx = Arc::new(VsockDevice::new(manager));
65         let device_for_tx = device_for_rx.clone();
66 
67         Builder::new()
68             .name(c"virtio_vsock_rx")
69             .priority(Priority::HIGH)
70             .spawn(move || {
71                 let ret = crate::vsock::vsock_rx_loop(device_for_rx);
72                 error!("vsock_rx_loop returned {:?}", ret);
73                 ret.err().unwrap_or(LkError::NO_ERROR.into()).into_c()
74             })
75             .map_err(|e| LkError::from_lk(e).unwrap_err())?;
76 
77         Builder::new()
78             .name(c"virtio_vsock_tx")
79             .priority(Priority::HIGH)
80             .spawn(move || {
81                 let ret = crate::vsock::vsock_tx_loop(device_for_tx);
82                 error!("vsock_tx_loop returned {:?}", ret);
83                 ret.err().unwrap_or(LkError::NO_ERROR.into()).into_c()
84             })
85             .map_err(|e| LkError::from_lk(e).unwrap_err())?;
86 
87         Ok(())
88     }
89 
init_all_vsocks(mut pci_root: PciRoot, pci_size: usize) -> Result<(), Error>90     fn init_all_vsocks(mut pci_root: PciRoot, pci_size: usize) -> Result<(), Error> {
91         for bus in u8::MIN..=u8::MAX {
92             // each bus can use up to one megabyte of address space, make sure we stay in range
93             if bus as usize * 0x100000 >= pci_size {
94                 break;
95             }
96             for (device_function, info) in pci_root.enumerate_bus(bus) {
97                 if virtio_device_type(&info) != Some(DeviceType::Socket) {
98                     continue;
99                 };
100 
101                 // Map the BARs of the device into virtual memory. Since the mappings must
102                 // outlive the `PciTransport` constructed in `init_vsock` we no make no
103                 // attempt to deallocate them.
104                 Self::mmio_alloc(&mut pci_root, device_function)?;
105 
106                 // Enable the device to use its BARs.
107                 pci_root.set_command(
108                     device_function,
109                     Command::IO_SPACE | Command::MEMORY_SPACE | Command::BUS_MASTER,
110                 );
111 
112                 Self::init_vsock(&mut pci_root, device_function)?;
113             }
114         }
115         Ok(())
116     }
117 }
118 
119 /// # Safety
120 ///
121 /// `pci_paddr` must be a valid physical address with `'static` lifetime to the base of the MMIO region,
122 /// which must have a size of `pci_size`.
map_pci_root( pci_paddr: paddr_t, pci_size: usize, cfg_size: usize, ) -> Result<PciRoot, Error>123 unsafe fn map_pci_root(
124     pci_paddr: paddr_t,
125     pci_size: usize,
126     cfg_size: usize,
127 ) -> Result<PciRoot, Error> {
128     // The ECAM is defined in Section 7.2.2 of the PCI Express Base Specification, Revision 2.0.
129     // The ECAM size must be a power of two with the exponent between 1 and 8.
130     let cam = match cfg_size / /* device functions */ 8 {
131         256 => Cam::MmioCam,
132         4096 => Cam::Ecam,
133         _ => return Err(LkError::ERR_BAD_LEN.into()),
134     };
135 
136     if !pci_size.is_power_of_two() || pci_size > cam.size() as usize {
137         return Err(LkError::ERR_BAD_LEN.into());
138     }
139     // The ECAM base must be 2^(n + 20)-bit aligned.
140     if cam == Cam::Ecam && pci_paddr & (pci_size - 1) != 0 {
141         return Err(LkError::ERR_INVALID_ARGS.into());
142     }
143 
144     // Map the PCI configuration space.
145     let pci_vaddr = ptr::null_mut();
146     // Safety:
147     // `aspace` is `vmm_get_kernel_aspace()`.
148     // `name` is a `&'static CStr`.
149     // `pci_paddr` and `pci_size` are safe by this function's safety requirements.
150     let e = unsafe {
151         vmm_alloc_physical(
152             vmm_get_kernel_aspace(),
153             c"pci_config_space".as_ptr(),
154             pci_size,
155             &pci_vaddr,
156             0,
157             pci_paddr,
158             0,
159             ARCH_MMU_FLAG_PERM_NO_EXECUTE | ARCH_MMU_FLAG_UNCACHED_DEVICE,
160         )
161     };
162     LkError::from_lk(e)?;
163 
164     // Safety:
165     // `pci_paddr` is a valid physical address to the base of the MMIO region.
166     // `pci_vaddr` is the mapped virtual address of that.
167     // `pci_paddr` has `'static` lifetime, and `pci_vaddr` is never unmapped,
168     // so it, too, has `'static` lifetime.
169     // We also check that the `cam` size is valid.
170     let pci_root = unsafe { PciRoot::new(pci_vaddr.cast(), cam) };
171 
172     Ok(pci_root)
173 }
174 
175 /// # Safety
176 ///
177 /// See [`map_pci_root`].
178 #[no_mangle]
pci_init_mmio( pci_paddr: paddr_t, pci_size: usize, cfg_size: usize, ) -> c_int179 pub unsafe extern "C" fn pci_init_mmio(
180     pci_paddr: paddr_t,
181     pci_size: usize,
182     cfg_size: usize,
183 ) -> c_int {
184     debug!("initializing vsock: pci_paddr 0x{pci_paddr:x}, pci_size 0x{pci_size:x}");
185     || -> Result<(), Error> {
186         // Safety: Delegated to `map_pci_root`.
187         let pci_root = unsafe { map_pci_root(pci_paddr, pci_size, cfg_size) }?;
188         TrustyHal::init_all_vsocks(pci_root, pci_size)?;
189         Ok(())
190     }()
191     .err()
192     .unwrap_or(LkError::NO_ERROR.into())
193     .into_c()
194 }
195