#include #include #include "ipc.h" #include "types/KProcess.h" namespace lightSwitch::kernel::ipc { IpcRequest::IpcRequest(bool is_domain, device_state &state) : is_domain(is_domain), state(state), tls() { u8 *curr_ptr = tls.data(); state.this_process->ReadMemory(curr_ptr, state.this_thread->tls, constant::tls_ipc_size); header = reinterpret_cast(curr_ptr); curr_ptr += sizeof(CommandHeader); if (header->handle_desc) { handle_desc = reinterpret_cast(curr_ptr); curr_ptr += sizeof(HandleDescriptor) + (handle_desc->send_pid ? sizeof(u8) : 0); for (uint index = 0; handle_desc->copy_count > index; index++) { copy_handles.push_back(*reinterpret_cast(curr_ptr)); curr_ptr += sizeof(handle_t); } for (uint index = 0; handle_desc->move_count > index; index++) { move_handles.push_back(*reinterpret_cast(curr_ptr)); curr_ptr += sizeof(handle_t); } } for (uint index = 0; header->x_no > index; index++) { vec_buf_x.push_back(reinterpret_cast(curr_ptr)); curr_ptr += sizeof(BufferDescriptorX); } for (uint index = 0; header->a_no > index; index++) { vec_buf_a.push_back(reinterpret_cast(curr_ptr)); curr_ptr += sizeof(BufferDescriptorABW); } for (uint index = 0; header->b_no > index; index++) { vec_buf_b.push_back(reinterpret_cast(curr_ptr)); curr_ptr += sizeof(BufferDescriptorABW); } for (uint index = 0; header->w_no > index; index++) { vec_buf_w.push_back(reinterpret_cast(curr_ptr)); curr_ptr += sizeof(BufferDescriptorABW); } auto raw_ptr = reinterpret_cast((((reinterpret_cast(curr_ptr) - reinterpret_cast(tls.data())) - 1U) & ~(constant::padding_sum - 1U)) + constant::padding_sum + reinterpret_cast(tls.data())); // Align to 16 bytes relative to start of TLS if (is_domain) { domain = reinterpret_cast(raw_ptr); payload = reinterpret_cast(raw_ptr + sizeof(DomainHeaderRequest)); cmd_arg_sz = domain->payload_sz - sizeof(PayloadHeader); } else { payload = reinterpret_cast(raw_ptr); cmd_arg_sz = (header->raw_sz * sizeof(u32)) - (constant::padding_sum + sizeof(PayloadHeader)); } if (payload->magic != constant::sfci_magic) throw exception(fmt::format("Unexpected Magic in PayloadHeader: 0x{:X}", reinterpret_cast(payload->magic))); cmd_arg = reinterpret_cast(payload) + sizeof(PayloadHeader); curr_ptr += header->raw_sz * sizeof(u32); if (header->c_flag == static_cast(BufferCFlag::SingleDescriptor)) { vec_buf_c.push_back(reinterpret_cast(curr_ptr)); } else if (header->c_flag > static_cast(BufferCFlag::SingleDescriptor)) { for (uint index = 0; (header->c_flag - 2) > index; index++) { // (c_flag - 2) C descriptors are present vec_buf_c.push_back(reinterpret_cast(curr_ptr)); curr_ptr += sizeof(BufferDescriptorC); } } } IpcResponse::IpcResponse(bool is_domain, device_state &state) : is_domain(is_domain), state(state) {} void IpcResponse::WriteTls() { std::array tls{}; u8 *curr_ptr = tls.data(); auto header = reinterpret_cast(curr_ptr); header->x_no = static_cast(vec_buf_x.size()); header->a_no = static_cast(vec_buf_a.size()); header->b_no = static_cast(vec_buf_b.size()); header->w_no = static_cast(vec_buf_w.size()); header->raw_sz = static_cast((sizeof(PayloadHeader) + arg_vec.size() + constant::padding_sum + (is_domain ? sizeof(DomainHeaderRequest) : 0)) / sizeof(u32)); // Size is in 32-bit units because Nintendo if (!vec_buf_c.empty()) header->c_flag = (vec_buf_c.size() == 1) ? static_cast(BufferCFlag::SingleDescriptor) : static_cast(vec_buf_c.size() + static_cast(BufferCFlag::SingleDescriptor)); header->handle_desc = (!copy_handles.empty() || !move_handles.empty()); curr_ptr += sizeof(CommandHeader); if (header->handle_desc) { auto handle_desc = reinterpret_cast(curr_ptr); handle_desc->send_pid = false; // TODO: Figure this out ? handle_desc->copy_count = static_cast(copy_handles.size()); handle_desc->move_count = static_cast(move_handles.size()); curr_ptr += sizeof(HandleDescriptor); for (uint index = 0; handle_desc->copy_count > index; index++) { *reinterpret_cast(curr_ptr) = copy_handles[index]; curr_ptr += sizeof(handle_t); } for (uint index = 0; handle_desc->move_count > index; index++) { *reinterpret_cast(curr_ptr) = move_handles[index]; curr_ptr += sizeof(handle_t); } } for (uint index = 0; header->x_no > index; index++) { *reinterpret_cast(curr_ptr) = vec_buf_x[index]; curr_ptr += sizeof(BufferDescriptorX); } for (uint index = 0; header->a_no > index; index++) { *reinterpret_cast(curr_ptr) = vec_buf_a[index]; curr_ptr += sizeof(BufferDescriptorABW); } for (uint index = 0; header->b_no > index; index++) { *reinterpret_cast(curr_ptr) = vec_buf_b[index]; curr_ptr += sizeof(BufferDescriptorABW); } for (uint index = 0; header->w_no > index; index++) { *reinterpret_cast(curr_ptr) = vec_buf_w[index]; curr_ptr += sizeof(BufferDescriptorABW); } u64 padding = ((((reinterpret_cast(curr_ptr) - reinterpret_cast(tls.data())) - 1U) & ~(constant::padding_sum - 1U)) + constant::padding_sum + (reinterpret_cast(tls.data()) - reinterpret_cast(curr_ptr))); // Calculate the amount of padding at the front curr_ptr += padding; PayloadHeader *payload; if (is_domain) { auto domain = reinterpret_cast(curr_ptr); domain->output_count = 0; // TODO: Figure this out payload = reinterpret_cast(curr_ptr + sizeof(DomainHeaderResponse)); } else { payload = reinterpret_cast(curr_ptr); } payload->magic = constant::sfco_magic; payload->version = 1; payload->value = error_code; curr_ptr += sizeof(PayloadHeader); if (!arg_vec.empty()) memcpy(curr_ptr, arg_vec.data(), arg_vec.size()); curr_ptr += arg_vec.size() + (constant::padding_sum - padding); if (header->c_flag == static_cast(BufferCFlag::SingleDescriptor)) { *reinterpret_cast(curr_ptr) = vec_buf_c[0]; } else if (header->c_flag > static_cast(BufferCFlag::SingleDescriptor)) { for (uint index = 0; (header->c_flag - 2) > index; index++) { *reinterpret_cast(curr_ptr) = vec_buf_c[index]; curr_ptr += sizeof(BufferDescriptorC); } } } }