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