PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/modules/hdd/hdldsvr/hdldsvr.c

https://bitbucket.org/ifcaro/open-ps2-loader/
C | 501 lines | 323 code | 113 blank | 65 comment | 49 complexity | ad455dc057b219048e6ae576bd2d6c37 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, MPL-2.0-no-copyleft-exception, GPL-2.0
  1. /*
  2. Copyright 2010, jimmikaelkael
  3. Licenced under Academic Free License version 3.0
  4. Review OpenUsbLd README & LICENSE files for further details.
  5. */
  6. #include <loadcore.h>
  7. #include <stdio.h>
  8. #include <iomanX.h>
  9. #include <ps2ip.h>
  10. #include <sysclib.h>
  11. #include <thbase.h>
  12. #include <thsemap.h>
  13. #include <errno.h>
  14. #include "smsutils.h"
  15. //#define FAKE_WRITES
  16. #define MODNAME "hdldsvr"
  17. IRX_ID(MODNAME, 1, 1);
  18. struct irx_export_table _exp_hdldsvr;
  19. #define TCP_SERVER_PORT 45233
  20. #define UDP_SERVER_PORT 45233
  21. #define CMD_SIZE 16
  22. #define CMD_STAT 0x73746174 // 'stat'; get HDD size in KB
  23. #define CMD_READ 0x72656164 // 'read'; read sectors from HDD
  24. #define CMD_WRIT 0x77726974 // 'writ'; write sectors to HDD
  25. #define CMD_WRIS 0x77726973 // 'wris'; get last write status
  26. #define CMD_FLSH 0x666c7368 // 'flsh'; flush write buff
  27. #define CMD_POWX 0x706f7778 // 'powx'; poweroff system
  28. #define HDD_SECTOR_SIZE 512 // HDD sector size in bytes
  29. #define NET_NUM_SECTORS 2048 // max # of sectors to move via network
  30. #define STATUS_AVAIL 0 // expecting command
  31. #define STATUS_BUSY_RESPOND 1 // sending back response (and readen data)
  32. #define STATUS_BUSY_WRITE 2 // expecting write data
  33. #define STATUS_WRITE_STAT 3 // sending back write stat response
  34. #define SETBIT(mask, bit) (mask)[(bit) / 32] |= 1 << ((bit) % 32)
  35. #define GETBIT(mask, bit) ((mask)[(bit) / 32] & (1 << ((bit) % 32)))
  36. #define APA_DEVCTL_MAX_SECTORS 0x00004801 // max partition size(in sectors)
  37. #define APA_DEVCTL_TOTAL_SECTORS 0x00004802
  38. #define APA_DEVCTL_IDLE 0x00004803
  39. #define APA_DEVCTL_FLUSH_CACHE 0x00004804
  40. #define APA_DEVCTL_SWAP_TMP 0x00004805
  41. #define APA_DEVCTL_DEV9_SHUTDOWN 0x00004806
  42. #define APA_DEVCTL_STATUS 0x00004807
  43. #define APA_DEVCTL_FORMAT 0x00004808
  44. #define APA_DEVCTL_SMART_STAT 0x00004809
  45. #define APA_DEVCTL_GETTIME 0x00006832
  46. #define APA_DEVCTL_SET_OSDMBR 0x00006833 // arg = hddSetOsdMBR_t
  47. #define APA_DEVCTL_GET_SECTOR_ERROR 0x00006834
  48. #define APA_DEVCTL_GET_ERROR_PART_NAME 0x00006835 // bufp = namebuffer[0x20]
  49. #define APA_DEVCTL_ATA_READ 0x00006836 // arg = hddAtaTransfer_t
  50. #define APA_DEVCTL_ATA_WRITE 0x00006837 // arg = hddAtaTransfer_t
  51. #define APA_DEVCTL_SCE_IDENTIFY_DRIVE 0x00006838 // bufp = buffer for atadSceIdentifyDrive
  52. #define APA_DEVCTL_IS_48BIT 0x00006840
  53. #define APA_DEVCTL_SET_TRANSFER_MODE 0x00006841
  54. #define APA_DEVCTL_ATA_IOP_WRITE 0x00006842
  55. void tcp_server_thread(void *args);
  56. void udp_server_thread(void *args);
  57. static int tcp_server_tid, udp_server_tid;
  58. static int udp_mutex = -1;
  59. static u8 tcp_buf[CMD_SIZE + HDD_SECTOR_SIZE*2] __attribute__((aligned(64)));
  60. static u8 udp_buf[8 + HDD_SECTOR_SIZE*2] __attribute__((aligned(64)));
  61. struct tcp_packet_header {
  62. u32 command;
  63. u32 start_sector;
  64. u32 num_sectors;
  65. u32 result;
  66. } __attribute__((packed));
  67. typedef struct {
  68. struct tcp_packet_header hdr;
  69. u8 data[HDD_SECTOR_SIZE*2];
  70. } tcp_packet_t __attribute__((packed));
  71. typedef struct {
  72. u8 data[HDD_SECTOR_SIZE * 2];
  73. u32 command;
  74. u32 start_sector;
  75. } udp_packet_t __attribute__((packed));
  76. struct stats {
  77. int status;
  78. u32 command;
  79. u32 start_sector;
  80. u32 num_sectors;
  81. u8 *data;
  82. u32 bitmask[(NET_NUM_SECTORS + 31) / 32];
  83. u32 bitmask_copy[(NET_NUM_SECTORS + 31) / 32]; // endian-neutral
  84. u8 buffer[HDD_SECTOR_SIZE * (NET_NUM_SECTORS + 1)]; // 1MB on IOP !!! Huge !
  85. };
  86. static struct stats gstats __attribute__((aligned(64)));
  87. //-------------------------------------------------------------------------
  88. int _start(int argc, char** argv)
  89. {
  90. iop_thread_t thread_param;
  91. // register exports
  92. RegisterLibraryEntries(&_exp_hdldsvr);
  93. // create a locked udp mutex
  94. udp_mutex = CreateMutex(IOP_MUTEX_LOCKED);
  95. // create & start the tcp thread
  96. thread_param.attr = TH_C;
  97. thread_param.thread = (void *)tcp_server_thread;
  98. thread_param.priority = 0x64;
  99. thread_param.stacksize = 0x1000;
  100. thread_param.option = 0;
  101. tcp_server_tid = CreateThread(&thread_param);
  102. StartThread(tcp_server_tid, 0);
  103. // create & start the udp thread
  104. thread_param.attr = TH_C;
  105. thread_param.thread = (void *)udp_server_thread;
  106. thread_param.priority = 0x64;
  107. thread_param.stacksize = 0x1000;
  108. thread_param.option = 0;
  109. udp_server_tid = CreateThread(&thread_param);
  110. StartThread(udp_server_tid, 0);
  111. return MODULE_RESIDENT_END;
  112. }
  113. //-------------------------------------------------------------------------
  114. int _shutdown(void)
  115. {
  116. // delete threads
  117. DeleteThread(tcp_server_tid);
  118. DeleteThread(udp_server_tid);
  119. // delete udp mutex
  120. DeleteSema(udp_mutex);
  121. return 0;
  122. }
  123. //-------------------------------------------------------------------------
  124. static int ack_tcp_command(int sock, void *buf, int bsize)
  125. {
  126. register int r;
  127. // acknowledge a received command
  128. gstats.status = STATUS_BUSY_RESPOND;
  129. r = lwip_send(sock, buf, bsize, 0);
  130. gstats.status = STATUS_AVAIL;
  131. return r;
  132. }
  133. //-------------------------------------------------------------------------
  134. static void reject_tcp_command(int sock, char *error_string)
  135. {
  136. // reject a received command
  137. gstats.status = STATUS_BUSY_RESPOND;
  138. lwip_send(sock, error_string, strlen(error_string), 0);
  139. gstats.status = STATUS_AVAIL;
  140. devctl("hdd0:", APA_DEVCTL_FLUSH_CACHE, NULL, 0, NULL, 0);
  141. }
  142. //-------------------------------------------------------------------------
  143. static int check_datas(u32 command, u32 start_sector, u32 num_sectors)
  144. {
  145. // check if all write data is here
  146. register int i, got_all_datas = 1;
  147. // wait that udp mutex is unlocked
  148. WaitSema(udp_mutex);
  149. for (i=0; i<num_sectors; ++i) {
  150. if (!GETBIT(gstats.bitmask, i)) {
  151. got_all_datas = 0;
  152. break;
  153. }
  154. }
  155. if (!got_all_datas) // some parts are missing; should ask for retransmit
  156. return -1;
  157. // all data here -- we can commit
  158. gstats.command = command;
  159. return 0;
  160. }
  161. //-------------------------------------------------------------------------
  162. static int handle_tcp_client(int tcp_client_socket)
  163. {
  164. register int r, i, size;
  165. u8 args[16];
  166. tcp_packet_t *pkt = (tcp_packet_t *)tcp_buf;
  167. while (1) {
  168. // receive incoming packets
  169. size = lwip_recv(tcp_client_socket, &tcp_buf[0], sizeof(tcp_buf), 0);
  170. if (size < 0)
  171. goto error;
  172. // check if valid command size
  173. if (size != CMD_SIZE) {
  174. reject_tcp_command(tcp_client_socket, "handle_recv: invalid packet received");
  175. goto error;
  176. }
  177. // don't accept 'wris' without previous 'writ'
  178. if ((gstats.status == STATUS_AVAIL) && (pkt->hdr.command == CMD_WRIS)) {
  179. reject_tcp_command(tcp_client_socket, "write stat denied");
  180. goto error;
  181. }
  182. else if ((!(gstats.status == STATUS_BUSY_WRITE) && (pkt->hdr.command == CMD_WRIS))) {
  183. reject_tcp_command(tcp_client_socket, "busy");
  184. goto error;
  185. }
  186. switch (pkt->hdr.command) {
  187. // ------------------------------------------------
  188. // 'writ' command
  189. // ------------------------------------------------
  190. case CMD_WRIT:
  191. // confirm write
  192. pkt->hdr.result = 0;
  193. r = ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header));
  194. if (r < 0) {
  195. reject_tcp_command(tcp_client_socket, "init_write b0rked");
  196. goto error;
  197. }
  198. gstats.status = STATUS_BUSY_WRITE;
  199. gstats.command = pkt->hdr.command;
  200. gstats.start_sector = pkt->hdr.start_sector;
  201. gstats.num_sectors = pkt->hdr.num_sectors;
  202. // set-up buffer and clear bitmask
  203. gstats.data = (u8*)(((long)&gstats.buffer[HDD_SECTOR_SIZE - 1]) & ~(HDD_SECTOR_SIZE - 1));
  204. mips_memset (gstats.bitmask, 0, sizeof (gstats.bitmask));
  205. break;
  206. // ------------------------------------------------
  207. // 'wris' command
  208. // ------------------------------------------------
  209. case CMD_WRIS:
  210. if ((pkt->hdr.start_sector != gstats.start_sector) || (pkt->hdr.num_sectors != gstats.num_sectors)) {
  211. reject_tcp_command(tcp_client_socket, "invalid write stat");
  212. goto error;
  213. }
  214. r = check_datas(pkt->hdr.command, pkt->hdr.start_sector, pkt->hdr.num_sectors);
  215. if (r < 0) {
  216. // means we need retransmission of some datas so we send bitmask stats to the client
  217. u32 *out = gstats.bitmask_copy;
  218. for (i=0; i<(NET_NUM_SECTORS+31)/32; ++i)
  219. out[i] = gstats.bitmask[i];
  220. mips_memcpy(pkt->data, (void *)out, sizeof(gstats.bitmask_copy));
  221. pkt->hdr.result = 0;
  222. r = ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header)+sizeof(gstats.bitmask));
  223. if (r < 0) {
  224. reject_tcp_command(tcp_client_socket, "init_write_stat failed");
  225. goto error;
  226. }
  227. gstats.status = STATUS_BUSY_WRITE;
  228. }
  229. else {
  230. pkt->hdr.result = pkt->hdr.num_sectors;
  231. #ifdef FAKE_WRITES
  232. // fake write, we read instead
  233. *(u32 *)&args[0] = pkt->hdr.start_sector;
  234. *(u32 *)&args[4] = pkt->hdr.num_sectors;
  235. devctl("hdd0:", APA_DEVCTL_ATA_READ, args, 8, gstats.data, pkt->hdr.num_sectors*HDD_SECTOR_SIZE);
  236. #else
  237. // !!! real writes !!!
  238. *(u32 *)&args[0] = pkt->hdr.start_sector;
  239. *(u32 *)&args[4] = pkt->hdr.num_sectors;
  240. *(u32 *)&args[8] = (u32)gstats.data;
  241. devctl("hdd0:", APA_DEVCTL_ATA_IOP_WRITE, args, 8+(pkt->hdr.num_sectors*HDD_SECTOR_SIZE), NULL, 0);
  242. #endif
  243. ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header));
  244. }
  245. break;
  246. // ------------------------------------------------
  247. // 'stat' command
  248. // ------------------------------------------------
  249. case CMD_STAT:
  250. r = devctl("hdd0:", APA_DEVCTL_TOTAL_SECTORS, NULL, 0, NULL, 0);
  251. if (r < 0)
  252. pkt->hdr.result = -1;
  253. else
  254. pkt->hdr.result = r >> 1;
  255. ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header));
  256. break;
  257. // ------------------------------------------------
  258. // 'read' command
  259. // ------------------------------------------------
  260. case CMD_READ:
  261. // set up buffer
  262. gstats.data = (u8 *)(((long)&gstats.buffer + HDD_SECTOR_SIZE - 1) & ~(HDD_SECTOR_SIZE - 1));
  263. *(u32 *)&args[0] = pkt->hdr.start_sector;
  264. *(u32 *)&args[4] = pkt->hdr.num_sectors;
  265. if (pkt->hdr.num_sectors > 2) {
  266. r = devctl("hdd0:", APA_DEVCTL_ATA_READ, args, 8, gstats.data, pkt->hdr.num_sectors*HDD_SECTOR_SIZE);
  267. if (r < 0)
  268. pkt->hdr.result = -1;
  269. else
  270. pkt->hdr.result = pkt->hdr.num_sectors;
  271. ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header));
  272. if (r == 0)
  273. ack_tcp_command(tcp_client_socket, gstats.data, pkt->hdr.num_sectors*HDD_SECTOR_SIZE);
  274. }
  275. else {
  276. r = devctl("hdd0:", APA_DEVCTL_ATA_READ, args, 8, pkt->data, pkt->hdr.num_sectors*HDD_SECTOR_SIZE);
  277. if (r < 0)
  278. pkt->hdr.result = -1;
  279. else
  280. pkt->hdr.result = pkt->hdr.num_sectors;
  281. ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(tcp_packet_t));
  282. }
  283. break;
  284. // ------------------------------------------------
  285. // 'flsh' command
  286. // ------------------------------------------------
  287. case CMD_FLSH:
  288. devctl("hdd0:", APA_DEVCTL_FLUSH_CACHE, NULL, 0, NULL, 0);
  289. break;
  290. // ------------------------------------------------
  291. // 'powx' command
  292. // ------------------------------------------------
  293. case CMD_POWX:
  294. devctl("hdd0:", APA_DEVCTL_FLUSH_CACHE, NULL, 0, NULL, 0);
  295. devctl("hdd0:", APA_DEVCTL_DEV9_SHUTDOWN, NULL, 0, NULL, 0);
  296. *((volatile u8 *)0xbf402017) = 0x00;
  297. *((volatile u8 *)0xbf402016) = 0x0f;
  298. break;
  299. default:
  300. reject_tcp_command(tcp_client_socket, "handle_recv: unknown command");
  301. goto error;
  302. }
  303. }
  304. return 0;
  305. error:
  306. return -1;
  307. }
  308. //-------------------------------------------------------------------------
  309. void tcp_server_thread(void *args)
  310. {
  311. int tcp_socket, client_socket = -1;
  312. struct sockaddr_in peer;
  313. int peerlen;
  314. register int r;
  315. while (1) {
  316. peer.sin_family = AF_INET;
  317. peer.sin_port = htons(TCP_SERVER_PORT);
  318. peer.sin_addr.s_addr = htonl(INADDR_ANY);
  319. // create the socket
  320. tcp_socket = lwip_socket(AF_INET, SOCK_STREAM, 0);
  321. if (tcp_socket < 0)
  322. goto error;
  323. // bind the socket
  324. r = lwip_bind(tcp_socket, (struct sockaddr *)&peer, sizeof(peer));
  325. if (r < 0)
  326. goto error;
  327. // we want to listen
  328. r = lwip_listen(tcp_socket, 3);
  329. if (r < 0)
  330. goto error;
  331. while(1) {
  332. peerlen = sizeof(peer);
  333. // wait for incoming connection
  334. client_socket = lwip_accept(tcp_socket, (struct sockaddr *)&peer, &peerlen);
  335. if (client_socket < 0)
  336. goto error;
  337. // got connection, handle the client
  338. r = handle_tcp_client(client_socket);
  339. if (r < 0)
  340. lwip_close(client_socket);
  341. }
  342. error:
  343. // close the socket
  344. lwip_close(tcp_socket);
  345. }
  346. }
  347. //-------------------------------------------------------------------------
  348. void udp_server_thread(void *args)
  349. {
  350. int udp_socket;
  351. struct sockaddr_in peer;
  352. register int r;
  353. udp_packet_t *pkt = (udp_packet_t *)udp_buf;
  354. while (1) {
  355. peer.sin_family = AF_INET;
  356. peer.sin_port = htons(UDP_SERVER_PORT);
  357. peer.sin_addr.s_addr = htonl(INADDR_ANY);
  358. // create the socket
  359. udp_socket = lwip_socket(AF_INET, SOCK_DGRAM, 0);
  360. if (udp_socket < 0)
  361. goto error;
  362. // bind the socket
  363. r = lwip_bind(udp_socket, (struct sockaddr *)&peer, sizeof(peer));
  364. if (r < 0)
  365. goto error;
  366. while(1) {
  367. // wait for packet
  368. r = lwip_recv(udp_socket, udp_buf, sizeof(udp_buf), 0);
  369. // check to see if it's the command we're expecting
  370. if ((r == sizeof (udp_packet_t)) && (pkt->command == gstats.command)) {
  371. // check the start sector is valid
  372. if ((gstats.start_sector <= pkt->start_sector) && (pkt->start_sector < gstats.start_sector + gstats.num_sectors)) {
  373. u32 start_sector = pkt->start_sector - gstats.start_sector;
  374. if (!GETBIT(gstats.bitmask, start_sector)) {
  375. mips_memcpy(gstats.data + start_sector*HDD_SECTOR_SIZE, pkt, HDD_SECTOR_SIZE*2);
  376. SETBIT(gstats.bitmask, start_sector);
  377. SETBIT(gstats.bitmask, start_sector + 1);
  378. // unlock udp mutex
  379. SignalSema(udp_mutex);
  380. }
  381. }
  382. }
  383. }
  384. error:
  385. // close the socket
  386. lwip_close(udp_socket);
  387. }
  388. }