1 /*
2 * Copyright (c) 2021 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* OSValueObject.h created by spoirier on Mon 28-Jun-2021 */
29
30 #ifndef _OS_OSVALUEOBJECT_H
31 #define _OS_OSVALUEOBJECT_H
32
33 #if KERNEL_PRIVATE
34 #if __cplusplus >= 201703L /* C++17 is required for this class */
35
36 #include <IOKit/IOLib.h>
37 #include <libkern/c++/OSObject.h>
38 #include <libkern/c++/OSPtr.h>
39 #include <os/base.h>
40 #include <string.h>
41
42 /*!
43 * @header
44 *
45 * @abstract
46 * This header declares the OSValueObject container class.
47 */
48
49
50 namespace os_detail {
51 kalloc_type_view_t GetOSValueObjectKTV();
52 }
53
54 /*!
55 * @class OSValueObject
56 *
57 * @abstract
58 * OSValueObject wraps a single C++ type allocation in a C++ object
59 * for use in Libkern collections.
60 *
61 * @discussion
62 * OSValueObject a single type heap allocated as a Libkern C++ object.
63 * OSValueObject objects are mutable:
64 * You can overwrite the value data it contains.
65 *
66 * <b>Use Restrictions</b>
67 *
68 * With very few exceptions in the I/O Kit, all Libkern-based C++
69 * classes, functions, and macros are <b>unsafe</b>
70 * to use in a primary interrupt context.
71 * Consult the I/O Kit documentation related to primary interrupts
72 * for more information.
73 *
74 * OSValueObject provides no concurrency protection;
75 * it's up to the usage context to provide any protection necessary.
76 * Some portions of the I/O Kit, such as
77 * @link //apple_ref/doc/class/IORegistryEntry IORegistryEntry@/link,
78 * handle synchronization via defined member functions for setting
79 * properties.
80 */
81 template <typename T>
82 class OSValueObject final : public OSObject
83 {
84 public:
85
86 /*!
87 * @function create
88 *
89 * @abstract
90 * Creates and initializes an empty instance of OSValueObject,
91 * where the contained object's memory has been zeroed and then
92 * default-constructed.
93 *
94 * @result
95 * An instance of OSValueObject with a reference count of 1;
96 * <code>nullptr</code> on failure.
97 */
98 static OSPtr<OSValueObject> create();
99
100 /*!
101 * @function withBytes
102 *
103 * @abstract
104 * Creates and initializes an instance of OSValueObject
105 * with a copy of the provided value.
106 *
107 * @param value A reference to the value to copy.
108 *
109 * @result
110 * An instance of OSValueObject containing a copy of the provided value,
111 * with a reference count of 1;
112 * <code>nullptr</code> on failure.
113 */
114 static OSPtr<OSValueObject> withValue(const T& value);
115
116 /*!
117 * @function withValueObject
118 *
119 * @abstract
120 * Creates and initializes an instance of OSValueObject
121 * with contents copied from another OSValueObject object.
122 *
123 * @param inValueObject An OSValueObject object that provides the initial data.
124 *
125 * @result
126 * An instance of OSValueObject containing a copy of the data in
127 * <code>inValueObject</code>, with a reference count of 1;
128 * <code>nullptr</code> on failure.
129 */
130 static OSPtr<OSValueObject> withValueObject(const OSValueObject * inValueObject);
131
132 /*!
133 * @function free
134 *
135 * @abstract
136 * Deallocates or releases any resources
137 * used by the OSValueObject instance.
138 *
139 * @discussion
140 * This function should not be called directly;
141 * use
142 * <code>@link
143 * //apple_ref/cpp/instm/OSObject/release/virtualvoid/()
144 * release@/link</code>
145 * instead.
146 */
147 void free() APPLE_KEXT_OVERRIDE;
148
149 /*!
150 * @function setValue
151 *
152 * @abstract
153 * Replaces the contents of the OSValueObject object's internal data buffer
154 * with a copy of the provided value.
155 *
156 * @param value A reference to the value to copy.
157 */
158 void setValue(const T& value);
159
160 /*!
161 * @function getBytesNoCopy
162 *
163 * @abstract
164 * Returns a pointer to the OSValueObject object's internal data buffer.
165 *
166 * @result
167 * A pointer to the OSValueObject object's internal data buffer.
168 *
169 * @discussion
170 * You cannot modify the existing contents of an OSValueObject object
171 * via this function.
172 */
173 const T * getBytesNoCopy() const;
174
175 /*!
176 * @function getMutableBytesNoCopy
177 *
178 * @abstract
179 * Returns a pointer to the OSValueObject object's internal data buffer.
180 *
181 * @result
182 * A pointer to the OSValueObject object's internal data buffer.
183 *
184 * @discussion
185 * You can modify the existing contents of an OSValueObject object
186 * via this function.
187 */
188 T * getMutableBytesNoCopy();
189
190 /*!
191 * @function getRef
192 *
193 * @abstract
194 * Returns a const reference to the OSValueObject object's internal value data.
195 *
196 * @result
197 * A const reference to the OSValueObject object's internal value data.
198 *
199 * @discussion
200 * You cannot modify the existing contents of an OSValueObject object
201 * via this function.
202 */
203 const T & getRef() const;
204
205 /*!
206 * @function getMutableRef
207 *
208 * @abstract
209 * Returns a pointer to the OSValueObject object's internal value data.
210 *
211 * @result
212 * A pointer to the OSValueObject object's internal value data.
213 *
214 * @discussion
215 * You can modify the existing contents of an OSValueObject object
216 * via this function.
217 */
218 T & getMutableRef();
219
220 /*!
221 * @function getLength
222 *
223 * @abstract
224 * Returns the number of bytes in or referenced by the OSValueObject object.
225 *
226 * @result
227 * The number of bytes in or referenced by the OSValueObject object.
228 */
229 constexpr size_t
getLength()230 getLength() const
231 {
232 return sizeof(T);
233 }
234
235 /*!
236 * @function isEqualTo
237 *
238 * @abstract
239 * Tests the equality of two OSValueObject objects.
240 *
241 * @param inValueObject The OSValueObject object being compared against the receiver.
242 *
243 * @result
244 * <code>true</code> if the two OSValueObject objects are equivalent,
245 * <code>false</code> otherwise.
246 *
247 * @discussion
248 * Two OSValueObject objects are considered equal
249 * if they have same length and if their
250 * byte buffers hold the same contents.
251 */
252 virtual bool isEqualTo(const OSValueObject * inValueObject) const;
253
254
255 /*!
256 * @function isEqualTo
257 *
258 * @abstract
259 * Tests the equality of an OSValueObject object's contents
260 * to a C array of bytes.
261 *
262 * @param value A reference to the value to compare.
263 *
264 * @result
265 * <code>true</code> if the values' data are equal,
266 * <code>false</code> otherwise.
267 */
268 virtual bool isEqualTo(const T& value) const;
269
270
271 /*!
272 * @function isEqualTo
273 *
274 * @abstract
275 * Tests the equality of an OSValueObject object to an arbitrary object.
276 *
277 * @param inObject The object to be compared against the receiver.
278 *
279 * @result
280 * <code>true</code> if the two objects are equivalent,
281 * <code>false</code> otherwise.
282 *
283 * @discussion
284 * An OSValueObject is considered equal to another object
285 * if that object is derived from OSValueObject<T>
286 * and contains the equivalent bytes of the same length.
287 */
288 virtual bool isEqualTo(const OSMetaClassBase * inObject) const APPLE_KEXT_OVERRIDE;
289
290 /*!
291 * @function serialize
292 *
293 * @abstract
294 * This class is not serializable.
295 *
296 * @param serializer The OSSerialize object.
297 *
298 * @result
299 * <code>false</code> always
300 */
301 virtual bool serialize(OSSerialize * serializer) const APPLE_KEXT_OVERRIDE;
302
303 protected:
304
305 /*!
306 * @function init
307 *
308 * @abstract
309 * Initializes an instance of OSValueObject with a zeroed
310 * and then default-constructed data buffer.
311 *
312 * @result
313 * <code>true</code> on success, <code>false</code> on failure.
314 *
315 * @discussion
316 * Not for general use. Use the static instance creation method
317 * <code>@link create create@/link</code> instead.
318 */
319 virtual bool init() APPLE_KEXT_OVERRIDE;
320
321 private:
322 T * OS_PTRAUTH_SIGNED_PTR("OSValueObject.data") data = nullptr;
323
324
325 // inline expansion of OSDeclareDefaultStructors and OSDefineMetaClassAndStructors macros
326 // (existing macros do not support template classes)
327 public:
OSValueObject()328 OSValueObject() : OSObject(&gMetaClass)
329 {
330 gMetaClass.instanceConstructed();
331 }
332
333 static inline class MetaClass : public OSMetaClass
334 {
335 public:
336 MetaClass();
337 virtual OSObject *
alloc()338 alloc() const APPLE_KEXT_OVERRIDE
339 {
340 return new OSValueObject;
341 }
342 } gMetaClass;
343 static inline const OSMetaClass * const metaClass = &OSValueObject::gMetaClass;
344
345 friend class OSValueObject::MetaClass;
346
347 virtual const OSMetaClass *
getMetaClass()348 getMetaClass() const APPLE_KEXT_OVERRIDE
349 {
350 return &gMetaClass;
351 }
352
353 static void *
new(size_t size)354 operator new(size_t size)
355 {
356 // requires alternate implementation if this SPI is ever made public API
357 return OSObject_typed_operator_new(os_detail::GetOSValueObjectKTV(), size);
358 }
359
360 protected:
OSValueObject(const OSMetaClass * meta)361 explicit OSValueObject(const OSMetaClass * meta) : OSObject(meta)
362 {
363 }
364
365 static void
delete(void * mem,size_t size)366 operator delete(void * mem, size_t size)
367 {
368 // requires alternate implementation if this SPI is ever made public API
369 return OSObject_typed_operator_delete(os_detail::GetOSValueObjectKTV(), mem, size);
370 }
371 };
372
373 /*!
374 * @define OSDefineValueObjectForDependentType
375 * @hidecontents
376 *
377 * @abstract
378 * Defines concrete instantiations of OSMetaClass registration,
379 * as templatized for a specific dependent type.
380 *
381 * @param typeName The name of the type you use as an
382 * OSValueObject template argument.
383 *
384 * @discussion
385 * For each individual type for which you use OSValueObject to wrap,
386 * you must use this in an implementation file.
387 */
388 #define OSDefineValueObjectForDependentType(typeName) \
389 template <> OSValueObject<typeName>::MetaClass::MetaClass() : \
390 OSMetaClass("OSValueObject<" #typeName ">", &OSObject::gMetaClass, sizeof(OSValueObject)) {}
391
392 /*!
393 * @function OSValueObjectWithValue
394 *
395 * @abstract
396 * Creates and initializes an instance of OSValueObject
397 * with a copy of the provided value.
398 * This is a free function wrapper of OSValueObject<T>::withValue to allow for
399 * type inference of the class' template argument from the function parameter
400 * (so that you do not need to explicitly provide the type template argument).
401 *
402 * @param value A reference to the value to copy.
403 *
404 * @result
405 * An instance of OSValueObject containing a copy of the provided value,
406 * with a reference count of 1;
407 * <code>nullptr</code> on failure.
408 */
409 template <typename T>
410 OSPtr<OSValueObject<T> > OSValueObjectWithValue(const T& value);
411
412
413 #pragma mark -
414
415 void* operator new(size_t, void*) noexcept; // forward declaration needed for placement-new
416
417 template <typename T>
418 OSPtr<OSValueObject<T> >
create()419 OSValueObject<T>::create()
420 {
421 #ifdef IOKIT_ENABLE_SHARED_PTR
422 auto me = OSMakeShared<OSValueObject<T> >();
423 #else
424 auto * me = OSTypeAlloc(OSValueObject<T>);
425 #endif
426 if (me && !me->init()) {
427 #ifndef IOKIT_ENABLE_SHARED_PTR
428 me->release();
429 #endif
430 return nullptr;
431 }
432 return me;
433 }
434
435 template <typename T>
436 OSPtr<OSValueObject<T> >
withValue(const T & value)437 OSValueObject<T>::withValue(const T& value)
438 {
439 #ifdef IOKIT_ENABLE_SHARED_PTR
440 OSSharedPtr<OSValueObject<T> > me = create();
441 #else
442 OSValueObject<T> * me = create();
443 #endif
444 if (me) {
445 me->setValue(value);
446 }
447 return me;
448 }
449
450 template <typename T>
451 OSPtr<OSValueObject<T> >
withValueObject(const OSValueObject * inValueObject)452 OSValueObject<T>::withValueObject(const OSValueObject * inValueObject)
453 {
454 if (!inValueObject || !inValueObject->getBytesNoCopy()) {
455 return {};
456 }
457 return withValue(inValueObject->getRef());
458 }
459
460 template <typename T>
461 bool
init()462 OSValueObject<T>::init()
463 {
464 if (!OSObject::init()) {
465 return false;
466 }
467
468 if (data) {
469 data->~T();
470 bzero(data, getLength());
471 } else {
472 data = IOMallocType(T);
473 if (!data) {
474 return false;
475 }
476 }
477
478 ::new (static_cast<void*>(data)) T();
479
480 return true;
481 }
482
483 template <typename T>
484 void
free()485 OSValueObject<T>::free()
486 {
487 IOFreeType(data, T);
488 data = nullptr;
489
490 OSObject::free();
491 }
492
493 template <typename T>
494 void
setValue(const T & value)495 OSValueObject<T>::setValue(const T& value)
496 {
497 //static_assert(__is_trivially_copyable(T) || __is_copy_assignable(T));
498 if (&value != data) {
499 if constexpr (__is_trivially_copyable(T)) {
500 memcpy(data, &value, getLength());
501 } else {
502 *data = value;
503 }
504 }
505 }
506
507 template <typename T>
508 const T *
getBytesNoCopy()509 OSValueObject<T>::getBytesNoCopy() const
510 {
511 return data;
512 }
513
514 template <typename T>
515 T *
getMutableBytesNoCopy()516 OSValueObject<T>::getMutableBytesNoCopy()
517 {
518 return data;
519 }
520
521 template <typename T>
522 const T &
getRef()523 OSValueObject<T>::getRef() const
524 {
525 assert(data);
526 return *data;
527 }
528
529 template <typename T>
530 T &
getMutableRef()531 OSValueObject<T>::getMutableRef()
532 {
533 assert(data);
534 return *data;
535 }
536
537 template <typename T>
538 bool
isEqualTo(const OSValueObject * inValueObject)539 OSValueObject<T>::isEqualTo(const OSValueObject * inValueObject) const
540 {
541 return inValueObject && isEqualTo(inValueObject->getRef());
542 }
543
544 template <typename T>
545 bool
isEqualTo(const T & value)546 OSValueObject<T>::isEqualTo(const T& value) const
547 {
548 if constexpr (__is_scalar(T) || __is_aggregate(T)) {
549 return memcmp(data, &value, getLength()) == 0;
550 } else {
551 return *data == value;
552 }
553 }
554
555 template <typename T>
556 bool
isEqualTo(const OSMetaClassBase * inObject)557 OSValueObject<T>::isEqualTo(const OSMetaClassBase * inObject) const
558 {
559 if (const auto * const otherValueObject = OSDynamicCast(OSValueObject, inObject)) {
560 return isEqualTo(otherValueObject);
561 }
562 return false;
563 }
564
565 template <typename T>
566 bool
serialize(__unused OSSerialize * serializer)567 OSValueObject<T>::serialize(__unused OSSerialize * serializer) const
568 {
569 return false;
570 }
571
572 template <typename T>
573 OSPtr<OSValueObject<T> >
OSValueObjectWithValue(const T & value)574 OSValueObjectWithValue(const T& value)
575 {
576 return OSValueObject<T>::withValue(value);
577 }
578
579
580 #endif /* __cplusplus */
581 #endif /* KERNEL_PRIVATE */
582
583 #endif /* !_OS_OSVALUEOBJECT_H */
584