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