Loading...
--- xnu/xnu-12377.101.15/libkern/c++/OSData.cpp
+++ xnu/xnu-6153.41.3/libkern/c++/OSData.cpp
@@ -29,9 +29,11 @@
#include <string.h>
+__BEGIN_DECLS
#include <vm/vm_kern.h>
-
-#define IOKIT_ENABLE_SHARED_PTR
+__END_DECLS
+
+#define LIBKERN_SMART_POINTERS
#include <libkern/c++/OSData.h>
#include <libkern/c++/OSSerialize.h>
@@ -41,8 +43,8 @@
#define super OSObject
-OSDefineMetaClassAndStructorsWithZone(OSData, OSObject, ZC_ZFREE_CLEARMEM)
-OSMetaClassDefineReservedUsedX86(OSData, 0); // setDeallocFunction
+OSDefineMetaClassAndStructors(OSData, OSObject)
+OSMetaClassDefineReservedUsed(OSData, 0); // setDeallocFunction
OSMetaClassDefineReservedUnused(OSData, 1);
OSMetaClassDefineReservedUnused(OSData, 2);
OSMetaClassDefineReservedUnused(OSData, 3);
@@ -56,60 +58,53 @@
bool
OSData::initWithCapacity(unsigned int inCapacity)
{
- struct kalloc_result kr;
- bool success = true;
+ if (data) {
+ OSCONTAINER_ACCUMSIZE(-((size_t)capacity));
+ if (!inCapacity || (capacity < inCapacity)) {
+ // clean out old data's storage if it isn't big enough
+ if (capacity < page_size) {
+ kfree(data, capacity);
+ } else {
+ kmem_free(kernel_map, (vm_offset_t)data, capacity);
+ }
+ data = NULL;
+ capacity = 0;
+ }
+ }
if (!super::init()) {
return false;
}
- /*
- * OSData use of Z_MAY_COPYINMAP serves 2 purpposes:
- *
- * - It makes sure than when it goes to the VM, it uses its own object
- * rather than the kernel object so that vm_map_copyin() can be used.
- *
- * - On Intel, it goes to the VM for any size >= PAGE_SIZE to maintain
- * old (inefficient) ABI. On arm64 it will use kalloc_data() instead
- * until the vm_map_copy_t msg_ool_size_small threshold for copies.
- */
-
- if (inCapacity == 0) {
- if (capacity) {
- OSCONTAINER_ACCUMSIZE(-(size_t)capacity);
- /* can't use kfree() as we need to pass Z_MAY_COPYINMAP */
- __kheap_realloc(KHEAP_DATA_PRIVATE, data, capacity, 0,
- Z_VM_TAG_BT(Z_WAITOK_ZERO | Z_FULLSIZE | Z_MAY_COPYINMAP,
- VM_KERN_MEMORY_LIBKERN), (void *)&this->data);
- data = nullptr;
- capacity = 0;
- }
- } else if (inCapacity <= capacity) {
- /*
- * Nothing to change
- */
+ if (inCapacity && !data) {
+ if (inCapacity < page_size) {
+ data = (void *) kalloc_container(inCapacity);
+ } else {
+ kern_return_t kr;
+ if (round_page_overflow(inCapacity, &inCapacity)) {
+ kr = KERN_RESOURCE_SHORTAGE;
+ } else {
+ kr = kmem_alloc(kernel_map, (vm_offset_t *)&data, inCapacity, IOMemoryTag(kernel_map));
+ }
+ if (KERN_SUCCESS != kr) {
+ data = NULL;
+ }
+ }
+ if (!data) {
+ return false;
+ }
+ capacity = inCapacity;
+ }
+ OSCONTAINER_ACCUMSIZE(capacity);
+
+ length = 0;
+ if (inCapacity < 16) {
+ capacityIncrement = 16;
} else {
- kr = kalloc_ext(KHEAP_DATA_PRIVATE, inCapacity,
- Z_VM_TAG_BT(Z_WAITOK_ZERO | Z_FULLSIZE | Z_MAY_COPYINMAP,
- VM_KERN_MEMORY_LIBKERN), (void *)&this->data);
-
- if (kr.addr) {
- size_t delta = 0;
-
- data = kr.addr;
- delta -= capacity;
- capacity = (uint32_t)MIN(kr.size, UINT32_MAX);
- delta += capacity;
- OSCONTAINER_ACCUMSIZE(delta);
- } else {
- success = false;
- }
- }
-
- length = 0;
- capacityIncrement = MAX(16, inCapacity);
-
- return success;
+ capacityIncrement = inCapacity;
+ }
+
+ return true;
}
bool
@@ -160,10 +155,10 @@
}
}
-OSSharedPtr<OSData>
+OSDataPtr
OSData::withCapacity(unsigned int inCapacity)
{
- OSSharedPtr<OSData> me = OSMakeShared<OSData>();
+ OSDataPtr me = OSDataPtr::alloc();
if (me && !me->initWithCapacity(inCapacity)) {
return nullptr;
@@ -172,10 +167,10 @@
return me;
}
-OSSharedPtr<OSData>
+OSDataPtr
OSData::withBytes(const void *bytes, unsigned int inLength)
{
- OSSharedPtr<OSData> me = OSMakeShared<OSData>();
+ OSDataPtr me = OSDataPtr::alloc();
if (me && !me->initWithBytes(bytes, inLength)) {
return nullptr;
@@ -183,10 +178,10 @@
return me;
}
-OSSharedPtr<OSData>
+OSDataPtr
OSData::withBytesNoCopy(void *bytes, unsigned int inLength)
{
- OSSharedPtr<OSData> me = OSMakeShared<OSData>();
+ OSDataPtr me = OSDataPtr::alloc();
if (me && !me->initWithBytesNoCopy(bytes, inLength)) {
return nullptr;
@@ -195,10 +190,10 @@
return me;
}
-OSSharedPtr<OSData>
+OSDataPtr
OSData::withData(const OSData *inData)
{
- OSSharedPtr<OSData> me = OSMakeShared<OSData>();
+ OSDataPtr me = OSDataPtr::alloc();
if (me && !me->initWithData(inData)) {
return nullptr;
@@ -207,11 +202,11 @@
return me;
}
-OSSharedPtr<OSData>
+OSDataPtr
OSData::withData(const OSData *inData,
unsigned int start, unsigned int inLength)
{
- OSSharedPtr<OSData> me = OSMakeShared<OSData>();
+ OSDataPtr me = OSDataPtr::alloc();
if (me && !me->initWithData(inData, start, inLength)) {
return nullptr;
@@ -224,10 +219,11 @@
OSData::free()
{
if ((capacity != EXTERNAL) && data && capacity) {
- /* can't use kfree() as we need to pass Z_MAY_COPYINMAP */
- __kheap_realloc(KHEAP_DATA_PRIVATE, data, capacity, 0,
- Z_VM_TAG_BT(Z_WAITOK_ZERO | Z_FULLSIZE | Z_MAY_COPYINMAP,
- VM_KERN_MEMORY_LIBKERN), (void *)&this->data);
+ if (capacity < page_size) {
+ kfree(data, capacity);
+ } else {
+ kmem_free(kernel_map, (vm_offset_t)data, capacity);
+ }
OSCONTAINER_ACCUMSIZE( -((size_t)capacity));
} else if (capacity == EXTERNAL) {
DeallocFunction freemem = reserved ? reserved->deallocFunction : NULL;
@@ -236,7 +232,7 @@
}
}
if (reserved) {
- kfree_type(ExpansionData, reserved);
+ kfree(reserved, sizeof(ExpansionData));
}
super::free();
}
@@ -269,8 +265,10 @@
unsigned int
OSData::ensureCapacity(unsigned int newCapacity)
{
- struct kalloc_result kr;
+ unsigned char * newData;
unsigned int finalCapacity;
+ void * copydata;
+ kern_return_t kr;
if (newCapacity <= capacity) {
return capacity;
@@ -284,50 +282,51 @@
return capacity;
}
- kr = krealloc_ext(KHEAP_DATA_PRIVATE, data, capacity, finalCapacity,
- Z_VM_TAG_BT(Z_WAITOK_ZERO | Z_FULLSIZE | Z_MAY_COPYINMAP,
- VM_KERN_MEMORY_LIBKERN), (void *)&this->data);
-
- if (kr.addr) {
- size_t delta = 0;
-
- data = kr.addr;
- delta -= capacity;
- capacity = (uint32_t)MIN(kr.size, UINT32_MAX);
- delta += capacity;
- OSCONTAINER_ACCUMSIZE(delta);
+ copydata = data;
+
+ if (finalCapacity >= page_size) {
+ // round up
+ finalCapacity = round_page_32(finalCapacity);
+ // integer overflow check
+ if (finalCapacity < newCapacity) {
+ return capacity;
+ }
+ if (capacity >= page_size) {
+ copydata = NULL;
+ kr = kmem_realloc(kernel_map,
+ (vm_offset_t)data,
+ capacity,
+ (vm_offset_t *)&newData,
+ finalCapacity,
+ IOMemoryTag(kernel_map));
+ } else {
+ kr = kmem_alloc(kernel_map, (vm_offset_t *)&newData, finalCapacity, IOMemoryTag(kernel_map));
+ }
+ if (KERN_SUCCESS != kr) {
+ newData = NULL;
+ }
+ } else {
+ newData = (unsigned char *) kalloc_container(finalCapacity);
+ }
+
+ if (newData) {
+ bzero(newData + capacity, finalCapacity - capacity);
+ if (copydata) {
+ bcopy(copydata, newData, capacity);
+ }
+ if (data) {
+ if (capacity < page_size) {
+ kfree(data, capacity);
+ } else {
+ kmem_free(kernel_map, (vm_offset_t)data, capacity);
+ }
+ }
+ OSCONTAINER_ACCUMSIZE(((size_t)finalCapacity) - ((size_t)capacity));
+ data = (void *) newData;
+ capacity = finalCapacity;
}
return capacity;
-}
-
-bool
-OSData::clipForCopyout()
-{
- unsigned int newCapacity = (uint32_t)round_page(length);
- __assert_only struct kalloc_result kr;
-
- /*
- * OSData allocations are atomic, which means that if copyoutkdata()
- * is used on them, and that there are fully unused pages at the end
- * of the OSData buffer, then vm_map_copyin() will try to clip the VM
- * entry which will panic.
- *
- * In order to avoid this, trim down the unused pages.
- *
- * We know this operation never fails and keeps the allocation
- * address stable.
- */
- if (length >= msg_ool_size_small && newCapacity < capacity) {
- kr = krealloc_ext(KHEAP_DATA_PRIVATE,
- data, capacity, newCapacity,
- Z_VM_TAG_BT(Z_WAITOK_ZERO | Z_FULLSIZE | Z_MAY_COPYINMAP,
- VM_KERN_MEMORY_LIBKERN), (void *)&this->data);
- assert(kr.addr == data);
- OSCONTAINER_ACCUMSIZE(((size_t)newCapacity) - ((size_t)capacity));
- capacity = newCapacity;
- }
- return true;
}
bool
@@ -583,10 +582,11 @@
OSData::setDeallocFunction(DeallocFunction func)
{
if (!reserved) {
- reserved = (typeof(reserved))kalloc_type(ExpansionData, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
+ reserved = (typeof(reserved))kalloc_container(sizeof(ExpansionData));
if (!reserved) {
return;
}
+ bzero(reserved, sizeof(ExpansionData));
}
reserved->deallocFunction = func;
}
@@ -595,10 +595,11 @@
OSData::setSerializable(bool serializable)
{
if (!reserved) {
- reserved = (typeof(reserved))kalloc_type(ExpansionData, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
+ reserved = (typeof(reserved))kalloc_container(sizeof(ExpansionData));
if (!reserved) {
return;
}
+ bzero(reserved, sizeof(ExpansionData));
}
reserved->disableSerialization = (!serializable);
}