ios.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * Copyright (C) 2008 segher, #wiidev efnet
  3. * Copyright (C) 2008 bushing, #wiidev efnet
  4. * Copyright (C) 2008 dhewg, #wiidev efnet
  5. * Copyright (C) 2008 marcan, #wiidev efnet
  6. *
  7. * this file is part of the Homebrew Channel
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22. */
  23. #include "stub_debug.h"
  24. #include "ios.h"
  25. #include "processor.h"
  26. #include "cache.h"
  27. #include "system.h"
  28. #define virt_to_phys(x) ((u32*)(((u32)(x))&0x7FFFFFFF))
  29. #define phys_to_virt(x) ((u32*)(((u32)(x))|0x80000000))
  30. // Timebase frequency is core frequency / 8. Ignore roundoff, this
  31. // doesn't have to be very accurate.
  32. #define TICKS_PER_USEC (729/8)
  33. static u32 mftb(void)
  34. {
  35. u32 x;
  36. asm volatile("mftb %0" : "=r"(x));
  37. return x;
  38. }
  39. static void __delay(u32 ticks)
  40. {
  41. u32 start = mftb();
  42. while (mftb() - start < ticks)
  43. ;
  44. }
  45. void udelay(u32 us)
  46. {
  47. __delay(TICKS_PER_USEC * us);
  48. }
  49. // Low-level IPC access.
  50. static inline u32 read32(u32 addr)
  51. {
  52. u32 x;
  53. asm volatile("lwz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr));
  54. return x;
  55. }
  56. static inline void write32(u32 addr, u32 x)
  57. {
  58. asm volatile("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr));
  59. }
  60. static u32 ipc_read(u32 reg) {
  61. return read32(0x0d000000 + 4*reg);
  62. }
  63. static void ipc_write(u32 reg, u32 value) {
  64. write32(0x0d000000 + 4*reg, value);
  65. }
  66. static void ipc_bell(u32 w)
  67. {
  68. ipc_write(1, (ipc_read(1) & 0x30) | w);
  69. }
  70. static void ipc_wait_ack(void)
  71. {
  72. while ((ipc_read(1) & 0x22) != 0x22)
  73. ;
  74. udelay(100);
  75. }
  76. static void ipc_wait_reply(void)
  77. {
  78. while ((ipc_read(1) & 0x14) != 0x14)
  79. ;
  80. udelay(100);
  81. }
  82. static void ipc_irq_ack(void)
  83. {
  84. ipc_write(12, 0x40000000);
  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 __attribute__((aligned(64)));
  95. static void ipc_send_request(void)
  96. {
  97. DCFlushRange(&ipc, 0x40);
  98. ipc_write(0, (u32)virt_to_phys(&ipc));
  99. ipc_bell(1);
  100. ipc_wait_ack();
  101. ipc_bell(2);
  102. ipc_irq_ack();
  103. }
  104. void ipc_send_twoack(void)
  105. {
  106. DCFlushRange(&ipc, 0x40);
  107. ipc_write(0, (u32)virt_to_phys(&ipc));
  108. ipc_bell(1);
  109. ipc_wait_ack();
  110. ipc_irq_ack();
  111. ipc_bell(2);
  112. ipc_wait_ack();
  113. ipc_irq_ack();
  114. ipc_bell(2);
  115. ipc_bell(8);
  116. }
  117. static void ipc_recv_reply(void)
  118. {
  119. for (;;) {
  120. u32 reply;
  121. ipc_wait_reply();
  122. reply = ipc_read(2);
  123. ipc_bell(4);
  124. ipc_irq_ack();
  125. ipc_bell(8);
  126. if (((u32*)reply) == virt_to_phys(&ipc))
  127. break;
  128. debug_string("Ignoring unexpected IPC reply @");
  129. debug_uint((u32)reply);
  130. debug_string("\n\r");
  131. }
  132. DCInvalidateRange(&ipc, sizeof ipc);
  133. }
  134. // High-level IPC access.
  135. int ios_open(const char *filename, u32 mode)
  136. {
  137. DCFlushRange((void*)filename, strlen(filename) + 1);
  138. memset(&ipc, 0, sizeof ipc);
  139. ipc.cmd = 1;
  140. ipc.fd = 0;
  141. ipc.arg[0] = (u32)virt_to_phys(filename);
  142. ipc.arg[1] = mode;
  143. ipc_send_request();
  144. ipc_recv_reply();
  145. return ipc.result;
  146. }
  147. int ios_close(int fd)
  148. {
  149. memset(&ipc, 0, sizeof ipc);
  150. ipc.cmd = 2;
  151. ipc.fd = fd;
  152. ipc_send_request();
  153. ipc_recv_reply();
  154. return ipc.result;
  155. }
  156. int _ios_ioctlv(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec, int reboot)
  157. {
  158. u32 i;
  159. memset(&ipc, 0, sizeof ipc);
  160. for (i = 0; i < in_count + out_count; i++)
  161. if (vec[i].data) {
  162. DCFlushRange(vec[i].data, vec[i].len);
  163. vec[i].data = (void *)virt_to_phys(vec[i].data);
  164. }
  165. DCFlushRange(vec, (in_count + out_count) * sizeof *vec);
  166. ipc.cmd = 7;
  167. ipc.fd = fd;
  168. ipc.arg[0] = n;
  169. ipc.arg[1] = in_count;
  170. ipc.arg[2] = out_count;
  171. ipc.arg[3] = (u32)virt_to_phys(vec);
  172. if(reboot) {
  173. ipc_send_twoack();
  174. return 0;
  175. } else {
  176. ipc_send_request();
  177. ipc_recv_reply();
  178. for (i = in_count; i < in_count + out_count; i++)
  179. if (vec[i].data) {
  180. vec[i].data = phys_to_virt((u32)vec[i].data);
  181. DCInvalidateRange(vec[i].data, vec[i].len);
  182. }
  183. return ipc.result;
  184. }
  185. }
  186. int ios_ioctlv(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec) {
  187. return _ios_ioctlv(fd, n, in_count, out_count, vec, 0);
  188. }
  189. int ios_ioctlvreboot(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec) {
  190. return _ios_ioctlv(fd, n, in_count, out_count, vec, 1);
  191. }
  192. // Cleanup any old state.
  193. static void ipc_cleanup_reply(void) {
  194. if ((ipc_read(1) & 0x14) != 0x14)
  195. return;
  196. ipc_read(2);
  197. ipc_bell(4);
  198. ipc_irq_ack();
  199. ipc_bell(8);
  200. }
  201. static void ipc_cleanup_request(void) {
  202. if ((ipc_read(1) & 0x22) == 0x22)
  203. ipc_bell(2);
  204. }
  205. void reset_ios(void) {
  206. int i;
  207. debug_string("Flushing IPC transactions");
  208. for (i = 0; i < 10; i++) {
  209. ipc_cleanup_request();
  210. ipc_cleanup_reply();
  211. ipc_irq_ack();
  212. udelay(1000);
  213. debug_string(".");
  214. }
  215. debug_string(" Done.\n\r");
  216. debug_string("Closing file descriptors");
  217. for (i = 0; i < 32; i++) {
  218. ios_close(i);
  219. debug_string(".");
  220. }
  221. debug_string(" Done.\n\r");
  222. }