Enable USBGecko output in the exception handler
[libogc.git] / libogc / es.c
blob7857d25daf1121de0ed00dc23916510d3fa67286
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, u16 index)
668 if(__es_fd<0) return ES_ENOTINIT;
669 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_OPENTITLECONTENT, "qi:", titleID, index);
672 s32 ES_ReadContent(s32 cfd, u8 *data, u32 data_size)
674 if(__es_fd<0) return ES_ENOTINIT;
675 if(cfd<0) return ES_EINVAL;
676 if(!data || !data_size) return ES_EINVAL;
677 if(!ISALIGNED(data)) return ES_EALIGN;
678 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_READCONTENT, "i:d", cfd, data, data_size);
681 s32 ES_SeekContent(s32 cfd, s32 where, s32 whence)
683 if(__es_fd<0) return ES_ENOTINIT;
684 if(cfd<0) return ES_EINVAL;
685 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_SEEKCONTENT, "iii:", cfd, where, whence);
688 s32 ES_CloseContent(s32 cfd)
690 if(__es_fd<0) return ES_ENOTINIT;
691 if(cfd<0) return ES_EINVAL;
692 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_CLOSECONTENT, "i:", cfd);
695 s32 ES_DeleteTitle(u64 titleID)
697 if(__es_fd<0) return ES_ENOTINIT;
698 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETITLE, "q:", titleID);
701 s32 ES_DeleteTitleContent(u64 titleID)
703 if(__es_fd<0) return ES_ENOTINIT;
704 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETITLECONTENT, "q:", titleID);
707 s32 ES_Encrypt(u32 keynum, u8 *iv, u8 *source, u32 size, u8 *dest)
709 if(__es_fd<0) return ES_ENOTINIT;
710 if(!iv || !source || !size || !dest) return ES_EINVAL;
711 if(!ISALIGNED(source) || !ISALIGNED(iv) || !ISALIGNED(dest)) return ES_EALIGN;
712 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ENCRYPT, "idd:dd", keynum, iv, 0x10, source, size, iv, 0x10, dest, size);
715 s32 ES_Decrypt(u32 keynum, u8 *iv, u8 *source, u32 size, u8 *dest)
717 if(__es_fd<0) return ES_ENOTINIT;
718 if(!iv || !source || !size || !dest) return ES_EINVAL;
719 if(!ISALIGNED(source) || !ISALIGNED(iv) || !ISALIGNED(dest)) return ES_EALIGN;
720 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DECRYPT, "idd:dd", keynum, iv, 0x10, source, size, iv, 0x10, dest, size);
723 s32 ES_Sign(u8 *source, u32 size, u8 *sig, u8 *certs)
725 if(__es_fd<0) return ES_ENOTINIT;
726 if(!source || !size || !sig || !certs) return ES_EINVAL;
727 if(!ISALIGNED(source) || !ISALIGNED(sig) || !ISALIGNED(certs)) return ES_EALIGN;
728 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_SIGN, "d:dd", source, size, sig, 0x3C, certs, 0x180);
731 s32 ES_GetDeviceCert(u8 *outbuf)
733 if(__es_fd<0) return ES_ENOTINIT;
734 if(!outbuf) return ES_EINVAL;
735 if(!ISALIGNED(outbuf)) return ES_EALIGN;
736 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETDEVICECERT, ":d", outbuf, 0x180);
739 s32 ES_GetDeviceID(u32 *device_id)
741 s32 ret;
742 u32 _device_id = 0;
744 if(__es_fd<0) return ES_ENOTINIT;
745 if(!device_id) return ES_EINVAL;
747 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETDEVICEID, ":i", &_device_id);
748 if (ret>=0) *device_id = _device_id;
750 return ret;
753 s32 ES_GetBoot2Version(u32 *version)
755 s32 ret;
756 u32 _version = 0;
758 if(__es_fd<0) return ES_ENOTINIT;
759 if(!version) return ES_EINVAL;
761 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETBOOT2VERSION, ":i", &_version);
762 if (ret>=0) *version = _version;
764 return ret;
767 // 64k buffer size for alignment
768 #define ES_READ_BUF_SIZE 65536
770 typedef struct {
771 s32 cfd;
772 u64 titleID;
773 tmd_content content;
774 void *iobuf;
775 mutex_t mutex;
776 } es_fd;
778 // valid path formats:
779 // format example description
780 // es:%08x es:00000004 Content index for current title ID
781 // es:ID%08x es:ID00000033 Content ID for current title ID
782 // es:%016llx/%08x es:0000000100000002/00000004 Content index for some title ID (not fully implemented yet)
783 // es:%016llx/ID%08x es:0000000100000002/ID00000033 Content ID for some title ID (not fully implemented yet)
784 // leading zeroes may be omitted, 0x prefix allowed. All numbers in hex.
786 static s32 _ES_decodepath (struct _reent *r, const char *path, u64 *titleID, tmd_content *content)
788 u64 _tid = 0;
789 u32 tmd_size;
790 STACK_ALIGN(u8, _tmdbuf, MAX_SIGNED_TMD_SIZE, 32);
791 signed_blob *_stmd;
792 tmd *_tmd;
793 tmd_content *_contents;
794 tmd_content _content;
795 int is_cid;
796 u32 arg;
797 char *bad;
798 int i;
799 u64 mytid;
801 // check the device
802 if(strncmp(path,"es:",3)) {
803 r->_errno = EINVAL;
804 return -1;
806 path += 3;
808 // Get our Title ID
809 if(ES_GetTitleID(&mytid) < 0) {
810 r->_errno = EIO;
811 return -1;
814 // Read in Title ID, if this is an absolute path
815 if(path[0] == '/') {
816 path++;
817 if(!path[0]) {
818 r->_errno = EINVAL;
819 return -1;
821 r->_errno = 0;
822 _tid = _strtoull_r(r, path, &bad, 16);
823 if(r->_errno) return -1;
824 if((bad == path) || (bad[0] != '/')) {
825 r->_errno = EINVAL;
826 return -1;
828 path = bad + 1;
829 } else {
830 _tid = mytid;
833 // check if path is a content ID
834 if(!strncmp(path,"ID",2)) {
835 path += 2;
836 is_cid = 1;
837 } else {
838 is_cid = 0;
841 // read in the argument (content ID or content index)
842 r->_errno = 0;
843 arg = _strtoul_r(r, path, &bad, 16);
844 if(r->_errno) return -1;
845 if((bad == path) || (bad[0] != 0)) {
846 r->_errno = EINVAL;
847 return -1;
850 // now get the TMD and find the content entry
851 if(ES_GetStoredTMDSize(_tid, &tmd_size) < 0) {
852 r->_errno = ENOENT;
853 return -1;
856 _stmd = (signed_blob*)_tmdbuf;
857 if(ES_GetStoredTMD(_tid, _stmd, tmd_size) < 0) {
858 r->_errno = EIO;
859 return -1;
861 if(!IS_VALID_SIGNATURE(_stmd)) {
862 r->_errno = EIO;
863 return -1;
865 _tmd = SIGNATURE_PAYLOAD(_stmd);
866 _contents = TMD_CONTENTS(_tmd);
868 for(i=0;i<_tmd->num_contents;i++) {
869 if(is_cid) {
870 if(_contents[i].cid == arg) {
871 _content = _contents[i];
872 break;
874 } else {
875 if(_contents[i].index == arg) {
876 _content = _contents[i];
877 break;
881 if(i >= _tmd->num_contents) {
882 r->_errno = ENOENT;
883 return -1;
886 if(titleID) {
887 if(_tid == mytid) *titleID = 0;
888 else *titleID = _tid;
890 if(content) *content = _content;
891 return 0;
894 static int _ES_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) {
895 es_fd *file = (es_fd *) fileStruct;
897 // decode the path
898 if(_ES_decodepath(r, path, &file->titleID, &file->content) < 0) {
899 return -1;
902 // writing not supported
903 if ((flags & 0x03) != O_RDONLY) {
904 r->_errno = EROFS;
905 return -1;
908 // open the content
909 if(file->titleID == 0)
910 file->cfd = ES_OpenContent(file->content.index);
911 else
912 file->cfd = ES_OpenTitleContent(file->titleID, file->content.index);
914 if(file->cfd<0) {
915 r->_errno = EIO;
916 return -1;
919 file->iobuf = NULL;
921 LWP_MutexInit(&file->mutex, false);
923 return (int)file;
926 static int _ES_close_r (struct _reent *r, int fd) {
927 es_fd *file = (es_fd *) fd;
929 LWP_MutexLock(file->mutex);
931 if(ES_CloseContent(file->cfd) < 0) {
932 r->_errno = EBADF;
933 return -1;
935 file->cfd = -1;
937 if(file->iobuf) _free_r(r,file->iobuf);
939 LWP_MutexUnlock(file->mutex);
940 LWP_MutexDestroy(file->mutex);
941 return 0;
944 static int _ES_read_r (struct _reent *r, int fd, char *ptr, size_t len) {
945 es_fd *file = (es_fd *) fd;
946 int read = 0;
947 int res;
950 LWP_MutexLock(file->mutex);
951 if(file->cfd < 0) {
952 LWP_MutexUnlock(file->mutex);
953 r->_errno = EBADF;
954 return -1;
957 // if aligned, just pass through the read
958 if(ISALIGNED(ptr))
960 res = ES_ReadContent(file->cfd, (u8*)ptr, len);
961 if(res < 0) {
962 LWP_MutexUnlock(file->mutex);
963 // we don't really know what the error codes mean...
964 r->_errno = EIO;
965 return -1;
967 read = res;
968 // otherwise read in blocks to an aligned buffer
969 } else {
970 int chunk;
971 if(!file->iobuf) {
972 file->iobuf = _memalign_r(r, 32, ES_READ_BUF_SIZE);
973 if(!file->iobuf) {
974 r->_errno = ENOMEM;
975 return -1;
978 while(len) {
979 if(len > ES_READ_BUF_SIZE) chunk = ES_READ_BUF_SIZE;
980 else chunk = len;
981 res = ES_ReadContent(file->cfd, file->iobuf, chunk);
982 if(res < 0) {
983 LWP_MutexUnlock(file->mutex);
984 // we don't really know what the error codes mean...
985 r->_errno = EIO;
986 return -1;
988 len -= res;
989 read += res;
990 memcpy(ptr, file->iobuf, res);
991 ptr += res;
992 if(res < chunk) break;
996 LWP_MutexUnlock(file->mutex);
997 return read;
1000 static off_t _ES_seek_r (struct _reent *r, int fd, off_t where, int whence) {
1001 es_fd *file = (es_fd *) fd;
1002 s32 res;
1004 LWP_MutexLock(file->mutex);
1005 if(file->cfd < 0) {
1006 LWP_MutexUnlock(file->mutex);
1007 r->_errno = EBADF;
1008 return -1;
1011 res = ES_SeekContent(file->cfd, where, whence);
1012 LWP_MutexUnlock(file->mutex);
1014 if(res < 0) {
1015 r->_errno = EINVAL;
1016 return -1;
1018 return res;
1021 static void _ES_fillstat(u64 titleID, tmd_content *content, struct stat *st) {
1022 memset(st, 0, sizeof(*st));
1023 // the inode is the content ID
1024 // (pretend each Title ID is a different filesystem)
1025 st->st_ino = content->cid;
1026 // st_dev is only a short, so do the best we can and use the middle two letters
1027 // of the title ID if it's not a system content, otherwise use the low 16 bits
1028 if((titleID>>32) == 1)
1029 st->st_dev = titleID & 0xFFFF;
1030 else
1031 st->st_dev = (titleID>>8) & 0xFFFF;
1033 // not necessarily true due to shared contents, but
1034 // we're not going to implement shared content scan here and now
1035 st->st_nlink = 1;
1036 // instead, give the file group read permissions if it's a shared content
1037 st->st_mode = S_IFREG | S_IRUSR;
1038 if(content->type & 0x8000)
1039 st->st_mode |= S_IRGRP;
1041 // use st_dev as a uid too, see above
1042 st->st_uid = st->st_dev;
1043 // no group
1044 st->st_gid = 0;
1045 // content size
1046 st->st_size = content->size;
1047 st->st_blocks = (st->st_size + 511) / 512;
1048 // NAND fs cluster size (not like anyone cares, but...)
1049 st->st_blksize = 16384;
1052 static int _ES_fstat_r (struct _reent *r, int fd, struct stat *st) {
1053 es_fd *file = (es_fd *) fd;
1055 LWP_MutexLock(file->mutex);
1056 if(file->cfd < 0) {
1057 LWP_MutexUnlock(file->mutex);
1058 r->_errno = EBADF;
1059 return -1;
1062 _ES_fillstat(file->titleID, &file->content, st);
1063 LWP_MutexUnlock(file->mutex);
1065 return 0;
1068 static int _ES_stat_r (struct _reent *r, const char *path, struct stat *st) {
1069 tmd_content content;
1070 u64 titleID;
1072 if(_ES_decodepath(r, path, &titleID, &content) < 0) {
1073 return -1;
1075 _ES_fillstat(titleID, &content, st);
1076 return 0;
1079 static const devoptab_t dotab_es = {
1080 "es",
1081 sizeof (es_fd),
1082 _ES_open_r,
1083 _ES_close_r,
1084 NULL,
1085 _ES_read_r,
1086 _ES_seek_r,
1087 _ES_fstat_r,
1088 _ES_stat_r,
1089 NULL,
1090 NULL,
1091 NULL,
1092 NULL,
1093 NULL,
1095 NULL,
1096 NULL,
1097 NULL,
1098 NULL,
1099 NULL
1102 static void __ES_InitFS(void) {
1103 AddDevice(&dotab_es);
1106 static void __ES_DeinitFS(void) {
1107 RemoveDevice("es");
1110 #endif /* defined(HW_RVL) */