Loading...
--- xnu/xnu-12377.101.15/libkern/c++/OSData.cpp
+++ xnu/xnu-7195.141.2/libkern/c++/OSData.cpp
@@ -29,7 +29,9 @@
#include <string.h>
+__BEGIN_DECLS
#include <vm/vm_kern.h>
+__END_DECLS
#define IOKIT_ENABLE_SHARED_PTR
@@ -56,60 +58,56 @@
bool
OSData::initWithCapacity(unsigned int inCapacity)
{
- struct kalloc_result kr;
- bool success = true;
+ void *_data = NULL;
+
+ 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_container(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_data_container(inCapacity, Z_WAITOK);
+ } 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));
+ data = _data;
+ }
+ 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
@@ -224,10 +222,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_container(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 +235,7 @@
}
}
if (reserved) {
- kfree_type(ExpansionData, reserved);
+ kfree(reserved, sizeof(ExpansionData));
}
super::free();
}
@@ -269,8 +268,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 +285,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_data_container(finalCapacity, Z_WAITOK);
+ }
+
+ if (newData) {
+ bzero(newData + capacity, finalCapacity - capacity);
+ if (copydata) {
+ bcopy(copydata, newData, capacity);
+ }
+ if (data) {
+ if (capacity < page_size) {
+ kfree_data_container(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 +585,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 +598,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);
}