xref: /openbmc/qemu/rust/system/src/memory.rs (revision ccafa85a97e38698b798115bba6c18c849846e25)
1 // Copyright 2024 Red Hat, Inc.
2 // Author(s): Paolo Bonzini <pbonzini@redhat.com>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 //! Bindings for `MemoryRegion`, `MemoryRegionOps` and `MemTxAttrs`
6 
7 use std::{
8     ffi::{c_uint, c_void, CStr, CString},
9     marker::PhantomData,
10 };
11 
12 use common::{callbacks::FnCall, uninit::MaybeUninitField, zeroable::Zeroable, Opaque};
13 use qom::prelude::*;
14 
15 use crate::bindings::{self, device_endian, memory_region_init_io};
16 pub use crate::bindings::{hwaddr, MemTxAttrs};
17 
18 pub struct MemoryRegionOps<T>(
19     bindings::MemoryRegionOps,
20     // Note: quite often you'll see PhantomData<fn(&T)> mentioned when discussing
21     // covariance and contravariance; you don't need any of those to understand
22     // this usage of PhantomData.  Quite simply, MemoryRegionOps<T> *logically*
23     // holds callbacks that take an argument of type &T, except the type is erased
24     // before the callback is stored in the bindings::MemoryRegionOps field.
25     // The argument of PhantomData is a function pointer in order to represent
26     // that relationship; while that will also provide desirable and safe variance
27     // for T, variance is not the point but just a consequence.
28     PhantomData<fn(&T)>,
29 );
30 
31 // SAFETY: When a *const T is passed to the callbacks, the call itself
32 // is done in a thread-safe manner.  The invocation is okay as long as
33 // T itself is `Sync`.
34 unsafe impl<T: Sync> Sync for MemoryRegionOps<T> {}
35 
36 #[derive(Clone)]
37 pub struct MemoryRegionOpsBuilder<T>(bindings::MemoryRegionOps, PhantomData<fn(&T)>);
38 
39 unsafe extern "C" fn memory_region_ops_read_cb<T, F: for<'a> FnCall<(&'a T, hwaddr, u32), u64>>(
40     opaque: *mut c_void,
41     addr: hwaddr,
42     size: c_uint,
43 ) -> u64 {
44     F::call((unsafe { &*(opaque.cast::<T>()) }, addr, size))
45 }
46 
47 unsafe extern "C" fn memory_region_ops_write_cb<T, F: for<'a> FnCall<(&'a T, hwaddr, u64, u32)>>(
48     opaque: *mut c_void,
49     addr: hwaddr,
50     data: u64,
51     size: c_uint,
52 ) {
53     F::call((unsafe { &*(opaque.cast::<T>()) }, addr, data, size))
54 }
55 
56 impl<T> MemoryRegionOpsBuilder<T> {
57     #[must_use]
58     pub const fn read<F: for<'a> FnCall<(&'a T, hwaddr, u32), u64>>(mut self, _f: &F) -> Self {
59         self.0.read = Some(memory_region_ops_read_cb::<T, F>);
60         self
61     }
62 
63     #[must_use]
64     pub const fn write<F: for<'a> FnCall<(&'a T, hwaddr, u64, u32)>>(mut self, _f: &F) -> Self {
65         self.0.write = Some(memory_region_ops_write_cb::<T, F>);
66         self
67     }
68 
69     #[must_use]
70     pub const fn big_endian(mut self) -> Self {
71         self.0.endianness = device_endian::DEVICE_BIG_ENDIAN;
72         self
73     }
74 
75     #[must_use]
76     pub const fn little_endian(mut self) -> Self {
77         self.0.endianness = device_endian::DEVICE_LITTLE_ENDIAN;
78         self
79     }
80 
81     #[must_use]
82     pub const fn native_endian(mut self) -> Self {
83         self.0.endianness = device_endian::DEVICE_NATIVE_ENDIAN;
84         self
85     }
86 
87     #[must_use]
88     pub const fn valid_sizes(mut self, min: u32, max: u32) -> Self {
89         self.0.valid.min_access_size = min;
90         self.0.valid.max_access_size = max;
91         self
92     }
93 
94     #[must_use]
95     pub const fn valid_unaligned(mut self) -> Self {
96         self.0.valid.unaligned = true;
97         self
98     }
99 
100     #[must_use]
101     pub const fn impl_sizes(mut self, min: u32, max: u32) -> Self {
102         self.0.impl_.min_access_size = min;
103         self.0.impl_.max_access_size = max;
104         self
105     }
106 
107     #[must_use]
108     pub const fn impl_unaligned(mut self) -> Self {
109         self.0.impl_.unaligned = true;
110         self
111     }
112 
113     #[must_use]
114     pub const fn build(self) -> MemoryRegionOps<T> {
115         MemoryRegionOps::<T>(self.0, PhantomData)
116     }
117 
118     #[must_use]
119     pub const fn new() -> Self {
120         Self(bindings::MemoryRegionOps::ZERO, PhantomData)
121     }
122 }
123 
124 impl<T> Default for MemoryRegionOpsBuilder<T> {
125     fn default() -> Self {
126         Self::new()
127     }
128 }
129 
130 /// A safe wrapper around [`bindings::MemoryRegion`].
131 #[repr(transparent)]
132 #[derive(common::Wrapper)]
133 pub struct MemoryRegion(Opaque<bindings::MemoryRegion>);
134 
135 unsafe impl Send for MemoryRegion {}
136 unsafe impl Sync for MemoryRegion {}
137 
138 impl MemoryRegion {
139     unsafe fn do_init_io(
140         slot: *mut bindings::MemoryRegion,
141         owner: *mut bindings::Object,
142         ops: &'static bindings::MemoryRegionOps,
143         name: &'static str,
144         size: u64,
145     ) {
146         unsafe {
147             let cstr = CString::new(name).unwrap();
148             memory_region_init_io(
149                 slot,
150                 owner,
151                 ops,
152                 owner.cast::<c_void>(),
153                 cstr.as_ptr(),
154                 size,
155             );
156         }
157     }
158 
159     pub fn init_io<T: IsA<Object>>(
160         this: &mut MaybeUninitField<'_, T, Self>,
161         ops: &'static MemoryRegionOps<T>,
162         name: &'static str,
163         size: u64,
164     ) {
165         unsafe {
166             Self::do_init_io(
167                 this.as_mut_ptr().cast(),
168                 MaybeUninitField::parent_mut(this).cast(),
169                 &ops.0,
170                 name,
171                 size,
172             );
173         }
174     }
175 }
176 
177 unsafe impl ObjectType for MemoryRegion {
178     type Class = bindings::MemoryRegionClass;
179     const TYPE_NAME: &'static CStr =
180         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_MEMORY_REGION) };
181 }
182 
183 qom_isa!(MemoryRegion: Object);
184 
185 /// A special `MemTxAttrs` constant, used to indicate that no memory
186 /// attributes are specified.
187 ///
188 /// Bus masters which don't specify any attributes will get this,
189 /// which has all attribute bits clear except the topmost one
190 /// (so that we can distinguish "all attributes deliberately clear"
191 /// from "didn't specify" if necessary).
192 pub const MEMTXATTRS_UNSPECIFIED: MemTxAttrs = MemTxAttrs {
193     unspecified: true,
194     ..Zeroable::ZERO
195 };
196