Autor Tópico: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR  (Lida 120430 vezes)

0 Membros e 1 Visitante estão vendo este tópico.

Carneiro

  • Visitante

Offline rafael_netto

  • Novato
  • *
  • Mensagens: 19
  • Aprovação: +4/-0
    • Ver Perfil
Re: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR
« Responder #21 Online: Março 08, 2011, 08:15:49 pm »
@rictad saiu a versão com agendamento.
http://www.ivision.net.br/uploads/product/file/ZBT-633/ZBT-633_1.14.4.zim

É bom lembrar que essa versão tem pelo menos um bug, o closed-caption é ativado toda vez que o drive USB é montado.

Enquanto o Rictad não traz novidades, resolvi fazer umas experiências com o Semp, rodando "versões alternativas" do zmw_base_zinwell a partir do pendrive. Não consegui nenhum sucesso. Tendo a versão 1.1.0 instalada, qualquer outra versão, mesmo a 14c do Semp, é interrompida com um erro, e quando isso acontece, mesmo tentar rodar a versão instalada a partir do prompt também dá erro. Felizmente tudo volta ao normal religando o conversor. Só funciona rodar uma cópia da versão que está instalada no conversor.

Ao executar a interface do Rictad, ela chega a mostrar o logo Zinwell (lembrando que o Semp não tem logo). No terminal aparecem mensagens indicando que o tuner não foi encontrado, como era de se esperar, mas ao que parece não é isso que impede a execução.

No fim das contas, eu tinha esperança que alguma configuração do hardware não estivesse no executável da interface e sim em algum outro arquivo, em especial o bcmdriver.ko que vem no mesmo bloco, ou talvez no próprio sistema operacional. Mas parece que não é bem assim.
« Última modificação: Março 08, 2011, 10:48:25 pm por rafael_netto »

FORUM.RYAN.COM.BR

Re: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR
« Responder #21 Online: Março 08, 2011, 08:15:49 pm »

Offline rictad

  • Hacker Honorário
  • Colaboradores
  • Papagaio
  • *
  • Mensagens: 285
  • Aprovação: +59/-0
    • Ver Perfil
Re: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR
« Responder #22 Online: Março 17, 2011, 05:40:54 am »
O MIPS utilizado no STB da Zinwell é um MIPS 32 (aparentemente R1 - revisão 1). Suas instruções são, em geral, de 4 bytes (palavras de 32 bits), mas existem algumas poucas que o IDA mostra como sendo de 8 bytes (2 palavras). As instruções precisam começar em endereços múltiplos de 4, pois são contadas de palavra em palavra. Como o zeurt já explicou acima, é um processador RISC, assim como ARM. A arquitetura RISC tem como algumas características uma quantidade reduzida de instruções e uma tentativa de fazer com que as instruções ocupem o mesmo espaço de memória e levem aproximadamente o mesmo tempo de execução. Isso faz com que um código mais enxuto seja quase sempre mais eficiente. Ao contrário da arquitetura CISC, usada nos x86, às vezes um código mais enxuto pode ser até bem mais lento, apesar de o programador ter um leque de instruções bem mais amplo à sua disposição.

Outra característica do MIPS é que ele é bi-endian: o código pode ser tanto little-endian como big-endian. O endiannes, também chamado de byte sex, neste caso específico, determina como é a ordem de armazenamento na memória dos bytes das palavras. No big-endian, os bytes mais significativos são armazenados primeiro, fazendo com que a referência às palavras no código seja feita na ordem direta. É assim no 8032 usado nos media player Mediatek. Já em um código little-endian, os dados são referenciados na ordem inversa. Então, se você quer guardar o valor 1A124C hexadecimal (0x1A124C) na memória usando um compilador little-endian de palavras de 32 bits, isso será escrito no código hexadecimal como 4C121A00. O ARM usa esse sistema por padrão, apesar de também ser bi-endian.

Bom, o MIPS do Zinwell está em modo little-endian. O compilador que o zeurt indicou acima também parece usar apenas esse modo. Apesar de não ser padrão, parece ser o modo mais utilizado. Nesse modo, o processador também é chamado de mipsel ou mips-ls ou, ainda, mipsl. Isso é importante, pois se mudarmos parte do código ou mesmo parte do sistema Linux embarcado (como eu já fiz e vou divulgar futuramente) devemos manter a arquitetura mipsel. Só daria para deixar em big-endian se mudássemos o sistema inteiro.

Uma outra característica do MIPS é um "cara" chamado delay slot. Achei muito estranho quando analisava algumas rotinas e via que instruções que carregavam valores em registradores localizadas imediatamente após um salto condicional eram executadas mesmo quando o salto era realizado. Como exemplo, temos o seguinte trecho de uma rotina que analisa códigos de tecla dos remotos (vou falar mais sobre essas rotinas depois):

Código: [Selecionar]
            loc_43DF74:                              # CODE XREF: sub_43DC2C+5C_j
.text:0043DF74 26 00 82 10                 beq     $a0, $v0, locret_43E010
.text:0043DF78 00 00 00 00                 nop
.text:0043DF7C C5 3A 02 24                 li      $v0, 0x3AC5
.text:0043DF80 49 FF 82 14                 bne     $a0, $v0, locret_43DCA8
.text:0043DF84 00 00 00 00                 nop
.text:0043DF88 08 00 E0 03                 jr      $ra
.text:0043DF8C 22 00 02 24                 li      $v0, 0x22
.text:0043DF90              # ---------------------------------------------------------------------------
.text:0043DF90
.text:0043DF90             locret_43DF90:                           # CODE XREF: sub_43DC2C:loc_43DDC4_j
.text:0043DF90 08 00 E0 03                 jr      $ra
.text:0043DF94 36 00 02 24                 li      $v0, 0x36

A sexta instrução é um jr (jump register). Ela faz um salto para o endereço guardado no registrador. No caso, $ra é o típico registrador de retorno de sub rotinas do MIPS. Toda vez que fazemos um salto para uma rotina, ele guarda o endereço de retorno em $ra para voltarmos com um jr $ra à rotina principal, no endereço imediatamente posterior ao da chamada. Esse registrador não é pilha. Se você fizer um salto após o outro, apenas será guardado o endereço do último retorno, perdendo-se o anterior. Para saltos recursivos, portanto, é preciso usar a pilha. No caso desta rotina, temos várias saídas possíveis (que vai depender do código de tecla identificado no trecho anterior). A saída leva o código da função identificada carregado em $v0. Mas notem que a instrução de atribuição, li $v0, xx é escrita após o jump. Isso acontece porque o MIPS irá ler a instrução de salto mas, antes de fazer o salto, ainda vai executar a instrução seguinte (e apenas ela). No caso de saltos condicionais, como os dois branchs do início do trecho (beq e bne), a instrução no delay slot será executada de qualquer forma. Daí, quando não se quer levar nenhum conteúdo novo após o salto que possa interferir na execução, usa-se um nop no delay slot. É estranho isso para quem não está acostumado, pois parece que contraria a ordem de execução. Um palpite meu para isso, pois não pesquisei a fundo, é que os saltos levam 3 ciclos do processador para se concretizar, enquanto uma operação store leva 4 ciclos e uma load, 5. Para manter a relação aproximadamente constante entre ciclos e instruções (um dos objetivos da arquitetura RISC), especialmente no caso dos saltos condicionais, optou-se por executar uma instrução a mais antes do salto ser realizado (que também será executada se o salto não for realizado), totalizando 2 instruções e 8 ou 9 ciclos, média de 4 ou 4,5 ciclos por instrução. Esse delay slot é comum em vários processadores RISC, sendo que alguns chegam a ter 2 slots. Mas alguns outros, como é o caso do ARM, não o possui.

Alguns compiladores corrigem a ordem das instruções para o programador não se preocupar com o delay slot. Podemos ver isso nessa dúvida de um programador que foi esclarecida. Também é possível desligar esse reordenamento, já que alguns vão querer programar no modo real. O IDA também tem uma opção "noreorder", que fica selecionada por padrão. Se você alterar essa opção, eu imagino que o código será mostrado na forma "mais humana", como se a instrução do delay slot viesse antes do salto.

Outra característica comum aos processadores RISC é a existência de pseudoinstruções. Uma delas é a "instrução" move $s0, $v0. Significa mover o valor que está no registrador $v0 para o registrador $s0. Mas isso não acontece dessa forma. A instrução real correspondente é add $s0,zero,$v0, que significa somar o valor de $v0 ao valor do registrador especial zero (que sempre tem valor 0) e colocar o resultado em $s0. Nesse caso, não há muitos problemas, pois equivale a apenas uma instrução real. Mas outras pseudoinstruções, como o mult, podem equivaler a várias instruções reais. O padrão do IDA é desassemblar com pseudoinstruções. Deve haver como mudar, mas isso não é importante para nós, já que não estamos preocupados com eficiência máxima.

Além disso tudo, o código MIPS costuma conter uma GOT (global offset table), criada pelos compiladores. É uma tabela anexada ao código que contém os endereços de todas as rotinas internas e também chamadas externas a bibliotecas. Os saltos entre as subrotinas não são referenciados diretamente. Ao contrário, um registrador, chamado $gp (global pointer, às vezes GOT pointer) fica apontando para as entradas da GOT. Quando se deseja saltar para outra rotina, o valor da GOT é carregado em algum registrador temporário, normalmente $t9, e o salto é feito para o endereço guardado nesse registrador. Na nova rotina, $gp é atualizado para apontar às próximas entradas. A vantagem dessa tabela é que permite que o código seja não dependente de posição. Em outras palavras, o código pode ser definido para rodar em outra posição de memória e o compilador apenas atualiza com o mesmo offset todas as entradas na GOT, sem mexer no código das rotinas. A desvantagem é que a desassemblagem fica mais difícil de ler. E aí que entra o script que citei no meu terceiro post do tópico. Ele percorre o código verificando as atualizações em $gp e remarcando os saltos para $t9 com o endereço real da rotina lido da GOT. Por enquanto, isso não é importante para entendermos as rotinas de teclas do controle remoto. Só será necessário para as rotinas do painel frontal. Mais informações sobre a GOT pode sem lidas aqui.

Offline rictad

  • Hacker Honorário
  • Colaboradores
  • Papagaio
  • *
  • Mensagens: 285
  • Aprovação: +59/-0
    • Ver Perfil
Re: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR
« Responder #23 Online: Março 17, 2011, 05:45:50 am »
Rotinas de identificação de teclas do controle remoto

Após abrir o zmw_base_zinwell no IDA, selecionar o processador mipsl e esperar o software percorrer o código e marcar todas as rotinas (demora um pouco), podemos ver que o código é automaticamente endereçado com um offset de 0x400000, pois deve rodar a partir deste endereço na memória. Para uma melhor visualização, é melhor irmos em options, general e colocarmos 8 bytes para o opcode (algumas instruções têm 8 bytes). Para achar as rotinas do controle remoto do ZBT-620A versão 1.7.2, eu primeiro procurei pela sequência de bytes do código mestre do controle, que, como dito nos posts anteriores, é 0x38C7. Como o código é little-endian, devemos procurar pela sequência de bytes (apertando "b") C7 38. A primeira correspondência foi a seguinte:

Código: [Selecionar]
_text:0043E3DC 37 C8 02 34                             li      $v0, 0xC837
_text:0043E3E0 8C 00 82 10                             beq     $a0, $v0, locret_0_43E614

Olhando melhor a rotina, já que isso poderia ser qualquer outra coisa, ainda mais que são apenas 2 bytes, descobri que, coincidentemente, essa é a rotina que analisa a segunda parte do código do remoto, a parte do código das teclas e não o código mestre. Isso aconteceu pois o código para a tecla de navegação direita é 37C8 37C8.  :) A rotina começa em 0x43E28C. Segue o trecho inicial dela:

Código: [Selecionar]
_text:0043E28C                          # inicio interpretacao de teclas do controle remoto
_text:0043E28C
_text:0043E28C                         sub_0_43E28C:                            # DATA XREF: _got:00BC7E30_o
_text:0043E28C 24 20 85 00                             and     $a0, $a1
_text:0043E290 8D 72 02 24                             li      $v0, 0x728D      # tecla canal abaixo
_text:0043E294 37 00 82 10                             beq     $a0, $v0, locret_0_43E374
_text:0043E298 00 00 00 00                             nop
_text:0043E29C 8E 72 82 2C                             sltiu   $v0, $a0, 0x728E
_text:0043E2A0 1B 00 40 10                             beqz    $v0, loc_0_43E310
_text:0043E2A4 4D B2 02 34                             li      $v0, 0xB24D
_text:0043E2A8 CD 32 02 24                             li      $v0, 0x32CD
_text:0043E2AC 59 00 82 10                             beq     $a0, $v0, locret_0_43E414
_text:0043E2B0 00 00 00 00                             nop
_text:0043E2B4 CE 32 82 2C                             sltiu   $v0, $a0, 0x32CE
_text:0043E2B8 30 00 40 10                             beqz    $v0, loc_0_43E37C
_text:0043E2BC AF 50 02 24                             li      $v0, 0x50AF
_text:0043E2C0 E7 18 02 24                             li      $v0, 0x18E7
_text:0043E2C4 89 00 82 10                             beq     $a0, $v0, locret_0_43E4EC
_text:0043E2C8 00 00 00 00                             nop
_text:0043E2CC E8 18 82 2C                             sltiu   $v0, $a0, 0x18E8
_text:0043E2D0 6B 00 40 14                             bnez    $v0, loc_0_43E480
_text:0043E2D4 F5 0A 02 24                             li      $v0, 0xAF5
_text:0043E2D8 D7 28 02 24                             li      $v0, 0x28D7
_text:0043E2DC C3 00 82 10                             beq     $a0, $v0, locret_0_43E5EC
_text:0043E2E0 00 00 00 00                             nop
_text:0043E2E4 D8 28 82 2C                             sltiu   $v0, $a0, 0x28D8
_text:0043E2E8 8D 00 40 10                             beqz    $v0, loc_0_43E520
_text:0043E2EC D5 2A 02 24                             li      $v0, 0x2AD5
_text:0043E2F0 E5 1A 02 24                             li      $v0, 0x1AE5      # tecla arquivo
_text:0043E2F4 D9 00 82 10                             beq     $a0, $v0, locret_0_43E65C
_text:0043E2F8 00 00 00 00                             nop
_text:0043E2FC DF 20 02 24                             li      $v0, 0x20DF
_text:0043E300 76 00 82 10                             beq     $a0, $v0, locret_0_43E4DC
_text:0043E304 00 00 00 00                             nop
_text:0043E308
_text:0043E308                         locret_0_43E308:                         # CODE XREF: sub_0_43E28C+D8_j
_text:0043E308                                                                  # sub_0_43E28C+12C_j ...
_text:0043E308 08 00 E0 03                             jr      $ra
_text:0043E30C 21 10 00 00                             move    $v0, $0
_text:0043E310                          # ---------------------------------------------------------------------------
_text:0043E310
_text:0043E310                         loc_0_43E310:                            # CODE XREF: sub_0_43E28C+14_j
_text:0043E310 42 00 82 10                             beq     $a0, $v0, locret_0_43E41C
_text:0043E314 00 00 00 00                             nop
_text:0043E318 2B 10 44 00                             sltu    $v0, $a0
_text:0043E31C 2A 00 40 14                             bnez    $v0, loc_0_43E3C8
_text:0043E320 1D E2 02 34                             li      $v0, 0xE21D
_text:0043E324 6D 92 02 34                             li      $v0, 0x926D
_text:0043E328 72 00 82 10                             beq     $a0, $v0, locret_0_43E4F4
_text:0043E32C 00 00 00 00                             nop
_text:0043E330 2B 10 44 00                             sltu    $v0, $a0
_text:0043E334 3B 00 40 10                             beqz    $v0, loc_0_43E424
_text:0043E338 85 7A 02 24                             li      $v0, 0x7A85
_text:0043E33C 57 A8 02 34                             li      $v0, 0xA857
_text:0043E340 B6 00 82 10                             beq     $a0, $v0, locret_0_43E61C
_text:0043E344 00 00 00 00                             nop
_text:0043E348 2B 10 44 00                             sltu    $v0, $a0
_text:0043E34C 9E 00 40 14                             bnez    $v0, loc_0_43E5C8
_text:0043E350 55 AA 02 34                             li      $v0, 0xAA55
_text:0043E354 67 98 02 34                             li      $v0, 0x9867
_text:0043E358 CA 00 82 10                             beq     $a0, $v0, locret_0_43E684
_text:0043E35C 00 00 00 00                             nop
_text:0043E360 65 9A 02 34                             li      $v0, 0x9A65
_text:0043E364 E8 FF 82 14                             bne     $a0, $v0, locret_0_43E308
_text:0043E368 00 00 00 00                             nop
_text:0043E36C 08 00 E0 03                             jr      $ra
_text:0043E370 14 00 02 24                             li      $v0, 0x14
_text:0043E374                          # ---------------------------------------------------------------------------

Continuando a pesquisa pela sequência C7 38, a próxima encontrada finalmente estava na rotina que verifica o código mestre e funciona como filtro antes de chamar a rotina que analisa as teclas acima. Eu a chamei de "valida controle", já que é ela que faz a verificação inicial do código do controle antes de repassar para a rotina de interpretação de teclas. Segue início da rotina:

Código: [Selecionar]
_text:0043E694                          # valida controle
_text:0043E694
_text:0043E694                         sub_0_43E694:                            # DATA XREF: _got:00BC61C4_o
_text:0043E694
_text:0043E694                         var_28          = -0x28
_text:0043E694                         var_20          = -0x20
_text:0043E694                         var_1C          = -0x1C
_text:0043E694                         var_18          = -0x18
_text:0043E694                         var_10          = -0x10
_text:0043E694                         var_C           = -0xC
_text:0043E694                         var_8           = -8
_text:0043E694                         arg_57B8        =  0x57B8
_text:0043E694
_text:0043E694 79 00 1C 3C 5C DF 9C 27                 la      $gp, unk_0_78DF5C
_text:0043E69C 21 E0 99 03                             addu    $gp, $t9
_text:0043E6A0 C8 FF BD 27                             addiu   $sp, -0x38
_text:0043E6A4 30 00 BF AF                             sw      $ra, 0x38+var_8($sp)
_text:0043E6A8 2C 00 B1 AF                             sw      $s1, 0x38+var_C($sp)
_text:0043E6AC 28 00 B0 AF                             sw      $s0, 0x38+var_10($sp)
_text:0043E6B0 10 00 BC AF                             sw      $gp, 0x38+var_28($sp)
_text:0043E6B4 3C 80 90 8F                             lw      $s0, -0x7FC4($gp)
_text:0043E6B8
_text:0043E6B8                         loc_0_43E6B8:                            # CODE XREF: sub_0_43E694+C0_j
_text:0043E6B8                                                                  # sub_0_43E694+120_j ...
_text:0043E6B8 94 BE 99 8F                             lw      $t9, -0x416C($gp)
_text:0043E6BC 54 A1 04 8E                             lw      $a0, -0x5EAC($s0)
_text:0043E6C0 1C 00 A5 27                             addiu   $a1, $sp, 0x38+var_1C
_text:0043E6C4 01 00 06 24                             li      $a2, 1
_text:0043E6C8 09 F8 20 03                             jalr    $t9
_text:0043E6CC 20 00 A7 27                             addiu   $a3, $sp, 0x38+var_18
_text:0043E6D0 14 00 40 14                             bnez    $v0, loc_0_43E724
_text:0043E6D4 10 00 BC 8F                             lw      $gp, 0x38+var_28($sp)
_text:0043E6D8
_text:0043E6D8                         loc_0_43E6D8:                            # CODE XREF: sub_0_43E694+88_j
_text:0043E6D8 20 00 A2 8F                             lw      $v0, 0x38+var_18($sp)
_text:0043E6DC 11 00 40 10                             beqz    $v0, loc_0_43E724
_text:0043E6E0 1C 00 A5 8F                             lw      $a1, 0x38+var_1C($sp)
_text:0043E6E4 35 00 A0 04                             bltz    $a1, loc_0_43E7BC
_text:0043E6E8 3C 80 82 8F                             lw      $v0, -0x7FC4($gp)
_text:0043E6EC 3C 80 83 8F                             lw      $v1, -0x7FC4($gp)
_text:0043E6F0 58 A1 40 AC                             sw      $0, -0x5EA8($v0)
_text:0043E6F4
_text:0043E6F4                         loc_0_43E6F4:                            # CODE XREF: sub_0_43E694+144_j
_text:0043E6F4 5C A1 62 8C                             lw      $v0, -0x5EA4($v1)
_text:0043E6F8 0F 00 40 10                             beqz    $v0, loc_0_43E738
_text:0043E6FC 3C 80 82 8F                             lw      $v0, -0x7FC4($gp)
_text:0043E700 94 BE 99 8F                             lw      $t9, -0x416C($gp)
_text:0043E704 54 A1 04 8E                             lw      $a0, -0x5EAC($s0)
_text:0043E708 5C A1 40 AC                             sw      $0, -0x5EA4($v0)
_text:0043E70C 1C 00 A5 27                             addiu   $a1, $sp, 0x38+var_1C
_text:0043E710 01 00 06 24                             li      $a2, 1
_text:0043E714 09 F8 20 03                             jalr    $t9
_text:0043E718 20 00 A7 27                             addiu   $a3, $sp, 0x38+var_18
_text:0043E71C EE FF 40 10                             beqz    $v0, loc_0_43E6D8
_text:0043E720 10 00 BC 8F                             lw      $gp, 0x38+var_28($sp)
_text:0043E724
_text:0043E724                         loc_0_43E724:                            # CODE XREF: sub_0_43E694+3C_j
_text:0043E724                                                                  # sub_0_43E694+48_j
_text:0043E724 30 00 BF 8F                             lw      $ra, 0x38+var_8($sp)
_text:0043E728 2C 00 B1 8F                             lw      $s1, 0x38+var_C($sp)
_text:0043E72C 28 00 B0 8F                             lw      $s0, 0x38+var_10($sp)
_text:0043E730 08 00 E0 03                             jr      $ra
_text:0043E734 38 00 BD 27                             addiu   $sp, 0x38
_text:0043E738                          # ---------------------------------------------------------------------------
_text:0043E738
_text:0043E738                         loc_0_43E738:                            # CODE XREF: sub_0_43E694+64_j
_text:0043E738 24 80 84 8F                             lw      $a0, -0x7FDC($gp)
_text:0043E73C 90 D5 99 8F                             lw      $t9, -0x2A70($gp)
_text:0043E740 09 F8 20 03                             jalr    $t9
_text:0043E744 F0 57 84 24                             addiu   $a0, 0x57F0
_text:0043E748 1E 00 A3 97                             lhu     $v1, 0x38+var_1C+2($sp)  # carrega inicio do código da tecla para conferir controle
_text:0043E74C C7 38 02 24                             li      $v0, 0x38C7      # codigo mestre controle prata
_text:0043E750 FF 7F 63 30                             andi    $v1, 0x7FFF
_text:0043E754 D8 FF 62 14                             bne     $v1, $v0, loc_0_43E6B8
_text:0043E758 10 00 BC 8F                             lw      $gp, 0x38+var_28($sp)
_text:0043E75C 3C 80 91 8F                             lw      $s1, -0x7FC4($gp)
_text:0043E760 D4 B2 99 8F                             lw      $t9, -0x4D2C($gp)
_text:0043E764 18 00 A5 27                             addiu   $a1, $sp, 0x38+var_20
_text:0043E768 09 F8 20 03                             jalr    $t9
_text:0043E76C 50 A1 24 8E                             lw      $a0, -0x5EB0($s1)
_text:0043E770 18 00 A3 8F                             lw      $v1, 0x38+var_20($sp)
_text:0043E774 97 00 63 28                             slti    $v1, 0x97
_text:0043E778 19 00 60 14                             bnez    $v1, loc_0_43E7E0
_text:0043E77C 10 00 BC 8F                             lw      $gp, 0x38+var_28($sp)
_text:0043E780 00 C0 99 8F                             lw      $t9, -0x4000($gp)
_text:0043E784 09 F8 20 03                             jalr    $t9
_text:0043E788 00 00 00 00                             nop
_text:0043E78C 10 00 BC 8F                             lw      $gp, 0x38+var_28($sp)
_text:0043E790 1C 00 A4 8F                             lw      $a0, 0x38+var_1C($sp)  # carrega em $a0 o código da tecla inteiro para ser interpretado.
_text:0043E794 FF FF 05 34                             li      $a1, 0xFFFF      # carrega 0xFFFF em $a1 para o 'and $a0, $a1' na rotina de interpretação
_text:0043E798 40 B8 99 8F                             lw      $t9, -0x47C0($gp)
_text:0043E79C 09 F8 20 03                             jalr    $t9              # chama rotina de interpretação
_text:0043E7A0 50 A1 22 AE                             sw      $v0, -0x5EB0($s1)
_text:0043E7A4 10 00 BC 8F                             lw      $gp, 0x38+var_28($sp)

Essas rotinas funcionam em conjunto. A rotina "valida controle" primeiro acessa o código mestre da tecla e testa para saber se vem do controle remoto certo. Em 0043E748 lhu $v1, 0x38+var_1C+2($sp) , a instrução lhu carrega a meia palavra (half word = 16 bits) em $v1, a partir de um endereço guardado na pilha. Aquela é uma variável de pilha criada pelo IDA. É importante notarmos que a base da variável esta sendo somada a dois. Se quisermos saber o valor correto, basta apertarmos a tecla k para alternarmos a exibição entre valor hexadecimal e variável de pilha do IDA. Assim, temos que a instrução é lhu $v1,0x1E(sp) . Isso é só para ilustrar que o valor carregado, portanto, está na memória, no endereço que está guardado na pilha, apontado por sp+0x1E (offset de 0x1E a partir do stack pointer). É aí que está a primeira parte do código da tecla, que deve ser igual ao código mestre do controle para ser validada. O código total da tecla (32 bits) está a partir de 0x1C (sp). Por isso que a variável de stack, no IDA, estava com +2 de deslocamento. E também por isso foi usado o lhu em 0x1E(sp). Para carregar apenas a meia palavra com o código mestre. Como $v1 é um registrador de 32 bits, seu valor será algo como 0x0000XXXX, em que XXXX é a meia palavra carregada. Em seguida temos 43E74C li $v0, 0x38C7 , que carrega o valor para comparar o código mestre do controle em $v0. Depois, temos um AND do valor que está em v1$ com 0x7FFF (o bit mais significativo ressetado). Isso é para deixar passar também o código mestre quando se mantém a tecla do remoto segurada por mais de 1 segundo (0xB8C7). Somente nesses dois casos o resultado do AND será 0x38C7. Finalmente, ele compara o resultado que está em $v1 com o valor esperado em $v0. (0043E754 bne $v1, $v0, loc_0_43E6B8. Se não for igual, vai embora. Se for, ele irá fazer mais algumas operações, chamar algumas rotinas e, em  0043E790 lw $a0, 0x38+var_1C($sp) ele irá carregar $a0 com a palavra inteira referente ao código de teclas (bastaria a primeira meia palavra, mas o compilador deixou assim). Em seguida, carrega $a1 com 0x0000FFFF para que seja feito um and $a0, $a1 na rotina de análise do código da tecla, que é justamente para eliminar a meia palavra com o código mestre do controle, ficando só o código de 16 bits refente à tecla. Em seguida ele vai na GOT procurar o endereço da rotina de interpretação e carrega o seu valor em $t9, fazendo o salto em 43E79C jalr $t9 . Descobrir que esse é o salto para a outra rotina dependeu de intuição e testes, já que ainda não conhecia o mips-analyser. O fato de que a rotina de interpretação começa justamente com um AND entre os dois últimos registradores ($a0 e $a1) foi decisivo. Só para adiantar como fica mais fácil a visualização com o mips-analyser (que eu vou explicar em outro post), segue o mesmo trecho após rodar o script:

Código: [Selecionar]
.text:0043E738                         loc_43E738:                              # CODE XREF: sub_43E694+64_j
.text:0043E738 24 80 84 8F                             lw      $a0, offset aKeyX  # "key %x\n"
.text:0043E73C 90 D5 99 8F                             lw      $t9, offset sub_65CCE0
.text:0043E740 09 F8 20 03                             jalr    $t9
.text:0043E744 F0 57 84 24                             addiu   $a0, 0x57F0      # "key %x\n"
.text:0043E748 1E 00 A3 97                             lhu     $v1, 0x38+var_1C+2($sp)
.text:0043E74C C7 38 02 24                             li      $v0, 0x38C7
.text:0043E750 FF 7F 63 30                             andi    $v1, 0x7FFF
.text:0043E754 D8 FF 62 14                             bne     $v1, $v0, loc_43E6B8
.text:0043E758 10 00 BC 8F                             lw      $gp, 0x38+var_28($sp)
.text:0043E75C 3C 80 91 8F                             lw      $s1, 0xbda150
.text:0043E760 D4 B2 99 8F                             lw      $t9, offset sub_4504C0
.text:0043E764 18 00 A5 27                             addiu   $a1, $sp, 0x38+var_20
.text:0043E768 09 F8 20 03                             jalr    $t9
.text:0043E76C 50 A1 24 8E                             lw      $a0, -0x5EB0($s1)
.text:0043E770 18 00 A3 8F                             lw      $v1, 0x38+var_20($sp)
.text:0043E774 97 00 63 28                             slti    $v1, 0x97
.text:0043E778 19 00 60 14                             bnez    $v1, loc_43E7E0
.text:0043E77C 10 00 BC 8F                             lw      $gp, 0x38+var_28($sp)
.text:0043E780 00 C0 99 8F                             lw      $t9, offset sub_43C788
.text:0043E784 09 F8 20 03                             jalr    $t9
.text:0043E788 00 00 00 00                             nop
.text:0043E78C 10 00 BC 8F                             lw      $gp, 0x38+var_28($sp)
.text:0043E790 1C 00 A4 8F                             lw      $a0, 0x38+var_1C($sp)
.text:0043E794 FF FF 05 34                             li      $a1, 0xFFFF
.text:0043E798 40 B8 99 8F                             lw      $t9, offset sub_43E28C
.text:0043E79C 09 F8 20 03                             jalr    $t9

Agora, indo para a rotina de interpretação, vemos o AND citado anteriormente sendo realizado em 0x43E28C. Em seguida, em $v0 é carregado o código da tecla "canal menos". Ele compara o valor com $a0 e, se for igual, salta para locret_0_43E374 (observe o NOP logo abaixo do salto, no delay slot). Em 0x43E374, temos um jump de retorno, com a instrução li $v0, 0x24 no delay slot. Quer dizer que a rotina devolverá o valor 0x24 (código da função) em $v0, caso a tecla "canal menos" seja pressionada. Caso essa não seja a tecla pressionada, demais comparações são feitas, buscando-se outras teclas. A maior parte das comparações são feitas como a anterior. Carrega-se o valor que se quer comparar em $v0 e depois compara-se com o valor de $a0. Mas algumas são realizadas entre operações matemáticas especiais de rotação de bits. Isso é feito automaticamente pelo compilador, quando possível, para tentar enxugar o código.

Então, praticamente é isso. Uma rotina que filtra o código mestre antes de repassar o código inteiro a outra que retira o código mestre e analisa o código restante procurando códigos de teclas e devolvendo o valor da função correspondente. Ao final, se o controle for reconhecido mas nenhuma tecla for, a rotina sai em 43E30C move $v0, $0 com o valor 0 em $v0. Esse não é o final da rotina, as demais saídas estão após esta, devido a saltos internos.

Procurei as mesmas rotinas no zmw_base_zinwell versão 1.13.6 do ZBT-633. Buscando os bytes 9F 00 02 24 (procurar o mesma instrução li da rotina "valida controle" do outro aparelho, mas agora com o código mestre do controle preto, ou seja, li $v0, 9F . Nessa outra versão, a rotina pode ser encontrada em sub_0_43A5A8. O trecho que nos interessa é este:

Código: [Selecionar]
_text:0043A65C                         loc_0_43A65C:                            # CODE XREF: sub_0_43A5A8+6C_j
_text:0043A65C 28 80 84 8F                             lw      $a0, -0x7FD8($gp)
_text:0043A660 28 8A 99 8F                             lw      $t9, -0x75D8($gp)
_text:0043A664 09 F8 20 03                             jalr    $t9
_text:0043A668 50 76 84 24                             addiu   $a0, 0x7650
_text:0043A66C 1E 00 A3 97                             lhu     $v1, 0x40+var_24+2($sp)  # carrega inicio do código da tecla para conferir controle
_text:0043A670 9F 00 02 24                             li      $v0, 0x9F        # codigo mestre do controle preto
_text:0043A674 FF 7F 63 30                             andi    $v1, 0x7FFF
_text:0043A678 D6 FF 62 14                             bne     $v1, $v0, loc_0_43A5D4
_text:0043A67C 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
_text:0043A680 2C 80 93 8F                             lw      $s3, -0x7FD4($gp)
_text:0043A684 CC A2 99 8F                             lw      $t9, -0x5D34($gp)
_text:0043A688 18 00 A5 27                             addiu   $a1, $sp, 0x40+var_28
_text:0043A68C 2C 80 92 8F                             lw      $s2, -0x7FD4($gp)
_text:0043A690 09 F8 20 03                             jalr    $t9
_text:0043A694 30 30 64 8E                             lw      $a0, 0x3030($s3)
_text:0043A698 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
_text:0043A69C 1C 00 A4 8F                             lw      $a0, 0x40+var_24($sp)  # carrega código inteiro da tecla para ser interpretado.
_text:0043A6A0 9C A1 99 8F                             lw      $t9, -0x5E64($gp)
_text:0043A6A4 09 F8 20 03                             jalr    $t9              # chama rotina de interpretação
_text:0043A6A8 FF FF 05 34                             li      $a1, 0xFFFF      # carrega a1 para o "and a0, a1" na rotina de interpretação
_text:0043A6AC 21 80 40 00                             move    $s0, $v0
_text:0043A6B0 18 00 A2 8F                             lw      $v0, 0x40+var_28($sp)
_text:0043A6B4 5E 01 42 28                             slti    $v0, 0x15E
_text:0043A6B8 04 00 40 10                             beqz    $v0, loc_0_43A6CC
_text:0043A6BC 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)

E a rotina que verifica os códigos de teclas começa em sub_0_43A18C. Foi possível achá-la buscando algum código de tecla final do controle preto em instruções similares às da rotina do controle prateado. O importante nela foi verificar se os códigos de retorno das funções das teclas ainda são os mesmos. E são.

Assim, o que eu fiz foi criar minha própria rotina no zmw_base_zinwell do ZBT-633 para verificar as teclas dos três controles (o preto, o prateado e o da Samsung). Tive que achar um lugar vazio no binário para colocá-la, depois modificar o filtro do código mestre na rotina "valida controle" e, por fim, alterar na GOT o apontamento para o endereço da rotina de verificação, da rotina antiga para a nova.

Primeiro, achei uma região vazia no código (com vários zeros) grande o suficiente para inserir algumas rotinas. No código hexadecimal puro (sem o offset de 0x400000), este espaço começa em 0x389165. Mas como as rotinas devem começar em endereços múltiplos de 4 (e também para garantir realmente estar num local vazio) marquei para começar a nova rotina em 0x389170 (que é 0x789170 na memória).

Antes de fazer a nova rotina, fiz as alterações na rotina "valida controle". A primeira delas foi no filtro. Antes o filtro era assim, como mostrado anteriormente:

Código: [Selecionar]
_text:0043E75C 1E 00 A3 97                             lhu     $v1, 0x38+var_1C+2($sp)  # carrega inicio do código da tecla para conferir controle
_text:0043E760 9F 00 02 24                             li      $v0, 0x9F        # inicio codigo controle preto
_text:0043E764 FF 7F 63 30                             andi    $v1, 0x7FFF
_text:0043E768 D8 FF 62 14                             bne     $v1, $v0, loc_0_43E6CC/code]

Pela forma como eu implementei a nova rotina de análise de teclas, bastaria ter eliminado esse trecho colocando 4 NOPs. Como não sabia como seria a nova rotina, acabei implementando um filtro que ficou redundante. Na próxima versão do firmware eu vou eliminá-lo. Mas o filtro redundante ficou assim:

[code].text:0043A66C 1E 00 A3 97                             lhu     $v1, 0x40+var_24+2($sp)
.text:0043A670 85 00 02 24                             li      $v0, 0x85
.text:0043A674 85 47 63 30                             andi    $v1, 0x4785
.text:0043A678 D6 FF 62 14                             bne     $v1, $v0, loc_43A5D4

Como os códigos mestres permitidos agora são B8C7 e 38C7 (controle prata, mantendo e não mantendo a tecla pressionada por mais de 1 segundo), 809F e 009F (controle preto, idem) e B0FD e 30FD (controle samsung), fiz alguns ANDs com os bits desses códigos. O resultado é que se fizermos um AND entre qualquer um desses códigos e 0x4785, o resultado será 0x85. Mas esse filtro meia boca que eu fiz acaba permitindo outros códigos passarem, o que poderia fazer com que outros controles remotos interferissem no funcionamento do STB. Além disso, os próprios controles possuem alguns códigos de teclas trocados entre si. Por exemplo, a tecla numérica 2 no controle prateado tem código 38C7 906F. Já a tecla 1 do controle preto tem código 009F 906F. Então, esse filtro não resolveria esse conflito se apenas deixasse passar ambos os códigos. A solução foi fazer um filtro determinístico no início da nova rotina (como veremos a seguir), o que acabou por fazer esse filtro redundante (mas que eu esqueci de retirar).

A segunda modificação nessa rotina é mais importante:

Código: [Selecionar]
_text:0043A69C 1C 00 A4 97                             lhu     $a0, 0x40+var_24($sp)
.text:0043A6A0 9C A1 99 8F                             lw      $t9, -0x5E64($gp)
.text:0043A6A4 09 F8 20 03                             jalr    $t9
.text:0043A6A8 1E 00 A5 97                             lhu     $a1, 0x40+var_24+2($sp)

As mudanças são os dois lhu. O primeiro guarda a meia palavra referente ao código individual da tecla em $a0 e o segundo, no delay slot, guarda o código mestre em $a1 antes do salto para $t9 (rotina de análise das teclas) ser realizado.

Após isso, modifiquei o apontamento na GOT para o início da nova rotina de análise. Se originalmente a rotina começava em sub_0_43A18C, fiz uma busca binária pelos bytes 8C A1 43 00 (os endereços são de 32 bits) e achei em _got:00BAF84C a entrada apontando para a rotina. Em um editor hexadecimal, se procurarmos pela sequência, encontraremos no endereço 0x7ABB7C. Além do offset de 0x400000, há um outro offset de mais 0x3CD0 na GOT. Não pesquisei o porquê disso. Mas foi só alterar essa sequência para 70 91 78 00 (0x789170) para apontar para o início da nova rotina.

Por fim, a nova rotina foi feita em parte digitando diretamente no editor hexadecimal e em parte copiando e colando trechos das rotinas originals do ZBT-620A e 633, sem ajuda de compilador, a partir do endereço 0x389170 (devido ao offset de 0x400000). Como as instrução são simples (eu não procurei nenhum tipo de otimização) e os opcodes puderam ser encontrados buscando instruções idênticas no próprio código aberto no IDA, não tive muitos problemas. Basicamente, a rotina analisa o que foi repassado em $a1 para saber de qual controle se trata (filtro determinístico). Se não for nenhum código mestre esperado, ela retorna sem nada. Se for, é chamado o desvio para analisar as teclas de cada controle. Segue o início e o fim da rotina, pois é enorme:

Código: [Selecionar]
_rodata:00789170                         loc_0_789170:                            # DATA XREF: _got:00BAF84C_o
_rodata:00789170 FD 30 02 24                             li      $v0, 0x30FD
_rodata:00789174 14 02 A2 10                             beq     $a1, $v0, loc_0_7899C8
_rodata:00789178 FD B0 02 34                             li      $v0, 0xB0FD
_rodata:0078917C 6A 02 A2 10                             beq     $a1, $v0, loc_0_789B28
_rodata:00789180 00 00 00 00                             nop
_rodata:00789184 FF 7F A5 30                             andi    $a1, 0x7FFF
_rodata:00789188 9F 00 02 24                             li      $v0, 0x9F
_rodata:0078918C 05 00 A2 10                             beq     $a1, $v0, loc_0_7891A4
_rodata:00789190 C7 38 02 24                             li      $v0, 0x38C7
_rodata:00789194 0A 01 A2 10                             beq     $a1, $v0, loc_0_7895C0
_rodata:00789198 00 00 00 00                             nop
_rodata:0078919C 08 00 E0 03                             jr      $ra
_rodata:007891A0 21 10 00 00                             move    $v0, $0
_rodata:007891A4                          # ---------------------------------------------------------------------------
_rodata:007891A4
_rodata:007891A4                         loc_0_7891A4:                            # CODE XREF: _rodata:0078918C_j
_rodata:007891A4 65 9A 02 34                             li      $v0, 0x9A65
_rodata:007891A8 37 00 82 10                             beq     $a0, $v0, locret_0_789288
_rodata:007891AC 00 00 00 00                             nop
_rodata:007891B0 2B 10 44 00                             sltu    $v0, $a0
_rodata:007891B4 1B 00 40 14                             bnez    $v0, loc_0_789224
_rodata:007891B8 1D E2 02 34                             li      $v0, 0xE21D
_rodata:007891BC B7 48 02 24                             li      $v0, 0x48B7
_rodata:007891C0 59 00 82 10                             beq     $a0, $v0, locret_0_789328
_rodata:007891C4 00 00 00 00                             nop
_rodata:007891C8 B8 48 82 2C                             sltiu   $v0, $a0, 0x48B8
_rodata:007891CC
_rodata:007891CC                         loc_0_7891CC:                            # DATA XREF: sub_0_42C4E4_o
_rodata:007891CC 30 00 40 10                             beqz    $v0, loc_0_789290
_rodata:007891D0 8D 72 02 24                             li      $v0, 0x728D
_rodata:007891D4 ED 12 02 24                             li      $v0, 0x12ED
_rodata:007891D8 8E 00 82 10                             beq     $a0, $v0, locret_0_789414
_rodata:007891DC 00 00 00 00                             nop
_rodata:007891E0 EE 12 82 2C                             sltiu   $v0, $a0, 0x12EE
_rodata:007891E4 6E 00 40 14                             bnez    $v0, loc_0_7893A0
_rodata:007891E8 FD 02 02 24                             li      $v0, 0x2FD
_rodata:007891EC CF 30 02 24                             li      $v0, 0x30CF
_rodata:007891F0 D2 00 82 10                             beq     $a0, $v0, locret_0_78953C
_rodata:007891F4 00 00 00 00                             nop
_rodata:007891F8 D0 30 82 2C                             sltiu   $v0, $a0, 0x30D0
_rodata:007891FC BA 00 40 10                             beqz    $v0, loc_0_7894E8
_rodata:00789200 C7 38 02 24                             li      $v0, 0x38C7
_rodata:00789204 E5 1A 02 24                             li      $v0, 0x1AE5
_rodata:00789208 E0 00 82 10                             beq     $a0, $v0, locret_0_78958C
_rodata:0078920C 00 00 00 00                             nop
_rodata:00789210 D7 28 02 24                             li      $v0, 0x28D7
_rodata:00789214 79 00 82 10                             beq     $a0, $v0, locret_0_7893FC
_rodata:00789218 00 00 00 00                             nop
_rodata:0078921C
_rodata:0078921C                         locret_0_78921C:                         # CODE XREF: _rodata:00789278_j
_rodata:0078921C                                                                  # _rodata:007892CC_j ...
_rodata:0078921C 08 00 E0 03                             jr      $ra
_rodata:00789220 21 10 00 00                             move    $v0, $0
_rodata:00789224                          # ---------------------------------------------------------------------------
..........................
..........................
..........................
_rodata:00789BD4
_rodata:00789BD4                         locret_0_789BD4:                         # CODE XREF: _rodata:00789B6C_j
_rodata:00789BD4 08 00 E0 03                             jr      $ra
_rodata:00789BD8 25 00 02 24                             li      $v0, 0x25
_rodata:00789BDC                          # ---------------------------------------------------------------------------
_rodata:00789BDC
_rodata:00789BDC                         locret_0_789BDC:                         # CODE XREF: _rodata:00789B74_j
_rodata:00789BDC 08 00 E0 03                             jr      $ra
_rodata:00789BE0 24 00 02 24                             li      $v0, 0x24
_rodata:00789BE4                          # ---------------------------------------------------------------------------
_rodata:00789BE4
_rodata:00789BE4                         locret_0_789BE4:                         # CODE XREF: _rodata:00789B7C_j
_rodata:00789BE4 08 00 E0 03                             jr      $ra
_rodata:00789BE8 43 00 02 24                             li      $v0, 0x43
_rodata:00789BEC                          # ---------------------------------------------------------------------------
_rodata:00789BEC
_rodata:00789BEC                         locret_0_789BEC:                         # CODE XREF: _rodata:00789B84_j
_rodata:00789BEC 08 00 E0 03                             jr      $ra
_rodata:00789BF0 40 00 02 24                             li      $v0, 0x40

Agora estão faltando as rotinas de inicialização do painel frontal. Para essas, é importante explicar como usar e instalar o mips-analyser que eu citei no meu terceiro post. Vou fazer isso com mais calma depois.
« Última modificação: Março 17, 2011, 05:52:01 am por rictad »

Offline rictad

  • Hacker Honorário
  • Colaboradores
  • Papagaio
  • *
  • Mensagens: 285
  • Aprovação: +59/-0
    • Ver Perfil
Re: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR
« Responder #24 Online: Março 17, 2011, 06:39:50 am »
Sobre a nova versão 1.14.4 com PVR e agendamento

Exatamente como eu vi em alguns relatos espalhados pela rede, essa versão tem um bug que liga o closed caption (CC) quando você conecta alguma coisa na porta USB. Esse seria apenas um pequeno bug inconveniente se não houvesse outro mais perigoso atrelado, que eu verifiquei. Quando o CC está ligado, o progresso de atualização de firmware some da tela em menos de 1 segundo (só reaparece se alguma legenda de CC é apresentada, alternando junto com ela). Então, se o usuário instalar a versão 1.14.4 e for fazer uma nova atualização no futuro, quando ele conectar o pendrive, o CC será ativado. Quando a atualização começar (e se não tiver passando nada na TV com closed caption), a tela de atualização irá sumir, mas a atualização continuará sendo feita! O usuário, sem saber o que está acontecendo, pode acabar desligando o STB antes da atualização acabar e matar o aparelho. Por isso, apesar de já ter feito as primeiras alterações para esta nova versão, só vou publicá-la se conseguir resolver este bug.

Mini modo de desenvolvimento

Além de adaptar essa nova versão para o ZBT-620A "tijolão", eu criei um mini modo de desenvolvimento de firmware por USB. Entre os principais recursos desse modo está a capacidade de se testar um binário zmw_base_zinwell gravado em uma pasta específica no pendrive, sem precisar gravar nada na flash antes e, portanto, com total segurança. O script bash que criei detecta o binário e o executa para testar.

Outras funções automáticas, que dependerão de uma determinada estrutura de pastas pré-criada no pendrive, são:
  • Copiar o conteúdo do bloco code montado no Linux para o pendrive, para poder ser modificado;
  • Criar uma imagem squashfs compatível com o aparelho, a partir dos arquivos contidos em uma determinada pasta;
  • Montar uma imagem squashfs de um bloco code modificado e testar o binário zmw_base_zinwell de dentro do bloco para saber se o mesmo foi criado de forma compatível;
  • Extrair o conteúdo de uma imagem squashfs compatível que esteja no pendrive;
  • Registrar todas as operações em uma arquivo de log.

Para fazer isso eu criei um novo sistema de arquivos raiz com uma nova compilação cruzada para mipsel (cross-compile) usando o buildroot. Com isso, incluí também a capacidade do STB formatar em FAT32 (pois compilei o pacote dosfstools). Mas não tentei alterar o padrão de formatação, que continua em ext3. Não sei se é possível, mas acho que é.

Tentativa de por suporte a NTFS

Porém, a ideia mesmo é tentar colocar NTFS no futuro. Ele já formata em NTFS (pacote ntfsprogs compilado). O problema é montar e utilizar um disco NTFS, pois precisaria compilar o ntfs-3g e o fuse, e isso é mais difícil. Além do ntfs-3g ser grandinho, o que dificulta pelo tamanho da flash, o fuse depende do Kernel e não consegui recompilar o Kernel, nem com o buildroot. Isso porque essa máquina tem algumas características de hardware específicas que parecem não estarem disponíveis para configuração no código fonte do Kernel, dependendo de patchs. O código fonte específico para o STB eu até consegui, mas é um Kernel muito antigo (2.6.12-4.0-brcmstb), que não tem suporte ao fuse. É possível injetar o fuse nesse Kernel, mas fazer o cross-compile assim é mais difícil. Também fazer uma compilação de um módulo fuse externo seria interessante. Até consegui compilar o fuse (os binários), mas o módulo por cross-compile não sai. Então, ainda estou tentando. E acho que é possível. STB Zinwell com suporte a NTFS.
« Última modificação: Março 17, 2011, 06:51:06 am por rictad »

Offline rictad

  • Hacker Honorário
  • Colaboradores
  • Papagaio
  • *
  • Mensagens: 285
  • Aprovação: +59/-0
    • Ver Perfil
Re: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR
« Responder #25 Online: Março 17, 2011, 09:03:21 pm »
Rafael,

Eu gostaria de começar a procurar as rotinas do sintonizador também, pois é algo que me interessa. Você chegou a repassar isso aqui para mim:

Citação de: rafael_netto
Eu reparei que existem referências a vários tuners, tanto no Zinwell quanto no Semp.

Isso pode nos ajudar. Como você verificou essas referências?


Offline rafael_netto

  • Novato
  • *
  • Mensagens: 19
  • Aprovação: +4/-0
    • Ver Perfil
Re: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR
« Responder #26 Online: Março 18, 2011, 12:31:54 am »
Vamos lá.

O único recurso que eu tenho é tentar correlacionar as mensagens que saem no terminal com o que aparece no código do software.
(aliás, no IDA 5.5 o disassembly já vem identificado, dispensando o mips-analyser que eu nem descobri como instalar)

Durante o boot, o Semp apresenta estas mensagens relacionadas ao tuner:
Código: [Selecionar]
task_create out tuner 6151
^@task_create out uartrx 7176
flash size = 8192KB
HDCPKey MagicWord = 00
Demod. I2C Device 0x30 and tuner 0xC2 via 0xFE detected, install TC90512 driver, DemodHandle = 0
tc90512 Initialising
config graphics 0
zw_tuner_halInit -> 0x11

E quando muda de canal (seja assistindo, ou nas telas de sintonia) as mensagens são assim:
Código: [Selecionar]
tc90512-> Tune to channel, frequency=563143 KHz
Writing RF = 563143
Set Frequency : Write tuner sequence = 0x10 0x9a 0xc1 0xa4 0x80
[TUNER]zw_frontend_VA6009Read=0x54 , fStatus=0
Tuner(0x11) PLL locked

Eu entendi que existem duas configurações de hardware ligadas ao sintonizador, que eu chamei de "driver" (o que aparece nas mensagens "Initialising" e "Tune to channel") e o que eu chamei de "frontend" (que aparece nas mensagens "[TUNER]zw_frontend...")

Acontece que procurando no código por estes termos, encontrei outras mensagens semelhantes, se referindo a outros tuners:
Código: [Selecionar]
.rodata:0066C058 aTunerZw_fronte:.ascii "[TUNER]zw_frontend_VA6009Read=0x%x , fStatus=%d\n"<0>

.rodata:0066EBF8 aTunerZw_fron_5:.ascii "[TUNER]zw_frontend_ED6084Read=0x%x , fStatus=%d\n"<0>

.rodata:0066B1D8 aTc90512TuneToC:.ascii "tc90512-> Tune to channel, frequency=%d KHz \n"<0>

.rodata:0066AE30 aCk451TuneToCha:.ascii "ck451-> Tune to channel, frequency=%d KHz \n"<0>

Assim, o software do Semp contém o seguinte:

"Driver"
TC90512
TC90507
CK451

"Frontend"
VA6009
ED6084
TD1311
EF2092
EF2093
TD1616
MAX3580

O Semp DC2008H usa o "driver" TC90512 e o "frontend" VA6009. Mas todos os outros também são mencionados no código executável, não apenas na área de dados.

UPDATE: Olhando com um pouco mais de cuidado verifiquei que no código do Semp existem referências a mais dispositivos ainda, mas as mensagens são ligeiramente diferentes, ex:
"Found CX24116 at i2c bus %d address 0x%x\n
"Found LNBP21 at bus %d address %x\n"
"LGS8913_tuneToSignal -> frequency = %d KHz\n"

Enquanto isso, quando eu tentei rodar o firmware do Zinwell/Rictad observei isto:
Código: [Selecionar]
task_create out tuner 6151
zw_uart7401_init channel A, baud = 9600
zw_uart7401_init channel B, baud = 115200
zw_uart7401_init done
boot time till here (io init done) 504
boot time till here (av hal init done) 641
>> zw_frontend_init -->
zw_tc90517_register
        Read TC90517 register C5h:  0
TC90517 not found!
zw_tc90507_register
TC90507 not found!
Error: No tuner installed ...

Ao que parece ele procura pelos "drivers" TC90517 e TC90507 e, não encontrando, desiste.

Buscando no código encontrei mensagens semelhantes às do Semp, apenas para estes dois "drivers":
Código: [Selecionar]
0675DC0 aTc90507TuneToC:.ascii "tc90507-> Tune to channel, frequency=%d KHz \n"<0>

.rodata:00675BD4 aZw_tc90517_tun:.ascii "zw_tc90517_tuneToChannel ( %d )\n"<0>

Quanto ao "frontend" procurei pelas mensagens semelhantes e encontrei apenas o TD1311:
Código: [Selecionar]
.rodata:00676880 aTunerZw_fronte:.ascii "[TUNER]zw_frontend_TD1311Read=0x%x , fStatus=%d\n"<0>

Portanto os dois softwares são a princípio incompatíveis, pois o Zinwell não possui a combinação "driver" + "frontend" necessária para o Semp e vice-versa. No entanto o Semp aparentemente possui apenas o "driver" equivalente ao Zinwell (TC90507), talvez seja um bom ponto de partida.
« Última modificação: Março 18, 2011, 03:17:40 am por rafael_netto »

Offline rafael_netto

  • Novato
  • *
  • Mensagens: 19
  • Aprovação: +4/-0
    • Ver Perfil
Re: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR
« Responder #27 Online: Março 18, 2011, 12:50:21 am »
Pesquisando um pouco mais verifiquei que TC90507, TC90517 e TC90512 são demoduladores OFDM da Toshiba. Dos três, o TC90512 (o do Semp) trabalha também com satélite (ISDB-S), os outros apenas com ISDB-T.

Quanto aos "frontend"

TD1311 e TD1616: (aparentemente) tuners DVB-T da Philips
MAX3580: tuner DVB-T da Maxim
os demais eu não encontrei.

Portanto o que eu chamei de "driver" é o demodulador, e o que chamei de "frontend" é o tuner em si.
« Última modificação: Março 18, 2011, 02:58:22 am por rafael_netto »

Offline rictad

  • Hacker Honorário
  • Colaboradores
  • Papagaio
  • *
  • Mensagens: 285
  • Aprovação: +59/-0
    • Ver Perfil
Re: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR
« Responder #28 Online: Março 18, 2011, 03:15:32 am »
O único recurso que eu tenho é tentar correlacionar as mensagens que saem no terminal com o que aparece no código do software.
(aliás, no IDA 5.5 o disassembly já vem identificado, dispensando o mips-analyser que eu nem descobri como instalar)

Muito bom saber disso! Vou adquirir uma atualização para testar. A minha versão é a 5.2


Durante o boot, o Semp apresenta estas mensagens relacionadas ao tuner:
Código: [Selecionar]
task_create out tuner 6151
^@task_create out uartrx 7176
flash size = 8192KB
HDCPKey MagicWord = 00
Demod. I2C Device 0x30 and tuner 0xC2 via 0xFE detected, install TC90512 driver, DemodHandle = 0
tc90512 Initialising
config graphics 0
zw_tuner_halInit -> 0x11

E quando muda de canal (seja assistindo, ou nas telas de sintonia) as mensagens são assim:
Código: [Selecionar]
tc90512-> Tune to channel, frequency=563143 KHz
Writing RF = 563143
Set Frequency : Write tuner sequence = 0x10 0x9a 0xc1 0xa4 0x80
[TUNER]zw_frontend_VA6009Read=0x54 , fStatus=0
Tuner(0x11) PLL locked


Essa é a mesma técnica que usei para achar as rotinas do FP (painel frontal). As strings indicando a inicialização do painel frontal durante o boot são "OnBoard fp init done" no ZBT-633 e "8051 fp init done" no ZBT-620A.

Vamos sem mips-analyser, já que parece não ser mais necessário. No início do código, é possível encontrarmos a rotina que chama as sub-rotinas que inicializam o hardware enquanto exibe as respectivas mensagens de boot. Eu lembro de começar a procurar as strings do tuner, mas acabei parando. Você fez uma pesquisa muito interessante sobre os sintonizadores usados nesses aparelhos todos. Se eu conseguir mostrar como achei as rotinas que inicializam o FP (não sei se são drivers, mas inicializam ;D), isso pode ajudar a descobrirmos se de fato suporte a outros tuners não estão disponíveis no código. Apesar das strings não estarem presentes, não significa que as rotinas não estejam. Veja só:

No código do ZBT-620, versão 1.7.2, temos:

Código: [Selecionar]
...........
...........
...........
.text:00400640 09 F8 20 03                             jalr    $t9 # executa 'ci init'
.text:00400644 00 00 00 00                             nop
.text:00400648 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:0040064C 50 02 05 26                             addiu   $a1, $s0, 0x250
.text:00400650 88 00 06 24                             li      $a2, 0x88
.text:00400654 24 80 84 8F                             lw      $a0, offset aCiInitDone  # "ci init done" -- carrega string em $a0
.text:00400658 2C D9 99 8F                             lw      $t9, offset sub_40398C # rotina que exibe a string
.text:0040065C 09 F8 20 03                             jalr    $t9
.text:00400660 44 03 84 24                             addiu   $a0, 0x344       # "ci init done"
.text:00400664 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:00400668 CC AE 99 8F                             lw      $t9, offset sub_451A00  # pre-executa 8051 fp init
.text:0040066C 09 F8 20 03                             jalr    $t9 # chama pre-executa 8051 fp init
.text:00400670 00 00 00 00                             nop
.text:00400674 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:00400678 50 02 05 26                             addiu   $a1, $s0, 0x250
.text:0040067C 90 00 06 24                             li      $a2, 0x90
.text:00400680 24 80 84 8F                             lw      $a0, offset a8051FpInitDone  # "8051 fp init done" -- carrega string em $a0
.text:00400684 2C D9 99 8F                             lw      $t9, offset sub_40398C # rotina que exibe a string
.text:00400688 09 F8 20 03                             jalr    $t9
.text:0040068C 54 03 84 24                             addiu   $a0, 0x354       # "8051 fp init done"
.text:00400690 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:00400694 04 C3 99 8F                             lw      $t9, offset sub_43E868
.text:00400698 09 F8 20 03                             jalr    $t9
.text:0040069C 00 00 00 00                             nop
.text:004006A0 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:004006A4 7C D3 99 8F                             lw      $t9, offset sub_6486F4 # executa ffs init
.text:004006A8 09 F8 20 03                             jalr    $t9
.text:004006AC 00 00 00 00                             nop
.text:004006B0 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:004006B4 50 02 05 26                             addiu   $a1, $s0, 0x250
.text:004006B8 9A 00 06 24                             li      $a2, 0x9A
.text:004006BC 24 80 84 8F                             lw      $a0, offset aFfsInitDone  # "ffs init done" -- carrega string em $a0
.text:004006C0 2C D9 99 8F                             lw      $t9, offset sub_40398C # rotina que exibe a string
...........
...........
...........

A rotina que exibe a string é a que é chamada várias vezes. E as chamadas imediatamente anteriores à exibição da string são sempre para as rotinas que inicializam o dispositivo "anunciado".

Eu chamei de "pre-executa 8051" por que no caso do ZBT-620A, essa rotina ainda chamará outra, que de fato inicializa o FP. A "executa 8051 fp init".

Rotina pre-executa 8051:

Código: [Selecionar]
.text:00451A00                          # pre-executa 8051 fp init
.text:00451A00
.text:00451A00                         sub_451A00:                              # DATA XREF: sub_40038C+2DC_t
.text:00451A00                                                                  # .got:00BC74BC_o
.text:00451A00
.text:00451A00                         var_18          = -0x18
.text:00451A00                         var_10          = -0x10
.text:00451A00                         var_C           = -0xC
.text:00451A00                         var_8           = -8
.text:00451A00                         var_4           = -4
.text:00451A00
.text:00451A00 78 00 1C 3C F0 AB 9C 27                 la      $gp, aScqw       # mips_analyser
.text:00451A08 21 E0 99 03                             addu    $gp, $t9
.text:00451A0C D8 FF BD 27                             addiu   $sp, -0x28
.text:00451A10 24 00 BF AF                             sw      $ra, 0x28+var_4($sp)
.text:00451A14 20 00 B2 AF                             sw      $s2, 0x28+var_8($sp)
.text:00451A18 1C 00 B1 AF                             sw      $s1, 0x28+var_C($sp)
.text:00451A1C 18 00 B0 AF                             sw      $s0, 0x28+var_10($sp)
.text:00451A20 10 00 BC AF                             sw      $gp, 0x28+var_18($sp)
.text:00451A24 10 94 99 8F                             lw      $t9, offset sub_4D51F8  # executa 8051 fp init
.text:00451A28 54 80 92 8F                             lw      $s2, 0xc423a4
.text:00451A2C 09 F8 20 03                             jalr    $t9
.text:00451A30 21 88 00 00                             move    $s1, $0
.text:00451A34 10 00 BC 8F                             lw      $gp, 0x28+var_18($sp)
.text:00451A38 44 80 82 8F                             lw      $v0, offset 0xb792a0
.text:00451A3C A0 92 50 24                             addiu   $s0, $v0, 0x92A0
.text:00451A40
.text:00451A40                         loc_451A40:                              # CODE XREF: sub_451A00+60_j
.text:00451A40 00 00 19 8E                             lw      $t9, 0($s0)
.text:00451A44 09 F8 20 03                             jalr    $t9
.text:00451A48 48 00 10 26                             addiu   $s0, 0x48
.text:00451A4C 0B 00 40 14                             bnez    $v0, loc_451A7C
.text:00451A50 10 00 BC 8F                             lw      $gp, 0x28+var_18($sp)
.text:00451A54 A4 23 42 8E                             lw      $v0, 0x23A4($s2)
.text:00451A58 01 00 31 26                             addiu   $s1, 1
.text:00451A5C 2B 10 51 00                             sltu    $v0, $s1
.text:00451A60 F7 FF 40 10                             beqz    $v0, loc_451A40
.text:00451A64 24 00 BF 8F                             lw      $ra, 0x28+var_4($sp)
.text:00451A68 20 00 B2 8F                             lw      $s2, 0x28+var_8($sp)
.text:00451A6C 1C 00 B1 8F                             lw      $s1, 0x28+var_C($sp)
.text:00451A70 18 00 B0 8F                             lw      $s0, 0x28+var_10($sp)
.text:00451A74 08 00 E0 03                             jr      $ra
.text:00451A78 28 00 BD 27                             addiu   $sp, 0x28
.text:00451A7C                          # ---------------------------------------------------------------------------
.text:00451A7C
.text:00451A7C                         loc_451A7C:                              # CODE XREF: sub_451A00+4C_j
.text:00451A7C 54 80 82 8F                             lw      $v0, 0xc423a0
.text:00451A80 24 00 BF 8F                             lw      $ra, 0x28+var_4($sp)
.text:00451A84 20 00 B2 8F                             lw      $s2, 0x28+var_8($sp)
.text:00451A88 A0 23 51 AC                             sw      $s1, 0x23A0($v0)
.text:00451A8C 18 00 B0 8F                             lw      $s0, 0x28+var_10($sp)
.text:00451A90 1C 00 B1 8F                             lw      $s1, 0x28+var_C($sp)
.text:00451A94 08 00 E0 03                             jr      $ra
.text:00451A98 28 00 BD 27                             addiu   $sp, 0x28
.text:00451A98                          # End of function sub_451A00

Início da rotina executa 8051:

Código: [Selecionar]
.text:004D51F8                          # executa 8051 fp init
.text:004D51F8
.text:004D51F8                         sub_4D51F8:                              # DATA XREF: sub_451A00+24_t
.text:004D51F8                                                                  # .got:00BC5A00_o
.text:004D51F8
.text:004D51F8                         var_20          = -0x20
.text:004D51F8                         var_1C          = -0x1C
.text:004D51F8                         var_18          = -0x18
.text:004D51F8                         var_10          = -0x10
.text:004D51F8                         var_C           = -0xC
.text:004D51F8                         var_8           = -8
.text:004D51F8
.text:004D51F8 6F 00 1C 3C F8 73 9C 27                 la      $gp, unk_6F73F8  # mips_analyser
.text:004D5200 21 E0 99 03                             addu    $gp, $t9
.text:004D5204 D0 FF BD 27                             addiu   $sp, -0x30
.text:004D5208 28 00 BF AF                             sw      $ra, 0x30+var_8($sp)
.text:004D520C 24 00 B1 AF                             sw      $s1, 0x30+var_C($sp)
.text:004D5210 20 00 B0 AF                             sw      $s0, 0x30+var_10($sp)
.text:004D5214 18 00 BC AF                             sw      $gp, 0x30+var_18($sp)
.text:004D5218 88 80 90 8F                             lw      $s0, 0xcdb690
.text:004D521C 2C 80 85 8F                             lw      $a1, offset a7401uarta  # "7401UARTA"
.text:004D5220 48 BC 99 8F                             lw      $t9, offset sub_4510F8
.text:004D5224 90 B6 04 26                             addiu   $a0, $s0, 0xB690
.text:004D5228 09 F8 20 03                             jalr    $t9
.text:004D522C A8 1F A5 24                             addiu   $a1, 0x1FA8      # "7401UARTA"
.text:004D5230 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:004D5234 E0 D9 99 8F                             lw      $t9, offset sub_4511A4
.text:004D5238 09 F8 20 03                             jalr    $t9
.text:004D523C 90 B6 04 26                             addiu   $a0, $s0, 0xB690
.text:004D5240 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:004D5244 21 20 00 00                             move    $a0, $0
.text:004D5248 70 A6 82 8F                             lw      $v0, 0xbca0d4
.text:004D524C 9C CD 83 8F                             lw      $v1, 0xcda550
.text:004D5250 10 8B 99 8F                             lw      $t9, offset sub_43C850
.text:004D5254 00 00 40 AC                             sw      $0, 0($v0)
.text:004D5258 68 C0 82 8F                             lw      $v0, 0xbca0d0
.text:004D525C 00 00 60 AC                             sw      $0, 0($v1)
.text:004D5260 00 00 40 AC                             sw      $0, 0($v0)
.text:004D5264 09 F8 20 03                             jalr    $t9
.text:004D5268 00 00 00 00                             nop
.text:004D526C 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:004D5270 01 00 04 24                             li      $a0, 1
.text:004D5274 88 80 83 8F                             lw      $v1, 0xcdb688
.text:004D5278 10 8B 99 8F                             lw      $t9, offset sub_43C850
.text:004D527C 09 F8 20 03                             jalr    $t9
.text:004D5280 88 B6 62 AC                             sw      $v0, -0x4978($v1)
.text:004D5284 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:004D5288 21 30 00 00                             move    $a2, $0
.text:004D528C 00 20 07 24                             li      $a3, 0x2000
.text:004D5290 88 80 83 8F                             lw      $v1, 0xcdb68c
.text:004D5294 2C 80 85 8F                             lw      $a1, offset aZw_fp  # "ZW_FP"
.text:004D5298 98 80 84 8F                             lw      $a0, offset sub_4D4CB8
.text:004D529C 2C 86 99 8F                             lw      $t9, offset sub_43C588
.text:004D52A0 8C B6 62 AC                             sw      $v0, -0x4974($v1)
.text:004D52A4 38 00 02 24                             li      $v0, 0x38
.text:004D52A8 B4 1F A5 24                             addiu   $a1, 0x1FB4      # "ZW_FP"
.text:004D52AC B8 4C 84 24                             addiu   $a0, 0x4CB8
.text:004D52B0 10 00 A2 AF                             sw      $v0, 0x30+var_20($sp)
.........
.........
.........

Podemos ver na rotina "executa 8051 fp init" referências à "ZW_FP" e "7401UARTA". Existem outras com essas referências que parecem terem sido feitas para inicializar outros FP.

Por exemplo, no início do código do ZBT-633 1.13.6, temos:

Código: [Selecionar]
.text:00400698 0C 94 99 8F                             lw      $t9, offset sub_4039EC
.text:0040069C 09 F8 20 03                             jalr    $t9
.text:004006A0 94 29 84 24                             addiu   $a0, 0x2994      # "ci init done"
.text:004006A4 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:004006A8 DC A7 99 8F                             lw      $t9, offset sub_4D6D30  # executa onboard fp init
.text:004006AC 09 F8 20 03                             jalr    $t9              # chama executa onboard fp init
.text:004006AC                                                                 
.text:004006B0 00 00 00 00                             nop
.text:004006B4 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:004006B8 A0 28 05 26                             addiu   $a1, $s0, 0x28A0
.text:004006BC 8A 00 06 24                             li      $a2, 0x8A
.text:004006C0 28 80 84 8F                             lw      $a0, offset aOnboardFpInitD  # "OnBoard fp init done"
.text:004006C4 0C 94 99 8F                             lw      $t9, offset sub_4039EC
.text:004006C8 09 F8 20 03                             jalr    $t9
.text:004006CC A4 29 84 24                             addiu   $a0, 0x29A4      # "OnBoard fp init done"
.text:004006D0 18 00 BC 8F                             lw      $gp, 0x30+var_18($sp)
.text:004006D4 0C A6 99 8F                             lw      $t9, offset sub_407270
.text:004006D8 09 F8 20 03                             jalr    $t9
.text:004006DC 00 00 00 00                             nop

Não existe "pre-executa fp" no ZBT-633. O início da rotina "executa onboard fp init" é o seguinte:

Código: [Selecionar]
.text:004D6D30                          # executa onboard fp init
.text:004D6D30
.text:004D6D30                         sub_4D6D30:                              # DATA XREF: sub_4003DC+2CC_t
.text:004D6D30                                                                  # sub_44EB40+24_t ...
.text:004D6D30
.text:004D6D30                         var_18          = -0x18
.text:004D6D30                         var_14          = -0x14
.text:004D6D30                         var_10          = -0x10
.text:004D6D30                         var_8           = -8
.text:004D6D30
.text:004D6D30 6E 00 1C 3C 80 E9 9C 27                 la      $gp, unk_6DE980  # mips_analyser
.text:004D6D38 21 E0 99 03                             addu    $gp, $t9
.text:004D6D3C D8 FF BD 27                             addiu   $sp, -0x28
.text:004D6D40 20 00 BF AF                             sw      $ra, 0x28+var_8($sp)
.text:004D6D44 18 00 BC AF                             sw      $gp, 0x28+var_10($sp)
.text:004D6D48 14 B1 99 8F                             lw      $t9, offset sub_438750
.text:004D6D4C 09 F8 20 03                             jalr    $t9
.text:004D6D50 21 20 00 00                             move    $a0, $0
.text:004D6D54 18 00 BC 8F                             lw      $gp, 0x28+var_10($sp)
.text:004D6D58 01 00 04 24                             li      $a0, 1
.text:004D6D5C A8 80 83 8F                             lw      $v1, 0xd45d08
.text:004D6D60 14 B1 99 8F                             lw      $t9, offset sub_438750
.text:004D6D64 09 F8 20 03                             jalr    $t9
.text:004D6D68 08 5D 62 AC                             sw      $v0, 0x5D08($v1)
.text:004D6D6C 18 00 BC 8F                             lw      $gp, 0x28+var_10($sp)
.text:004D6D70 21 30 00 00                             move    $a2, $0
.text:004D6D74 00 20 07 24                             li      $a3, 0x2000
.text:004D6D78 A8 80 83 8F                             lw      $v1, 0xd45d0c
.text:004D6D7C AC 80 84 8F                             lw      $a0, offset sub_4D6EE0
.text:004D6D80 30 80 85 8F                             lw      $a1, offset aZw_fp  # "ZW_FP"
.text:004D6D84 34 D8 99 8F                             lw      $t9, offset sub_4383F8
.text:004D6D88 0C 5D 62 AC                             sw      $v0, 0x5D0C($v1)
.text:004D6D8C 2E 00 02 24                             li      $v0, 0x2E
.text:004D6D90 CC 59 A5 24                             addiu   $a1, 0x59CC      # "ZW_FP"
.text:004D6D94 10 00 A2 AF                             sw      $v0, 0x28+var_18($sp)
.text:004D6D98 E0 6E 84 24                             addiu   $a0, 0x6EE0
.text:004D6D9C 09 F8 20 03                             jalr    $t9
....
....
....

Podemos observar as mesmas referências ("ZW_FP" e "UART"), mas a rotina é diferente da "executa 8051 fp init" do ZBT-620A. Mas, se sairmos buscando pelo texto "ZW_FP", vamos encontrar a mesma "executa 8051 fp init" no código do ZBT-633 em sub_4D5DB8. Para não precisar comparar as rotinas instrução por instrução, podemos fazer algumas comparações simples de olho no IDA (possuem, em seu início, a mesma quantidade de variáveis definidas pelo IDA e elas ainda são as mesmas, possuem a mesma visão gráfica no mini-fluxograma, as mesmas subdivisões etc) de forma que há indícios para serem as mesmas. Além disso, também é possível acharmos uma "pre-executa 8051 fp init" em sub_44EB40. O interessante é que essa "pre-executa 8051" chama a "executa onboard fp init", apesar de não ser nunca executada (o IDA marca em vermelho, sem criar a função, mas a qual podemos mandá-lo criar para nos facilitar).

A primeira coisa que fiz para testar foi alterar o apontamento da GOT em 0xBAFE8C do endereço da "executa onboard fp init" para a "executa 8051". Mas isso não funcionou. A "executa 8051 fp init" precisa da "pré-executa" antes.

Bom, com a alteração feita anteriormente, a "pre-executa" passou a apontar corretamente para a "executa 8051", já que ela usava a mesma referência na GOT (pois apontava estranhamente para a "executa onboard fp init"). O problema agora era alterar o apontamento na rotina de inicialização e exibição de strings no boot sem mexer novamente neste ponto da GOT. Como não havia nenhuma entrada na GOT que já apontasse para o endereço da "pré-executa", tive que criar uma nova entrada. Se olharmos a GOT, veremos que há alguns buracos com quatro 0's de tempos em tempos, onde podemos inserir novos endereços de apontamento. O mais próximo de 0xBAFE8C fica justamente duas palavras após, em 0xBAFE94. Então incluí os valores 40 EB 44 00 no lugar da palavra zerada, criando uma nova entrada que aponta para 0x44EB40 ("pre-executa 8051 fp init"). Agora, faltava alterar a referência para a nova entrada da GOT na rotina de inicialização. Tínhamos:

Código: [Selecionar]
.text:004006A4 18 00 BC 8F                        lw      $gp, 0x30+var_18($sp)
.text:004006A8 DC A7 99 8F                        lw      $t9, offset sub_4D6D30  # executa onboard fp init
.text:004006AC 09 F8 20 03                        jalr    $t9              # chama executa onboard fp init
.text:004006B0 00 00 00 00                        nop

Em 0x4006A8, $t9 é carregado com o valor que está no endereço 0xBAFE8C. Se apertamos a tecla "h", veremos que isso equivale a lw $t9, -0x5824($gp) (*). Como agora queria que se referisse à nova entrada na GOT, que fica em 0xBAFE92 (8 bytes a mais), mudei a instrução para lw $t9, -0x581C($gp), ficando assim:

Código: [Selecionar]
_text:004006A4     18 00 BC 8F            lw      $gp, 0x30+var_18($sp)
_text:004006A8     E4 A7 99 8F            lw      $t9, -0x581C($gp)
_text:004006AC     09 F8 20 03            jalr    $t9
_text:004006B0     00 00 00 00            nop

Isso garante que $t9 seja carregado com o que está na GOT, 8 bytes à frente do endereço anterior (0xBAFE92).

Assim, a rotina de inicialização agora chama a "pre-executa 8051 fp init". E esta chama "executa 8051 fp init", devido à primeira alteração na GOT, fazendo com que o FP do ZBT-620A seja iniciado pelo firmware 1.13.6. Mas a string exibida durante o boot ainda é "OnBoard fp init done".

(*)EDIT: No caso do IDA 5.5 (e possivelmente as versões seguintes), apertar "h" não é suficiente para mostrar o offset real em relação ao registrador $gp. Vai apenas alternar entre o valor decimal e hexadecimal do operando. Isso ocorre porque, por padrão, a versão 5.5 vem com a opção "simplificar instruções com $gp" habilitada, o que cria a pseudoinstrução la (e facilita muito a leitura, sem precisar do mips-analyser, como o rafael_netto havia dito).

Código: [Selecionar]
.text:004006A4  18 00 BC 8F               lw      $gp, 0x30+var_18($sp)
.text:004006A8  DC A7 99 8F               la      $t9, sub_4D6D30
.text:004006AC  09 F8 20 03               jalr    $t9 ; sub_4D6D30
.text:004006B0  00 00 00 00               nop

Para vermos a instrução real, lw $t9, -0x5824($gp), temos que ir em "Options", "General", aba "Analysis", botão "Processor specific analysis options" e desmarcar "Simplify $gp expressions" (nessa tela também é possível vermos onde se inicia a GOT).
« Última modificação: Março 18, 2011, 06:16:45 am por rictad »

Offline rictad

  • Hacker Honorário
  • Colaboradores
  • Papagaio
  • *
  • Mensagens: 285
  • Aprovação: +59/-0
    • Ver Perfil
Re: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR
« Responder #29 Online: Março 18, 2011, 03:47:32 am »
Olha só, no caso do ZBT-633, a rotina que começa a inicialização do tuner é esta:

Código: [Selecionar]
.text:00400310                         sub_400310:                              # DATA XREF: sub_4003DC+D8_t
.text:00400310
.text:00400310                         var_10          = -0x10
.text:00400310                         var_8           = -8
.text:00400310                         var_4           = -4
.text:00400310
.text:00400310 7B 00 1C 3C A0 53 9C 27                 la      $gp, unk_7B53A0  # mips_analyser
.text:00400318 21 E0 99 03                             addu    $gp, $t9
.text:0040031C E0 FF BD 27                             addiu   $sp, -0x20
.text:00400320 1C 00 BF AF                             sw      $ra, 0x20+var_4($sp)
.text:00400324 18 00 B0 AF                             sw      $s0, 0x20+var_8($sp)
.text:00400328 10 00 BC AF                             sw      $gp, 0x20+var_10($sp)
.text:0040032C 28 80 90 8F                             lw      $s0, offset a__SrcMain_c  # "../src/main.c"
.text:00400330 28 80 84 8F                             lw      $a0, offset aTunerInitStart  # "tuner init start"
.text:00400334 0C 94 99 8F                             lw      $t9, offset sub_4039EC
.text:00400338 A0 28 05 26                             addiu   $a1, $s0, 0x28A0  # "../src/main.c"
.text:0040033C B0 28 84 24                             addiu   $a0, 0x28B0      # "tuner init start"
.text:00400340 09 F8 20 03                             jalr    $t9
.text:00400344 37 00 06 24                             li      $a2, 0x37
.text:00400348 10 00 BC 8F                             lw      $gp, 0x20+var_10($sp)
.text:0040034C 70 D5 99 8F                             lw      $t9, offset sub_43B240 ## Inicializa tuner?
.text:00400350 09 F8 20 03                             jalr    $t9
.text:00400354 00 00 00 00                             nop
.text:00400358 10 00 BC 8F                             lw      $gp, 0x20+var_10($sp)
.text:0040035C A0 28 05 26                             addiu   $a1, $s0, 0x28A0
.text:00400360 39 00 06 24                             li      $a2, 0x39
.text:00400364 28 80 84 8F                             lw      $a0, offset aTunerInitDone  # "tuner init done"
.text:00400368 0C 94 99 8F                             lw      $t9, offset sub_4039EC
.text:0040036C 09 F8 20 03                             jalr    $t9
.text:00400370 C4 28 84 24                             addiu   $a0, 0x28C4      # "tuner init done"
.text:00400374 10 00 BC 8F                             lw      $gp, 0x20+var_10($sp)
.text:00400378 1C 00 BF 8F                             lw      $ra, 0x20+var_4($sp)
.text:0040037C 18 00 B0 8F                             lw      $s0, 0x20+var_8($sp)
.text:00400380 58 BF 82 8F                             lw      $v0, 0xbb2eec
.text:00400384 B4 B3 99 8F                             lw      $t9, offset sub_438598
.text:00400388 20 00 BD 27                             addiu   $sp, 0x20
.text:0040038C 08 00 20 03                             jr      $t9
.text:00400390 00 00 44 8C                             lw      $a0, 0($v0)
.text:00400390                          # End of function sub_400310


Se a gente seguir aquela chamada de inicialização, vemos isso (que possui as strings que você mencionou):

Código: [Selecionar]
.text:0043B240                         sub_43B240:                              # DATA XREF: sub_400310+3C_t
.text:0043B240                                                                  # .got:00BB2C20_o
.text:0043B240
.text:0043B240                         var_30          = -0x30
.text:0043B240                         var_28          = -0x28
.text:0043B240                         var_24          = -0x24
.text:0043B240                         var_20          = -0x20
.text:0043B240                         var_1C          = -0x1C
.text:0043B240                         var_18          = -0x18
.text:0043B240                         var_14          = -0x14
.text:0043B240                         var_10          = -0x10
.text:0043B240                         var_C           = -0xC
.text:0043B240                         var_8           = -8
.text:0043B240                         var_4           = -4
.text:0043B240
.text:0043B240 78 00 1C 3C 70 A4 9C 27                 la      $gp, a7uD        # mips_analyser
.text:0043B248 21 E0 99 03                             addu    $gp, $t9
.text:0043B24C C0 FF BD 27                             addiu   $sp, -0x40
.text:0043B250 3C 00 BF AF                             sw      $ra, 0x40+var_4($sp)
.text:0043B254 38 00 BE AF                             sw      $fp, 0x40+var_8($sp)
.text:0043B258 34 00 B7 AF                             sw      $s7, 0x40+var_C($sp)
.text:0043B25C 30 00 B6 AF                             sw      $s6, 0x40+var_10($sp)
.text:0043B260 2C 00 B5 AF                             sw      $s5, 0x40+var_14($sp)
.text:0043B264 28 00 B4 AF                             sw      $s4, 0x40+var_18($sp)
.text:0043B268 24 00 B3 AF                             sw      $s3, 0x40+var_1C($sp)
.text:0043B26C 20 00 B2 AF                             sw      $s2, 0x40+var_20($sp)
.text:0043B270 1C 00 B1 AF                             sw      $s1, 0x40+var_24($sp)
.text:0043B274 18 00 B0 AF                             sw      $s0, 0x40+var_28($sp)
.text:0043B278 10 00 BC AF                             sw      $gp, 0x40+var_30($sp)
.text:0043B27C 2C 80 82 8F                             lw      $v0, 0xbc38a8
.text:0043B280 DC 9F 99 8F                             lw      $t9, offset sub_664A60
.text:0043B284 21 28 00 00                             move    $a1, $0
.text:0043B288 A8 38 50 24                             addiu   $s0, $v0, 0x38A8
.text:0043B28C 78 00 06 24                             li      $a2, 0x78
.text:0043B290 09 F8 20 03                             jalr    $t9
.text:0043B294 21 20 00 02                             move    $a0, $s0
.text:0043B298 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
.text:0043B29C 50 80 82 8F                             lw      $v0, offset sub_43B0D0
.text:0043B2A0 2C 80 96 8F                             lw      $s6, 0xbc38a1
.text:0043B2A4 D0 B0 51 24                             addiu   $s1, $v0, 0xB0D0
.text:0043B2A8 21 C8 20 02                             move    $t9, $s1
.text:0043B2AC 09 F8 20 03                             jalr    $t9
.text:0043B2B0 0C 00 14 24                             li      $s4, 0xC
.text:0043B2B4 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
.text:0043B2B8 28 80 84 8F                             lw      $a0, offset aZw_frontend_in  # ">> zw_frontend_init -->"
.text:0043B2BC 98 88 99 8F                             lw      $t9, offset sub_65EB40
.text:0043B2C0 09 F8 20 03                             jalr    $t9
.text:0043B2C4 B0 76 84 24                             addiu   $a0, 0x76B0      # ">> zw_frontend_init -->"
.text:0043B2C8 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
.text:0043B2CC 28 80 84 8F                             lw      $a0, offset aZw_tc90517_reg  # "zw_tc90517_register"
.text:0043B2D0 98 88 99 8F                             lw      $t9, offset sub_65EB40
.text:0043B2D4 09 F8 20 03                             jalr    $t9
.text:0043B2D8 C8 76 84 24                             addiu   $a0, 0x76C8      # "zw_tc90517_register"
.text:0043B2DC 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
.text:0043B2E0 21 20 00 02                             move    $a0, $s0
.text:0043B2E4 A0 94 99 8F                             lw      $t9, offset sub_42AEF0
.text:0043B2E8 09 F8 20 03                             jalr    $t9
.text:0043B2EC A1 38 C5 26                             addiu   $a1, $s6, 0x38A1
.text:0043B2F0 01 00 03 24                             li      $v1, 1
.text:0043B2F4 4D 00 43 10                             beq     $v0, $v1, loc_43B42C
.text:0043B2F8 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
.text:0043B2FC
.text:0043B2FC                         loc_43B2FC:                              # CODE XREF: sub_43B240+218_j
.text:0043B2FC A1 38 C2 92                             lbu     $v0, 0x38A1($s6)
.text:0043B300 44 00 40 10                             beqz    $v0, loc_43B414
.text:0043B304 28 80 84 8F                             lw      $a0, offset sub_670000
.text:0043B308
.text:0043B308                         loc_43B308:                              # CODE XREF: sub_43B240+1E4_j
.text:0043B308 FF 00 42 30                             andi    $v0, 0xFF
.text:0043B30C 34 00 40 10                             beqz    $v0, loc_43B3E0
.text:0043B310 21 90 00 00                             move    $s2, $0
.text:0043B314 21 F0 00 02                             move    $fp, $s0
.text:0043B318 00 11 12 00                             sll     $v0, $s2, 4
.text:0043B31C
.text:0043B31C                         loc_43B31C:                              # CODE XREF: sub_43B240+198_j
.text:0043B31C 23 10 52 00                             subu    $v0, $s2
.text:0043B320 80 10 02 00                             sll     $v0, 2
.text:0043B324 21 10 5E 00                             addu    $v0, $fp
.text:0043B328 10 00 43 8C                             lw      $v1, 0x10($v0)
.text:0043B32C 26 00 60 10                             beqz    $v1, loc_43B3C8
.text:0043B330 00 00 00 00                             nop
.text:0043B334 24 00 80 12                             beqz    $s4, loc_43B3C8
.text:0043B338 00 00 00 00                             nop
.text:0043B33C 21 80 40 00                             move    $s0, $v0
.text:0043B340 01 00 13 24                             li      $s3, 1
.text:0043B344 28 80 95 8F                             lw      $s5, offset sub_670000
.text:0043B348 20 80 82 8F                             lw      $v0, offset 0x7f83b8
.text:0043B34C B8 83 42 24                             addiu   $v0, 0x83B8
.text:0043B350 06 00 00 10                             b       loc_43B36C
.text:0043B354 00 00 57 8C                             lw      $s7, 0($v0)
.text:0043B358                          # ---------------------------------------------------------------------------
.text:0043B358
.text:0043B358                         loc_43B358:                              # CODE XREF: sub_43B240+14C_j
.text:0043B358 FF FF 82 26                             addiu   $v0, $s4, 0xFFFF
.text:0043B35C 1A 00 33 16                             bne     $s1, $s3, loc_43B3C8
.text:0043B360 FF 00 54 30                             andi    $s4, $v0, 0xFF
.text:0043B364
.text:0043B364                         loc_43B364:                              # CODE XREF: sub_43B240+180_j
.text:0043B364 19 00 80 12                             beqz    $s4, loc_43B3CC
.text:0043B368 A1 38 C2 92                             lbu     $v0, 0x38A1($s6)
.text:0043B36C
.text:0043B36C                         loc_43B36C:                              # CODE XREF: sub_43B240+110_j
.text:0043B36C 00 00 04 92                             lbu     $a0, 0($s0)
.text:0043B370 10 00 19 8E                             lw      $t9, 0x10($s0)
.text:0043B374 09 F8 20 03                             jalr    $t9
.text:0043B378 01 00 05 92                             lbu     $a1, 1($s0)
.text:0043B37C 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
.text:0043B380 21 88 40 00                             move    $s1, $v0
.text:0043B384 FC 76 A4 26                             addiu   $a0, $s5, 0x76FC
.text:0043B388 28 8A 99 8F                             lw      $t9, offset sub_65ECD0
.text:0043B38C F2 FF 53 14                             bne     $v0, $s3, loc_43B358
.text:0043B390 21 28 40 02                             move    $a1, $s2
.text:0043B394 09 F8 20 03                             jalr    $t9
.text:0043B398 00 00 00 00                             nop
.text:0043B39C 21 C8 E0 02                             move    $t9, $s7
.text:0043B3A0 09 F8 20 03                             jalr    $t9
.text:0043B3A4 00 00 00 00                             nop
.text:0043B3A8 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
.text:0043B3AC 40 BE 99 8F                             lw      $t9, offset sub_438364
.text:0043B3B0 09 F8 20 03                             jalr    $t9
.text:0043B3B4 64 00 04 24                             li      $a0, 0x64
.text:0043B3B8 FF FF 82 26                             addiu   $v0, $s4, 0xFFFF
.text:0043B3BC 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
.text:0043B3C0 E8 FF 33 12                             beq     $s1, $s3, loc_43B364
.text:0043B3C4 FF 00 54 30                             andi    $s4, $v0, 0xFF
.text:0043B3C8
.text:0043B3C8                         loc_43B3C8:                              # CODE XREF: sub_43B240+EC_j
.text:0043B3C8                                                                  # sub_43B240+F4_j ...
.text:0043B3C8 A1 38 C2 92                             lbu     $v0, 0x38A1($s6)
.text:0043B3CC
.text:0043B3CC                         loc_43B3CC:                              # CODE XREF: sub_43B240:loc_43B364_j
.text:0043B3CC 01 00 43 26                             addiu   $v1, $s2, 1
.text:0043B3D0 FF 00 72 30                             andi    $s2, $v1, 0xFF
.text:0043B3D4 2B 10 42 02                             sltu    $v0, $s2, $v0
.text:0043B3D8 D0 FF 40 14                             bnez    $v0, loc_43B31C
.text:0043B3DC 00 11 12 00                             sll     $v0, $s2, 4
.text:0043B3E0
.text:0043B3E0                         loc_43B3E0:                              # CODE XREF: sub_43B240+CC_j
.text:0043B3E0 3C 00 BF 8F                             lw      $ra, 0x40+var_4($sp)
.text:0043B3E4 38 00 BE 8F                             lw      $fp, 0x40+var_8($sp)
.text:0043B3E8 34 00 B7 8F                             lw      $s7, 0x40+var_C($sp)
.text:0043B3EC 30 00 B6 8F                             lw      $s6, 0x40+var_10($sp)
.text:0043B3F0 2C 00 B5 8F                             lw      $s5, 0x40+var_14($sp)
.text:0043B3F4 28 00 B4 8F                             lw      $s4, 0x40+var_18($sp)
.text:0043B3F8 24 00 B3 8F                             lw      $s3, 0x40+var_1C($sp)
.text:0043B3FC 20 00 B2 8F                             lw      $s2, 0x40+var_20($sp)
.text:0043B400 1C 00 B1 8F                             lw      $s1, 0x40+var_24($sp)
.text:0043B404 18 00 B0 8F                             lw      $s0, 0x40+var_28($sp)
.text:0043B408 21 10 00 00                             move    $v0, $0
.text:0043B40C 08 00 E0 03                             jr      $ra
.text:0043B410 40 00 BD 27                             addiu   $sp, 0x40
.text:0043B414                          # ---------------------------------------------------------------------------
.text:0043B414
.text:0043B414                         loc_43B414:                              # CODE XREF: sub_43B240+C0_j
.text:0043B414 98 88 99 8F                             lw      $t9, offset sub_65EB40
.text:0043B418 09 F8 20 03                             jalr    $t9
.text:0043B41C DC 76 84 24                             addiu   $a0, 0x76DC
.text:0043B420 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
.text:0043B424 B8 FF 00 10                             b       loc_43B308
.text:0043B428 A1 38 C2 92                             lbu     $v0, 0x38A1($s6)
.text:0043B42C                          # ---------------------------------------------------------------------------
.text:0043B42C
.text:0043B42C                         loc_43B42C:                              # CODE XREF: sub_43B240+B4_j
.text:0043B42C 28 80 84 8F                             lw      $a0, offset aZw_tc90507_reg  # "zw_tc90507_register"
.text:0043B430 98 88 99 8F                             lw      $t9, offset sub_65EB40
.text:0043B434 09 F8 20 03                             jalr    $t9
.text:0043B438 18 77 84 24                             addiu   $a0, 0x7718      # "zw_tc90507_register"
.text:0043B43C 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
.text:0043B440 21 20 00 02                             move    $a0, $s0
.text:0043B444 8C 85 99 8F                             lw      $t9, offset sub_42CC74
.text:0043B448 09 F8 20 03                             jalr    $t9
.text:0043B44C A1 38 C5 26                             addiu   $a1, $s6, 0x38A1
.text:0043B450 10 00 BC 8F                             lw      $gp, 0x40+var_30($sp)
.text:0043B454 40 00 03 24                             li      $v1, 0x40
.text:0043B458 A8 FF 00 10                             b       loc_43B2FC
.text:0043B45C 01 00 03 A2                             sb      $v1, 1($s0)
.text:0043B45C                          # End of function sub_43B240
.text:0043B45C

As strings são importantes para nos indicar que estamos no local certo. Mas é mais importante seguirmos as chamadas que devem nos levar às rotinas reais de inicialização, como por exemplo a que está em sub_42AEF0. Segue seu início:

Código: [Selecionar]
.text:0042AEF0                         sub_42AEF0:                              # DATA XREF: sub_43B240+A4_t
.text:0042AEF0                                                                  # .got:00BAEB50_o
.text:0042AEF0
.text:0042AEF0                         var_20          = -0x20
.text:0042AEF0                         var_18          = -0x18
.text:0042AEF0                         var_14          = -0x14
.text:0042AEF0                         var_10          = -0x10
.text:0042AEF0                         var_C           = -0xC
.text:0042AEF0                         var_8           = -8
.text:0042AEF0
.text:0042AEF0 79 00 1C 3C C0 A7 9C 27                 la      $gp, unk_78A7C0  # mips_analyser
.text:0042AEF8 21 E0 99 03                             addu    $gp, $t9
.text:0042AEFC D0 FF BD 27                             addiu   $sp, -0x30
.text:0042AF00 28 00 BF AF                             sw      $ra, 0x30+var_8($sp)
.text:0042AF04 24 00 B3 AF                             sw      $s3, 0x30+var_C($sp)
.text:0042AF08 20 00 B2 AF                             sw      $s2, 0x30+var_10($sp)
.text:0042AF0C 1C 00 B1 AF                             sw      $s1, 0x30+var_14($sp)
.text:0042AF10 18 00 B0 AF                             sw      $s0, 0x30+var_18($sp)
.text:0042AF14 10 00 BC AF                             sw      $gp, 0x30+var_20($sp)
.text:0042AF18 10 D6 99 8F                             lw      $t9, offset sub_42C588
.text:0042AF1C 21 90 80 00                             move    $s2, $a0
.text:0042AF20 09 F8 20 03                             jalr    $t9
.text:0042AF24 21 88 A0 00                             move    $s1, $a1
.text:0042AF28 01 00 13 24                             li      $s3, 1
.text:0042AF2C 9C 00 40 14                             bnez    $v0, loc_42B1A0
.text:0042AF30 10 00 BC 8F                             lw      $gp, 0x30+var_20($sp)
.text:0042AF34 00 00 22 92                             lbu     $v0, 0($s1)
.text:0042AF38 DC 9F 99 8F                             lw      $t9, offset sub_664A60
.text:0042AF3C 2C 80 90 8F                             lw      $s0, 0xbc2760
.text:0042AF40 00 21 02 00                             sll     $a0, $v0, 4
.text:0042AF44 23 20 82 00                             subu    $a0, $v0
.text:0042AF48 80 20 04 00                             sll     $a0, 2
.text:0042AF4C 21 20 92 00                             addu    $a0, $s2
.text:0042AF50 3C 00 06 24                             li      $a2, 0x3C
.text:0042AF54 09 F8 20 03                             jalr    $t9
.text:0042AF58 21 28 00 00                             move    $a1, $0
.text:0042AF5C 10 00 BC 8F                             lw      $gp, 0x30+var_20($sp)
.text:0042AF60 60 27 05 92                             lbu     $a1, 0x2760($s0)
.text:0042AF64 2C 80 82 8F                             lw      $v0, 0xbc276c
.text:0042AF68 FF 00 A3 30                             andi    $v1, $a1, 0xFF
.text:0042AF6C 00 19 03 00                             sll     $v1, 4
.text:0042AF70 6C 27 42 24                             addiu   $v0, 0x276C
.text:0042AF74 21 18 62 00                             addu    $v1, $v0
.text:0042AF78 00 00 65 A0                             sb      $a1, 0($v1)
.text:0042AF7C 00 00 24 92                             lbu     $a0, 0($s1)
.text:0042AF80 28 8A 99 8F                             lw      $t9, offset sub_65ECD0
.text:0042AF84 00 11 04 00                             sll     $v0, $a0, 4
.text:0042AF88 23 10 44 00                             subu    $v0, $a0
.text:0042AF8C 80 10 02 00                             sll     $v0, 2
.text:0042AF90 21 10 52 00                             addu    $v0, $s2
.text:0042AF94 00 00 45 A0                             sb      $a1, 0($v0)
.text:0042AF98 00 00 23 92                             lbu     $v1, 0($s1)
.text:0042AF9C 00 11 03 00                             sll     $v0, $v1, 4
.text:0042AFA0 23 10 43 00                             subu    $v0, $v1
.text:0042AFA4 80 10 02 00                             sll     $v0, 2
.text:0042AFA8 21 10 52 00                             addu    $v0, $s2
.text:0042AFAC 09 00 03 24                             li      $v1, 9
.text:0042AFB0 02 00 43 A0                             sb      $v1, 2($v0)
.text:0042AFB4 00 00 24 92                             lbu     $a0, 0($s1)
.text:0042AFB8 00 11 04 00                             sll     $v0, $a0, 4
.text:0042AFBC 23 10 44 00                             subu    $v0, $a0
.text:0042AFC0 80 10 02 00                             sll     $v0, 2
.text:0042AFC4 21 10 52 00                             addu    $v0, $s2
.text:0042AFC8 03 00 40 A0                             sb      $0, 3($v0)
.text:0042AFCC 00 00 23 92                             lbu     $v1, 0($s1)
.text:0042AFD0 00 11 03 00                             sll     $v0, $v1, 4
.text:0042AFD4 23 10 43 00                             subu    $v0, $v1
.text:0042AFD8 80 10 02 00                             sll     $v0, 2
.text:0042AFDC 21 10 52 00                             addu    $v0, $s2
.text:0042AFE0 04 00 53 A0                             sb      $s3, 4($v0)
.text:0042AFE4 00 00 23 92                             lbu     $v1, 0($s1)
.text:0042AFE8 00 11 03 00                             sll     $v0, $v1, 4
.text:0042AFEC 23 10 43 00                             subu    $v0, $v1
.text:0042AFF0 80 10 02 00                             sll     $v0, 2
.text:0042AFF4 21 10 52 00                             addu    $v0, $s2
.text:0042AFF8 05 00 53 A0                             sb      $s3, 5($v0)
.text:0042AFFC 00 00 23 92                             lbu     $v1, 0($s1)
.text:0042B000 60 27 05 92                             lbu     $a1, 0x2760($s0)
.text:0042B004 21 98 00 00                             move    $s3, $0
.text:0042B008 00 11 03 00                             sll     $v0, $v1, 4
.text:0042B00C 23 10 43 00                             subu    $v0, $v1
.text:0042B010 80 10 02 00                             sll     $v0, 2
.text:0042B014 21 10 52 00                             addu    $v0, $s2
.text:0042B018 DC 05 03 24                             li      $v1, 0x5DC
.text:0042B01C 0C 00 43 AC                             sw      $v1, 0xC($v0)
.text:0042B020 00 00 24 92                             lbu     $a0, 0($s1)
.text:0042B024 44 80 83 8F                             lw      $v1, offset sub_42B1D4
.text:0042B028 00 11 04 00                             sll     $v0, $a0, 4
.text:0042B02C 23 10 44 00                             subu    $v0, $a0
.text:0042B030 80 10 02 00                             sll     $v0, 2
.text:0042B034 21 10 52 00                             addu    $v0, $s2
.text:0042B038 D4 B1 63 24                             addiu   $v1, 0xB1D4
.text:0042B03C 10 00 43 AC                             sw      $v1, 0x10($v0)
.text:0042B040 00 00 24 92                             lbu     $a0, 0($s1)
.text:0042B044 44 80 83 8F                             lw      $v1, offset sub_42B220
.text:0042B048 00 11 04 00                             sll     $v0, $a0, 4
.text:0042B04C 23 10 44 00                             subu    $v0, $a0
.text:0042B050 80 10 02 00                             sll     $v0, 2
.text:0042B054 21 10 52 00                             addu    $v0, $s2
.text:0042B058 20 B2 63 24                             addiu   $v1, 0xB220
.text:0042B05C 14 00 43 AC                             sw      $v1, 0x14($v0)
.text:0042B060 00 00 24 92                             lbu     $a0, 0($s1)
.text:0042B064 44 80 83 8F                             lw      $v1, offset sub_42B6BC
.text:0042B068 00 11 04 00                             sll     $v0, $a0, 4
.text:0042B06C 23 10 44 00                             subu    $v0, $a0
.text:0042B070 80 10 02 00                             sll     $v0, 2
.text:0042B074 21 10 52 00                             addu    $v0, $s2
.text:0042B078 BC B6 63 24                             addiu   $v1, 0xB6BC
.text:0042B07C 1C 00 43 AC                             sw      $v1, 0x1C($v0)
.text:0042B080 00 00 24 92                             lbu     $a0, 0($s1)
.text:0042B084 44 80 83 8F                             lw      $v1, offset sub_42B2CC
.text:0042B088 00 11 04 00                             sll     $v0, $a0, 4
.text:0042B08C 23 10 44 00                             subu    $v0, $a0
.text:0042B090 80 10 02 00                             sll     $v0, 2
.text:0042B094 21 10 52 00                             addu    $v0, $s2
.text:0042B098 CC B2 63 24                             addiu   $v1, 0xB2CC
.text:0042B09C 20 00 43 AC                             sw      $v1, 0x20($v0)
.text:0042B0A0 00 00 24 92                             lbu     $a0, 0($s1)
.text:0042B0A4 44 80 83 8F                             lw      $v1, offset sub_42B414
.text:0042B0A8 00 11 04 00                             sll     $v0, $a0, 4
.text:0042B0AC 23 10 44 00                             subu    $v0, $a0
.text:0042B0B0 80 10 02 00                             sll     $v0, 2
.text:0042B0B4 21 10 52 00                             addu    $v0, $s2
.text:0042B0B8 14 B4 63 24                             addiu   $v1, 0xB414
.text:0042B0BC 24 00 43 AC                             sw      $v1, 0x24($v0)
.text:0042B0C0 00 00 26 92                             lbu     $a2, 0($s1)
.text:0042B0C4 44 80 83 8F                             lw      $v1, offset sub_42B49C
.text:0042B0C8 28 80 84 8F                             lw      $a0, offset aDemod_I2cDevic  # "Demod. I2C Device 0x30 and tuner 0xC2 v"...
.text:0042B0CC 00 11 06 00                             sll     $v0, $a2, 4
.text:0042B0D0 23 10 46 00                             subu    $v0, $a2
.text:0042B0D4 80 10 02 00                             sll     $v0, 2
.text:0042B0D8 21 10 52 00                             addu    $v0, $s2
.text:0042B0DC 9C B4 63 24                             addiu   $v1, 0xB49C
.text:0042B0E0 28 00 43 AC                             sw      $v1, 0x28($v0)
.text:0042B0E4 00 00 26 92                             lbu     $a2, 0($s1)
.text:0042B0E8 44 80 83 8F                             lw      $v1, offset sub_42B524
.text:0042B0EC 44 5B 84 24                             addiu   $a0, 0x5B44      # "Demod. I2C Device 0x30 and tuner 0xC2 v"...
.text:0042B0F0 00 11 06 00                             sll     $v0, $a2, 4
.text:0042B0F4 23 10 46 00                             subu    $v0, $a2
.text:0042B0F8 80 10 02 00                             sll     $v0, 2
.text:0042B0FC 21 10 52 00                             addu    $v0, $s2
.text:0042B100 24 B5 63 24                             addiu   $v1, 0xB524
.text:0042B104 2C 00 43 AC                             sw      $v1, 0x2C($v0)
.text:0042B108 00 00 26 92                             lbu     $a2, 0($s1)
..............
..............
..............

Se isso for a inicialização do tuner do ZBT-633 e no SEMP tiver uma rotina igual, então é possível fazer uma adaptação. O problema é que talvez, como você apontou, possam existir várias fases de inicialização. Aí seriam várias rotinas.

FORUM.RYAN.COM.BR

Re: Firmware do conversor digital Zinwell ZBT-620A "tijolão" com função PVR
« Responder #29 Online: Março 18, 2011, 03:47:32 am »