xref: /xnu-10002.61.3/libkern/libkern/c++/OSValueObject.h (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
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