mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2025-01-18 11:16:10 +00:00
tma: First pass at tio file read/write
This commit is contained in:
parent
efcce68a56
commit
600ad660a6
16 changed files with 600 additions and 15 deletions
|
@ -84,8 +84,8 @@ class DebugMonitorService final : public IServiceObject {
|
||||||
|
|
||||||
Result TargetIO_FileOpen(OutBuffer<u64> out_hnd, InBuffer<char> path, int open_mode, u32 create_mode);
|
Result TargetIO_FileOpen(OutBuffer<u64> out_hnd, InBuffer<char> path, int open_mode, u32 create_mode);
|
||||||
Result TargetIO_FileClose(InBuffer<u64> hnd);
|
Result TargetIO_FileClose(InBuffer<u64> hnd);
|
||||||
Result TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8> out_data, Out<u32> out_read, u64 offset);
|
Result TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8, BufferType_Type1> out_data, Out<u32> out_read, u64 offset);
|
||||||
Result TargetIO_FileWrite(InBuffer<u64> hnd, InBuffer<u8> data, Out<u32> out_written, u64 offset);
|
Result TargetIO_FileWrite(InBuffer<u64> hnd, InBuffer<u8, BufferType_Type1> data, Out<u32> out_written, u64 offset);
|
||||||
Result TargetIO_FileSetAttributes(InBuffer<char> path, InBuffer<u8> attributes);
|
Result TargetIO_FileSetAttributes(InBuffer<char> path, InBuffer<u8> attributes);
|
||||||
Result TargetIO_FileGetInformation(InBuffer<char> path, OutBuffer<u64> out_info, Out<int> is_directory);
|
Result TargetIO_FileGetInformation(InBuffer<char> path, OutBuffer<u64> out_info, Out<int> is_directory);
|
||||||
Result TargetIO_FileSetTime(InBuffer<char> path, u64 create, u64 access, u64 modify);
|
Result TargetIO_FileSetTime(InBuffer<char> path, u64 create, u64 access, u64 modify);
|
||||||
|
|
|
@ -157,7 +157,7 @@ Result DebugMonitorService::TargetIO_FileClose(InBuffer<u64> hnd) {
|
||||||
return CloseFileByHandle(hnd[0]);
|
return CloseFileByHandle(hnd[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DebugMonitorService::TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8> out_data, Out<u32> out_read, u64 offset) {
|
Result DebugMonitorService::TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8, BufferType_Type1> out_data, Out<u32> out_read, u64 offset) {
|
||||||
if (hnd.num_elements != 1) {
|
if (hnd.num_elements != 1) {
|
||||||
return 0xF601;
|
return 0xF601;
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ Result DebugMonitorService::TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8> o
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DebugMonitorService::TargetIO_FileWrite(InBuffer<u64> hnd, InBuffer<u8> data, Out<u32> out_written, u64 offset) {
|
Result DebugMonitorService::TargetIO_FileWrite(InBuffer<u64> hnd, InBuffer<u8, BufferType_Type1> data, Out<u32> out_written, u64 offset) {
|
||||||
if (hnd.num_elements != 1) {
|
if (hnd.num_elements != 1) {
|
||||||
return 0xF601;
|
return 0xF601;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ include $(DEVKITPRO)/libnx/switch_rules
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
TARGET := $(notdir $(CURDIR))
|
TARGET := $(notdir $(CURDIR))
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := source source/test source/settings
|
SOURCES := source source/test source/settings source/target_io
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := include ../../common/include
|
INCLUDES := include ../../common/include
|
||||||
EXEFS_SRC := exefs_src
|
EXEFS_SRC := exefs_src
|
||||||
|
|
|
@ -20,16 +20,15 @@ def main(argc, argv):
|
||||||
print 'Waiting for connection...'
|
print 'Waiting for connection...'
|
||||||
c.wait_connected()
|
c.wait_connected()
|
||||||
print 'Connected!'
|
print 'Connected!'
|
||||||
c.intf.send_packet(Packet().set_service(ServiceId.SETTINGS_SERVICE).set_task(0x01000000).set_cmd(0).write_str('platformconfig').write_str('platformtype'))
|
print 'Reading atmosphere/BCT.ini...'
|
||||||
|
c.intf.send_packet(Packet().set_service(ServiceId.TARGETIO_SERVICE).set_task(0x01000000).set_cmd(2).write_str('atmosphere/BCT.ini').write_u64(0x109).write_u64(0))
|
||||||
resp = c.intf.read_packet()
|
resp = c.intf.read_packet()
|
||||||
success = resp.read_u8() != 0
|
res_packet = c.intf.read_packet()
|
||||||
print 'Succeeded: %s' % str(success)
|
read_res, size_read = resp.read_u32(), resp.read_u32()
|
||||||
if success:
|
print 'Final Result: 0x%x' % res_packet.read_u32()
|
||||||
size = resp.read_u32()
|
print 'Size Read: 0x%x' % size_read
|
||||||
value = resp.body[resp.offset:resp.offset+size]
|
print 'Data:\n%s' % resp.body[resp.offset:]
|
||||||
print 'Value Size: 0x%x' % size
|
|
||||||
print 'Value: %s' % repr(value)
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -25,5 +25,6 @@ USB_CONNECT = hash("USBConnect")
|
||||||
USB_DISCONNECT = hash("USBDisconnect")
|
USB_DISCONNECT = hash("USBDisconnect")
|
||||||
|
|
||||||
ATMOSPHERE_TEST_SERVICE = hash("AtmosphereTestService")
|
ATMOSPHERE_TEST_SERVICE = hash("AtmosphereTestService")
|
||||||
SETTINGS_SERVICE = hash ("SettingsService")
|
SETTINGS_SERVICE = hash("SettingsService")
|
||||||
|
TARGETIO_SERVICE = hash("TIOService")
|
||||||
|
|
188
stratosphere/tma/source/dmnt.c
Normal file
188
stratosphere/tma/source/dmnt.c
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
#include "dmnt.h"
|
||||||
|
|
||||||
|
static Service g_dmntSrv;
|
||||||
|
static u64 g_refCnt;
|
||||||
|
|
||||||
|
Result dmntInitialize(void) {
|
||||||
|
atomicIncrement64(&g_refCnt);
|
||||||
|
|
||||||
|
if (serviceIsActive(&g_dmntSrv))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return smGetService(&g_dmntSrv, "dmnt:-");
|
||||||
|
}
|
||||||
|
|
||||||
|
void dmntExit(void) {
|
||||||
|
if (atomicDecrement64(&g_refCnt) == 0)
|
||||||
|
serviceClose(&g_dmntSrv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result dmntTargetIOFileOpen(DmntFile *out, const char *path, int flags, DmntTIOCreateOption create_option) {
|
||||||
|
IpcCommand c;
|
||||||
|
ipcInitialize(&c);
|
||||||
|
ipcAddSendBuffer(&c, path, FS_MAX_PATH, BufferType_Normal);
|
||||||
|
ipcAddRecvBuffer(&c, out, sizeof(*out), BufferType_Normal);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u64 magic;
|
||||||
|
u64 cmd_id;
|
||||||
|
int flags;
|
||||||
|
u32 create_option;
|
||||||
|
} *raw;
|
||||||
|
|
||||||
|
raw = serviceIpcPrepareHeader(&g_dmntSrv, &c, sizeof(*raw));
|
||||||
|
|
||||||
|
raw->magic = SFCI_MAGIC;
|
||||||
|
raw->cmd_id = 29;
|
||||||
|
raw->flags = flags;
|
||||||
|
raw->create_option = create_option;
|
||||||
|
|
||||||
|
Result rc = serviceIpcDispatch(&g_dmntSrv);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
IpcParsedCommand r;
|
||||||
|
struct {
|
||||||
|
u64 magic;
|
||||||
|
u64 result;
|
||||||
|
} *resp;
|
||||||
|
|
||||||
|
serviceIpcParse(&g_dmntSrv, &r, sizeof(*resp));
|
||||||
|
resp = r.Raw;
|
||||||
|
|
||||||
|
rc = resp->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result dmntTargetIOFileClose(DmntFile *f) {
|
||||||
|
IpcCommand c;
|
||||||
|
ipcInitialize(&c);
|
||||||
|
ipcAddSendBuffer(&c, f, sizeof(*f), BufferType_Normal);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u64 magic;
|
||||||
|
u64 cmd_id;
|
||||||
|
} *raw;
|
||||||
|
|
||||||
|
raw = serviceIpcPrepareHeader(&g_dmntSrv, &c, sizeof(*raw));
|
||||||
|
|
||||||
|
raw->magic = SFCI_MAGIC;
|
||||||
|
raw->cmd_id = 30;
|
||||||
|
|
||||||
|
Result rc = serviceIpcDispatch(&g_dmntSrv);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
IpcParsedCommand r;
|
||||||
|
struct {
|
||||||
|
u64 magic;
|
||||||
|
u64 result;
|
||||||
|
} *resp;
|
||||||
|
|
||||||
|
serviceIpcParse(&g_dmntSrv, &r, sizeof(*resp));
|
||||||
|
resp = r.Raw;
|
||||||
|
|
||||||
|
rc = resp->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result dmntTargetIOFileRead(DmntFile *f, u64 off, void* buf, size_t len, size_t *out_read) {
|
||||||
|
IpcCommand c;
|
||||||
|
ipcInitialize(&c);
|
||||||
|
ipcAddSendBuffer(&c, f, sizeof(*f), BufferType_Normal);
|
||||||
|
ipcAddRecvBuffer(&c, buf, len, BufferType_Type1);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u64 magic;
|
||||||
|
u64 cmd_id;
|
||||||
|
u64 offset;
|
||||||
|
} *raw;
|
||||||
|
|
||||||
|
raw = serviceIpcPrepareHeader(&g_dmntSrv, &c, sizeof(*raw));
|
||||||
|
|
||||||
|
raw->magic = SFCI_MAGIC;
|
||||||
|
raw->cmd_id = 31;
|
||||||
|
raw->offset = off;
|
||||||
|
|
||||||
|
Result rc = serviceIpcDispatch(&g_dmntSrv);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
IpcParsedCommand r;
|
||||||
|
struct {
|
||||||
|
u64 magic;
|
||||||
|
u64 result;
|
||||||
|
u32 out_read;
|
||||||
|
} *resp;
|
||||||
|
|
||||||
|
serviceIpcParse(&g_dmntSrv, &r, sizeof(*resp));
|
||||||
|
resp = r.Raw;
|
||||||
|
|
||||||
|
rc = resp->result;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) && out_read) {
|
||||||
|
*out_read = resp->out_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result dmntTargetIOFileWrite(DmntFile *f, u64 off, const void* buf, size_t len, size_t *out_written) {
|
||||||
|
IpcCommand c;
|
||||||
|
ipcInitialize(&c);
|
||||||
|
ipcAddSendBuffer(&c, f, sizeof(*f), BufferType_Normal);
|
||||||
|
ipcAddSendBuffer(&c, buf, len, BufferType_Type1);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u64 magic;
|
||||||
|
u64 cmd_id;
|
||||||
|
u64 offset;
|
||||||
|
} *raw;
|
||||||
|
|
||||||
|
raw = serviceIpcPrepareHeader(&g_dmntSrv, &c, sizeof(*raw));
|
||||||
|
|
||||||
|
raw->magic = SFCI_MAGIC;
|
||||||
|
raw->cmd_id = 32;
|
||||||
|
raw->offset = off;
|
||||||
|
|
||||||
|
Result rc = serviceIpcDispatch(&g_dmntSrv);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
IpcParsedCommand r;
|
||||||
|
struct {
|
||||||
|
u64 magic;
|
||||||
|
u64 result;
|
||||||
|
u32 out_written;
|
||||||
|
} *resp;
|
||||||
|
|
||||||
|
serviceIpcParse(&g_dmntSrv, &r, sizeof(*resp));
|
||||||
|
resp = r.Raw;
|
||||||
|
|
||||||
|
rc = resp->result;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) && out_written) {
|
||||||
|
*out_written = resp->out_written;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
46
stratosphere/tma/source/dmnt.h
Normal file
46
stratosphere/tma/source/dmnt.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u64 handle;
|
||||||
|
} DmntFile;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DmntTIOCreateOption_CreateNew = 1,
|
||||||
|
DmntTIOCreateOption_CreateAlways = 2,
|
||||||
|
DmntTIOCreateOption_OpenExisting = 3,
|
||||||
|
DmntTIOCreateOption_OpenAlways = 4,
|
||||||
|
DmntTIOCreateOption_ResetSize = 5,
|
||||||
|
} DmntTIOCreateOption;
|
||||||
|
|
||||||
|
Result dmntInitialize(void);
|
||||||
|
void dmntExit(void);
|
||||||
|
|
||||||
|
Result dmntTargetIOFileOpen(DmntFile *out, const char *path, int flags, DmntTIOCreateOption create_option);
|
||||||
|
Result dmntTargetIOFileClose(DmntFile *f);
|
||||||
|
Result dmntTargetIOFileRead(DmntFile *f, u64 off, void* buf, size_t len, size_t* out_read);
|
||||||
|
Result dmntTargetIOFileWrite(DmntFile *f, u64 off, const void* buf, size_t len, size_t* out_written);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
47
stratosphere/tma/source/target_io/tio_service.cpp
Normal file
47
stratosphere/tma/source/target_io/tio_service.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "tio_service.hpp"
|
||||||
|
#include "tio_task.hpp"
|
||||||
|
|
||||||
|
TmaTask *TIOService::NewTask(TmaPacket *packet) {
|
||||||
|
TmaTask *new_task = nullptr;
|
||||||
|
switch (packet->GetCommand()) {
|
||||||
|
case TIOServiceCmd_FileRead:
|
||||||
|
{
|
||||||
|
new_task = new TIOFileReadTask(this->manager);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TIOServiceCmd_FileWrite:
|
||||||
|
{
|
||||||
|
new_task = new TIOFileWriteTask(this->manager);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
new_task = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (new_task != nullptr) {
|
||||||
|
new_task->SetServiceId(this->GetServiceId());
|
||||||
|
new_task->SetTaskId(packet->GetTaskId());
|
||||||
|
new_task->OnStart(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_task;
|
||||||
|
}
|
35
stratosphere/tma/source/target_io/tio_service.hpp
Normal file
35
stratosphere/tma/source/target_io/tio_service.hpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "../tma_conn_service_ids.hpp"
|
||||||
|
#include "../tma_service.hpp"
|
||||||
|
|
||||||
|
enum TIOServiceCmd : u32 {
|
||||||
|
TIOServiceCmd_FileRead = 2,
|
||||||
|
TIOServiceCmd_FileWrite = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
class TIOService : public TmaService {
|
||||||
|
public:
|
||||||
|
TIOService(TmaServiceManager *m) : TmaService(m, "TIOService") { }
|
||||||
|
virtual ~TIOService() { }
|
||||||
|
|
||||||
|
virtual TmaTask *NewTask(TmaPacket *packet) override;
|
||||||
|
};
|
152
stratosphere/tma/source/target_io/tio_task.cpp
Normal file
152
stratosphere/tma/source/target_io/tio_task.cpp
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "tio_task.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
void TIOFileReadTask::OnStart(TmaPacket *packet) {
|
||||||
|
char path[FS_MAX_PATH];
|
||||||
|
|
||||||
|
packet->ReadString(path, sizeof(path), nullptr);
|
||||||
|
packet->Read<u64>(this->size_remaining);
|
||||||
|
packet->Read<u64>(this->cur_offset);
|
||||||
|
|
||||||
|
if (strlen(path) == 0) {
|
||||||
|
this->SendResult(0x202);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result rc = dmntTargetIOFileOpen(&this->handle, path, FS_OPEN_READ, DmntTIOCreateOption_OpenExisting);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
this->SendResult(rc);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
auto packet = this->AllocateSendPacket();
|
||||||
|
rc = this->ProcessPacket(packet);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
this->manager->SendPacket(packet);
|
||||||
|
if (this->size_remaining) {
|
||||||
|
this->SetNeedsPackets(true);
|
||||||
|
} else {
|
||||||
|
this->SendResult(rc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this->manager->FreePacket(packet);
|
||||||
|
this->SendResult(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TIOFileReadTask::OnSendPacket(TmaPacket *packet) {
|
||||||
|
Result rc = this->ProcessPacket(packet);
|
||||||
|
|
||||||
|
if (this->size_remaining == 0 || R_FAILED(rc)) {
|
||||||
|
this->SendResult(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TIOFileReadTask::SendResult(Result rc) {
|
||||||
|
dmntTargetIOFileClose(&this->handle);
|
||||||
|
this->SetNeedsPackets(false);
|
||||||
|
|
||||||
|
auto packet = this->AllocateSendPacket();
|
||||||
|
packet->Write<Result>(rc);
|
||||||
|
this->manager->SendPacket(packet);
|
||||||
|
Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result TIOFileReadTask::ProcessPacket(TmaPacket *packet) {
|
||||||
|
Result rc = 0x196002;
|
||||||
|
|
||||||
|
size_t cur_read = static_cast<u32>((this->size_remaining > MaxDataSize) ? MaxDataSize : this->size_remaining);
|
||||||
|
|
||||||
|
u8 *buf = new u8[cur_read];
|
||||||
|
if (buf != nullptr) {
|
||||||
|
size_t actual_read = 0;
|
||||||
|
rc = dmntTargetIOFileRead(&this->handle, this->cur_offset, buf, cur_read, &actual_read);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
packet->Write<Result>(rc);
|
||||||
|
packet->Write<u32>(actual_read);
|
||||||
|
packet->Write(buf, actual_read);
|
||||||
|
this->cur_offset += actual_read;
|
||||||
|
this->size_remaining -= actual_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TIOFileWriteTask::OnStart(TmaPacket *packet) {
|
||||||
|
char path[FS_MAX_PATH];
|
||||||
|
|
||||||
|
packet->ReadString(path, sizeof(path), nullptr);
|
||||||
|
packet->Read<u64>(this->size_remaining);
|
||||||
|
packet->Read<u64>(this->cur_offset);
|
||||||
|
|
||||||
|
if (strlen(path) == 0) {
|
||||||
|
this->SendResult(0x202);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result rc = dmntTargetIOFileOpen(&this->handle, path, FS_OPEN_READ, DmntTIOCreateOption_OpenExisting);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
this->SendResult(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TIOFileWriteTask::OnReceivePacket(TmaPacket *packet) {
|
||||||
|
Result rc = this->ProcessPacket(packet);
|
||||||
|
|
||||||
|
if (this->size_remaining == 0 || R_FAILED(rc)) {
|
||||||
|
this->SendResult(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TIOFileWriteTask::SendResult(Result rc) {
|
||||||
|
dmntTargetIOFileClose(&this->handle);
|
||||||
|
|
||||||
|
auto packet = this->AllocateSendPacket();
|
||||||
|
packet->Write<Result>(rc);
|
||||||
|
this->manager->SendPacket(packet);
|
||||||
|
Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result TIOFileWriteTask::ProcessPacket(TmaPacket *packet) {
|
||||||
|
Result rc = 0x196002;
|
||||||
|
|
||||||
|
/* Note: N does not bounds check this. We do. */
|
||||||
|
u32 cur_write = 0;
|
||||||
|
packet->Read<u32>(cur_write);
|
||||||
|
|
||||||
|
size_t actual_written = 0;
|
||||||
|
if (cur_write < MaxDataSize) {
|
||||||
|
if (cur_write > this->size_remaining) {
|
||||||
|
cur_write = this->size_remaining;
|
||||||
|
}
|
||||||
|
rc = dmntTargetIOFileWrite(&this->handle, this->cur_offset, packet->GetCurrentBodyPtr(), cur_write, &actual_written);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
this->size_remaining -= actual_written;
|
||||||
|
this->cur_offset += actual_written;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
85
stratosphere/tma/source/target_io/tio_task.hpp
Normal file
85
stratosphere/tma/source/target_io/tio_task.hpp
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "../tma_task.hpp"
|
||||||
|
#include "../tma_service_manager.hpp"
|
||||||
|
#include "../dmnt.h"
|
||||||
|
|
||||||
|
class TIOTask : public TmaTask {
|
||||||
|
public:
|
||||||
|
TIOTask(TmaServiceManager *m) : TmaTask(m) { }
|
||||||
|
virtual ~TIOTask() { }
|
||||||
|
|
||||||
|
virtual void SendResult(Result rc) {
|
||||||
|
TmaPacket *packet = this->AllocateSendPacket();
|
||||||
|
packet->Write<Result>(rc);
|
||||||
|
this->manager->SendPacket(packet);
|
||||||
|
this->Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnStart(TmaPacket *packet) = 0;
|
||||||
|
|
||||||
|
virtual void OnReceivePacket(TmaPacket *packet) override {
|
||||||
|
this->Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnSendPacket(TmaPacket *packet) override {
|
||||||
|
this->Complete();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TIOFileReadTask : public TIOTask {
|
||||||
|
private:
|
||||||
|
static constexpr size_t HeaderSize = sizeof(Result) + sizeof(u32);
|
||||||
|
static constexpr size_t MaxDataSize = TmaPacket::MaxBodySize - HeaderSize;
|
||||||
|
private:
|
||||||
|
DmntFile handle = {0};
|
||||||
|
u64 size_remaining = 0;
|
||||||
|
u64 cur_offset = 0;
|
||||||
|
public:
|
||||||
|
TIOFileReadTask(TmaServiceManager *m) : TIOTask(m) { }
|
||||||
|
virtual ~TIOFileReadTask() { }
|
||||||
|
|
||||||
|
virtual void OnStart(TmaPacket *packet) override;
|
||||||
|
virtual void OnSendPacket(TmaPacket *packet) override;
|
||||||
|
virtual void SendResult(Result rc) override;
|
||||||
|
|
||||||
|
Result ProcessPacket(TmaPacket *packet);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TIOFileWriteTask : public TIOTask {
|
||||||
|
private:
|
||||||
|
static constexpr size_t HeaderSize = sizeof(u32);
|
||||||
|
static constexpr size_t MaxDataSize = TmaPacket::MaxBodySize - HeaderSize;
|
||||||
|
private:
|
||||||
|
DmntFile handle = {0};
|
||||||
|
u64 size_remaining = 0;
|
||||||
|
u64 cur_offset = 0;
|
||||||
|
public:
|
||||||
|
TIOFileWriteTask(TmaServiceManager *m) : TIOTask(m) { }
|
||||||
|
virtual ~TIOFileWriteTask() { }
|
||||||
|
|
||||||
|
virtual void OnStart(TmaPacket *packet) override;
|
||||||
|
virtual void OnReceivePacket(TmaPacket *packet) override;
|
||||||
|
virtual void SendResult(Result rc) override;
|
||||||
|
|
||||||
|
Result ProcessPacket(TmaPacket *packet);
|
||||||
|
};
|
||||||
|
|
|
@ -166,6 +166,10 @@ class TmaPacket {
|
||||||
return GetHeader()->version;
|
return GetHeader()->version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 *GetCurrentBodyPtr() {
|
||||||
|
return GetBody(this->offset);
|
||||||
|
}
|
||||||
|
|
||||||
void ClearOffset() {
|
void ClearOffset() {
|
||||||
this->offset = 0;
|
this->offset = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include "tma_target.hpp"
|
#include "tma_target.hpp"
|
||||||
|
|
||||||
|
#include "dmnt.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
extern u32 __start__;
|
extern u32 __start__;
|
||||||
|
|
||||||
|
@ -70,11 +72,17 @@ void __appInit(void) {
|
||||||
fatalSimple(rc);
|
fatalSimple(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = dmntInitialize();
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
fatalSimple(rc);
|
||||||
|
}
|
||||||
|
|
||||||
CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION);
|
CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __appExit(void) {
|
void __appExit(void) {
|
||||||
/* Cleanup services. */
|
/* Cleanup services. */
|
||||||
|
dmntExit();
|
||||||
setsysExit();
|
setsysExit();
|
||||||
pscExit();
|
pscExit();
|
||||||
smExit();
|
smExit();
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include "test/atmosphere_test_service.hpp"
|
#include "test/atmosphere_test_service.hpp"
|
||||||
#include "settings/settings_service.hpp"
|
#include "settings/settings_service.hpp"
|
||||||
|
#include "target_io/tio_service.hpp"
|
||||||
|
|
||||||
struct TmaTargetConfig {
|
struct TmaTargetConfig {
|
||||||
char configuration_id1[0x80];
|
char configuration_id1[0x80];
|
||||||
|
@ -210,6 +211,7 @@ void TmaTarget::Initialize() {
|
||||||
/* TODO: Make this better. */
|
/* TODO: Make this better. */
|
||||||
g_service_manager->AddService(new AtmosphereTestService(g_service_manager));
|
g_service_manager->AddService(new AtmosphereTestService(g_service_manager));
|
||||||
g_service_manager->AddService(new SettingsService(g_service_manager));
|
g_service_manager->AddService(new SettingsService(g_service_manager));
|
||||||
|
g_service_manager->AddService(new TIOService(g_service_manager));
|
||||||
|
|
||||||
RefreshTargetConfig();
|
RefreshTargetConfig();
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,21 @@ void TmaTask::SetNeedsPackets(bool n) {
|
||||||
this->manager->Tick();
|
this->manager->Tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TmaPacket *TmaTask::AllocateSendPacket(bool continuation) {
|
||||||
|
auto packet = this->manager->AllocateSendPacket();
|
||||||
|
packet->SetServiceId(this->service_id);
|
||||||
|
packet->SetTaskId(this->task_id);
|
||||||
|
packet->SetCommand(this->command);
|
||||||
|
packet->SetContinuation(continuation);
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TmaTask::FreePacket(TmaPacket *packet) {
|
||||||
|
this->manager->FreePacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
void TmaTask::Complete() {
|
void TmaTask::Complete() {
|
||||||
SetNeedsPackets(false);
|
SetNeedsPackets(false);
|
||||||
this->state = TmaTaskState::Complete;
|
this->state = TmaTaskState::Complete;
|
||||||
|
|
|
@ -68,6 +68,9 @@ class TmaTask {
|
||||||
void Signal() { this->signal.Signal(); }
|
void Signal() { this->signal.Signal(); }
|
||||||
void ResetSignal() { this->signal.Reset(); }
|
void ResetSignal() { this->signal.Reset(); }
|
||||||
|
|
||||||
|
TmaPacket *AllocateSendPacket(bool continuation = true);
|
||||||
|
void FreePacket(TmaPacket *packet);
|
||||||
|
|
||||||
void Complete();
|
void Complete();
|
||||||
void Cancel();
|
void Cancel();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue