• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #![no_std]
25 
26 use core::ffi::CStr;
27 use core::marker::PhantomPinned;
28 use core::pin::Pin;
29 use rust_support::{
30     ktipc::{ktipc_port_acl, ktipc_server, ktipc_server_new, ktipc_server_start},
31     mmu::PAGE_SIZE,
32     vmm::{
33         vmm_get_kernel_aspace, vmm_get_obj, vmm_obj_service, vmm_obj_service_add,
34         vmm_obj_service_create_ro, vmm_obj_service_destroy, vmm_obj_slice, vmm_obj_slice_init,
35         vmm_obj_slice_release, VmmPageArray,
36     },
37     Error,
38 };
39 use trusty_std::boxed::Box;
40 use zerocopy::{Immutable, IntoBytes};
41 
42 #[derive(Immutable, IntoBytes)]
43 #[repr(C)]
44 pub struct VmmObjServiceHeader {
45     data_start: u32,
46     size: u32,
47 }
48 const HDR_SIZE: usize = core::mem::size_of::<VmmObjServiceHeader>();
49 
create_obj_service_ro( port: &'static CStr, acl: &'static ktipc_port_acl, slice: &vmm_obj_slice, size: usize, ) -> Result<*mut vmm_obj_service, Error>50 fn create_obj_service_ro(
51     port: &'static CStr,
52     acl: &'static ktipc_port_acl,
53     slice: &vmm_obj_slice,
54     size: usize,
55 ) -> Result<*mut vmm_obj_service, Error> {
56     let mut svc: *mut vmm_obj_service = core::ptr::null_mut();
57     // SAFETY: port and acl are static and therefore valid for the lifetime of vmm_obj_service.
58     let rc = unsafe { vmm_obj_service_create_ro(port.as_ptr(), acl, slice.obj, 0, size, &mut svc) };
59     if rc < 0 {
60         log::error!("Failed to create service {:X}", rc);
61         Error::from_lk(rc)?;
62     }
63     Ok(svc)
64 }
65 
66 struct VmmObj {
67     page_array: VmmPageArray,
68     slice: vmm_obj_slice,
69     _marker: PhantomPinned,
70 }
71 impl VmmObj {
new(page_array: VmmPageArray) -> Result<Pin<Box<Self>>, Error>72     fn new(page_array: VmmPageArray) -> Result<Pin<Box<Self>>, Error> {
73         let aspace = vmm_get_kernel_aspace();
74         let ptr = page_array.ptr();
75         let size = page_array.size();
76         let mut slice = Box::<Self>::new_uninit();
77         // SAFETY: Initializes a vmm_obj_slice to a default state. Slice is allocated above.
78         unsafe { vmm_obj_slice_init(&raw mut (*slice.as_mut_ptr()).slice) };
79         // SAFETY: Move page_array since we're aliasing it's pointer and want to prevent anyone
80         // else from accessing it. This also ensures that underlying memory remains allocated for
81         // the lifetime of VmmObj.
82         unsafe { (*slice.as_mut_ptr()).page_array = page_array };
83         // SAFETY: The object has been initialized by the two operations above.
84         let mut slice = unsafe { slice.assume_init() };
85         // SAFETY: ptr allocated by the vmm service. slice has been default initialized above and
86         // is populated by this call with the object backing aligned buffer.
87         let rc = unsafe { vmm_get_obj(aspace, ptr as usize, size, &mut slice.as_mut().slice) };
88         if rc < 0 {
89             Error::from_lk(rc)?;
90         }
91         // obj_ref in vmm_obj_slice cannot be moved, to convert this into Pin.
92         let slice = Box::<VmmObj>::into_pin(slice);
93         Ok(slice)
94     }
95 }
96 
97 impl Drop for VmmObj {
drop(&mut self)98     fn drop(&mut self) {
99         // SAFETY: Deallocating resources on failure. vmm_obj_slice_release is safe to call on an
100         // object in the default state.
101         unsafe { vmm_obj_slice_release(&mut self.slice) };
102     }
103 }
104 
105 /// Shares a buffer with the TAs specified in acl. The buffer is copied to new pages and prefixed
106 /// with size of the passed in data as a usize. This size will differ from that provided by
107 /// vmm_obj_service_create_ro and vmm_obj_map_ro as those function operate in increments of
108 /// PAGE_SIZE.
109 ///
110 /// # Arguments
111 ///
112 /// * `buffer` - a buffer to share with TAs.
113 /// * `size` - size of buffer.
114 /// * `align_log2` - alignment to use for the start of the destination data.
115 /// * `port` - a tipc port name for TAs to request the mapped buffer.
116 /// * `acl` - a ktipc_port_acl specifying which trust zones may connect and which apps may connect.
117 ///     If uuids is empty, any app may connect.
118 ///
share_sized_buffer( buffer: *const u8, size: usize, align_log2: u8, port: &'static CStr, acl: &'static ktipc_port_acl, ) -> Result<(), Error>119 pub fn share_sized_buffer(
120     buffer: *const u8,
121     size: usize,
122     align_log2: u8,
123     port: &'static CStr,
124     acl: &'static ktipc_port_acl,
125 ) -> Result<(), Error> {
126     let aligned_ptr: usize = buffer as usize & !(PAGE_SIZE as usize - 1);
127     let offset = buffer as usize - aligned_ptr;
128     let aligned_size = (size + offset).next_multiple_of(PAGE_SIZE as usize);
129 
130     let mut phys_page_array = VmmPageArray::new_physical(port, aligned_ptr, aligned_size, 0, 0)?;
131 
132     let align = 1usize << align_log2;
133     let dst_data_start = HDR_SIZE.next_multiple_of(align);
134     let dst_size = (size + dst_data_start).next_multiple_of(PAGE_SIZE as usize);
135 
136     let mut page_array = VmmPageArray::new(port, dst_size, 0, 0)?;
137     let header = VmmObjServiceHeader { data_start: dst_data_start as u32, size: size as u32 };
138     page_array.as_mut_slice()[..HDR_SIZE].copy_from_slice(header.as_bytes());
139     page_array.as_mut_slice()[dst_data_start..size + dst_data_start]
140         .copy_from_slice(&phys_page_array.as_mut_slice()[offset..offset + size]);
141 
142     let slice = VmmObj::new(page_array)?;
143 
144     let srv = ktipc_server_new(port);
145     // srv becomes owned by a new thread in ktipc_server_start, so leak the box to ensure Rust
146     // doesn't deallocate it.
147     let srv: *mut ktipc_server = Box::<ktipc_server>::leak(srv);
148     // SAFETY: srv has been intentionally leaked and ownership is transferred to a thread create by
149     // ktipc_server_start.
150     let rc = unsafe { ktipc_server_start(srv) };
151     if rc < 0 {
152         log::error!("Failed to create thread: {:X}", rc);
153         Error::from_lk(rc)?;
154     }
155 
156     let mut svc = create_obj_service_ro(port, acl, &slice.slice, dst_size)?;
157 
158     // SAFETY: vmm_obj_service_add add a new service (svc) to the ktipc server (srv). srv has
159     // already been moved to its own thread and svc now becomes owned by srv.
160     let rc = unsafe { vmm_obj_service_add(svc, srv) };
161     if rc < 0 {
162         log::error!("Failed to add service: {:X}", rc);
163         // SAFETY: Deallocating resources on failure.
164         unsafe { vmm_obj_service_destroy(&mut svc) };
165         Error::from_lk(rc)?;
166     }
167 
168     Ok(())
169 }
170