Changes

1,966 bytes added ,  22:02, 22 January 2018
no edit summary
Line 571: Line 571:     
== Device key generation ==
 
== Device key generation ==
The Falcon device key is generated by reading SOR registers modified by Falcon.
+
The TSEC device key is generated by reading SOR1 registers modified by the Falcon CPU.
 
  // Clear something in unknown host1x channel 0 sync register (HOST1X_SYNC_UNK_300)
 
  // Clear something in unknown host1x channel 0 sync register (HOST1X_SYNC_UNK_300)
 
  // This appears to revoke TSEC's exclusive access to host1x
 
  // This appears to revoke TSEC's exclusive access to host1x
 
  *(u32 *)0x50003300 = 0;
 
  *(u32 *)0x50003300 = 0;
 
   
 
   
  // Generate Falcon device key
+
  // Read TSEC device key
  u32 falcon_device_key[4];  
+
  u32 tsec_device_key[4];  
  falcon_device_key[0] = *(u32 *)NV_SOR_DP_HDCP_BKSV_LSB;
+
  tsec_device_key[0] = *(u32 *)NV_SOR_DP_HDCP_BKSV_LSB;
  falcon_device_key[1] = *(u32 *)NV_SOR_TMDS_HDCP_BKSV_LSB;
+
  tsec_device_key[1] = *(u32 *)NV_SOR_TMDS_HDCP_BKSV_LSB;
  falcon_device_key[2] = *(u32 *)NV_SOR_TMDS_HDCP_CN_MSB;
+
  tsec_device_key[2] = *(u32 *)NV_SOR_TMDS_HDCP_CN_MSB;
  falcon_device_key[3] = *(u32 *)NV_SOR_TMDS_HDCP_CN_LSB;
+
  tsec_device_key[3] = *(u32 *)NV_SOR_TMDS_HDCP_CN_LSB;
 
   
 
   
  // Clear SOR registers
+
  // Clear SOR1 registers
 
  *(u32 *)NV_SOR_DP_HDCP_BKSV_LSB = 0;
 
  *(u32 *)NV_SOR_DP_HDCP_BKSV_LSB = 0;
 
  *(u32 *)NV_SOR_TMDS_HDCP_BKSV_LSB = 0;
 
  *(u32 *)NV_SOR_TMDS_HDCP_BKSV_LSB = 0;
Line 592: Line 592:  
     out_size = 0x10;
 
     out_size = 0x10;
 
   
 
   
  // Copy back the Falcon key
+
  // Copy back the TSEC device key
  memcpy(out_buf, falcon_device_key, out_size);
+
  memcpy(out_buf, tsec_device_key, out_size);
    
== Cleanup ==
 
== Cleanup ==
Line 744: Line 744:  
  }
 
  }
 
   
 
   
  // Write Falcon device key to registers
+
  // Write TSEC device key to registers
 
  set_device_key(key_data_buf);
 
  set_device_key(key_data_buf);
 
   
 
   
 
  return boot_res;
 
  return boot_res;
 +
 +
==== set_device_key ====
 +
This method takes '''key_data_buf''' as argument and writes the TSEC key to SOR1 registers.
 +
// This is TSEC_MMIO + 0x1000 + (0x1C300 / 0x40)
 +
*(u32 *)TSEC_DMA_UNK = 0xFFF;
 +
 +
// Read the key's words
 +
u32 key0 = *(u32 *)(key_data_buf + 0x00);
 +
u32 key1 = *(u32 *)(key_data_buf + 0x04);
 +
u32 key2 = *(u32 *)(key_data_buf + 0x08);
 +
u32 key3 = *(u32 *)(key_data_buf + 0x0C);
 +
 +
u32 result = 0;
 +
 +
// Write to SOR1 register
 +
result = tsec_dma_write(NV_SOR_DP_HDCP_BKSV_LSB, key0);
 +
 +
// Failed to write
 +
if (result)
 +
    return result;
 +
 +
// Write to SOR1 register
 +
result = tsec_dma_write(NV_SOR_TMDS_HDCP_BKSV_LSB, key1);
 +
 +
// Failed to write
 +
if (result)
 +
    return result;
 +
 +
// Write to SOR1 register
 +
result = tsec_dma_write(NV_SOR_TMDS_HDCP_CN_MSB, key2);
 +
 +
// Failed to write
 +
if (result)
 +
    return result;
 +
 +
// Write to SOR1 register
 +
result = tsec_dma_write(NV_SOR_TMDS_HDCP_CN_LSB, key3);
 +
 +
// Failed to write
 +
if (result)
 +
    return result;
 +
 +
return result;
 +
 +
===== tsec_dma_write =====
 +
This method takes '''addr''' and '''value''' as arguments and performs a DMA write using TSEC MMIO.
 +
u32 result = 0;
 +
 +
// Wait for TSEC DMA engine
 +
// This waits for bit 0x0C in TSEC_DMA_CMD to be 0
 +
result = wait_tsec_dma();
 +
 +
// Wait failed
 +
if (result)
 +
    return 1;
 +
 +
// Set the destination address
 +
// This is TSEC_MMIO + 0x1000 + (0x1C100 / 0x40)
 +
*(u32 *)TSEC_DMA_ADDR = addr;
 +
 +
// Set the value
 +
// This is TSEC_MMIO + 0x1000 + (0x1C200 / 0x40)
 +
*(u32 *)TSEC_DMA_VAL = value;
 +
 +
// Start transfer?
 +
// This is TSEC_MMIO + 0x1000 + (0x1C000 / 0x40)
 +
*(u32 *)TSEC_DMA_CMD = 0x800000F2;
 +
 +
// Wait for TSEC DMA engine
 +
// This waits for bit 0x0C in TSEC_DMA_CMD to be 0
 +
result = wait_tsec_dma();
 +
 +
// Wait failed
 +
if (result)
 +
    return 1;
 +
 +
return 0;
    
== Stage 1 ==
 
== Stage 1 ==
Line 763: Line 840:  
   
 
   
 
  // fuc5 crypt cauth instruction
 
  // fuc5 crypt cauth instruction
  // Clear auth_addr
+
  // Clear bit 0x13 in cauth
  cauth(cauth_old & 0x7FFFF);
+
  cauth(cauth_old & ~(1 << 0x13));
 
   
 
   
 
  // Set the target port for memory transfers
 
  // Set the target port for memory transfers
// Target will now be 0 (DMA)
   
  xtargets(0);
 
  xtargets(0);
 
   
 
   
Line 872: Line 948:  
   
 
   
 
  // Compare the hashes
 
  // Compare the hashes
  if (memcmp(sig_key, key_buf + 0x10, 0x10))
+
  if (memcmp(dst_addr, key_buf + 0x10, 0x10))
 
  {
 
  {
 
   res = 0xDEADBEEF;
 
   res = 0xDEADBEEF;
Line 975: Line 1,051:  
  get_seed(seed_buf, type);
 
  get_seed(seed_buf, type);
 
   
 
   
  // This will write the seed into crypt register c0  
+
  // This will write the seed into crypto register c0  
 
  crypt_store(0, seed_buf);
 
  crypt_store(0, seed_buf);
 
   
 
   
 
  // fuc5 csecret instruction
 
  // fuc5 csecret instruction
  // Load selected secret into crypt register c1
+
  // Load selected secret into crypto register c1
 
  csecret(c1, 0x26);
 
  csecret(c1, 0x26);
 
   
 
   
 
  // fuc5 ckeyreg instruction
 
  // fuc5 ckeyreg instruction
  // Binds c1 register as the key for enc/dec operations
+
  // Bind c1 register as the key for enc/dec operations
 
  ckeyreg(c1);
 
  ckeyreg(c1);
 
   
 
   
 
  // fuc5 cenc instruction
 
  // fuc5 cenc instruction
  // Encrypts seed_buf (in c0) using keyreg value as key into c1
+
  // Encrypt seed_buf (in c0) using keyreg value as key into c1
 
  cenc(c1, c0);
 
  cenc(c1, c0);
 
   
 
   
 
  // fuc5 csigenc instruction
 
  // fuc5 csigenc instruction
  // Encrypt code sig with c1 register as key
+
  // Encrypt c1 register with the auth signature stored in c6
 
  csigenc(c1, c1);
 
  csigenc(c1, c1);
 
   
 
   
Line 1,016: Line 1,092:  
  *(u32 *)(buf + 0x0C) = size;
 
  *(u32 *)(buf + 0x0C) = size;
 
   
 
   
  // This will write buf into crypt register c3  
+
  // This will write buf into crypto register c3  
 
  crypt_store(0x03, buf);
 
  crypt_store(0x03, buf);
 
   
 
   
 
  // fuc5 ckeyreg instruction
 
  // fuc5 ckeyreg instruction
  // Binds c4 register (from keygen) as the key for enc/dec operations
+
  // Bind c4 register (from keygen) as the key for enc/dec operations
 
  ckeyreg(c4);
 
  ckeyreg(c4);
 
   
 
   
 
  // fuc5 cenc instruction
 
  // fuc5 cenc instruction
  // Encrypts buf (in c3) using keyreg value as key into c5
+
  // Encrypt buf (in c3) using keyreg value as key into c5
 
  cenc(c5, c3);
 
  cenc(c5, c3);
 
   
 
   
  // This will read into buf from crypt register c5  
+
  // This will read into buf from crypto register c5  
 
  crypt_load(0x05, buf);
 
  crypt_load(0x05, buf);
 
   
 
   
Line 1,049: Line 1,125:  
  if (iv_addr)
 
  if (iv_addr)
 
  {
 
  {
   // This will write the iv_addr into crypt register c5  
+
   // This will write the iv_addr into crypto register c5  
 
   crypt_store(0x05, iv_addr);
 
   crypt_store(0x05, iv_addr);
 
  }
 
  }
Line 1,061: Line 1,137:  
  ckeyreg(c4);
 
  ckeyreg(c4);
 
   
 
   
  // AES-128-ECB? decrypt
+
  // AES-128-ECB decrypt
 
  if (mode == 0x00)
 
  if (mode == 0x00)
 
  {
 
  {
Line 1,073: Line 1,149:  
   cmov(c5, c3);                // Move c3 into c5
 
   cmov(c5, c3);                // Move c3 into c5
 
  }
 
  }
  else if (mode == 0x01) // AES-128-ECB? encrypt
+
  else if (mode == 0x01) // AES-128-ECB encrypt
 
  {
 
  {
 
   // Create crypto script with 4 instructions
 
   // Create crypto script with 4 instructions
Line 1,092: Line 1,168:  
   cenc(c5, c5);                // Encrypt from c5 into c5
 
   cenc(c5, c5);                // Encrypt from c5 into c5
 
  }
 
  }
  else if (mode == 0x03) // AES-128-ECB? decrypt (no IV)
+
  else if (mode == 0x03) // AES-128-ECB decrypt (no IV)
 
  {
 
  {
 
   // Create crypto script with 3 instructions
 
   // Create crypto script with 3 instructions
Line 1,101: Line 1,177:  
   cxsout(c5);                  // Write 0x10 bytes into crypto stream from c5
 
   cxsout(c5);                  // Write 0x10 bytes into crypto stream from c5
 
  }
 
  }
  else if (mode == 0x04) // AES-128-ECB? encrypt (no IV)
+
  else if (mode == 0x04) // AES-128-ECB encrypt (no IV)
 
  {
 
  {
 
   // Create crypto script with 3 instructions
 
   // Create crypto script with 3 instructions
Line 1,176: Line 1,252:  
   // fuc5 crypt cxset instruction
 
   // fuc5 crypt cxset instruction
 
   // The next xfer instruction will be overridden
 
   // The next xfer instruction will be overridden
   // and target changes from DMA to crypto  
+
   // and target changes from DMA to crypto input/output stream
 
   if (crypt_ver == 0x01)
 
   if (crypt_ver == 0x01)
     cxset(0xA1);        // Flag 0xA0 is unknown
+
     cxset(0xA1);        // Flag 0xA0 is (0x80 | 0x20)
 
   else
 
   else
     cxset(0x21);        // Flag 0x20 is unknown
+
     cxset(0x21);        // Flag 0x20 is external mem <-> crypto input/output stream
 
   
 
   
   // Transfer data into the selected crypto register
+
   // Transfer data into the crypto input/output stream
 
   xdst(crypt_xfer_src, crypt_xfer_src);
 
   xdst(crypt_xfer_src, crypt_xfer_src);
 
    
 
    
Line 1,190: Line 1,266:  
       // fuc5 crypt cxset instruction
 
       // fuc5 crypt cxset instruction
 
       // The next xfer instruction will be overridden
 
       // The next xfer instruction will be overridden
       // and target changes from DMA to crypto  
+
       // and target changes from DMA to crypto input/output stream
 
       if (crypt_ver == 0x01)
 
       if (crypt_ver == 0x01)
         cxset(0xA1);    // Flag 0xA0 is unknown
+
         cxset(0xA1);    // Flag 0xA0 is (0x80 | 0x20)
 
       else
 
       else
         cxset(0x21);    // Flag 0x20 is unknown
+
         cxset(0x21);    // Flag 0x20 is external mem <-> crypto input/output stream
 
 
 
 
 
       // Wait for all data loads/stores to finish
 
       // Wait for all data loads/stores to finish
Line 1,203: Line 1,279:  
       // fuc5 crypt cxset instruction
 
       // fuc5 crypt cxset instruction
 
       // The next 2 xfer instructions will be overridden
 
       // The next 2 xfer instructions will be overridden
       // and target changes from DMA to crypto  
+
       // and target changes from DMA to crypto input/output stream
 
       if (crypt_ver == 0x01)
 
       if (crypt_ver == 0x01)
         cxset(0xA2);            // Flag 0xA0 is unknown
+
         cxset(0xA2);            // Flag 0xA0 is (0x80 | 0x20)
 
       else
 
       else
         cxset(0x22);            // Flag 0x20 is unknown
+
         cxset(0x22);            // Flag 0x20 is external mem <-> crypto input/output stream
 
   
 
   
       // Transfer data from the selected crypto register
+
       // Transfer data from the crypto input/output stream
       xdst(crypt_xfer_dst, crypt_xfer_dst);
+
       xdld(crypt_xfer_dst, crypt_xfer_dst);
 
 
 
 
 
       // Wait for all data loads/stores to finish
 
       // Wait for all data loads/stores to finish
Line 1,229: Line 1,305:  
  if (mode == 0x02)
 
  if (mode == 0x02)
 
  {
 
  {
     // This will read into dst_addr from crypt register c5  
+
     // This will read into dst_addr from crypto register c5  
 
     crypt_load(0x05, dst_addr);
 
     crypt_load(0x05, dst_addr);
 
  }
 
  }