xref: /xnu-8020.101.4/libkern/libkern/c++/OSValueObject.h (revision e7776783b89a353188416a9a346c6cdb4928faad)
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:
MetaClass()336 		MetaClass() : OSMetaClass("OSValueObject", &OSObject::gMetaClass, sizeof(OSValueObject))
337 		{
338 		}
339 		virtual OSObject *
alloc()340 		alloc() const APPLE_KEXT_OVERRIDE
341 		{
342 			return new OSValueObject;
343 		}
344 	} gMetaClass;
345 	static inline const OSMetaClass * const metaClass = &OSValueObject::gMetaClass;
346 
347 	friend class OSValueObject::MetaClass;
348 
349 	virtual const OSMetaClass *
getMetaClass()350 	getMetaClass() const APPLE_KEXT_OVERRIDE
351 	{
352 		return &gMetaClass;
353 	}
354 
355 	static void *
new(size_t size)356 	operator new(size_t size)
357 	{
358 		// requires alternate implementation if this SPI is ever made public API
359 		return OSObject_typed_operator_new(os_detail::GetOSValueObjectKTV(), size);
360 	}
361 
362 protected:
OSValueObject(const OSMetaClass * meta)363 	explicit OSValueObject(const OSMetaClass * meta) : OSObject(meta)
364 	{
365 	}
366 
367 	static void
delete(void * mem,size_t size)368 	operator delete(void * mem, size_t size)
369 	{
370 		// requires alternate implementation if this SPI is ever made public API
371 		return OSObject_typed_operator_delete(os_detail::GetOSValueObjectKTV(), mem, size);
372 	}
373 };
374 
375 /*!
376  * @function OSValueObjectWithValue
377  *
378  * @abstract
379  * Creates and initializes an instance of OSValueObject
380  * with a copy of the provided value.
381  * This is a free function wrapper of OSValueObject<T>::withValue to allow for
382  * type inference of the class' template argument from the function parameter
383  * (so that you do not need to explicitly provide the type template argument).
384  *
385  * @param value    A reference to the value to copy.
386  *
387  * @result
388  * An instance of OSValueObject containing a copy of the provided value,
389  * with a reference count of 1;
390  * <code>nullptr</code> on failure.
391  */
392 template <typename T>
393 OSPtr<OSValueObject<T> > OSValueObjectWithValue(const T& value);
394 
395 
396 #pragma mark -
397 
398 void* operator new(size_t, void*) noexcept; // forward declaration needed for placement-new
399 
400 template <typename T>
401 OSPtr<OSValueObject<T> >
create()402 OSValueObject<T>::create()
403 {
404 #ifdef IOKIT_ENABLE_SHARED_PTR
405 	auto me = OSMakeShared<OSValueObject<T> >();
406 #else
407 	auto * me = OSTypeAlloc(OSValueObject<T>);
408 #endif
409 	if (me && !me->init()) {
410 #ifndef IOKIT_ENABLE_SHARED_PTR
411 		me->release();
412 #endif
413 		return nullptr;
414 	}
415 	return me;
416 }
417 
418 template <typename T>
419 OSPtr<OSValueObject<T> >
withValue(const T & value)420 OSValueObject<T>::withValue(const T& value)
421 {
422 #ifdef IOKIT_ENABLE_SHARED_PTR
423 	OSSharedPtr<OSValueObject<T> > me = create();
424 #else
425 	OSValueObject<T> * me = create();
426 #endif
427 	if (me) {
428 		me->setValue(value);
429 	}
430 	return me;
431 }
432 
433 template <typename T>
434 OSPtr<OSValueObject<T> >
withValueObject(const OSValueObject * inValueObject)435 OSValueObject<T>::withValueObject(const OSValueObject * inValueObject)
436 {
437 	if (!inValueObject || !inValueObject->getBytesNoCopy()) {
438 		return {};
439 	}
440 	return withValue(inValueObject->getRef());
441 }
442 
443 template <typename T>
444 bool
init()445 OSValueObject<T>::init()
446 {
447 	if (!OSObject::init()) {
448 		return false;
449 	}
450 
451 	if (data) {
452 		data->~T();
453 		bzero(data, getLength());
454 	} else {
455 		data = IOMallocType(T);
456 		if (!data) {
457 			return false;
458 		}
459 	}
460 
461 	::new (static_cast<void*>(data)) T();
462 
463 	return true;
464 }
465 
466 template <typename T>
467 void
free()468 OSValueObject<T>::free()
469 {
470 	IOFreeType(data, T);
471 	data = nullptr;
472 
473 	OSObject::free();
474 }
475 
476 template <typename T>
477 void
setValue(const T & value)478 OSValueObject<T>::setValue(const T& value)
479 {
480 	//static_assert(__is_trivially_copyable(T) || __is_copy_assignable(T));
481 	if (&value != data) {
482 		if constexpr (__is_trivially_copyable(T)) {
483 			memcpy(data, &value, getLength());
484 		} else {
485 			*data = value;
486 		}
487 	}
488 }
489 
490 template <typename T>
491 const T *
getBytesNoCopy()492 OSValueObject<T>::getBytesNoCopy() const
493 {
494 	return data;
495 }
496 
497 template <typename T>
498 T *
getMutableBytesNoCopy()499 OSValueObject<T>::getMutableBytesNoCopy()
500 {
501 	return data;
502 }
503 
504 template <typename T>
505 const T &
getRef()506 OSValueObject<T>::getRef() const
507 {
508 	assert(data);
509 	return *data;
510 }
511 
512 template <typename T>
513 T &
getMutableRef()514 OSValueObject<T>::getMutableRef()
515 {
516 	assert(data);
517 	return *data;
518 }
519 
520 template <typename T>
521 bool
isEqualTo(const OSValueObject * inValueObject)522 OSValueObject<T>::isEqualTo(const OSValueObject * inValueObject) const
523 {
524 	return inValueObject && isEqualTo(inValueObject->getRef());
525 }
526 
527 template <typename T>
528 bool
isEqualTo(const T & value)529 OSValueObject<T>::isEqualTo(const T& value) const
530 {
531 	if constexpr (__is_scalar(T) || __is_aggregate(T)) {
532 		return memcmp(data, &value, getLength()) == 0;
533 	} else {
534 		return *data == value;
535 	}
536 }
537 
538 template <typename T>
539 bool
isEqualTo(const OSMetaClassBase * inObject)540 OSValueObject<T>::isEqualTo(const OSMetaClassBase * inObject) const
541 {
542 	if (const auto * const otherValueObject = OSDynamicCast(OSValueObject, inObject)) {
543 		return isEqualTo(otherValueObject);
544 	}
545 	return false;
546 }
547 
548 template <typename T>
549 bool
serialize(__unused OSSerialize * serializer)550 OSValueObject<T>::serialize(__unused OSSerialize * serializer) const
551 {
552 	return false;
553 }
554 
555 template <typename T>
556 OSPtr<OSValueObject<T> >
OSValueObjectWithValue(const T & value)557 OSValueObjectWithValue(const T& value)
558 {
559 	return OSValueObject<T>::withValue(value);
560 }
561 
562 
563 #endif /* __cplusplus */
564 #endif /* KERNEL_PRIVATE */
565 
566 #endif /* !_OS_OSVALUEOBJECT_H */
567