LimHD:DVDCSS
Unfortunately, libdvdcss's csstest program claim all the disks I've tried are not scrambled:
uclibc[/tmp]# ./csstest /dev/scsi/host0/bus0/target0/lun0/cd cool, I found libdvdcss version 1.2.9 examples: ./csstest /dev/hdc 1024 ./csstest D: 1024 ./csstest scrambledfile.vob 1024 uclibc[/tmp]# ./csstest /dev/scsi/host0/bus0/target0/lun0/cd 1024 cool, I found libdvdcss version 1.2.9 requested sector: 00 00 01 2u... 2{ 1i 0� 2e 2� 17 1n 1} 2� 0d 05 1} 2� 09 1� 1� 2s 3g 2� 0l 03 2�... sector is not scrambled uclibc[/tmp]# ./csstest /mnt/USB1/video_ts/vts_01_2.vob 1024 cool, I found libdvdcss version 1.2.9 zS@j>-�301�}�<O2NR���BV1�cn����-�pC>݃�"��?���?��E?��v?��?���?�̂?��E?���?��?���?@j>zS@j>-�30�...<O2NR���BV1�cn����-��?���?��E?��v?��?���?�̂?��E?���?��?���?��"Q sector is not scrambled
Ah just a misunderstanding of how csstest works. That's the block I want to unscramble, and only video streams are scrambled.
uclibc[/tmp]# ./csstest /dev/scsi/host0/bus0/target0/lun0/cd 1000001 cool, I found libdvdcss version 1.2.9 requested sector: 00 00 01 2c... 0� 0� 2� 18 1� 2~ 2� 2� 0� 0} 1w 0� 2� 1p 0g 2 2� 0� 2e 2g 0� 0d 0�... unscrambled sector: 00 00 01 2c... 2� 1� 1s 1z 1� 2 2� 1� 0� 1f 1u 0| 2p 0� 0� 1� 0� 0� 27 0� 13 1l...
So, I remain positive that this can be done. However, since Fuse does not want to run easily, I thought I would attempt to get CSS internal to em8xxx.o to work. All the code is in there, but curacao does not call it, or set it up.
The EM8xxx.PDF file claim to enable DVD-CSS you need but to load the title key with set_CSStitlekey() before demuxing begins.
I thought I would dlopen('em8xxx.o') from my program and call said function, but unfortunately you can not use dlopen in uClinux. (or at least not the version I have / LimHD runs).
So, the proper way is actually to open /dev/em8xxx0 device, and use ioctl to communicate with it. This is what curacao does after all. I have not done much ioctl programming lately, so I am rusty. This is the next thing I shall try however.
My pseudo-code for the daemon would be:
$cd_dev=/dev/scsi/host0/target0/lun0/cd loop forver if $cd_dev has changed (how can we detect a new CD? research) call libdvdread and obtain disckey and titlekey call em8xxx.o via ioctl to hand over both. hope to hell that that just magically works.
Right, so the ioctl looks like:
#define EM8XXX_IOCTL_MAGIC 'E' #define EM8XXX_IOCTL_SET_PROPERTY _IOWR( EM8XXX_IOCTL_MAGIC, 1, struct em8xxx_property) struct em8xxx_property { RMuint32 moduleId; RMuint32 propId; void *propInVal; RMuint32 propInSize; void *propOutVal; RMuint32 propOutSize; RMstatus status; }; RMVideoDecoderPropertyID_CSSdisckey = 6123 0x17eb RMVideoDecoderPropertyID_CSStitlekey = 6124
I am not sure what ModuleId is of yet. It is used when the kernel code calls em8xxx library (private.o).
The documentation on the matter say:
The DVD decryption unit is controlled by 5 registers. The controller register indicates the number of bytes to process, typically 2048 for a DVD sector. If the count is programmed to 4095 (reset value), then the DVD decryption block is transparent. The start indicates how many bytes must be transferred before the decryption begins, typically 128 for a DVD sector. In a 2048-byte encrypted sector, the first 128-byte are clear and the last 1920- byte are encrypted. Before starting the decryption, the 40-bit title key must be pro- grammed in the key registers. The two state registers allow a backup of the decryption block internal state. This is required when a context switch occurs while a DVD sector is only partially processed.
I grabbed a disc and title key from a known disk, wrote a program to issue the ioctl to set the keys, setting moduleId to 0 (what should it be I wonder?) but unfortunately:
uclibc[/tmp]# ./2dvd_em8xxx /dev/em8xxx0 1 ./2dvd_em8xxx: Patch Disc and Title keys into em8xxx.o 1' ... set_CSStitlekey says 0
and then it hangs. Quite peculiar. ioctl actually returns, and successfully at that. And yet the machine dies before the program can exit.
Minor success. Using moduleId of 9 make it do "something". It loads both disckey and titlekey without crashing. Then when I try to play that vts_02_1.vob file it actually starts to play. First frame is perfect. However, play is very jerky (stop/start) and have a lot of macroblocks / corruption. I am used to the video being all "green" when it's encrypted so I am not sure what to think.
My current train of thought is that the DVDRom that I have will not let me read the data without first authenticating with the drive. With all my hacks, I must have eventually done so, which enabled LimHD to attempt to play the DVD. The jerks and corruption could be failure to descramble the blocks, but not all blocks are scrambled.
I am thinking I should call all the ewhlib functions to authenticate the drive now.
But ultimately, if a title changes key in the middle, we have no way to succeed.
Ok, what it comes down to is me authenticating the drive, which lets me play the files. They are not unscrambled so that is why they appear blocky. My loading of CSStitlekey is failing, 99% sure it is due to me not knowing what moduleId to use.
Looking at the assembler inside of em8xxx.o it seems clear that get_CSSchlgkey1 call is propId of 6177. Although, that could be wrong?
loc_15144 LDR R3, =0x1821 CMP R12, R3 BEQ loc_15314 ; getCSSchglkey1 BHI loc_15164 ; test for 0x1824
So, propId is 0x1812 or 6177.
This is all inside the EMhwlibGetDemuxTaskProperty function, which is listed as:
.data:0009985C EMhwlibVtable DCD GetNotFound ; 0 .data:0009985C ; DATA XREF: EMhwlibSetProperty:off_4F20�o .data:0009985C ; EMhwlibGetProperty:off_4FBC�o ... .data:0009985C DCD SetNotFound ; 1 .data:0009985C DCD ExchangeNotFound ; 2 .data:0009985C DCD SendNotFound ; 3 .data:0009985C DCD ReceiveNotFound ; 4 .data:0009985C DCD loc_28+2 ; 483 .data:0009985C DCD EMhwlibGetDemuxTaskProperty; 484 .data:0009985C DCD EMhwlibSetDemuxTaskProperty; 485 .data:0009985C DCD EMhwlibExchangeDemuxTaskProperty; 486
So, the 484th 4-byte entry in the EMhwlibVtable, or byte offset 1936.
The function that loads this up, is called EMhwlibGetProperty and the moduleId is stuffed into R1.
AND R0, R1, #0xFF MOV R3, R1,LSR#8 AND R6, R3, #0xFF MOV R8, R1,LSR#16 CMP R0, #0x3A ; ':' ; Maximum moduleId. So it should be between 0 and 0x3A. BHI loc_4FC0 ; Sets R0 to 0x12 and "returns", ie, failure. LDR R4, =EMhwlibVtable ADD R12, R0, R0,LSL#2 ADD R12, R0, R12,LSL#1 MOV R12, R12,LSL#2 [snip] MOV LR, PC LDR PC, [R4,R12] ; Jump to EMhwlibVtable + value in R12. B loc_4FC4 ; "returns".
By my calculations, using R1 with value 11, makes R12 have 484. However, does LDR take +484 (4 byte pointers) or, should it actually be 1936? If so, R1 needs to be 44. The example sources I have, which we know are already slightly different, has:
DispGFXMultiScaler = 10, DispMainMixer = 12, DispVCRMixer = 13, DemuxEngine = 23, Demux = 24, DemuxProgram = 39, MpegEngine = 25, PLL = 43, DemuxTask = 44, DemuxOutput = 45,
Which makes me think that 44 is a better bet. Now it also uses bits 8-16 for index, and 24-16 as moduleTarget. No idea what they are. Many of the samples use 0 for index.
If I just call get_CSSchlgkey1 it just hangs. But perhaps I should call set_CSSkey1 first.
set_CSSkey1 is at: 0x1822 or 6178. It is in EMhwlibSetDemuxTaskProperty this time. This is at index 485 in EMhwlibVtable. However, EMhwlibSetDemuxTaskProperty loads the address of EMhwLibVtable + 4, which would call Set method instead of Get, with the same moduleId of 44.
The ioctl call is different. Set is 1, Get is 2.
Should we fiddle with the moduleIndex though? Using 1 crashes less than using 0.
Nearly all examples using module DemuxTask uses it like this:
RMuint32 demux_task = EMHWLIB_MODULE(DemuxTask, EMHWLIB_MODULE_INDEX(demux)); EMHWLIB_MODULE_INDEX(RMuint32 ModuleID) { return (ModuleID >> 8) & 0xff; }
Which it seems to get from:
Tasks[i].Spi = FALSE; Tasks[i].SourceType = SourceType_dvd; Tasks[i].Id = i; Tasks[i].dcc_info = &dcc_info; err = RUACreateInstance(&pRUA, play_opt->chip_num); err = DCCOpen(pRUA, &pDCC); err = DCCInitMicroCodeEx(pDCC, DCCInitMode_InitDisplay); /*DCCInitMode_L
eaveDisplay*/
// open & connect Demux and DemuxProgramId. demux_profile.BitstreamFIFOSize = Tasks[i].Spi ? 0:DEMUX_FIFO_SIZE; demux_profile.XferFIFOCount = Tasks[i].Spi ? 0:DEMUX_XFER_FIFO_COUNT; demux_profile.DemuxID = Tasks[i].Id; demux_profile.DemuxProgram0 = i; demux_profile.DemuxProgram1 = 0xff; err = DCCOpenDemuxSource(pDCC, &demux_profile, &pDemuxSource); dcc_info.pDemuxSource = pDemuxSource; err = DCCGetDemuxSourceInfo(pDemuxSource, &(dcc_info.demux), &(dcc_info.demuxProgram0), &(dcc_info.demuxProgram1));
This I do not know about. So clearly there should be a specific value to be used. I'm hoping it is hard-coded/stable enough that I can use a static between firmwares, but it is also possible it is assigned dynamically it order of codecs loaded, or similar.