don't do a DVD_Mount for GC-mode on Wii, add ifdef for Wii-only SMB code
[libogc.git] / libogc / es.c
blobae8775b7f1408b4f00431e093a30e01e2fa1b3bc
1 /*-------------------------------------------------------------
3 es.c -- ETicket services
5 Copyright (C) 2008
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
8 Hector Martin (marcan)
10 This software is provided 'as-is', without any express or implied
11 warranty. In no event will the authors be held liable for any
12 damages arising from the use of this software.
14 Permission is granted to anyone to use this software for any
15 purpose, including commercial applications, and to alter it and
16 redistribute it freely, subject to the following restrictions:
18 1. The origin of this software must not be misrepresented; you
19 must not claim that you wrote the original software. If you use
20 this software in a product, an acknowledgment in the product
21 documentation would be appreciated but is not required.
23 2. Altered source versions must be plainly marked as such, and
24 must not be misrepresented as being the original software.
26 3. This notice may not be removed or altered from any source
27 distribution.
29 -------------------------------------------------------------*/
31 #if defined(HW_RVL)
33 #include <sys/iosupport.h>
34 #include <sys/fcntl.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <malloc.h>
39 #include <sys/errno.h>
40 #include "ipc.h"
41 #include "asm.h"
42 #include "processor.h"
43 #include "mutex.h"
44 #include "es.h"
46 //#define DEBUG_ES
48 #define IOCTL_ES_ADDTICKET 0x01
49 #define IOCTL_ES_ADDTITLESTART 0x02
50 #define IOCTL_ES_ADDCONTENTSTART 0x03
51 #define IOCTL_ES_ADDCONTENTDATA 0x04
52 #define IOCTL_ES_ADDCONTENTFINISH 0x05
53 #define IOCTL_ES_ADDTITLEFINISH 0x06
54 #define IOCTL_ES_GETDEVICEID 0x07
55 #define IOCTL_ES_LAUNCH 0x08
56 #define IOCTL_ES_OPENCONTENT 0x09
57 #define IOCTL_ES_READCONTENT 0x0A
58 #define IOCTL_ES_CLOSECONTENT 0x0B
59 #define IOCTL_ES_GETOWNEDTITLECNT 0x0C
60 #define IOCTL_ES_GETOWNEDTITLES 0x0D
61 #define IOCTL_ES_GETTITLECNT 0x0E
62 #define IOCTL_ES_GETTITLES 0x0F
63 #define IOCTL_ES_GETTITLECONTENTSCNT 0x10
64 #define IOCTL_ES_GETTITLECONTENTS 0x11
65 #define IOCTL_ES_GETVIEWCNT 0x12
66 #define IOCTL_ES_GETVIEWS 0x13
67 #define IOCTL_ES_GETTMDVIEWCNT 0x14
68 #define IOCTL_ES_GETTMDVIEWS 0x15
69 //#define IOCTL_ES_GETCONSUMPTION 0x16
70 #define IOCTL_ES_DELETETITLE 0x17
71 #define IOCTL_ES_DELETETICKET 0x18
72 //#define IOCTL_ES_DIGETTMDVIEWSIZE 0x19
73 //#define IOCTL_ES_DIGETTMDVIEW 0x1A
74 //#define IOCTL_ES_DIGETTICKETVIEW 0x1B
75 #define IOCTL_ES_DIVERIFY 0x1C
76 #define IOCTL_ES_GETTITLEDIR 0x1D
77 #define IOCTL_ES_GETDEVICECERT 0x1E
78 #define IOCTL_ES_IMPORTBOOT 0x1F
79 #define IOCTL_ES_GETTITLEID 0x20
80 #define IOCTL_ES_SETUID 0x21
81 #define IOCTL_ES_DELETETITLECONTENT 0x22
82 #define IOCTL_ES_SEEKCONTENT 0x23
83 #define IOCTL_ES_OPENTITLECONTENT 0x24
84 //#define IOCTL_ES_LAUNCHBC 0x25
85 //#define IOCTL_ES_EXPORTTITLEINIT 0x26
86 //#define IOCTL_ES_EXPORTCONTENTBEGIN 0x27
87 //#define IOCTL_ES_EXPORTCONTENTDATA 0x28
88 //#define IOCTL_ES_EXPORTCONTENTEND 0x29
89 //#define IOCTL_ES_EXPORTTITLEDONE 0x2A
90 #define IOCTL_ES_ADDTMD 0x2B
91 #define IOCTL_ES_ENCRYPT 0x2C
92 #define IOCTL_ES_DECRYPT 0x2D
93 #define IOCTL_ES_GETBOOT2VERSION 0x2E
94 #define IOCTL_ES_ADDTITLECANCEL 0x2F
95 #define IOCTL_ES_SIGN 0x30
96 //#define IOCTL_ES_VERIFYSIGN 0x31
97 #define IOCTL_ES_GETSTOREDCONTENTCNT 0x32
98 #define IOCTL_ES_GETSTOREDCONTENTS 0x33
99 #define IOCTL_ES_GETSTOREDTMDSIZE 0x34
100 #define IOCTL_ES_GETSTOREDTMD 0x35
101 #define IOCTL_ES_GETSHAREDCONTENTCNT 0x36
102 #define IOCTL_ES_GETSHAREDCONTENTS 0x37
105 #define ES_HEAP_SIZE 0x800
107 #define ISALIGNED(x) ((((u32)x)&0x1F)==0)
109 static char __es_fs[] ATTRIBUTE_ALIGN(32) = "/dev/es";
111 static s32 __es_fd = -1;
112 static s32 __es_hid = -1;
114 static void __ES_InitFS(void);
115 static void __ES_DeinitFS(void);
117 s32 __ES_Init(void)
119 s32 ret = 0;
121 #ifdef DEBUG_ES
122 printf("ES Init\n");
123 #endif
125 if(__es_hid <0 ) {
126 __es_hid = iosCreateHeap(ES_HEAP_SIZE);
127 if(__es_hid < 0) return __es_hid;
130 ret = IOS_Open(__es_fs,0);
131 if(ret<0) return ret;
132 __es_fd = ret;
134 #ifdef DEBUG_ES
135 printf("ES FD %d\n",__es_fd);
136 #endif
138 __ES_InitFS();
140 return 0;
143 s32 __ES_Close(void)
145 s32 ret;
147 if(__es_fd < 0) return 0;
149 __ES_DeinitFS();
151 ret = IOS_Close(__es_fd);
153 // If close fails, I'd rather return error but still reset the fd.
154 // Otherwise you're stuck with an uncloseable ES, and you can't open again either
155 //if(ret<0) return ret;
156 if(ret<0) {
157 __es_fd = -1;
158 return ret;
161 __es_fd = -1;
162 return 0;
165 // Used by ios.c after reloading IOS
166 s32 __ES_Reset(void)
168 __es_fd = -1;
169 return 0;
172 s32 ES_GetTitleID(u64 *titleID)
174 s32 ret;
175 u64 title;
177 if(__es_fd<0) return ES_ENOTINIT;
178 if(!titleID) return ES_EINVAL;
180 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLEID,":q",&title);
181 if(ret<0) return ret;
183 *titleID = title;
184 return ret;
187 s32 ES_SetUID(u64 uid)
189 if(__es_fd<0) return ES_ENOTINIT;
191 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_SETUID,"q:",uid);
194 s32 ES_GetDataDir(u64 titleID,char *filepath)
196 s32 ret;
198 if(__es_fd<0) return ES_ENOTINIT;
199 if(!filepath) return ES_EINVAL;
200 if(!ISALIGNED(filepath)) return ES_EALIGN;
202 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLEDIR,"q:d",titleID,filepath,30);
204 return ret;
207 s32 ES_LaunchTitle(u64 titleID, const tikview *view)
210 s32 res;
211 STACK_ALIGN(u64,title,1,32);
212 STACK_ALIGN(ioctlv,vectors,2,32);
214 if(__es_fd<0) return ES_ENOTINIT;
215 if(!view) return ES_EINVAL;
216 if(!ISALIGNED(view)) return ES_EALIGN;
218 #ifdef DEBUG_ES
219 printf("ES LaunchTitle %d %016llx 0x%08x 0x%02x\n",__es_fd,titleID,(u32)view,sizeof(tikview));
220 #endif
223 *title = titleID;
224 vectors[0].data = (void*)title;
225 vectors[0].len = sizeof(u64);
226 vectors[1].data = (void*)view;
227 vectors[1].len = sizeof(tikview);
228 res = IOS_IoctlvReboot(__es_fd,IOCTL_ES_LAUNCH,2,0,vectors);
230 #ifdef DEBUG_ES
231 printf(" =%d\n",res);
232 #endif
234 return res;
237 s32 ES_LaunchTitleBackground(u64 titleID, const tikview *view)
240 s32 res;
241 STACK_ALIGN(u64,title,1,32);
242 STACK_ALIGN(ioctlv,vectors,2,32);
244 if(__es_fd<0) return ES_ENOTINIT;
245 if(!view) return ES_EINVAL;
246 if(!ISALIGNED(view)) return ES_EALIGN;
248 #ifdef DEBUG_ES
249 printf("ES LaunchTitleBackground %d %016llx 0x%08x 0x%02x\n",__es_fd,titleID,(u32)view,sizeof(tikview));
250 #endif
252 *title = titleID;
253 vectors[0].data = (void*)title;
254 vectors[0].len = sizeof(u64);
255 vectors[1].data = (void*)view;
256 vectors[1].len = sizeof(tikview);
257 res = IOS_IoctlvRebootBackground(__es_fd,IOCTL_ES_LAUNCH,2,0,vectors);
259 #ifdef DEBUG_ES
260 printf(" =%d\n",res);
261 #endif
263 return res;
266 s32 ES_GetNumTicketViews(u64 titleID, u32 *cnt)
268 s32 ret;
269 u32 cntviews;
271 if(__es_fd<0) return ES_ENOTINIT;
272 if(!cnt) return ES_EINVAL;
274 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETVIEWCNT,"q:i",titleID,&cntviews);
276 if(ret<0) return ret;
277 *cnt = cntviews;
278 return ret;
281 s32 ES_GetTicketViews(u64 titleID, tikview *views, u32 cnt)
283 if(__es_fd<0) return ES_ENOTINIT;
284 if(cnt <= 0) return ES_EINVAL;
285 if(!views) return ES_EINVAL;
286 if(!ISALIGNED(views)) return ES_EALIGN;
288 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETVIEWS,"qi:d",titleID,cnt,views,sizeof(tikview)*cnt);
291 s32 ES_GetNumOwnedTitles(u32 *cnt)
293 s32 ret;
294 u32 cnttitles;
296 if(__es_fd<0) return ES_ENOTINIT;
297 if(cnt == NULL) return ES_EINVAL;
299 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETOWNEDTITLECNT,":i",&cnttitles);
301 if(ret<0) return ret;
302 *cnt = cnttitles;
303 return ret;
306 s32 ES_GetOwnedTitles(u64 *titles, u32 cnt)
308 if(__es_fd<0) return ES_ENOTINIT;
309 if(cnt <= 0) return ES_EINVAL;
310 if(!titles) return ES_EINVAL;
311 if(!ISALIGNED(titles)) return ES_EALIGN;
313 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETOWNEDTITLES,"i:d",cnt,titles,sizeof(u64)*cnt);
316 s32 ES_GetNumTitles(u32 *cnt)
318 s32 ret;
319 u32 cnttitles;
321 if(__es_fd<0) return ES_ENOTINIT;
322 if(cnt == NULL) return ES_EINVAL;
324 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLECNT,":i",&cnttitles);
326 if(ret<0) return ret;
327 *cnt = cnttitles;
328 return ret;
331 s32 ES_GetTitles(u64 *titles, u32 cnt)
333 if(__es_fd<0) return ES_ENOTINIT;
334 if(cnt <= 0) return ES_EINVAL;
335 if(!titles) return ES_EINVAL;
336 if(!ISALIGNED(titles)) return ES_EALIGN;
338 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLES,"i:d",cnt,titles,sizeof(u64)*cnt);
341 s32 ES_GetNumStoredTMDContents(const signed_blob *stmd, u32 tmd_size, u32 *cnt)
343 s32 ret;
344 u32 cntct;
346 if(__es_fd<0) return ES_ENOTINIT;
347 if(!cnt) return ES_EINVAL;
348 if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL;
349 if(!ISALIGNED(stmd)) return ES_EALIGN;
351 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDCONTENTCNT,"d:i",stmd,tmd_size,&cntct);
353 if(ret<0) return ret;
354 *cnt = cntct;
355 return ret;
358 s32 ES_GetStoredTMDContents(const signed_blob *stmd, u32 tmd_size, u32 *contents, u32 cnt)
360 if(__es_fd<0) return ES_ENOTINIT;
361 if(cnt <= 0) return ES_EINVAL;
362 if(!contents) return ES_EINVAL;
363 if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL;
364 if(!ISALIGNED(stmd)) return ES_EALIGN;
365 if(!ISALIGNED(contents)) return ES_EALIGN;
366 if(tmd_size > MAX_SIGNED_TMD_SIZE) return ES_EINVAL;
368 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDCONTENTS,"di:d",stmd,tmd_size,cnt,contents,sizeof(u32)*cnt);
371 s32 ES_GetTitleContentsCount(u64 titleID, u32 *num)
373 s32 ret;
374 u32 _num;
376 if(__es_fd<0) return ES_ENOTINIT;
377 if(!num) return ES_EINVAL;
379 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLECONTENTSCNT,"q:i",titleID,&_num);
381 if(ret<0) return ret;
382 *num = _num;
383 return ret;
386 s32 ES_GetTitleContents(u64 titleID, u8 *data, u32 size)
388 if(__es_fd<0) return ES_ENOTINIT;
389 if(size <= 0) return ES_EINVAL;
390 if(!data) return ES_EINVAL;
391 if(!ISALIGNED(data)) return ES_EALIGN;
393 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDTMD,"qi:d",titleID,size,data,size);
396 s32 ES_GetTMDViewSize(u64 titleID, u32 *size)
398 s32 ret;
399 u32 tmdsize;
401 if(__es_fd<0) return ES_ENOTINIT;
402 if(!size) return ES_EINVAL;
404 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTMDVIEWCNT,"q:i",titleID,&tmdsize);
406 if(ret<0) return ret;
407 *size = tmdsize;
408 return ret;
411 s32 ES_GetTMDView(u64 titleID, u8 *data, u32 size)
413 if(__es_fd<0) return ES_ENOTINIT;
414 if(size <= 0) return ES_EINVAL;
415 if(!data) return ES_EINVAL;
416 if(!ISALIGNED(data)) return ES_EALIGN;
418 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTMDVIEWS,"qi:d",titleID,size,data,size);
421 s32 ES_GetStoredTMDSize(u64 titleID, u32 *size)
423 s32 ret;
424 u32 tmdsize;
426 if(__es_fd<0) return ES_ENOTINIT;
427 if(!size) return ES_EINVAL;
429 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDTMDSIZE,"q:i",titleID,&tmdsize);
431 if(ret<0) return ret;
432 *size = tmdsize;
433 return ret;
436 s32 ES_GetStoredTMD(u64 titleID, signed_blob *stmd, u32 size)
438 if(__es_fd<0) return ES_ENOTINIT;
439 if(size <= 0) return ES_EINVAL;
440 if(!stmd) return ES_EINVAL;
441 if(!ISALIGNED(stmd)) return ES_EALIGN;
442 if(size > MAX_SIGNED_TMD_SIZE) return ES_EINVAL;
444 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDTMD,"qi:d",titleID,size,stmd,size);
447 s32 ES_GetNumSharedContents(u32 *cnt)
449 s32 ret;
450 u32 cntct;
452 if(__es_fd<0) return ES_ENOTINIT;
453 if(!cnt) return ES_EINVAL;
455 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSHAREDCONTENTCNT,":i",&cntct);
457 if(ret<0) return ret;
458 *cnt = cntct;
459 return ret;
462 s32 ES_GetSharedContents(sha1 *contents, u32 cnt)
464 if(__es_fd<0) return ES_ENOTINIT;
465 if(cnt <= 0) return ES_EINVAL;
466 if(!contents) return ES_EINVAL;
467 if(!ISALIGNED(contents)) return ES_EALIGN;
469 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSHAREDCONTENTS,"i:d",cnt,contents,sizeof(sha1)*cnt);
472 signed_blob *ES_NextCert(const signed_blob *certs)
474 cert_header *cert;
475 if(!SIGNATURE_SIZE(certs)) return NULL;
476 cert = SIGNATURE_PAYLOAD(certs);
477 if(!CERTIFICATE_SIZE(cert)) return NULL;
478 return (signed_blob*)(((u8*)cert) + CERTIFICATE_SIZE(cert));
481 s32 __ES_sanity_check_certlist(const signed_blob *certs, u32 certsize)
483 int count = 0;
484 signed_blob *end;
486 if(!certs || !certsize) return 0;
488 end = (signed_blob*)(((u8*)certs) + certsize);
489 while(certs != end) {
490 #ifdef DEBUG_ES
491 printf("Checking certificate at %p\n",certs);
492 #endif
493 certs = ES_NextCert(certs);
494 if(!certs) return 0;
495 count++;
497 #ifdef DEBUG_ES
498 printf("Num of certificates: %d\n",count);
499 #endif
500 return count;
503 s32 ES_Identify(const signed_blob *certificates, u32 certificates_size, const signed_blob *stmd, u32 tmd_size, const signed_blob *sticket, u32 ticket_size, u32 *keyid)
506 tmd *p_tmd;
507 u8 *hashes;
508 s32 ret;
509 u32 *keyid_buf;
511 if(__es_fd<0) return ES_ENOTINIT;
513 if(ticket_size != STD_SIGNED_TIK_SIZE) return ES_EINVAL;
514 if(!stmd || !tmd_size || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL;
515 if(!sticket || !IS_VALID_SIGNATURE(sticket)) return ES_EINVAL;
516 if(!__ES_sanity_check_certlist(certificates, certificates_size)) return ES_EINVAL;
517 if(!ISALIGNED(certificates)) return ES_EALIGN;
518 if(!ISALIGNED(stmd)) return ES_EALIGN;
519 if(!ISALIGNED(sticket)) return ES_EALIGN;
520 if(tmd_size > MAX_SIGNED_TMD_SIZE) return ES_EINVAL;
522 p_tmd = SIGNATURE_PAYLOAD(stmd);
524 if(!(keyid_buf = iosAlloc(__es_hid, 4))) return ES_ENOMEM;
525 if(!(hashes = iosAlloc(__es_hid, p_tmd->num_contents*20))) {
526 iosFree(__es_hid, keyid_buf);
527 return ES_ENOMEM;
530 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DIVERIFY, "dddd:id", certificates, certificates_size, 0, 0, sticket, ticket_size, stmd, tmd_size, keyid_buf, hashes, p_tmd->num_contents*20);
531 if(ret >= 0 && keyid) *keyid = *keyid_buf;
533 iosFree(__es_hid, keyid_buf);
534 iosFree(__es_hid, hashes);
536 if(ret >= 0) {
537 __ES_Close();
538 __ES_Init();
541 return ret;
544 s32 ES_AddTicket(const signed_blob *stik, u32 stik_size, const signed_blob *certificates, u32 certificates_size, const signed_blob *crl, u32 crl_size)
546 s32 ret;
548 if(__es_fd<0) return ES_ENOTINIT;
549 if(stik_size != STD_SIGNED_TIK_SIZE) return ES_EINVAL;
550 if(!stik || !IS_VALID_SIGNATURE(stik)) return ES_EINVAL;
551 if(crl_size && (!crl || !IS_VALID_SIGNATURE(crl))) return ES_EINVAL;
552 if(!__ES_sanity_check_certlist(certificates, certificates_size)) return ES_EINVAL;
553 if(!certificates || !ISALIGNED(certificates)) return ES_EALIGN;
554 if(!ISALIGNED(stik)) return ES_EALIGN;
555 if(!ISALIGNED(certificates)) return ES_EALIGN;
556 if(!ISALIGNED(crl)) return ES_EALIGN;
558 if(!crl_size) crl=NULL;
560 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTICKET, "ddd:", stik, stik_size, certificates, certificates_size, crl, crl_size);
561 return ret;
565 s32 ES_DeleteTicket(const tikview *view)
567 s32 ret;
569 if(__es_fd<0) return ES_ENOTINIT;
570 if(!view) return ES_EINVAL;
571 if(!ISALIGNED(view)) return ES_EALIGN;
572 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETICKET, "d:", view, sizeof(tikview));
573 return ret;
576 s32 ES_AddTitleTMD(const signed_blob *stmd, u32 stmd_size)
578 s32 ret;
580 if(__es_fd<0) return ES_ENOTINIT;
581 if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL;
582 if(stmd_size != SIGNED_TMD_SIZE(stmd)) return ES_EINVAL;
583 if(!ISALIGNED(stmd)) return ES_EALIGN;
585 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTMD, "d:", stmd, stmd_size);
586 return ret;
590 s32 ES_AddTitleStart(const signed_blob *stmd, u32 tmd_size, const signed_blob *certificates, u32 certificates_size, const signed_blob *crl, u32 crl_size)
592 s32 ret;
594 if(__es_fd<0) return ES_ENOTINIT;
595 if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL;
596 if(tmd_size != SIGNED_TMD_SIZE(stmd)) return ES_EINVAL;
597 if(crl_size && (!crl || !IS_VALID_SIGNATURE(crl))) return ES_EINVAL;
598 if(!__ES_sanity_check_certlist(certificates, certificates_size)) return ES_EINVAL;
599 if(!certificates || !ISALIGNED(certificates)) return ES_EALIGN;
600 if(!ISALIGNED(stmd)) return ES_EALIGN;
601 if(!ISALIGNED(certificates)) return ES_EALIGN;
602 if(!ISALIGNED(crl)) return ES_EALIGN;
604 if(!crl_size) crl=NULL;
606 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTITLESTART, "dddi:", stmd, tmd_size, certificates, certificates_size, crl, crl_size, 1);
607 return ret;
610 s32 ES_AddContentStart(u64 titleID, u32 cid)
612 if(__es_fd<0) return ES_ENOTINIT;
613 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDCONTENTSTART, "qi:", titleID, cid);
616 s32 ES_AddContentData(s32 cfd, u8 *data, u32 data_size)
618 if(__es_fd<0) return ES_ENOTINIT;
619 if(cfd<0) return ES_EINVAL;
620 if(!data || !data_size) return ES_EINVAL;
621 if(!ISALIGNED(data)) return ES_EALIGN;
622 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDCONTENTDATA, "id:", cfd, data, data_size);
625 s32 ES_AddContentFinish(u32 cid)
627 if(__es_fd<0) return ES_ENOTINIT;
628 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDCONTENTFINISH, "i:", cid);
631 s32 ES_AddTitleFinish(void)
633 if(__es_fd<0) return ES_ENOTINIT;
634 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTITLEFINISH, "");
637 s32 ES_AddTitleCancel(void)
639 if(__es_fd<0) return ES_ENOTINIT;
640 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTITLECANCEL, "");
643 s32 ES_ImportBoot(const signed_blob *tik, u32 tik_size,const signed_blob *tik_certs,u32 tik_certs_size,const signed_blob *tmd,u32 tmd_size,const signed_blob *tmd_certs,u32 tmd_certs_size,const u8 *content,u32 content_size)
645 if(__es_fd<0) return ES_ENOTINIT;
646 if(!tik || !tik_size) return ES_EINVAL;
647 if(!tik_certs || !tik_certs_size) return ES_EINVAL;
648 if(!tmd || !tmd_size) return ES_EINVAL;
649 if(!tmd_certs || !tmd_certs_size) return ES_EINVAL;
650 if(!content || !content_size) return ES_EINVAL;
651 if(!ISALIGNED(tik)) return ES_EALIGN;
652 if(!ISALIGNED(tmd)) return ES_EALIGN;
653 if(!ISALIGNED(tik_certs)) return ES_EALIGN;
654 if(!ISALIGNED(tmd_certs)) return ES_EALIGN;
655 if(!ISALIGNED(content)) return ES_EALIGN;
657 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_IMPORTBOOT, "dddddd:", tik, tik_size, tik_certs, tik_certs_size, tmd, tmd_size, tmd_certs, tmd_certs_size, NULL, 0, content, content_size);
660 s32 ES_OpenContent(u16 index)
662 if(__es_fd<0) return ES_ENOTINIT;
663 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_OPENCONTENT, "i:", index);
666 s32 ES_OpenTitleContent(u64 titleID, tikview *views, u16 index)
668 if(__es_fd<0) return ES_ENOTINIT;
669 if(!ISALIGNED(views)) return ES_EALIGN;
670 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_OPENTITLECONTENT, "qdi:", titleID, views, sizeof(tikview), index);
673 s32 ES_ReadContent(s32 cfd, u8 *data, u32 data_size)
675 if(__es_fd<0) return ES_ENOTINIT;
676 if(cfd<0) return ES_EINVAL;
677 if(!data || !data_size) return ES_EINVAL;
678 if(!ISALIGNED(data)) return ES_EALIGN;
679 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_READCONTENT, "i:d", cfd, data, data_size);
682 s32 ES_SeekContent(s32 cfd, s32 where, s32 whence)
684 if(__es_fd<0) return ES_ENOTINIT;
685 if(cfd<0) return ES_EINVAL;
686 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_SEEKCONTENT, "iii:", cfd, where, whence);
689 s32 ES_CloseContent(s32 cfd)
691 if(__es_fd<0) return ES_ENOTINIT;
692 if(cfd<0) return ES_EINVAL;
693 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_CLOSECONTENT, "i:", cfd);
696 s32 ES_DeleteTitle(u64 titleID)
698 if(__es_fd<0) return ES_ENOTINIT;
699 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETITLE, "q:", titleID);
702 s32 ES_DeleteTitleContent(u64 titleID)
704 if(__es_fd<0) return ES_ENOTINIT;
705 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETITLECONTENT, "q:", titleID);
708 s32 ES_Encrypt(u32 keynum, u8 *iv, u8 *source, u32 size, u8 *dest)
710 if(__es_fd<0) return ES_ENOTINIT;
711 if(!iv || !source || !size || !dest) return ES_EINVAL;
712 if(!ISALIGNED(source) || !ISALIGNED(iv) || !ISALIGNED(dest)) return ES_EALIGN;
713 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ENCRYPT, "idd:dd", keynum, iv, 0x10, source, size, iv, 0x10, dest, size);
716 s32 ES_Decrypt(u32 keynum, u8 *iv, u8 *source, u32 size, u8 *dest)
718 if(__es_fd<0) return ES_ENOTINIT;
719 if(!iv || !source || !size || !dest) return ES_EINVAL;
720 if(!ISALIGNED(source) || !ISALIGNED(iv) || !ISALIGNED(dest)) return ES_EALIGN;
721 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DECRYPT, "idd:dd", keynum, iv, 0x10, source, size, iv, 0x10, dest, size);
724 s32 ES_Sign(u8 *source, u32 size, u8 *sig, u8 *certs)
726 if(__es_fd<0) return ES_ENOTINIT;
727 if(!source || !size || !sig || !certs) return ES_EINVAL;
728 if(!ISALIGNED(source) || !ISALIGNED(sig) || !ISALIGNED(certs)) return ES_EALIGN;
729 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_SIGN, "d:dd", source, size, sig, 0x3C, certs, 0x180);
732 s32 ES_GetDeviceCert(u8 *outbuf)
734 if(__es_fd<0) return ES_ENOTINIT;
735 if(!outbuf) return ES_EINVAL;
736 if(!ISALIGNED(outbuf)) return ES_EALIGN;
737 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETDEVICECERT, ":d", outbuf, 0x180);
740 s32 ES_GetDeviceID(u32 *device_id)
742 s32 ret;
743 u32 _device_id = 0;
745 if(__es_fd<0) return ES_ENOTINIT;
746 if(!device_id) return ES_EINVAL;
748 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETDEVICEID, ":i", &_device_id);
749 if (ret>=0) *device_id = _device_id;
751 return ret;
754 s32 ES_GetBoot2Version(u32 *version)
756 s32 ret;
757 u32 _version = 0;
759 if(__es_fd<0) return ES_ENOTINIT;
760 if(!version) return ES_EINVAL;
762 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETBOOT2VERSION, ":i", &_version);
763 if (ret>=0) *version = _version;
765 return ret;
768 // 64k buffer size for alignment
769 #define ES_READ_BUF_SIZE 65536
771 typedef struct {
772 s32 cfd;
773 u64 titleID;
774 tmd_content content;
775 void *iobuf;
776 mutex_t mutex;
777 } es_fd;
779 // valid path formats:
780 // format example description
781 // es:%08x es:00000004 Content index for current title ID
782 // es:ID%08x es:ID00000033 Content ID for current title ID
783 // es:%016llx/%08x es:0000000100000002/00000004 Content index for some title ID (not fully implemented yet)
784 // es:%016llx/ID%08x es:0000000100000002/ID00000033 Content ID for some title ID (not fully implemented yet)
785 // leading zeroes may be omitted, 0x prefix allowed. All numbers in hex.
787 static s32 _ES_decodepath (struct _reent *r, const char *path, u64 *titleID, tmd_content *content)
789 u64 _tid = 0;
790 u32 tmd_size;
791 STACK_ALIGN(u8, _tmdbuf, MAX_SIGNED_TMD_SIZE, 32);
792 signed_blob *_stmd;
793 tmd *_tmd;
794 tmd_content *_contents;
795 tmd_content _content;
796 int is_cid;
797 u32 arg;
798 char *bad;
799 int i;
800 u64 mytid;
802 // check the device
803 if(strncmp(path,"es:",3)) {
804 r->_errno = EINVAL;
805 return -1;
807 path += 3;
809 // Get our Title ID
810 if(ES_GetTitleID(&mytid) < 0) {
811 r->_errno = EIO;
812 return -1;
815 // Read in Title ID, if this is an absolute path
816 if(path[0] == '/') {
817 path++;
818 if(!path[0]) {
819 r->_errno = EINVAL;
820 return -1;
822 r->_errno = 0;
823 _tid = _strtoull_r(r, path, &bad, 16);
824 if(r->_errno) return -1;
825 if((bad == path) || (bad[0] != '/')) {
826 r->_errno = EINVAL;
827 return -1;
829 path = bad + 1;
830 } else {
831 _tid = mytid;
834 // check if path is a content ID
835 if(!strncmp(path,"ID",2)) {
836 path += 2;
837 is_cid = 1;
838 } else {
839 is_cid = 0;
842 // read in the argument (content ID or content index)
843 r->_errno = 0;
844 arg = _strtoul_r(r, path, &bad, 16);
845 if(r->_errno) return -1;
846 if((bad == path) || (bad[0] != 0)) {
847 r->_errno = EINVAL;
848 return -1;
851 // now get the TMD and find the content entry
852 if(ES_GetStoredTMDSize(_tid, &tmd_size) < 0) {
853 r->_errno = ENOENT;
854 return -1;
857 _stmd = (signed_blob*)_tmdbuf;
858 if(ES_GetStoredTMD(_tid, _stmd, tmd_size) < 0) {
859 r->_errno = EIO;
860 return -1;
862 if(!IS_VALID_SIGNATURE(_stmd)) {
863 r->_errno = EIO;
864 return -1;
866 _tmd = SIGNATURE_PAYLOAD(_stmd);
867 _contents = TMD_CONTENTS(_tmd);
869 for(i=0;i<_tmd->num_contents;i++) {
870 if(is_cid) {
871 if(_contents[i].cid == arg) {
872 _content = _contents[i];
873 break;
875 } else {
876 if(_contents[i].index == arg) {
877 _content = _contents[i];
878 break;
882 if(i >= _tmd->num_contents) {
883 r->_errno = ENOENT;
884 return -1;
887 if(titleID) {
888 if(_tid == mytid) *titleID = 0;
889 else *titleID = _tid;
891 if(content) *content = _content;
892 return 0;
895 static int _ES_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) {
896 es_fd *file = (es_fd *) fileStruct;
898 // decode the path
899 if(_ES_decodepath(r, path, &file->titleID, &file->content) < 0) {
900 return -1;
903 // writing not supported
904 if ((flags & 0x03) != O_RDONLY) {
905 r->_errno = EROFS;
906 return -1;
909 // open the content
910 if(file->titleID == 0)
911 file->cfd = ES_OpenContent(file->content.index);
912 else
914 u32 cnt ATTRIBUTE_ALIGN(32);
915 ES_GetNumTicketViews(file->titleID, &cnt);
916 tikview *views = (tikview *)memalign( 32, sizeof(tikview)*cnt );
917 if(views == NULL)
919 return -1;
921 ES_GetTicketViews(file->titleID, views, cnt);
922 file->cfd = ES_OpenTitleContent(file->titleID, views, file->content.index);
923 free(views);
926 if(file->cfd<0) {
927 r->_errno = EIO;
928 return -1;
931 file->iobuf = NULL;
933 LWP_MutexInit(&file->mutex, false);
935 return (int)file;
938 static int _ES_close_r (struct _reent *r, int fd) {
939 es_fd *file = (es_fd *) fd;
941 LWP_MutexLock(file->mutex);
943 if(ES_CloseContent(file->cfd) < 0) {
944 r->_errno = EBADF;
945 return -1;
947 file->cfd = -1;
949 if(file->iobuf) _free_r(r,file->iobuf);
951 LWP_MutexUnlock(file->mutex);
952 LWP_MutexDestroy(file->mutex);
953 return 0;
956 static int _ES_read_r (struct _reent *r, int fd, char *ptr, size_t len) {
957 es_fd *file = (es_fd *) fd;
958 int read = 0;
959 int res;
962 LWP_MutexLock(file->mutex);
963 if(file->cfd < 0) {
964 LWP_MutexUnlock(file->mutex);
965 r->_errno = EBADF;
966 return -1;
969 // if aligned, just pass through the read
970 if(ISALIGNED(ptr))
972 res = ES_ReadContent(file->cfd, (u8*)ptr, len);
973 if(res < 0) {
974 LWP_MutexUnlock(file->mutex);
975 // we don't really know what the error codes mean...
976 r->_errno = EIO;
977 return -1;
979 read = res;
980 // otherwise read in blocks to an aligned buffer
981 } else {
982 int chunk;
983 if(!file->iobuf) {
984 file->iobuf = _memalign_r(r, 32, ES_READ_BUF_SIZE);
985 if(!file->iobuf) {
986 r->_errno = ENOMEM;
987 return -1;
990 while(len) {
991 if(len > ES_READ_BUF_SIZE) chunk = ES_READ_BUF_SIZE;
992 else chunk = len;
993 res = ES_ReadContent(file->cfd, file->iobuf, chunk);
994 if(res < 0) {
995 LWP_MutexUnlock(file->mutex);
996 // we don't really know what the error codes mean...
997 r->_errno = EIO;
998 return -1;
1000 len -= res;
1001 read += res;
1002 memcpy(ptr, file->iobuf, res);
1003 ptr += res;
1004 if(res < chunk) break;
1008 LWP_MutexUnlock(file->mutex);
1009 return read;
1012 static off_t _ES_seek_r (struct _reent *r, int fd, off_t where, int whence) {
1013 es_fd *file = (es_fd *) fd;
1014 s32 res;
1016 LWP_MutexLock(file->mutex);
1017 if(file->cfd < 0) {
1018 LWP_MutexUnlock(file->mutex);
1019 r->_errno = EBADF;
1020 return -1;
1023 res = ES_SeekContent(file->cfd, where, whence);
1024 LWP_MutexUnlock(file->mutex);
1026 if(res < 0) {
1027 r->_errno = EINVAL;
1028 return -1;
1030 return res;
1033 static void _ES_fillstat(u64 titleID, tmd_content *content, struct stat *st) {
1034 memset(st, 0, sizeof(*st));
1035 // the inode is the content ID
1036 // (pretend each Title ID is a different filesystem)
1037 st->st_ino = content->cid;
1038 // st_dev is only a short, so do the best we can and use the middle two letters
1039 // of the title ID if it's not a system content, otherwise use the low 16 bits
1040 if((titleID>>32) == 1)
1041 st->st_dev = titleID & 0xFFFF;
1042 else
1043 st->st_dev = (titleID>>8) & 0xFFFF;
1045 // not necessarily true due to shared contents, but
1046 // we're not going to implement shared content scan here and now
1047 st->st_nlink = 1;
1048 // instead, give the file group read permissions if it's a shared content
1049 st->st_mode = S_IFREG | S_IRUSR;
1050 if(content->type & 0x8000)
1051 st->st_mode |= S_IRGRP;
1053 // use st_dev as a uid too, see above
1054 st->st_uid = st->st_dev;
1055 // no group
1056 st->st_gid = 0;
1057 // content size
1058 st->st_size = content->size;
1059 st->st_blocks = (st->st_size + 511) / 512;
1060 // NAND fs cluster size (not like anyone cares, but...)
1061 st->st_blksize = 16384;
1064 static int _ES_fstat_r (struct _reent *r, int fd, struct stat *st) {
1065 es_fd *file = (es_fd *) fd;
1067 LWP_MutexLock(file->mutex);
1068 if(file->cfd < 0) {
1069 LWP_MutexUnlock(file->mutex);
1070 r->_errno = EBADF;
1071 return -1;
1074 _ES_fillstat(file->titleID, &file->content, st);
1075 LWP_MutexUnlock(file->mutex);
1077 return 0;
1080 static int _ES_stat_r (struct _reent *r, const char *path, struct stat *st) {
1081 tmd_content content;
1082 u64 titleID;
1084 if(_ES_decodepath(r, path, &titleID, &content) < 0) {
1085 return -1;
1087 _ES_fillstat(titleID, &content, st);
1088 return 0;
1091 static const devoptab_t dotab_es = {
1092 "es",
1093 sizeof (es_fd),
1094 _ES_open_r,
1095 _ES_close_r,
1096 NULL,
1097 _ES_read_r,
1098 _ES_seek_r,
1099 _ES_fstat_r,
1100 _ES_stat_r,
1101 NULL,
1102 NULL,
1103 NULL,
1104 NULL,
1105 NULL,
1107 NULL,
1108 NULL,
1109 NULL,
1110 NULL,
1111 NULL
1114 static void __ES_InitFS(void) {
1115 AddDevice(&dotab_es);
1118 static void __ES_DeinitFS(void) {
1119 RemoveDevice("es:");
1122 #endif /* defined(HW_RVL) */