[XAM] Enumerator improvements.

- [Kernel] XEnumerator::WriteItems no longer cares about provided
  buffer size, since we know the size when the XEnumerator was created.
- [Kernel] Added XStaticEnumerator template. Previous
  XStaticEnumerator renamed to XStaticUntypedEnumerator.
- [XAM] Deferred xeXamEnumerate.
This commit is contained in:
gibbed
2020-12-04 14:52:05 -06:00
committed by Rick Gibbed
parent b18f73b949
commit e8fda5878c
8 changed files with 92 additions and 91 deletions

View File

@@ -32,49 +32,37 @@ uint32_t xeXamEnumerate(uint32_t handle, uint32_t flags, lpvoid_t buffer_ptr,
uint32_t overlapped_ptr) {
assert_true(flags == 0);
X_RESULT result;
uint32_t item_count = 0;
auto e = kernel_state()->object_table()->LookupObject<XEnumerator>(handle);
if (!e) {
result = X_ERROR_INVALID_HANDLE;
} else if (!buffer_ptr) {
result = X_ERROR_INVALID_PARAMETER;
} else {
size_t needed_buffer_size = e->item_size() * e->items_per_enumerate();
uint32_t actual_buffer_size = buffer_size;
if (buffer_size == e->items_per_enumerate()) {
actual_buffer_size = static_cast<uint32_t>(needed_buffer_size);
// Known culprits:
// Final Fight: Double Impact (saves)
XELOGW(
"Broken usage of XamEnumerate! buffer size={:X} vs actual "
"size={:X} (item size={:X}, items per enumerate={})",
buffer_size, actual_buffer_size, e->item_size(),
e->items_per_enumerate());
}
result = X_ERROR_INSUFFICIENT_BUFFER;
if (actual_buffer_size >= needed_buffer_size) {
buffer_ptr.Zero(actual_buffer_size);
result =
e->WriteItems(buffer_ptr.guest_address(), buffer_ptr.as<uint8_t*>(),
actual_buffer_size, &item_count);
}
return X_ERROR_INVALID_HANDLE;
}
auto run = [e, buffer_ptr](uint32_t& extended_error,
uint32_t& length) -> X_RESULT {
X_RESULT result;
uint32_t item_count;
if (!buffer_ptr) {
result = X_ERROR_INVALID_PARAMETER;
item_count = 0;
} else {
result = e->WriteItems(buffer_ptr.guest_address(),
buffer_ptr.as<uint8_t*>(), &item_count);
}
extended_error = X_HRESULT_FROM_WIN32(result);
length = item_count;
return result;
};
if (items_returned) {
assert_true(!overlapped_ptr);
uint32_t extended_error;
uint32_t item_count;
X_RESULT result = run(extended_error, item_count);
*items_returned = result == X_ERROR_SUCCESS ? item_count : 0;
return result;
} else if (overlapped_ptr) {
assert_true(!items_returned);
kernel_state()->CompleteOverlappedImmediateEx(
overlapped_ptr,
result == X_ERROR_SUCCESS ? X_ERROR_SUCCESS : X_ERROR_FUNCTION_FAILED,
X_HRESULT_FROM_WIN32(result),
result == X_ERROR_SUCCESS ? item_count : 0);
kernel_state()->CompleteOverlappedDeferredEx(run, overlapped_ptr);
return X_ERROR_IO_PENDING;
} else {
assert_always();