diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 125a5ea..48adc16 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -55,6 +55,8 @@ extern "C" { #include <3ds/services/y2r.h> #include <3ds/services/hb.h> +#include <3ds/services/ampxi.h> + #include <3ds/gpu/gx.h> #include <3ds/gpu/gpu.h> #include <3ds/gpu/gpu-old.h> diff --git a/libctru/include/3ds/services/ampxi.h b/libctru/include/3ds/services/ampxi.h new file mode 100644 index 0000000..43f8741 --- /dev/null +++ b/libctru/include/3ds/services/ampxi.h @@ -0,0 +1,25 @@ +/** + * @file ampxi.h + * @brief AMPXI service. This is normally not accessible to userland apps. https://3dbrew.org/wiki/Application_Manager_Services_PXI + */ +#pragma once + +/** + * @brief Initializes AMPXI. + * @param servhandle Optional service session handle to use for AMPXI, if zero srvGetServiceHandle() will be used. + */ +Result ampxiInit(Handle servhandle); + +/// Exits AMPXI. +void ampxiExit(void); + +/** + * @brief Writes a TWL save-file to NAND. https://www.3dbrew.org/wiki/AMPXI:WriteTWLSavedata + * @param titleid ID of the TWL title. + * @param buffer Savedata buffer ptr. + * @param size Size of the savedata buffer. + * @param image_filepos Filepos to use for writing the data to the NAND savedata file. + * @param section_type https://www.3dbrew.org/wiki/AMPXI:WriteTWLSavedata + * @param operation https://3dbrew.org/wiki/AM:ImportDSiWare + */ +Result ampxiWriteTWLSavedata(u64 titleid, u8 *buffer, u32 size, u32 image_filepos, u8 section_type, u8 operation); diff --git a/libctru/source/services/ampxi.c b/libctru/source/services/ampxi.c new file mode 100644 index 0000000..5465755 --- /dev/null +++ b/libctru/source/services/ampxi.c @@ -0,0 +1,54 @@ +#include +#include <3ds/types.h> +#include <3ds/result.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/synchronization.h> +#include <3ds/services/ampxi.h> +#include <3ds/ipc.h> + +static Handle ampxiHandle; +static int ampxiRefCount; + +Result ampxiInit(Handle servhandle) +{ + Result res=0; + if (AtomicPostIncrement(&xiRefCount)) return 0; + if(servhandle) + { + ampxiHandle = servhandle; + } + else + { + res = srvGetServiceHandle(&xiHandle, "pxi:am9"); + if (R_FAILED(res)) AtomicDecrement(&xiRefCount); + } + return res; +} + +void ampxiExit(void) +{ + if (AtomicDecrement(&xiRefCount)) return; + svcCloseHandle(ampxiHandle); +} + +Result ampxiWriteTWLSavedata(u64 titleid, u8 *buffer, u32 size, u32 image_filepos, u8 section_type, u8 operation) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x46,6,2); // 0x460182 + cmdbuf[1] = titleid & 0xffffffff; + cmdbuf[2] = (titleid >> 32) & 0xffffffff; + cmdbuf[3] = size; + cmdbuf[4] = image_filepos; + cmdbuf[5] = section_type; + cmdbuf[6] = operation; + + cmdbuf[7] = IPC_Desc_PXIBuffer(size, 0, 0); + cmdbuf[8] = (u32)buffer; + + if(R_FAILED(ret = svcSendSyncRequest(ampxiHandle)))return ret; + + return (Result)cmdbuf[1]; +}