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
26 use core::ffi::c_int;
27 use core::ptr;
28
29 use log::debug;
30
31 use virtio_drivers::device::socket::VirtIOSocket;
32 use virtio_drivers::device::socket::VsockConnectionManager;
33 use virtio_drivers::transport::pci::bus::Cam;
34 use virtio_drivers::transport::pci::bus::Command;
35 use virtio_drivers::transport::pci::bus::DeviceFunction;
36 use virtio_drivers::transport::pci::bus::PciRoot;
37 use virtio_drivers::transport::pci::virtio_device_type;
38 use virtio_drivers::transport::pci::PciTransport;
39 use virtio_drivers::transport::DeviceType;
40
41 use rust_support::mmu::ARCH_MMU_FLAG_PERM_NO_EXECUTE;
42 use rust_support::mmu::ARCH_MMU_FLAG_UNCACHED_DEVICE;
43 use rust_support::paddr_t;
44 use rust_support::thread::Builder;
45 use rust_support::thread::Priority;
46 use rust_support::vmm::vmm_alloc_physical;
47 use rust_support::vmm::vmm_get_kernel_aspace;
48 use rust_support::Error as LkError;
49
50 use crate::err::Error;
51 use crate::hal::TrustyHal;
52
53 impl TrustyHal {
init_vsock(pci_root: &mut PciRoot, device_function: DeviceFunction) -> Result<(), Error>54 fn init_vsock(pci_root: &mut PciRoot, device_function: DeviceFunction) -> Result<(), Error> {
55 let transport = PciTransport::new::<Self>(pci_root, device_function)?;
56 let driver: VirtIOSocket<TrustyHal, PciTransport> = VirtIOSocket::new(transport)?;
57 let _manager = VsockConnectionManager::new(driver); // TODO move
58
59 Builder::new()
60 .name(c"virtio_vsock_rx")
61 .priority(Priority::HIGH)
62 .spawn(move || {
63 todo!("Call routine for virtio rx worker");
64 })
65 .map_err(|e| LkError::from_lk(e).unwrap_err())?;
66
67 Builder::new()
68 .name(c"virtio_vsock_tx")
69 .priority(Priority::HIGH)
70 .spawn(move || {
71 todo!("Call routine for virtio tx worker");
72 })
73 .map_err(|e| LkError::from_lk(e).unwrap_err())?;
74
75 Ok(())
76 }
77
init_all_vsocks(mut pci_root: PciRoot, pci_size: usize) -> Result<(), Error>78 fn init_all_vsocks(mut pci_root: PciRoot, pci_size: usize) -> Result<(), Error> {
79 for bus in u8::MIN..=u8::MAX {
80 // each bus can use up to one megabyte of address space, make sure we stay in range
81 if bus as usize * 0x100000 >= pci_size {
82 break;
83 }
84 for (device_function, info) in pci_root.enumerate_bus(bus) {
85 if virtio_device_type(&info) != Some(DeviceType::Socket) {
86 continue;
87 };
88
89 // Map the BARs of the device into virtual memory. Since the mappings must
90 // outlive the `PciTransport` constructed in `init_vsock` we no make no
91 // attempt to deallocate them.
92 Self::mmio_alloc(&mut pci_root, device_function)?;
93
94 // Enable the device to use its BARs.
95 pci_root.set_command(
96 device_function,
97 Command::IO_SPACE | Command::MEMORY_SPACE | Command::BUS_MASTER,
98 );
99
100 Self::init_vsock(&mut pci_root, device_function)?;
101 }
102 }
103 Ok(())
104 }
105 }
106
107 /// # Safety
108 ///
109 /// `pci_paddr` must be a valid physical address with `'static` lifetime to the base of the MMIO region,
110 /// which must have a size of `pci_size`.
map_pci_root( pci_paddr: paddr_t, pci_size: usize, _cfg_size: usize, ) -> Result<PciRoot, Error>111 unsafe fn map_pci_root(
112 pci_paddr: paddr_t,
113 pci_size: usize,
114 _cfg_size: usize,
115 ) -> Result<PciRoot, Error> {
116 // The ECAM is defined in Section 7.2.2 of the PCI Express Base Specification, Revision 2.0.
117 // The ECAM size must be a power of two with the exponent between 1 and 8.
118 let cam = Cam::Ecam;
119 if !pci_size.is_power_of_two() || pci_size > cam.size() as usize {
120 return Err(LkError::ERR_BAD_LEN.into());
121 }
122 // The ECAM base must be 2^(n + 20)-bit aligned.
123 if pci_paddr & (pci_size - 1) != 0 {
124 return Err(LkError::ERR_INVALID_ARGS.into());
125 }
126
127 // Map the PCI configuration space.
128 let pci_vaddr = ptr::null_mut();
129 // # Safety
130 // `aspace` is `vmm_get_kernel_aspace()`.
131 // `name` is a `&'static CStr`.
132 // `pci_paddr` and `pci_size` are safe by this function's safety requirements.
133 let e = unsafe {
134 vmm_alloc_physical(
135 vmm_get_kernel_aspace(),
136 c"pci_config_space".as_ptr(),
137 pci_size,
138 &pci_vaddr,
139 0,
140 pci_paddr,
141 0,
142 ARCH_MMU_FLAG_PERM_NO_EXECUTE | ARCH_MMU_FLAG_UNCACHED_DEVICE,
143 )
144 };
145 LkError::from_lk(e)?;
146
147 // # Safety:
148 // `pci_paddr` is a valid physical address to the base of the MMIO region.
149 // `pci_vaddr` is the mapped virtual address of that.
150 // `pci_paddr` has `'static` lifetime, and `pci_vaddr` is never unmapped,
151 // so it, too, has `'static` lifetime.
152 // We also check that the `cam` size is valid.
153 let pci_root = unsafe { PciRoot::new(pci_vaddr.cast(), cam) };
154
155 Ok(pci_root)
156 }
157
158 /// # Safety
159 ///
160 /// See [`map_pci_root`].
161 #[no_mangle]
pci_init_mmio( pci_paddr: paddr_t, pci_size: usize, cfg_size: usize, ) -> c_int162 pub unsafe extern "C" fn pci_init_mmio(
163 pci_paddr: paddr_t,
164 pci_size: usize,
165 cfg_size: usize,
166 ) -> c_int {
167 debug!("initializing vsock: pci_paddr 0x{pci_paddr:x}, pci_size 0x{pci_size:x}");
168 || -> Result<(), Error> {
169 // Safety: Delegated to `map_pci_root`.
170 let pci_root = unsafe { map_pci_root(pci_paddr, pci_size, cfg_size) }?;
171 TrustyHal::init_all_vsocks(pci_root, pci_size)?;
172 Ok(())
173 }()
174 .err()
175 .unwrap_or(LkError::NO_ERROR.into())
176 .into_c()
177 }
178