mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 14:26:53 +01:00
ampr: keep commands in one append-ordered sequence
This commit is contained in:
+103
-156
@@ -18,6 +18,7 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef min
|
#ifdef min
|
||||||
@@ -705,41 +706,38 @@ struct CommandBufferState {
|
|||||||
bool header_validated = false;
|
bool header_validated = false;
|
||||||
bool buffer_validated = false;
|
bool buffer_validated = false;
|
||||||
struct ReadFileCommand {
|
struct ReadFileCommand {
|
||||||
uint64_t record_offset = 0;
|
uint32_t file_id = 0;
|
||||||
uint32_t file_id = 0;
|
uint64_t destination = 0;
|
||||||
uint64_t destination = 0;
|
uint64_t size = 0;
|
||||||
uint64_t size = 0;
|
uint64_t file_offset = 0;
|
||||||
uint64_t file_offset = 0;
|
|
||||||
};
|
};
|
||||||
struct KernelEventCommand {
|
struct KernelEventCommand {
|
||||||
uint64_t record_offset = 0;
|
uint64_t eq = 0;
|
||||||
uint64_t eq = 0;
|
int32_t id = 0;
|
||||||
int32_t id = 0;
|
uint64_t data = 0;
|
||||||
uint64_t data = 0;
|
|
||||||
};
|
};
|
||||||
struct WriteAddressCommand {
|
struct WriteAddressCommand {
|
||||||
uint64_t record_offset = 0;
|
uint64_t address = 0;
|
||||||
uint64_t address = 0;
|
uint64_t value = 0;
|
||||||
uint64_t value = 0;
|
|
||||||
};
|
};
|
||||||
struct AmmMapCommand {
|
struct AmmMapCommand {
|
||||||
uint64_t record_offset = 0;
|
AmmCommandKind kind = AmmCommandKind::MapAuto;
|
||||||
AmmCommandKind kind = AmmCommandKind::MapAuto;
|
uint64_t va = 0;
|
||||||
uint64_t va = 0;
|
uint64_t dmem_offset = 0;
|
||||||
uint64_t dmem_offset = 0;
|
uint64_t size = 0;
|
||||||
uint64_t size = 0;
|
int32_t type = 0;
|
||||||
int32_t type = 0;
|
int32_t prot = 0;
|
||||||
int32_t prot = 0;
|
uint8_t gpu_mask_id = 0;
|
||||||
uint8_t gpu_mask_id = 0;
|
|
||||||
};
|
};
|
||||||
std::vector<ReadFileCommand> read_file_commands;
|
struct Command {
|
||||||
std::vector<KernelEventCommand> kernel_event_commands;
|
uint64_t record_offset;
|
||||||
std::vector<WriteAddressCommand> write_address_commands;
|
std::variant<ReadFileCommand, KernelEventCommand, WriteAddressCommand, AmmMapCommand> data;
|
||||||
std::vector<AmmMapCommand> amm_map_commands;
|
};
|
||||||
bool gather_scatter_valid = false;
|
std::vector<Command> commands;
|
||||||
uint32_t gather_scatter_file_id = 0;
|
bool gather_scatter_valid = false;
|
||||||
uint64_t gather_scatter_destination = 0;
|
uint32_t gather_scatter_file_id = 0;
|
||||||
uint64_t gather_scatter_file_offset = 0;
|
uint64_t gather_scatter_destination = 0;
|
||||||
|
uint64_t gather_scatter_file_offset = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AmmUsageStatsData {
|
struct AmmUsageStatsData {
|
||||||
@@ -757,11 +755,6 @@ static std::unordered_map<uint64_t, CommandBufferState> g_command_buffers;
|
|||||||
static std::unordered_map<uint64_t, uint64_t> g_command_buffer_aliases;
|
static std::unordered_map<uint64_t, uint64_t> g_command_buffer_aliases;
|
||||||
using CommandBufferIterator = std::unordered_map<uint64_t, CommandBufferState>::iterator;
|
using CommandBufferIterator = std::unordered_map<uint64_t, CommandBufferState>::iterator;
|
||||||
|
|
||||||
static bool HasQueuedCommands(const CommandBufferState& state) {
|
|
||||||
return !state.read_file_commands.empty() || !state.kernel_event_commands.empty() ||
|
|
||||||
!state.write_address_commands.empty() || !state.amm_map_commands.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RegisterCommandBufferAliasLocked(uint64_t command_buffer, uint64_t buffer) {
|
static void RegisterCommandBufferAliasLocked(uint64_t command_buffer, uint64_t buffer) {
|
||||||
for (auto it = g_command_buffer_aliases.begin(); it != g_command_buffer_aliases.end();) {
|
for (auto it = g_command_buffer_aliases.begin(); it != g_command_buffer_aliases.end();) {
|
||||||
if (it->second == command_buffer) {
|
if (it->second == command_buffer) {
|
||||||
@@ -950,7 +943,7 @@ static bool UpdateCommandBufferTypeFlags(uint64_t command_buffer, uint32_t set_b
|
|||||||
static std::unordered_map<uint64_t, CommandBufferState>::iterator
|
static std::unordered_map<uint64_t, CommandBufferState>::iterator
|
||||||
ResolveCommandBufferStateLocked(uint64_t command_buffer) {
|
ResolveCommandBufferStateLocked(uint64_t command_buffer) {
|
||||||
auto it = g_command_buffers.find(command_buffer);
|
auto it = g_command_buffers.find(command_buffer);
|
||||||
if (it != g_command_buffers.end() && HasQueuedCommands(it->second)) {
|
if (it != g_command_buffers.end() && !it->second.commands.empty()) {
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -999,10 +992,7 @@ static bool WriteCommandBufferPointers(uint64_t command_buffer, uint64_t buffer,
|
|||||||
state.write_offset = write_offset;
|
state.write_offset = write_offset;
|
||||||
state.header_validated = true;
|
state.header_validated = true;
|
||||||
state.buffer_validated = false;
|
state.buffer_validated = false;
|
||||||
state.read_file_commands.clear();
|
state.commands.clear();
|
||||||
state.kernel_event_commands.clear();
|
|
||||||
state.write_address_commands.clear();
|
|
||||||
state.amm_map_commands.clear();
|
|
||||||
state.gather_scatter_valid = false;
|
state.gather_scatter_valid = false;
|
||||||
state.gather_scatter_file_id = 0;
|
state.gather_scatter_file_id = 0;
|
||||||
state.gather_scatter_destination = 0;
|
state.gather_scatter_destination = 0;
|
||||||
@@ -1107,7 +1097,8 @@ static bool AppendReadFileRecord(uint64_t command_buffer, uint8_t opcode, uint32
|
|||||||
std::memset(reinterpret_cast<void*>(state.buffer + record_offset), 0,
|
std::memset(reinterpret_cast<void*>(state.buffer + record_offset), 0,
|
||||||
static_cast<size_t>(record_size));
|
static_cast<size_t>(record_size));
|
||||||
std::memcpy(reinterpret_cast<void*>(state.buffer + record_offset), &opcode, sizeof(opcode));
|
std::memcpy(reinterpret_cast<void*>(state.buffer + record_offset), &opcode, sizeof(opcode));
|
||||||
state.read_file_commands.push_back({record_offset, file_id, destination, size, file_offset});
|
state.commands.push_back({record_offset, CommandBufferState::ReadFileCommand {
|
||||||
|
file_id, destination, size, file_offset}});
|
||||||
if (!CommitCommandBufferRecord(command_buffer, &state, record_size)) {
|
if (!CommitCommandBufferRecord(command_buffer, &state, record_size)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1145,7 +1136,8 @@ static bool AppendKernelEventRecord(uint64_t command_buffer, uint64_t eq, int32_
|
|||||||
const auto record_offset = state.write_offset;
|
const auto record_offset = state.write_offset;
|
||||||
std::memcpy(reinterpret_cast<void*>(state.buffer + record_offset), record.data(),
|
std::memcpy(reinterpret_cast<void*>(state.buffer + record_offset), record.data(),
|
||||||
record.size());
|
record.size());
|
||||||
state.kernel_event_commands.push_back({record_offset, eq, id, data});
|
state.commands.push_back(
|
||||||
|
{record_offset, CommandBufferState::KernelEventCommand {eq, id, data}});
|
||||||
return CommitCommandBufferRecord(command_buffer, &state, KERNEL_EVENT_RECORD_SIZE);
|
return CommitCommandBufferRecord(command_buffer, &state, KERNEL_EVENT_RECORD_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1165,7 +1157,8 @@ static bool AppendWriteAddressRecord(uint64_t command_buffer, uint64_t address,
|
|||||||
const auto record_offset = state.write_offset;
|
const auto record_offset = state.write_offset;
|
||||||
std::memset(reinterpret_cast<void*>(state.buffer + record_offset), 0,
|
std::memset(reinterpret_cast<void*>(state.buffer + record_offset), 0,
|
||||||
static_cast<size_t>(record_size));
|
static_cast<size_t>(record_size));
|
||||||
state.write_address_commands.push_back({record_offset, address, value});
|
state.commands.push_back(
|
||||||
|
{record_offset, CommandBufferState::WriteAddressCommand {address, value}});
|
||||||
return CommitCommandBufferRecord(command_buffer, &state, record_size);
|
return CommitCommandBufferRecord(command_buffer, &state, record_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1239,11 +1232,9 @@ static bool AppendAmmMapRecord(uint64_t command_
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto record = cmd;
|
|
||||||
record.record_offset = state.write_offset;
|
|
||||||
auto* record_addr = reinterpret_cast<void*>(state.buffer + state.write_offset);
|
auto* record_addr = reinterpret_cast<void*>(state.buffer + state.write_offset);
|
||||||
std::memset(record_addr, 0, static_cast<size_t>(record_size));
|
std::memset(record_addr, 0, static_cast<size_t>(record_size));
|
||||||
state.amm_map_commands.push_back(record);
|
state.commands.push_back({state.write_offset, cmd});
|
||||||
return CommitCommandBufferRecord(command_buffer, &state, record_size);
|
return CommitCommandBufferRecord(command_buffer, &state, record_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1264,121 +1255,77 @@ static int ExecuteAprCommandBuffer(uint64_t command_buffer, int32_t* execution_r
|
|||||||
return LibKernel::KERNEL_ERROR_EFAULT;
|
return LibKernel::KERNEL_ERROR_EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class CommandKind {
|
for (const auto& entry: state.commands) {
|
||||||
ReadFile,
|
if (entry.record_offset >= state.write_offset) {
|
||||||
KernelEvent,
|
break;
|
||||||
WriteAddress,
|
|
||||||
AmmMap,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct OrderedCommand {
|
|
||||||
uint64_t record_offset = 0;
|
|
||||||
CommandKind kind = CommandKind::ReadFile;
|
|
||||||
size_t index = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<OrderedCommand> ordered;
|
|
||||||
ordered.reserve(state.read_file_commands.size() + state.kernel_event_commands.size() +
|
|
||||||
state.write_address_commands.size() + state.amm_map_commands.size());
|
|
||||||
for (size_t i = 0; i < state.read_file_commands.size(); i++) {
|
|
||||||
if (state.read_file_commands[i].record_offset < state.write_offset) {
|
|
||||||
ordered.push_back(
|
|
||||||
{state.read_file_commands[i].record_offset, CommandKind::ReadFile, i});
|
|
||||||
}
|
}
|
||||||
}
|
if (const auto* payload = std::get_if<CommandBufferState::ReadFileCommand>(&entry.data)) {
|
||||||
for (size_t i = 0; i < state.kernel_event_commands.size(); i++) {
|
const auto& command = *payload;
|
||||||
if (state.kernel_event_commands[i].record_offset < state.write_offset) {
|
std::string host_path;
|
||||||
ordered.push_back(
|
if (!AprShared::TryGetHostPath(command.file_id, &host_path)) {
|
||||||
{state.kernel_event_commands[i].record_offset, CommandKind::KernelEvent, i});
|
LOGF("\tAPR submit failed for unknown file id: 0x%08" PRIx32 "\n", command.file_id);
|
||||||
}
|
*execution_result = LibKernel::KERNEL_ERROR_ENOENT;
|
||||||
}
|
*error_offset = static_cast<uint32_t>(entry.record_offset);
|
||||||
for (size_t i = 0; i < state.write_address_commands.size(); i++) {
|
return OK;
|
||||||
if (state.write_address_commands[i].record_offset < state.write_offset) {
|
}
|
||||||
ordered.push_back(
|
|
||||||
{state.write_address_commands[i].record_offset, CommandKind::WriteAddress, i});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < state.amm_map_commands.size(); i++) {
|
|
||||||
if (state.amm_map_commands[i].record_offset < state.write_offset) {
|
|
||||||
ordered.push_back({state.amm_map_commands[i].record_offset, CommandKind::AmmMap, i});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::sort(ordered.begin(), ordered.end(), [](const OrderedCommand& a, const OrderedCommand& b) {
|
uint64_t bytes_read = 0;
|
||||||
return a.record_offset < b.record_offset;
|
auto result = ReadHostFileToGuest(host_path, command.file_offset, command.destination,
|
||||||
});
|
command.size, &bytes_read);
|
||||||
|
if (result != OK) {
|
||||||
|
LOGF("\tAPR submit read failed: id=0x%08" PRIx32 ", result=0x%08" PRIx32
|
||||||
|
", path=%s\n",
|
||||||
|
command.file_id, static_cast<uint32_t>(result), host_path.c_str());
|
||||||
|
*execution_result = result;
|
||||||
|
*error_offset = static_cast<uint32_t>(entry.record_offset);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
} else if (const auto* payload =
|
||||||
|
std::get_if<CommandBufferState::KernelEventCommand>(&entry.data)) {
|
||||||
|
const auto& command = *payload;
|
||||||
|
const auto eq = static_cast<LibKernel::EventQueue::KernelEqueue>(command.eq);
|
||||||
|
auto result = LibKernel::EventQueue::KernelTriggerUserEvent(
|
||||||
|
eq, command.id, reinterpret_cast<void*>(command.data));
|
||||||
|
if (result != OK) {
|
||||||
|
LOGF("\tAPR submit event failed: eq=0x%016" PRIx64 ", id=%" PRId32
|
||||||
|
", result=0x%08" PRIx32 "\n",
|
||||||
|
command.eq, command.id, static_cast<uint32_t>(result));
|
||||||
|
*execution_result = result;
|
||||||
|
*error_offset = static_cast<uint32_t>(entry.record_offset);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
} else if (const auto* payload =
|
||||||
|
std::get_if<CommandBufferState::WriteAddressCommand>(&entry.data)) {
|
||||||
|
const auto& command = *payload;
|
||||||
|
if (!AprShared::WriteGuest(command.address, command.value)) {
|
||||||
|
LOGF("\tAMPR submit write-address failed: address=0x%016" PRIx64
|
||||||
|
" value=0x%016" PRIx64 "\n",
|
||||||
|
command.address, command.value);
|
||||||
|
*execution_result = LibKernel::KERNEL_ERROR_EFAULT;
|
||||||
|
*error_offset = static_cast<uint32_t>(entry.record_offset);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
} else if (const auto* payload =
|
||||||
|
std::get_if<CommandBufferState::AmmMapCommand>(&entry.data)) {
|
||||||
|
const auto& command = *payload;
|
||||||
|
int result = OK;
|
||||||
|
if (command.kind == AmmCommandKind::Unmap) {
|
||||||
|
result = LibKernel::Memory::KernelMunmap(command.va, command.size);
|
||||||
|
} else {
|
||||||
|
result = ExecuteAmmMapCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& entry: ordered) {
|
if (result != OK) {
|
||||||
switch (entry.kind) {
|
LOGF("\tAMM submit command failed: kind=%u va=0x%016" PRIx64 " dmem=0x%016" PRIx64
|
||||||
case CommandKind::ReadFile: {
|
" size=0x%016" PRIx64 " type=%" PRId32 " prot=0x%08" PRIx32
|
||||||
const auto& command = state.read_file_commands[entry.index];
|
" result=0x%08" PRIx32 "\n",
|
||||||
std::string host_path;
|
static_cast<uint32_t>(command.kind), command.va, command.dmem_offset,
|
||||||
if (!AprShared::TryGetHostPath(command.file_id, &host_path)) {
|
command.size, command.type, static_cast<uint32_t>(command.prot),
|
||||||
LOGF("\tAPR submit failed for unknown file id: 0x%08" PRIx32 "\n",
|
static_cast<uint32_t>(result));
|
||||||
command.file_id);
|
*execution_result = result;
|
||||||
*execution_result = LibKernel::KERNEL_ERROR_ENOENT;
|
*error_offset = static_cast<uint32_t>(entry.record_offset);
|
||||||
*error_offset = static_cast<uint32_t>(command.record_offset);
|
return OK;
|
||||||
return OK;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t bytes_read = 0;
|
|
||||||
auto result = ReadHostFileToGuest(host_path, command.file_offset,
|
|
||||||
command.destination, command.size, &bytes_read);
|
|
||||||
if (result != OK) {
|
|
||||||
LOGF("\tAPR submit read failed: id=0x%08" PRIx32 ", result=0x%08" PRIx32
|
|
||||||
", path=%s\n",
|
|
||||||
command.file_id, static_cast<uint32_t>(result), host_path.c_str());
|
|
||||||
*execution_result = result;
|
|
||||||
*error_offset = static_cast<uint32_t>(command.record_offset);
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case CommandKind::KernelEvent: {
|
|
||||||
const auto& command = state.kernel_event_commands[entry.index];
|
|
||||||
const auto eq = static_cast<LibKernel::EventQueue::KernelEqueue>(command.eq);
|
|
||||||
auto result = LibKernel::EventQueue::KernelTriggerUserEvent(
|
|
||||||
eq, command.id, reinterpret_cast<void*>(command.data));
|
|
||||||
if (result != OK) {
|
|
||||||
LOGF("\tAPR submit event failed: eq=0x%016" PRIx64 ", id=%" PRId32
|
|
||||||
", result=0x%08" PRIx32 "\n",
|
|
||||||
command.eq, command.id, static_cast<uint32_t>(result));
|
|
||||||
*execution_result = result;
|
|
||||||
*error_offset = static_cast<uint32_t>(command.record_offset);
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case CommandKind::WriteAddress: {
|
|
||||||
const auto& command = state.write_address_commands[entry.index];
|
|
||||||
if (!AprShared::WriteGuest(command.address, command.value)) {
|
|
||||||
LOGF("\tAMPR submit write-address failed: address=0x%016" PRIx64
|
|
||||||
" value=0x%016" PRIx64 "\n",
|
|
||||||
command.address, command.value);
|
|
||||||
*execution_result = LibKernel::KERNEL_ERROR_EFAULT;
|
|
||||||
*error_offset = static_cast<uint32_t>(command.record_offset);
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case CommandKind::AmmMap: {
|
|
||||||
const auto& command = state.amm_map_commands[entry.index];
|
|
||||||
int result = OK;
|
|
||||||
if (command.kind == AmmCommandKind::Unmap) {
|
|
||||||
result = LibKernel::Memory::KernelMunmap(command.va, command.size);
|
|
||||||
} else {
|
|
||||||
result = ExecuteAmmMapCommand(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != OK) {
|
|
||||||
LOGF("\tAMM submit command failed: kind=%u va=0x%016" PRIx64
|
|
||||||
" dmem=0x%016" PRIx64 " size=0x%016" PRIx64 " type=%" PRId32
|
|
||||||
" prot=0x%08" PRIx32 " result=0x%08" PRIx32 "\n",
|
|
||||||
static_cast<uint32_t>(command.kind), command.va, command.dmem_offset,
|
|
||||||
command.size, command.type, static_cast<uint32_t>(command.prot),
|
|
||||||
static_cast<uint32_t>(result));
|
|
||||||
*execution_result = result;
|
|
||||||
*error_offset = static_cast<uint32_t>(command.record_offset);
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user