smb improvements (rodries)
[libogc.git] / libogc / es.c
blob997b1ee70101d87f76955d8466957738fbf80bce
1 /*-------------------------------------------------------------
3 es.c -- ETicket services
5 Copyright (C) 2008
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
8 Hector Martin (marcan)
9 Andre Heider (dhewg)
11 This software is provided 'as-is', without any express or implied
12 warranty. In no event will the authors be held liable for any
13 damages arising from the use of this software.
15 Permission is granted to anyone to use this software for any
16 purpose, including commercial applications, and to alter it and
17 redistribute it freely, subject to the following restrictions:
19 1. The origin of this software must not be misrepresented; you
20 must not claim that you wrote the original software. If you use
21 this software in a product, an acknowledgment in the product
22 documentation would be appreciated but is not required.
24 2. Altered source versions must be plainly marked as such, and
25 must not be misrepresented as being the original software.
27 3. This notice may not be removed or altered from any source
28 distribution.
30 -------------------------------------------------------------*/
32 #if defined(HW_RVL)
34 #include <sys/iosupport.h>
35 #include <sys/fcntl.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <malloc.h>
40 #include <sys/errno.h>
41 #include "ipc.h"
42 #include "asm.h"
43 #include "processor.h"
44 #include "mutex.h"
45 #include "es.h"
47 //#define DEBUG_ES
49 #define IOCTL_ES_ADDTICKET 0x01
50 #define IOCTL_ES_ADDTITLESTART 0x02
51 #define IOCTL_ES_ADDCONTENTSTART 0x03
52 #define IOCTL_ES_ADDCONTENTDATA 0x04
53 #define IOCTL_ES_ADDCONTENTFINISH 0x05
54 #define IOCTL_ES_ADDTITLEFINISH 0x06
55 #define IOCTL_ES_GETDEVICEID 0x07
56 #define IOCTL_ES_LAUNCH 0x08
57 #define IOCTL_ES_OPENCONTENT 0x09
58 #define IOCTL_ES_READCONTENT 0x0A
59 #define IOCTL_ES_CLOSECONTENT 0x0B
60 #define IOCTL_ES_GETOWNEDTITLECNT 0x0C
61 #define IOCTL_ES_GETOWNEDTITLES 0x0D
62 #define IOCTL_ES_GETTITLECNT 0x0E
63 #define IOCTL_ES_GETTITLES 0x0F
64 #define IOCTL_ES_GETTITLECONTENTSCNT 0x10
65 #define IOCTL_ES_GETTITLECONTENTS 0x11
66 #define IOCTL_ES_GETVIEWCNT 0x12
67 #define IOCTL_ES_GETVIEWS 0x13
68 #define IOCTL_ES_GETTMDVIEWCNT 0x14
69 #define IOCTL_ES_GETTMDVIEWS 0x15
70 //#define IOCTL_ES_GETCONSUMPTION 0x16
71 #define IOCTL_ES_DELETETITLE 0x17
72 #define IOCTL_ES_DELETETICKET 0x18
73 //#define IOCTL_ES_DIGETTMDVIEWSIZE 0x19
74 //#define IOCTL_ES_DIGETTMDVIEW 0x1A
75 //#define IOCTL_ES_DIGETTICKETVIEW 0x1B
76 #define IOCTL_ES_DIVERIFY 0x1C
77 #define IOCTL_ES_GETTITLEDIR 0x1D
78 #define IOCTL_ES_GETDEVICECERT 0x1E
79 #define IOCTL_ES_IMPORTBOOT 0x1F
80 #define IOCTL_ES_GETTITLEID 0x20
81 #define IOCTL_ES_SETUID 0x21
82 #define IOCTL_ES_DELETETITLECONTENT 0x22
83 #define IOCTL_ES_SEEKCONTENT 0x23
84 #define IOCTL_ES_OPENTITLECONTENT 0x24
85 //#define IOCTL_ES_LAUNCHBC 0x25
86 //#define IOCTL_ES_EXPORTTITLEINIT 0x26
87 //#define IOCTL_ES_EXPORTCONTENTBEGIN 0x27
88 //#define IOCTL_ES_EXPORTCONTENTDATA 0x28
89 //#define IOCTL_ES_EXPORTCONTENTEND 0x29
90 //#define IOCTL_ES_EXPORTTITLEDONE 0x2A
91 #define IOCTL_ES_ADDTMD 0x2B
92 #define IOCTL_ES_ENCRYPT 0x2C
93 #define IOCTL_ES_DECRYPT 0x2D
94 #define IOCTL_ES_GETBOOT2VERSION 0x2E
95 #define IOCTL_ES_ADDTITLECANCEL 0x2F
96 #define IOCTL_ES_SIGN 0x30
97 //#define IOCTL_ES_VERIFYSIGN 0x31
98 #define IOCTL_ES_GETSTOREDCONTENTCNT 0x32
99 #define IOCTL_ES_GETSTOREDCONTENTS 0x33
100 #define IOCTL_ES_GETSTOREDTMDSIZE 0x34
101 #define IOCTL_ES_GETSTOREDTMD 0x35
102 #define IOCTL_ES_GETSHAREDCONTENTCNT 0x36
103 #define IOCTL_ES_GETSHAREDCONTENTS 0x37
106 #define ES_HEAP_SIZE 0x800
108 #define ISALIGNED(x) ((((u32)x)&0x1F)==0)
110 static char __es_fs[] ATTRIBUTE_ALIGN(32) = "/dev/es";
112 static s32 __es_fd = -1;
113 static s32 __es_hid = -1;
115 static void __ES_InitFS(void);
116 static void __ES_DeinitFS(void);
118 s32 __ES_Init(void)
120 s32 ret = 0;
122 #ifdef DEBUG_ES
123 printf("ES Init\n");
124 #endif
126 if(__es_hid < 0 ) {
127 __es_hid = iosCreateHeap(ES_HEAP_SIZE);
128 if(__es_hid < 0)
129 return __es_hid;
132 if (__es_fd < 0) {
133 ret = IOS_Open(__es_fs,0);
134 if(ret<0)
135 return ret;
136 __es_fd = ret;
139 #ifdef DEBUG_ES
140 printf("ES FD %d\n",__es_fd);
141 #endif
143 __ES_InitFS();
145 return 0;
148 s32 __ES_Close(void)
150 s32 ret;
152 if(__es_fd < 0) return 0;
154 __ES_DeinitFS();
156 ret = IOS_Close(__es_fd);
158 __es_fd = -1;
160 if(ret<0)
161 return ret;
163 return 0;
166 // Used by ios.c after reloading IOS
167 s32 __ES_Reset(void)
169 __es_fd = -1;
170 return 0;
173 s32 ES_GetTitleID(u64 *titleID)
175 s32 ret;
176 u64 title;
178 if(__es_fd<0) return ES_ENOTINIT;
179 if(!titleID) return ES_EINVAL;
181 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLEID,":q",&title);
182 if(ret<0) return ret;
184 *titleID = title;
185 return ret;
188 s32 ES_SetUID(u64 uid)
190 if(__es_fd<0) return ES_ENOTINIT;
192 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_SETUID,"q:",uid);
195 s32 ES_GetDataDir(u64 titleID,char *filepath)
197 s32 ret;
199 if(__es_fd<0) return ES_ENOTINIT;
200 if(!filepath) return ES_EINVAL;
201 if(!ISALIGNED(filepath)) return ES_EALIGN;
203 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLEDIR,"q:d",titleID,filepath,30);
205 return ret;
208 s32 ES_LaunchTitle(u64 titleID, const tikview *view)
211 s32 res;
212 STACK_ALIGN(u64,title,1,32);
213 STACK_ALIGN(ioctlv,vectors,2,32);
215 if(__es_fd<0) return ES_ENOTINIT;
216 if(!view) return ES_EINVAL;
217 if(!ISALIGNED(view)) return ES_EALIGN;
219 #ifdef DEBUG_ES
220 printf("ES LaunchTitle %d %016llx 0x%08x 0x%02x\n",__es_fd,titleID,(u32)view,sizeof(tikview));
221 #endif
224 *title = titleID;
225 vectors[0].data = (void*)title;
226 vectors[0].len = sizeof(u64);
227 vectors[1].data = (void*)view;
228 vectors[1].len = sizeof(tikview);
229 res = IOS_IoctlvReboot(__es_fd,IOCTL_ES_LAUNCH,2,0,vectors);
231 #ifdef DEBUG_ES
232 printf(" =%d\n",res);
233 #endif
235 return res;
238 s32 ES_LaunchTitleBackground(u64 titleID, const tikview *view)
241 s32 res;
242 STACK_ALIGN(u64,title,1,32);
243 STACK_ALIGN(ioctlv,vectors,2,32);
245 if(__es_fd<0) return ES_ENOTINIT;
246 if(!view) return ES_EINVAL;
247 if(!ISALIGNED(view)) return ES_EALIGN;
249 #ifdef DEBUG_ES
250 printf("ES LaunchTitleBackground %d %016llx 0x%08x 0x%02x\n",__es_fd,titleID,(u32)view,sizeof(tikview));
251 #endif
253 *title = titleID;
254 vectors[0].data = (void*)title;
255 vectors[0].len = sizeof(u64);
256 vectors[1].data = (void*)view;
257 vectors[1].len = sizeof(tikview);
258 res = IOS_IoctlvRebootBackground(__es_fd,IOCTL_ES_LAUNCH,2,0,vectors);
260 #ifdef DEBUG_ES
261 printf(" =%d\n",res);
262 #endif
264 return res;
267 s32 ES_GetNumTicketViews(u64 titleID, u32 *cnt)
269 s32 ret;
270 u32 cntviews;
272 if(__es_fd<0) return ES_ENOTINIT;
273 if(!cnt) return ES_EINVAL;
275 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETVIEWCNT,"q:i",titleID,&cntviews);
277 if(ret<0) return ret;
278 *cnt = cntviews;
279 return ret;
282 s32 ES_GetTicketViews(u64 titleID, tikview *views, u32 cnt)
284 if(__es_fd<0) return ES_ENOTINIT;
285 if(cnt <= 0) return ES_EINVAL;
286 if(!views) return ES_EINVAL;
287 if(!ISALIGNED(views)) return ES_EALIGN;
289 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETVIEWS,"qi:d",titleID,cnt,views,sizeof(tikview)*cnt);
292 s32 ES_GetNumOwnedTitles(u32 *cnt)
294 s32 ret;
295 u32 cnttitles;
297 if(__es_fd<0) return ES_ENOTINIT;
298 if(cnt == NULL) return ES_EINVAL;
300 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETOWNEDTITLECNT,":i",&cnttitles);
302 if(ret<0) return ret;
303 *cnt = cnttitles;
304 return ret;
307 s32 ES_GetOwnedTitles(u64 *titles, u32 cnt)
309 if(__es_fd<0) return ES_ENOTINIT;
310 if(cnt <= 0) return ES_EINVAL;
311 if(!titles) return ES_EINVAL;
312 if(!ISALIGNED(titles)) return ES_EALIGN;
314 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETOWNEDTITLES,"i:d",cnt,titles,sizeof(u64)*cnt);
317 s32 ES_GetNumTitles(u32 *cnt)
319 s32 ret;
320 u32 cnttitles;
322 if(__es_fd<0) return ES_ENOTINIT;
323 if(cnt == NULL) return ES_EINVAL;
325 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLECNT,":i",&cnttitles);
327 if(ret<0) return ret;
328 *cnt = cnttitles;
329 return ret;
332 s32 ES_GetTitles(u64 *titles, u32 cnt)
334 if(__es_fd<0) return ES_ENOTINIT;
335 if(cnt <= 0) return ES_EINVAL;
336 if(!titles) return ES_EINVAL;
337 if(!ISALIGNED(titles)) return ES_EALIGN;
339 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLES,"i:d",cnt,titles,sizeof(u64)*cnt);
342 s32 ES_GetNumStoredTMDContents(const signed_blob *stmd, u32 tmd_size, u32 *cnt)
344 s32 ret;
345 u32 cntct;
347 if(__es_fd<0) return ES_ENOTINIT;
348 if(!cnt) return ES_EINVAL;
349 if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL;
350 if(!ISALIGNED(stmd)) return ES_EALIGN;
352 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDCONTENTCNT,"d:i",stmd,tmd_size,&cntct);
354 if(ret<0) return ret;
355 *cnt = cntct;
356 return ret;
359 s32 ES_GetStoredTMDContents(const signed_blob *stmd, u32 tmd_size, u32 *contents, u32 cnt)
361 if(__es_fd<0) return ES_ENOTINIT;
362 if(cnt <= 0) return ES_EINVAL;
363 if(!contents) return ES_EINVAL;
364 if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL;
365 if(!ISALIGNED(stmd)) return ES_EALIGN;
366 if(!ISALIGNED(contents)) return ES_EALIGN;
367 if(tmd_size > MAX_SIGNED_TMD_SIZE) return ES_EINVAL;
369 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDCONTENTS,"di:d",stmd,tmd_size,cnt,contents,sizeof(u32)*cnt);
372 s32 ES_GetTitleContentsCount(u64 titleID, u32 *num)
374 s32 ret;
375 u32 _num;
377 if(__es_fd<0) return ES_ENOTINIT;
378 if(!num) return ES_EINVAL;
380 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTITLECONTENTSCNT,"q:i",titleID,&_num);
382 if(ret<0) return ret;
383 *num = _num;
384 return ret;
387 s32 ES_GetTitleContents(u64 titleID, u8 *data, u32 size)
389 if(__es_fd<0) return ES_ENOTINIT;
390 if(size <= 0) return ES_EINVAL;
391 if(!data) return ES_EINVAL;
392 if(!ISALIGNED(data)) return ES_EALIGN;
394 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDTMD,"qi:d",titleID,size,data,size);
397 s32 ES_GetTMDViewSize(u64 titleID, u32 *size)
399 s32 ret;
400 u32 tmdsize;
402 if(__es_fd<0) return ES_ENOTINIT;
403 if(!size) return ES_EINVAL;
405 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTMDVIEWCNT,"q:i",titleID,&tmdsize);
407 if(ret<0) return ret;
408 *size = tmdsize;
409 return ret;
412 s32 ES_GetTMDView(u64 titleID, u8 *data, u32 size)
414 if(__es_fd<0) return ES_ENOTINIT;
415 if(size <= 0) return ES_EINVAL;
416 if(!data) return ES_EINVAL;
417 if(!ISALIGNED(data)) return ES_EALIGN;
419 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTMDVIEWS,"qi:d",titleID,size,data,size);
422 s32 ES_GetStoredTMDSize(u64 titleID, u32 *size)
424 s32 ret;
425 u32 tmdsize;
427 if(__es_fd<0) return ES_ENOTINIT;
428 if(!size) return ES_EINVAL;
430 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDTMDSIZE,"q:i",titleID,&tmdsize);
432 if(ret<0) return ret;
433 *size = tmdsize;
434 return ret;
437 s32 ES_GetStoredTMD(u64 titleID, signed_blob *stmd, u32 size)
439 if(__es_fd<0) return ES_ENOTINIT;
440 if(size <= 0) return ES_EINVAL;
441 if(!stmd) return ES_EINVAL;
442 if(!ISALIGNED(stmd)) return ES_EALIGN;
443 if(size > MAX_SIGNED_TMD_SIZE) return ES_EINVAL;
445 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDTMD,"qi:d",titleID,size,stmd,size);
448 s32 ES_GetNumSharedContents(u32 *cnt)
450 s32 ret;
451 u32 cntct;
453 if(__es_fd<0) return ES_ENOTINIT;
454 if(!cnt) return ES_EINVAL;
456 ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSHAREDCONTENTCNT,":i",&cntct);
458 if(ret<0) return ret;
459 *cnt = cntct;
460 return ret;
463 s32 ES_GetSharedContents(sha1 *contents, u32 cnt)
465 if(__es_fd<0) return ES_ENOTINIT;
466 if(cnt <= 0) return ES_EINVAL;
467 if(!contents) return ES_EINVAL;
468 if(!ISALIGNED(contents)) return ES_EALIGN;
470 return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSHAREDCONTENTS,"i:d",cnt,contents,sizeof(sha1)*cnt);
473 signed_blob *ES_NextCert(const signed_blob *certs)
475 cert_header *cert;
476 if(!SIGNATURE_SIZE(certs)) return NULL;
477 cert = SIGNATURE_PAYLOAD(certs);
478 if(!CERTIFICATE_SIZE(cert)) return NULL;
479 return (signed_blob*)(((u8*)cert) + CERTIFICATE_SIZE(cert));
482 s32 __ES_sanity_check_certlist(const signed_blob *certs, u32 certsize)
484 int count = 0;
485 signed_blob *end;
487 if(!certs || !certsize) return 0;
489 end = (signed_blob*)(((u8*)certs) + certsize);
490 while(certs != end) {
491 #ifdef DEBUG_ES
492 printf("Checking certificate at %p\n",certs);
493 #endif
494 certs = ES_NextCert(certs);
495 if(!certs) return 0;
496 count++;
498 #ifdef DEBUG_ES
499 printf("Num of certificates: %d\n",count);
500 #endif
501 return count;
504 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)
507 tmd *p_tmd;
508 u8 *hashes;
509 s32 ret;
510 u32 *keyid_buf;
512 if(__es_fd<0) return ES_ENOTINIT;
514 if(ticket_size != STD_SIGNED_TIK_SIZE) return ES_EINVAL;
515 if(!stmd || !tmd_size || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL;
516 if(!sticket || !IS_VALID_SIGNATURE(sticket)) return ES_EINVAL;
517 if(!__ES_sanity_check_certlist(certificates, certificates_size)) return ES_EINVAL;
518 if(!ISALIGNED(certificates)) return ES_EALIGN;
519 if(!ISALIGNED(stmd)) return ES_EALIGN;
520 if(!ISALIGNED(sticket)) return ES_EALIGN;
521 if(tmd_size > MAX_SIGNED_TMD_SIZE) return ES_EINVAL;
523 p_tmd = SIGNATURE_PAYLOAD(stmd);
525 if(!(keyid_buf = iosAlloc(__es_hid, 4))) return ES_ENOMEM;
526 if(!(hashes = iosAlloc(__es_hid, p_tmd->num_contents*20))) {
527 iosFree(__es_hid, keyid_buf);
528 return ES_ENOMEM;
531 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);
532 if(ret >= 0 && keyid) *keyid = *keyid_buf;
534 iosFree(__es_hid, keyid_buf);
535 iosFree(__es_hid, hashes);
537 if(ret >= 0) {
538 __ES_Close();
539 __ES_Init();
542 return ret;
545 s32 ES_AddTicket(const signed_blob *stik, u32 stik_size, const signed_blob *certificates, u32 certificates_size, const signed_blob *crl, u32 crl_size)
547 s32 ret;
549 if(__es_fd<0) return ES_ENOTINIT;
550 if(stik_size != STD_SIGNED_TIK_SIZE) return ES_EINVAL;
551 if(!stik || !IS_VALID_SIGNATURE(stik)) return ES_EINVAL;
552 if(crl_size && (!crl || !IS_VALID_SIGNATURE(crl))) return ES_EINVAL;
553 if(!__ES_sanity_check_certlist(certificates, certificates_size)) return ES_EINVAL;
554 if(!certificates || !ISALIGNED(certificates)) return ES_EALIGN;
555 if(!ISALIGNED(stik)) return ES_EALIGN;
556 if(!ISALIGNED(certificates)) return ES_EALIGN;
557 if(!ISALIGNED(crl)) return ES_EALIGN;
559 if(!crl_size) crl=NULL;
561 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTICKET, "ddd:", stik, stik_size, certificates, certificates_size, crl, crl_size);
562 return ret;
566 s32 ES_DeleteTicket(const tikview *view)
568 s32 ret;
570 if(__es_fd<0) return ES_ENOTINIT;
571 if(!view) return ES_EINVAL;
572 if(!ISALIGNED(view)) return ES_EALIGN;
573 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETICKET, "d:", view, sizeof(tikview));
574 return ret;
577 s32 ES_AddTitleTMD(const signed_blob *stmd, u32 stmd_size)
579 s32 ret;
581 if(__es_fd<0) return ES_ENOTINIT;
582 if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL;
583 if(stmd_size != SIGNED_TMD_SIZE(stmd)) return ES_EINVAL;
584 if(!ISALIGNED(stmd)) return ES_EALIGN;
586 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTMD, "d:", stmd, stmd_size);
587 return ret;
591 s32 ES_AddTitleStart(const signed_blob *stmd, u32 tmd_size, const signed_blob *certificates, u32 certificates_size, const signed_blob *crl, u32 crl_size)
593 s32 ret;
595 if(__es_fd<0) return ES_ENOTINIT;
596 if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL;
597 if(tmd_size != SIGNED_TMD_SIZE(stmd)) return ES_EINVAL;
598 if(crl_size && (!crl || !IS_VALID_SIGNATURE(crl))) return ES_EINVAL;
599 if(!__ES_sanity_check_certlist(certificates, certificates_size)) return ES_EINVAL;
600 if(!certificates || !ISALIGNED(certificates)) return ES_EALIGN;
601 if(!ISALIGNED(stmd)) return ES_EALIGN;
602 if(!ISALIGNED(certificates)) return ES_EALIGN;
603 if(!ISALIGNED(crl)) return ES_EALIGN;
605 if(!crl_size) crl=NULL;
607 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTITLESTART, "dddi:", stmd, tmd_size, certificates, certificates_size, crl, crl_size, 1);
608 return ret;
611 s32 ES_AddContentStart(u64 titleID, u32 cid)
613 if(__es_fd<0) return ES_ENOTINIT;
614 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDCONTENTSTART, "qi:", titleID, cid);
617 s32 ES_AddContentData(s32 cfd, u8 *data, u32 data_size)
619 if(__es_fd<0) return ES_ENOTINIT;
620 if(cfd<0) return ES_EINVAL;
621 if(!data || !data_size) return ES_EINVAL;
622 if(!ISALIGNED(data)) return ES_EALIGN;
623 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDCONTENTDATA, "id:", cfd, data, data_size);
626 s32 ES_AddContentFinish(u32 cid)
628 if(__es_fd<0) return ES_ENOTINIT;
629 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDCONTENTFINISH, "i:", cid);
632 s32 ES_AddTitleFinish(void)
634 if(__es_fd<0) return ES_ENOTINIT;
635 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTITLEFINISH, "");
638 s32 ES_AddTitleCancel(void)
640 if(__es_fd<0) return ES_ENOTINIT;
641 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDTITLECANCEL, "");
644 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)
646 if(__es_fd<0) return ES_ENOTINIT;
647 if(!tik || !tik_size) return ES_EINVAL;
648 if(!tik_certs || !tik_certs_size) return ES_EINVAL;
649 if(!tmd || !tmd_size) return ES_EINVAL;
650 if(!tmd_certs || !tmd_certs_size) return ES_EINVAL;
651 if(!content || !content_size) return ES_EINVAL;
652 if(!ISALIGNED(tik)) return ES_EALIGN;
653 if(!ISALIGNED(tmd)) return ES_EALIGN;
654 if(!ISALIGNED(tik_certs)) return ES_EALIGN;
655 if(!ISALIGNED(tmd_certs)) return ES_EALIGN;
656 if(!ISALIGNED(content)) return ES_EALIGN;
658 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);
661 s32 ES_OpenContent(u16 index)
663 if(__es_fd<0) return ES_ENOTINIT;
664 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_OPENCONTENT, "i:", index);
667 s32 ES_OpenTitleContent(u64 titleID, tikview *views, u16 index)
669 if(__es_fd<0) return ES_ENOTINIT;
670 if(!ISALIGNED(views)) return ES_EALIGN;
671 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_OPENTITLECONTENT, "qdi:", titleID, views, sizeof(tikview), index);
674 s32 ES_ReadContent(s32 cfd, u8 *data, u32 data_size)
676 if(__es_fd<0) return ES_ENOTINIT;
677 if(cfd<0) return ES_EINVAL;
678 if(!data || !data_size) return ES_EINVAL;
679 if(!ISALIGNED(data)) return ES_EALIGN;
680 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_READCONTENT, "i:d", cfd, data, data_size);
683 s32 ES_SeekContent(s32 cfd, s32 where, s32 whence)
685 if(__es_fd<0) return ES_ENOTINIT;
686 if(cfd<0) return ES_EINVAL;
687 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_SEEKCONTENT, "iii:", cfd, where, whence);
690 s32 ES_CloseContent(s32 cfd)
692 if(__es_fd<0) return ES_ENOTINIT;
693 if(cfd<0) return ES_EINVAL;
694 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_CLOSECONTENT, "i:", cfd);
697 s32 ES_DeleteTitle(u64 titleID)
699 if(__es_fd<0) return ES_ENOTINIT;
700 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETITLE, "q:", titleID);
703 s32 ES_DeleteTitleContent(u64 titleID)
705 if(__es_fd<0) return ES_ENOTINIT;
706 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETITLECONTENT, "q:", titleID);
709 s32 ES_Encrypt(u32 keynum, u8 *iv, u8 *source, u32 size, u8 *dest)
711 if(__es_fd<0) return ES_ENOTINIT;
712 if(!iv || !source || !size || !dest) return ES_EINVAL;
713 if(!ISALIGNED(source) || !ISALIGNED(iv) || !ISALIGNED(dest)) return ES_EALIGN;
714 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ENCRYPT, "idd:dd", keynum, iv, 0x10, source, size, iv, 0x10, dest, size);
717 s32 ES_Decrypt(u32 keynum, u8 *iv, u8 *source, u32 size, u8 *dest)
719 if(__es_fd<0) return ES_ENOTINIT;
720 if(!iv || !source || !size || !dest) return ES_EINVAL;
721 if(!ISALIGNED(source) || !ISALIGNED(iv) || !ISALIGNED(dest)) return ES_EALIGN;
722 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DECRYPT, "idd:dd", keynum, iv, 0x10, source, size, iv, 0x10, dest, size);
725 s32 ES_Sign(u8 *source, u32 size, u8 *sig, u8 *certs)
727 if(__es_fd<0) return ES_ENOTINIT;
728 if(!source || !size || !sig || !certs) return ES_EINVAL;
729 if(!ISALIGNED(source) || !ISALIGNED(sig) || !ISALIGNED(certs)) return ES_EALIGN;
730 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_SIGN, "d:dd", source, size, sig, 0x3C, certs, 0x180);
733 s32 ES_GetDeviceCert(u8 *outbuf)
735 if(__es_fd<0) return ES_ENOTINIT;
736 if(!outbuf) return ES_EINVAL;
737 if(!ISALIGNED(outbuf)) return ES_EALIGN;
738 return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETDEVICECERT, ":d", outbuf, 0x180);
741 s32 ES_GetDeviceID(u32 *device_id)
743 s32 ret;
744 u32 _device_id = 0;
746 if(__es_fd<0) return ES_ENOTINIT;
747 if(!device_id) return ES_EINVAL;
749 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETDEVICEID, ":i", &_device_id);
750 if (ret>=0) *device_id = _device_id;
752 return ret;
755 s32 ES_GetBoot2Version(u32 *version)
757 s32 ret;
758 u32 _version = 0;
760 if(__es_fd<0) return ES_ENOTINIT;
761 if(!version) return ES_EINVAL;
763 ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETBOOT2VERSION, ":i", &_version);
764 if (ret>=0) *version = _version;
766 return ret;
769 // 64k buffer size for alignment
770 #define ES_READ_BUF_SIZE 65536
772 typedef struct {
773 s32 cfd;
774 u64 titleID;
775 tmd_content content;
776 void *iobuf;
777 mutex_t mutex;
778 } es_fd;
780 // valid path formats:
781 // format example description
782 // es:%08x es:00000004 Content index for current title ID
783 // es:ID%08x es:ID00000033 Content ID for current title ID
784 // es:%016llx/%08x es:0000000100000002/00000004 Content index for some title ID (not fully implemented yet)
785 // es:%016llx/ID%08x es:0000000100000002/ID00000033 Content ID for some title ID (not fully implemented yet)
786 // leading zeroes may be omitted, 0x prefix allowed. All numbers in hex.
788 static s32 _ES_decodepath (struct _reent *r, const char *path, u64 *titleID, tmd_content *content)
790 u64 _tid = 0;
791 u32 tmd_size;
792 STACK_ALIGN(u8, _tmdbuf, MAX_SIGNED_TMD_SIZE, 32);
793 signed_blob *_stmd;
794 tmd *_tmd;
795 tmd_content *_contents;
796 tmd_content _content;
797 int is_cid;
798 u32 arg;
799 char *bad;
800 int i;
801 u64 mytid;
803 // check the device
804 if(strncmp(path,"es:",3)) {
805 r->_errno = EINVAL;
806 return -1;
808 path += 3;
810 // Get our Title ID
811 if(ES_GetTitleID(&mytid) < 0) {
812 r->_errno = EIO;
813 return -1;
816 // Read in Title ID, if this is an absolute path
817 if(path[0] == '/') {
818 path++;
819 if(!path[0]) {
820 r->_errno = EINVAL;
821 return -1;
823 r->_errno = 0;
824 _tid = _strtoull_r(r, path, &bad, 16);
825 if(r->_errno) return -1;
826 if((bad == path) || (bad[0] != '/')) {
827 r->_errno = EINVAL;
828 return -1;
830 path = bad + 1;
831 } else {
832 _tid = mytid;
835 // check if path is a content ID
836 if(!strncmp(path,"ID",2)) {
837 path += 2;
838 is_cid = 1;
839 } else {
840 is_cid = 0;
843 // read in the argument (content ID or content index)
844 r->_errno = 0;
845 arg = _strtoul_r(r, path, &bad, 16);
846 if(r->_errno) return -1;
847 if((bad == path) || (bad[0] != 0)) {
848 r->_errno = EINVAL;
849 return -1;
852 // now get the TMD and find the content entry
853 if(ES_GetStoredTMDSize(_tid, &tmd_size) < 0) {
854 r->_errno = ENOENT;
855 return -1;
858 _stmd = (signed_blob*)_tmdbuf;
859 if(ES_GetStoredTMD(_tid, _stmd, tmd_size) < 0) {
860 r->_errno = EIO;
861 return -1;
863 if(!IS_VALID_SIGNATURE(_stmd)) {
864 r->_errno = EIO;
865 return -1;
867 _tmd = SIGNATURE_PAYLOAD(_stmd);
868 _contents = TMD_CONTENTS(_tmd);
870 for(i=0;i<_tmd->num_contents;i++) {
871 if(is_cid) {
872 if(_contents[i].cid == arg) {
873 _content = _contents[i];
874 break;
876 } else {
877 if(_contents[i].index == arg) {
878 _content = _contents[i];
879 break;
883 if(i >= _tmd->num_contents) {
884 r->_errno = ENOENT;
885 return -1;
888 if(titleID) {
889 if(_tid == mytid) *titleID = 0;
890 else *titleID = _tid;
892 if(content) *content = _content;
893 return 0;
896 static int _ES_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) {
897 es_fd *file = (es_fd *) fileStruct;
899 // decode the path
900 if(_ES_decodepath(r, path, &file->titleID, &file->content) < 0) {
901 return -1;
904 // writing not supported
905 if ((flags & 0x03) != O_RDONLY) {
906 r->_errno = EROFS;
907 return -1;
910 // open the content
911 if(file->titleID == 0)
912 file->cfd = ES_OpenContent(file->content.index);
913 else
915 u32 cnt ATTRIBUTE_ALIGN(32);
916 ES_GetNumTicketViews(file->titleID, &cnt);
917 tikview *views = (tikview *)memalign( 32, sizeof(tikview)*cnt );
918 if(views == NULL)
920 return -1;
922 ES_GetTicketViews(file->titleID, views, cnt);
923 file->cfd = ES_OpenTitleContent(file->titleID, views, file->content.index);
924 free(views);
927 if(file->cfd<0) {
928 r->_errno = EIO;
929 return -1;
932 file->iobuf = NULL;
934 LWP_MutexInit(&file->mutex, false);
936 return (int)file;
939 static int _ES_close_r (struct _reent *r, int fd) {
940 es_fd *file = (es_fd *) fd;
942 LWP_MutexLock(file->mutex);
944 if(ES_CloseContent(file->cfd) < 0) {
945 r->_errno = EBADF;
946 return -1;
948 file->cfd = -1;
950 if(file->iobuf) _free_r(r,file->iobuf);
952 LWP_MutexUnlock(file->mutex);
953 LWP_MutexDestroy(file->mutex);
954 return 0;
957 static int _ES_read_r (struct _reent *r, int fd, char *ptr, size_t len) {
958 es_fd *file = (es_fd *) fd;
959 int read = 0;
960 int res;
963 LWP_MutexLock(file->mutex);
964 if(file->cfd < 0) {
965 LWP_MutexUnlock(file->mutex);
966 r->_errno = EBADF;
967 return -1;
970 // if aligned, just pass through the read
971 if(ISALIGNED(ptr))
973 res = ES_ReadContent(file->cfd, (u8*)ptr, len);
974 if(res < 0) {
975 LWP_MutexUnlock(file->mutex);
976 // we don't really know what the error codes mean...
977 r->_errno = EIO;
978 return -1;
980 read = res;
981 // otherwise read in blocks to an aligned buffer
982 } else {
983 int chunk;
984 if(!file->iobuf) {
985 file->iobuf = _memalign_r(r, 32, ES_READ_BUF_SIZE);
986 if(!file->iobuf) {
987 r->_errno = ENOMEM;
988 return -1;
991 while(len) {
992 if(len > ES_READ_BUF_SIZE) chunk = ES_READ_BUF_SIZE;
993 else chunk = len;
994 res = ES_ReadContent(file->cfd, file->iobuf, chunk);
995 if(res < 0) {
996 LWP_MutexUnlock(file->mutex);
997 // we don't really know what the error codes mean...
998 r->_errno = EIO;
999 return -1;
1001 len -= res;
1002 read += res;
1003 memcpy(ptr, file->iobuf, res);
1004 ptr += res;
1005 if(res < chunk) break;
1009 LWP_MutexUnlock(file->mutex);
1010 return read;
1013 static off_t _ES_seek_r (struct _reent *r, int fd, off_t where, int whence) {
1014 es_fd *file = (es_fd *) fd;
1015 s32 res;
1017 LWP_MutexLock(file->mutex);
1018 if(file->cfd < 0) {
1019 LWP_MutexUnlock(file->mutex);
1020 r->_errno = EBADF;
1021 return -1;
1024 res = ES_SeekContent(file->cfd, where, whence);
1025 LWP_MutexUnlock(file->mutex);
1027 if(res < 0) {
1028 r->_errno = EINVAL;
1029 return -1;
1031 return res;
1034 static void _ES_fillstat(u64 titleID, tmd_content *content, struct stat *st) {
1035 memset(st, 0, sizeof(*st));
1036 // the inode is the content ID
1037 // (pretend each Title ID is a different filesystem)
1038 st->st_ino = content->cid;
1039 // st_dev is only a short, so do the best we can and use the middle two letters
1040 // of the title ID if it's not a system content, otherwise use the low 16 bits
1041 if((titleID>>32) == 1)
1042 st->st_dev = titleID & 0xFFFF;
1043 else
1044 st->st_dev = (titleID>>8) & 0xFFFF;
1046 // not necessarily true due to shared contents, but
1047 // we're not going to implement shared content scan here and now
1048 st->st_nlink = 1;
1049 // instead, give the file group read permissions if it's a shared content
1050 st->st_mode = S_IFREG | S_IRUSR;
1051 if(content->type & 0x8000)
1052 st->st_mode |= S_IRGRP;
1054 // use st_dev as a uid too, see above
1055 st->st_uid = st->st_dev;
1056 // no group
1057 st->st_gid = 0;
1058 // content size
1059 st->st_size = content->size;
1060 st->st_blocks = (st->st_size + 511) / 512;
1061 // NAND fs cluster size (not like anyone cares, but...)
1062 st->st_blksize = 16384;
1065 static int _ES_fstat_r (struct _reent *r, int fd, struct stat *st) {
1066 es_fd *file = (es_fd *) fd;
1068 LWP_MutexLock(file->mutex);
1069 if(file->cfd < 0) {
1070 LWP_MutexUnlock(file->mutex);
1071 r->_errno = EBADF;
1072 return -1;
1075 _ES_fillstat(file->titleID, &file->content, st);
1076 LWP_MutexUnlock(file->mutex);
1078 return 0;
1081 static int _ES_stat_r (struct _reent *r, const char *path, struct stat *st) {
1082 tmd_content content;
1083 u64 titleID;
1085 if(_ES_decodepath(r, path, &titleID, &content) < 0) {
1086 return -1;
1088 _ES_fillstat(titleID, &content, st);
1089 return 0;
1092 static const devoptab_t dotab_es = {
1093 "es",
1094 sizeof (es_fd),
1095 _ES_open_r,
1096 _ES_close_r,
1097 NULL,
1098 _ES_read_r,
1099 _ES_seek_r,
1100 _ES_fstat_r,
1101 _ES_stat_r,
1102 NULL,
1103 NULL,
1104 NULL,
1105 NULL,
1106 NULL,
1108 NULL,
1109 NULL,
1110 NULL,
1111 NULL,
1112 NULL
1115 static void __ES_InitFS(void) {
1116 AddDevice(&dotab_es);
1119 static void __ES_DeinitFS(void) {
1120 RemoveDevice("es:");
1123 #endif /* defined(HW_RVL) */