PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/minipc/source/minipc.c

https://github.com/comex/somestuff
C | 404 lines | 316 code | 81 blank | 7 comment | 17 complexity | ec4a5d7e4d5f0822b1dd2d076a270118 MD5 | raw file
  1. #include <gctypes.h>
  2. #include <gcutil.h>
  3. #include <stdio.h>
  4. #include "usbprintf.h"
  5. #define IPC_REQ_MAGIC 0x4C4F4743
  6. void DCFlushRange(void *startaddress,u32 len);
  7. //#define DEBUG_MINIPC_SORTA
  8. #ifdef DEBUG_MINIPC
  9. #define debug_printf usbprintf
  10. void dump_mem(void *stuff, int len) {
  11. char *s = (char *) stuff;
  12. while(len--) {
  13. debug_printf("%02hhx ", *(s++));
  14. }
  15. debug_printf("\n");
  16. }
  17. #else
  18. #ifdef DEBUG_MINIPC_SORTA
  19. #define debug_printf usbprint
  20. #else
  21. #define debug_printf(...)
  22. #endif
  23. inline void dump_mem(void *stuff, int len) {}
  24. #endif
  25. typedef struct _ioctlv
  26. {
  27. void *data;
  28. u32 len;
  29. } ioctlv;
  30. struct _ipcreq
  31. { //ipc struct size: 32
  32. u32 cmd; //0
  33. s32 result; //4
  34. union { //8
  35. s32 fd;
  36. u32 req_cmd;
  37. };
  38. union {
  39. struct {
  40. char *filepath;
  41. u32 mode;
  42. } open;
  43. struct {
  44. void *data;
  45. u32 len;
  46. } read, write;
  47. struct {
  48. s32 where;
  49. s32 whence;
  50. } seek;
  51. struct {
  52. u32 ioctl;
  53. void *buffer_in;
  54. u32 len_in;
  55. void *buffer_io;
  56. u32 len_io;
  57. } ioctl;
  58. struct {
  59. u32 ioctl;
  60. u32 argcin;
  61. u32 argcio;
  62. struct _ioctlv *argv;
  63. } ioctlv;
  64. u32 args[5];
  65. };
  66. void * /* ipccallback*/ cb; //32
  67. u32 usrdata; //36 =
  68. u32 relnch; //40
  69. void * /*lwpq_t*/ syncqueue; //44
  70. u32 magic; //48 - used to avoid spurious responses, like from zelda.
  71. u8 pad1[12]; //52 - 60
  72. } __attribute__((packed));
  73. typedef struct _tiklimit {
  74. u32 tag;
  75. u32 value;
  76. } __attribute__((packed)) tiklimit;
  77. typedef struct _tikview {
  78. u32 view;
  79. u64 ticketid;
  80. u32 devicetype;
  81. u64 titleid;
  82. u16 access_mask;
  83. u8 reserved[0x3c];
  84. u8 cidx_mask[0x40];
  85. u16 padding;
  86. tiklimit limits[8];
  87. } __attribute__((packed)) tikview;
  88. struct _ipcreqres
  89. {
  90. u32 cnt_sent;
  91. u32 cnt_queue;
  92. u32 req_send_no;
  93. u32 req_queue_no;
  94. struct _ipcreq *reqs[16];
  95. };
  96. typedef struct {
  97. u32 checksum;
  98. u8 flags;
  99. u8 type;
  100. u8 discstate;
  101. u8 returnto;
  102. u32 unknown[6];
  103. } StateFlags;
  104. static vu32 *_ipcReg = (u32*)0xCD000000;
  105. #define v2p(x) (((u32)(x)) & ~(0xC0000000))
  106. static inline u32 IPC_ReadReg(u32 reg)
  107. {
  108. return _ipcReg[reg];
  109. }
  110. static inline void IPC_WriteReg(u32 reg,u32 val)
  111. {
  112. _ipcReg[reg] = val;
  113. }
  114. char *ipcland;
  115. char *ipcland_base;
  116. int ipcland_size;
  117. void init() {
  118. ipcland_base = (char *) 0x80902c00;//0x933f0000; //933e
  119. ipcland_size = 0x2000;
  120. IPC_WriteReg(1, 56);
  121. ipcland = ipcland_base;
  122. memset(ipcland, 0, ipcland_size);
  123. DCFlushRange(ipcland, ipcland_size);
  124. }
  125. void *ios_alloc(int len) { // worst allocator ever
  126. void *ret = (void *) (ipcland += ((len & ~31) + 32));
  127. if(ipcland > ipcland_base + ipcland_size) {
  128. debug_printf("oom\n");
  129. while(1);
  130. }
  131. return ret;
  132. }
  133. s32 send_request(struct _ipcreq *req) {
  134. debug_printf("[send request]\n");
  135. req->result = 0xdeadbeef;
  136. req->cb = 0;
  137. req->usrdata = 0xfeedb0bb;
  138. req->magic = IPC_REQ_MAGIC;
  139. dump_mem(req, sizeof(struct _ipcreq));
  140. // Flush the world, why not
  141. DCFlushRange(ipcland_base, ipcland_size);
  142. IPC_WriteReg(0, v2p(req));
  143. u32 ipc_send = (IPC_ReadReg(1) & 0x30) | 0x01;
  144. IPC_WriteReg(1, ipc_send);
  145. // do something --> interrupt handler?
  146. while(1) {
  147. u32 ipc_int;
  148. ipc_int = IPC_ReadReg(1);
  149. if((ipc_int & 0x0014) == 0x0014) {
  150. IPC_WriteReg(1, (IPC_ReadReg(1) & 0x30) | 0x4);
  151. IPC_WriteReg(48 >> 2,0x40000000);
  152. struct _ipcreq *req2 = (struct _ipcreq *) IPC_ReadReg(2);
  153. if(!req2) {
  154. debug_printf("Invalid req\n");
  155. continue;
  156. }
  157. req2 = (struct _ipcreq *) (((u32) req2) + 0x80000000);
  158. debug_printf("[req is %x]\n", req2);
  159. DCInvalidateRange(req2, sizeof(struct _ipcreq));
  160. debug_printf("%x = %x?\n", req2->magic, IPC_REQ_MAGIC);
  161. dump_mem(req2, sizeof(struct _ipcreq));
  162. if(req2->magic != IPC_REQ_MAGIC) {
  163. continue;
  164. }
  165. u32 ipc_ack = ((IPC_ReadReg(1)&0x30)|0x08);
  166. IPC_WriteReg(1,ipc_ack);
  167. // IPC_WriteReg(1, (IPC_ReadReg(1) & 0x30) | 0x8);
  168. if(req2->usrdata != 0xfeedb0bb) {
  169. debug_printf("Ignoring spurious response\n");
  170. continue;
  171. }
  172. DCInvalidateRange(ipcland_base, ipcland_size);
  173. return req2->result;
  174. }
  175. ipc_int = IPC_ReadReg(1);
  176. if((ipc_int & 0x0022) == 0x0022) { // Okay, we got it!
  177. debug_printf("[ack]\n");
  178. IPC_WriteReg(1, (IPC_ReadReg(1) & 0x30) | 0x2);
  179. IPC_WriteReg(48 >> 2,0x40000000);
  180. }
  181. }
  182. }
  183. static u32 __CalcChecksum(u32 *buf, int len)
  184. {
  185. u32 sum = 0;
  186. int i;
  187. len = (len/4);
  188. for(i=1; i<len; i++)
  189. sum += buf[i];
  190. return sum;
  191. }
  192. static void __SetChecksum(void *buf, int len)
  193. {
  194. u32 *p = (u32*)buf;
  195. p[0] = __CalcChecksum(p, len);
  196. }
  197. void write_state_flags() {
  198. static char __stateflags[] ATTRIBUTE_ALIGN(32) = "/title/00000001/00000002/data/state.dat";
  199. struct _ipcreq *req = ios_alloc(sizeof(struct _ipcreq));
  200. memset(req, 0xee, sizeof(struct _ipcreq));
  201. req->cmd = 1; // open
  202. req->fd = 0;
  203. req->open.filepath = v2p(__stateflags);
  204. req->open.mode = 3;
  205. int fd = send_request(req);
  206. debug_printf("Flags FD: %d\n", fd);
  207. StateFlags *stateflags = (StateFlags *) ios_alloc(sizeof(StateFlags));
  208. req->cmd = 3; // read
  209. req->fd = fd;
  210. req->read.data = v2p(stateflags);
  211. req->read.len = sizeof(StateFlags);
  212. int res = send_request(req);
  213. debug_printf("Read:%d\n", res);
  214. if(res < 0) return;
  215. // Now modify
  216. stateflags->type = 3;//TYPE_RETURN;
  217. stateflags->returnto = 0;//RETURN_TO_MENU;
  218. __SetChecksum(stateflags, sizeof(StateFlags));
  219. debug_printf("OK...\n");
  220. req->cmd = 5; // seek
  221. req->fd = fd;
  222. req->seek.where = 0;
  223. req->seek.whence = 0;
  224. res = send_request(req);
  225. debug_printf("Seek:%d\n", res);
  226. if(res < 0) return;
  227. req->cmd = 4; // write
  228. req->fd = fd;
  229. req->write.data = v2p(stateflags);
  230. req->write.len = sizeof(StateFlags);
  231. res = send_request(req);
  232. debug_printf("Write:%d\n", res);
  233. if(res < 0) return;
  234. req->cmd = 2; // close
  235. req->fd = fd;
  236. res = send_request(req);
  237. debug_printf("Close:%d\n", res);
  238. return;
  239. }
  240. void do_something() {
  241. debug_printf("Hi!");
  242. init();
  243. debug_printf("!\n");
  244. struct _ipcreq *req = ios_alloc(sizeof(struct _ipcreq));
  245. debug_printf("(alloc req)\n");
  246. memset(req, 0xee, sizeof(struct _ipcreq));
  247. char *dev_es = ios_alloc(32);
  248. memset(dev_es, 0, 32);
  249. dev_es[0] = '/';
  250. dev_es[1] = 'd';
  251. dev_es[2] = 'e';
  252. dev_es[3] = 'v';
  253. dev_es[4] = '/';
  254. dev_es[5] = 'e';
  255. dev_es[6] = 's';
  256. debug_printf("(/dev/es)\n");
  257. ioctlv *argv = (ioctlv *) ios_alloc(40);
  258. u32 *numviews = (u32 *) ios_alloc(8); // 4
  259. *numviews = 0;
  260. u64 *titleid = (u64 *) ios_alloc(8);
  261. *titleid = 0x100000002LL;
  262. debug_printf("(set stuff)\n");
  263. req->cmd = 1; // open
  264. req->fd = 0;
  265. debug_printf("Taking the plunge...\n");
  266. req->open.filepath = v2p(dev_es);
  267. req->open.mode = 0;
  268. int fd = send_request(req);
  269. debug_printf("Result: %d\n", fd);
  270. if(fd < 0) return;
  271. write_state_flags();
  272. req->cmd = 7; // ioctlv
  273. req->fd = fd;
  274. req->ioctlv.ioctl = 0x12; // ES_GETVIEWCNT = 0x12
  275. req->ioctlv.argcin = 1;
  276. req->ioctlv.argcio = 1;
  277. req->ioctlv.argv = v2p(argv);
  278. argv[0].data = v2p(titleid);
  279. argv[0].len = 8;
  280. argv[1].data = v2p(numviews);
  281. argv[1].len = 4;
  282. debug_printf("argv:%x argv[0].data: %x\nargv[1].data: %x\n", req->ioctlv.argv, argv[0].data, argv[1].data);
  283. dump_mem(argv, 20);
  284. dump_mem(titleid, 8);
  285. int res = send_request(req);
  286. DCInvalidateRange(titleid, 8);
  287. DCInvalidateRange(numviews, 4);
  288. debug_printf("[NumViews] Result: %d (%ux)\n", res, res);
  289. if(res >= 0) {
  290. debug_printf("Num views: %x\n", *numviews);
  291. }
  292. // return;
  293. if(*numviews > 4) return;
  294. void *views = (void *) 0x90009000;
  295. req->cmd = 7; // ioctlv
  296. req->fd = fd;
  297. req->ioctlv.ioctl = 0x13; // ES_GETVIEWS
  298. req->ioctlv.argcin = 2;
  299. req->ioctlv.argcio = 1;
  300. req->ioctlv.argv = v2p(argv);
  301. argv[0].data = v2p(titleid);
  302. argv[0].len = 8;
  303. argv[1].data = v2p(numviews);
  304. argv[1].len = 4;
  305. argv[2].data = v2p(views);
  306. argv[2].len = sizeof(tikview) * (*numviews);
  307. res = send_request(req);
  308. debug_printf("[GetViews] Result: %d\n", res);
  309. // Now launch it!
  310. req->cmd = 7; // ioctlv
  311. req->fd = fd;
  312. req->ioctlv.ioctl = 0x8; // ES_LAUNCH
  313. req->ioctlv.argcin = 2;
  314. req->ioctlv.argcio = 0;
  315. req->ioctlv.argv = v2p(argv);
  316. req->relnch = 1; // RELNCH_RELAUNCH
  317. argv[0].data = v2p(titleid);
  318. argv[0].len = 8;
  319. argv[1].data = v2p(views);
  320. argv[1].len = sizeof(tikview);
  321. res = send_request(req);
  322. debug_printf("[Launch] Result: %d\n", res);
  323. }