ios.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. TinyLoad - a simple region free (original) game launcher in 4k
  3. # This code is licensed to you under the terms of the GNU GPL, version 2;
  4. # see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
  5. */
  6. /* This code comes from HBC's stub which was based on the Twilight Hack code */
  7. // Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
  8. // Copyright 2008-2009 Andre Heider <dhewg@wiibrew.org>
  9. // Copyright 2008-2009 Hector Martin <marcan@marcansoft.com>
  10. #include "ios.h"
  11. #include "cache.h"
  12. #include "utils.h"
  13. #define virt_to_phys(x) ((u32*)(((u32)(x))&0x3FFFFFFF))
  14. #define phys_to_virt(x) ((u32*)(((u32)(x))|0x80000000))
  15. // Low-level IPC access.
  16. static inline u32
  17. iread32(u32 addr)
  18. {
  19. u32 x;
  20. asm volatile("lwz %0,0(%1) ; sync ; isync" : "=r"(x) : "b"(0xc0000000 | addr));
  21. return x;
  22. }
  23. static inline void
  24. iwrite32(u32 addr, u32 x)
  25. {
  26. asm volatile("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr));
  27. }
  28. static u32 _ipc_read(u32 reg) __attribute__((noinline));
  29. static void _ipc_write(u32 reg, u32 value) __attribute__((noinline));
  30. static void ipc_bell(u32 w) __attribute__((noinline));
  31. // inline the 4*, don't inline the 0x0d0 stuff. yes, this saves a few bytes.
  32. static u32
  33. _ipc_read(u32 reg)
  34. {
  35. return iread32(0x0d000000 + reg);
  36. }
  37. static void
  38. _ipc_write(u32 reg, u32 value)
  39. {
  40. iwrite32(0x0d000000 + reg, value);
  41. }
  42. static inline u32
  43. ipc_read(u32 reg)
  44. {
  45. return _ipc_read(4*reg);
  46. }
  47. static inline void
  48. ipc_write(u32 reg, u32 value)
  49. {
  50. _ipc_write(4*reg, value);
  51. }
  52. static void
  53. ipc_bell(u32 w)
  54. {
  55. ipc_write(1, w);
  56. }
  57. static void ios_delay(void) __attribute__((noinline));
  58. static void
  59. ios_delay(void)
  60. {
  61. usleep(500);
  62. }
  63. static void
  64. ipc_wait_ack(void)
  65. {
  66. while(!(ipc_read(1) & 0x2))
  67. ;
  68. ios_delay();
  69. }
  70. static void
  71. ipc_wait_reply(void)
  72. {
  73. while(!(ipc_read(1) & 0x4))
  74. ;
  75. ios_delay();
  76. }
  77. static u32
  78. ipc_wait(void)
  79. {
  80. u32 ret;
  81. while(!((ret = ipc_read(1)) & 0x6))
  82. ;
  83. ios_delay();
  84. return ret;
  85. }
  86. // Mid-level IPC access.
  87. struct ipc {
  88. u32 cmd;
  89. int result;
  90. int fd;
  91. u32 arg[5];
  92. u32 user[8];
  93. };
  94. static struct ipc ipc ALIGNED(64);
  95. static void
  96. ipc_send_request(void)
  97. {
  98. sync_after_write(&ipc, 0x40);
  99. ipc_write(0, (u32)virt_to_phys(&ipc));
  100. ipc_bell(1);
  101. ipc_wait_ack();
  102. ipc_bell(2);
  103. }
  104. static int
  105. ipc_send_twoack(void)
  106. {
  107. sync_after_write(&ipc, 0x40);
  108. ios_delay();
  109. ipc_write(0, (u32)virt_to_phys(&ipc));
  110. ipc_bell(1);
  111. if(ipc_wait() & 4)
  112. return 0;
  113. ipc_bell(2);
  114. if(ipc_wait() & 4)
  115. return 0;
  116. ipc_bell(2);
  117. ipc_bell(8);
  118. return 1;
  119. }
  120. static void
  121. ipc_recv_reply(void)
  122. {
  123. for (;;)
  124. {
  125. u32 reply;
  126. ipc_wait_reply();
  127. reply = ipc_read(2);
  128. ipc_bell(4);
  129. ipc_bell(8);
  130. if (((u32*)reply) == virt_to_phys(&ipc))
  131. break;
  132. }
  133. sync_before_read(&ipc, 0x40);
  134. }
  135. // High-level IPC access.
  136. void
  137. ios_cleanup()
  138. {
  139. int loops = 0xA;
  140. do
  141. {
  142. if ((ipc_read(1) & 0x22) == 0x22)
  143. {
  144. ipc_write(1, (ipc_read(1)&~0x30) | 2);
  145. }
  146. if ((ipc_read(1) & 0x14) == 0x14)
  147. {
  148. ipc_read(2);
  149. ipc_write(1, (ipc_read(1)&~0x30) | 4);
  150. ipc_write(12, 0x4000);
  151. ipc_write(1, (ipc_read(1)&~0x30) | 8);
  152. }
  153. ipc_write(12, 0x4000);
  154. usleep(1000);
  155. loops--;
  156. } while(loops != 0);
  157. int fd;
  158. for (fd = 0; fd != 31; fd++)
  159. {
  160. ios_close(fd);
  161. }
  162. }
  163. int
  164. ios_open(const char *filename, u32 mode)
  165. {
  166. sync_after_write((void*)filename, 0x20);
  167. ipc.cmd = 1;
  168. ipc.fd = 0;
  169. ipc.arg[0] = (u32)virt_to_phys(filename);
  170. ipc.arg[1] = mode;
  171. ipc_send_request();
  172. ipc_recv_reply();
  173. return ipc.result;
  174. }
  175. int
  176. ios_close(int fd)
  177. {
  178. ipc.cmd = 2;
  179. ipc.fd = fd;
  180. ipc_send_request();
  181. ipc_recv_reply();
  182. return ipc.result;
  183. }
  184. static void
  185. ios_std(int fd, int cmd)
  186. {
  187. ipc.cmd = cmd;
  188. ipc.fd = fd;
  189. ipc_send_request();
  190. ipc_recv_reply();
  191. }
  192. int
  193. ios_read(int fd, void *buf, u32 size)
  194. {
  195. ipc.arg[0] = (u32)virt_to_phys(buf);
  196. ipc.arg[1] = size;
  197. ios_std(fd, 3);
  198. sync_before_read(buf, size);
  199. return ipc.result;
  200. }
  201. int
  202. _ios_ioctlv(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec, int reboot)
  203. {
  204. u32 i;
  205. for (i = 0; i < in_count + out_count; i++)
  206. {
  207. if (vec[i].data)
  208. {
  209. sync_after_write(vec[i].data, vec[i].len);
  210. vec[i].data = (void *)virt_to_phys(vec[i].data);
  211. }
  212. }
  213. sync_after_write(vec, (in_count + out_count) * sizeof *vec);
  214. ipc.cmd = 7;
  215. ipc.fd = fd;
  216. ipc.arg[0] = n;
  217. ipc.arg[1] = in_count;
  218. ipc.arg[2] = out_count;
  219. ipc.arg[3] = (u32)virt_to_phys(vec);
  220. if(reboot)
  221. {
  222. if(ipc_send_twoack())
  223. return 0;
  224. }
  225. else
  226. ipc_send_request();
  227. ipc_recv_reply();
  228. for(i = in_count; i < in_count + out_count; i++)
  229. {
  230. if (vec[i].data)
  231. {
  232. vec[i].data = phys_to_virt((u32)vec[i].data);
  233. sync_before_read(vec[i].data, vec[i].len);
  234. }
  235. }
  236. if(reboot && (ipc.result >= 0))
  237. return -100;
  238. return ipc.result;
  239. }
  240. int
  241. ios_ioctlv(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec)
  242. {
  243. return _ios_ioctlv(fd, n, in_count, out_count, vec, 0);
  244. }
  245. int
  246. ios_ioctlvreboot(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec)
  247. {
  248. return _ios_ioctlv(fd, n, in_count, out_count, vec, 1);
  249. }