Tenho dúvidas de que o emulador JTAG da Texas Instruments para depuração de processadores seja um dispositivo tão difundido que seria interessante para alguém ressuscitá-lo. No entanto, o artigo pode ser útil para aqueles que estão tentando reanimar algo baseado em um sistema Linux de placa única, com recursos e informações limitados. Você pode considerar isso como um trabalho prático com o U-Boot.

Em vez do prefácio
Qualquer pessoa que depure programas para sistemas embarcados sabe que você precisa usar dispositivos especiais para se conectar aos processadores. Adaptadores chamados emuladores JTAG são usados para a família de processadores Texas Instruments.
Existem muitos e de diferentes fabricantes. No meu parque, entre outros, o Blackhawk USB560v2 aparece . Devo admitir que não é o pedaço de ferro mais barato. E então um dia ela parou de trabalhar sem motivo aparente.
Sintomas
Tudo aconteceu um dia, o dispositivo parou de carregar e foi detectado via USB. O LED piscou, mas não entrou no estado "pronto para usar".
Este dispositivo possui um modo documentado divertido: após 10 a 15 downloads sem êxito, ele deve ter mudado para um modo especial (modo de segurança) que permitiria a atualização novamente. No entanto, meu dispositivo se recusou a mudar para este modo, não atingiu o estágio de numeração USB e, portanto, não havia possibilidade de atualizar com o utilitário padrão. A correspondência com o serviço de suporte não levou a nada: eles se recusaram a me ajudar com equipamentos técnicos, oferecendo apenas o envio (às suas próprias custas) de um dispositivo para eles nos EUA para diagnóstico e reparo.
Não havia escolha a não ser iniciar um reparo independente.
O Ubuntu está instalado no host, alguns utilitários usados estão incluídos na distribuição, outros são instalados via apt.
Inspeção externa

Nós desmontamos, olha o quadro. No quadro estão localizados:
Fiquei especialmente satisfeito com o conector UART cuidadosamente desgastado, que, além disso, foi criado para um pente padrão de 2,54 mm, para que os contatos fossem assinados. Não vejo isso há muito tempo, no máximo cinco posições no quadro e até com marcas insignificantes, como TP1, etc.
Vamos começar
Nós conectamos o USB-UART (não se esqueça do nível, é de 3,3 V aqui). Começamos o minicom, recebemos:
TI UBL Version: 1.13, Flash type: NAND Booting PSP Boot Loader PSPBootMode = NAND Starting NAND Copy... Initializing NAND flash... Manufacturer ID = 0x0000002C Device ID = 0x000000A1 Pages Per Block = 0x00000040 Number of Blocks = 0x00000400 Bytes Per Page = 0x00000800 Valid MagicNum found at block 0x00000001, page 0x00000008 NAND Boot success. DONE U-Boot 2010.12 (May 09 2012 - 13:10:23) Cores: ARM 257 MHz, DSP 513 MHz DDR: 162 MHz I2C: ready DRAM: 256 MiB NAND: 128 MiB MMC: Bad block table found at page 65472, version 0x01 Bad block table found at page 65408, version 0x01 In: serial Out: serial Err: serial Read USBID pin : DEVICE Read boot progress legacy : 0 Read boot progress : 0 Write boot progress legacy : 0 Write boot progress : 0 Hit any key to stop autoboot: 0 Loading from NAND 128MiB 1,8V 8-bit, offset 0x60000 Image Name: Linux-2.6.10_mvl401-xds560 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 1236292 Bytes = 1.2 MiB Load Address: 80008000 Entry Point: 80008000 NAND read from offset 60000 failed -74 ** Read error
Como você pode ver, a sequência é bastante padrão: o primeiro carregador de inicialização (TI UBL) é carregado e o U-Boot, que por sua vez carrega o kernel do Linux.
De acordo com o log, é óbvio que algo ocorreu no NAND Flash interno; quando o kernel do Linux é carregado, a soma de verificação não converge. No entanto, você pode interromper o download e entrar no console do U-Boot.
Dê uma olhada nos comandos disponíveis:
Existem muitos deles U-Boot > help ? - alias for 'help' askenv - get environment variables from stdin base - print or set address offset boot - boot default, ie, run 'bootcmd' bootd - boot default, ie, run 'bootcmd' bootm - boot application image from memory cmp - memory compare coninfo - print console devices and information cp - memory copy crc32 - checksum calculation echo - echo args to console editenv - edit environment variable eeprom - EEPROM sub-system env - environment handling commands exit - exit script false - do nothing, unsuccessfully fatinfo - print information about filesystem fatload - load binary file from a dos filesystem fatls - list files in a directory (default /) go - start application at address 'addr' help - print command description/usage i2c - I2C sub-system iminfo - print header information for application image imxtract- extract a part of a multi-image itest - return true/false on integer compare loadb - load binary file over serial line (kermit mode) loads - load S-Record file over serial line loady - load binary file over serial line (ymodem mode) loop - infinite loop on address range md - memory display mdc - memory display cyclic mii - MII utility commands mm - memory modify (auto-incrementing address) mmc - MMC sub system mmcinfo - display MMC info mtest - simple RAM read/write test mw - memory write (fill) mwc - memory write cyclic nand - NAND sub-system nboot - boot from NAND device nm - memory modify (constant address) printenv- print environment variables reset - Perform RESET of the CPU run - run commands in an environment variable saveenv - save environment variables to persistent storage saves - save S-Record file over serial line setenv - set environment variables showvar - print local hushshell variables sleep - delay execution for some time source - run script from memory test - minimal test like /bin/sh true - do nothing, successfully usb - USB sub-system usbboot - boot from USB device version - print monitor version
Vamos ver as variáveis de ambiente:
U-Boot > printenv autokern=0x60000 autoroot=/dev/mtdblock3 baudrate=115200 bootcmd=nboot 80700000 0 ${autokern}; run setbootargsnand; bootm setbootargsnand=setenv bootargs mem=64M console=ttyS0,${baudrate}n8 root=${autoroot} rw rootfstype=jffs2 ip=off stderr=serial stdin=serial stdout=serial ver=U-Boot 2010.12 (May 09 2012 - 13:10:23) Environment size: 338/16380 bytes
A primeira coisa que tentei foi desativar a verificação e inicializar usando os comandos U-Boot.
U-Boot > setenv verify n U-Boot > boot
Movemos um pouco mais, mas não muito:
Além disso, o dispositivo trava.
Pode ser visto pelas variáveis de ambiente que a imagem do kernel está no NAND Flash com um deslocamento de 0x60000, quando carregada, é copiada para o endereço 0x80700000 (de acordo com o mapa de memória do processador, este é o espaço de endereço da DRAM externa) e carregada. O tamanho da imagem do kernel, como pode ser visto no log, é 1236292 bytes. Eu tentei fazer isso manualmente. Assumimos que a imagem é armazenada no formato uImage; portanto, lançamos 64 bytes no cabeçalho, obtemos 1236356 bytes = 0x12DD84:
U-Boot > nand read 80700000 60000 12dd84 U-Boot > iminfo
Em seguida, eu queria enviar o despejo de imagem para o computador para brincar com ele. Não criei nada melhor do que escrever um log do console com a saída de memória na tela e depois convertê-lo em um arquivo binário.
Execute o minicom com o log:
minicom -C orig-uImage.txt
Exibimos o conteúdo da memória na tela:
U-Boot > md.b 80700000 12dd84
Saímos do minicom, editamos o log, removemos as linhas extras e o convertemos no binário:
xxd -r -seek -0x80700000 orig-uImage.txt orig-uImage
Eu queria reembalar a imagem para que não produzisse erros de soma de verificação. Exclua os primeiros 64 bytes e faça uma nova uImage:
mkimage -A arm -T kernel -C none -a 80008000 -e 80008000 -n "Linux-2.6.10_mvl401-xds560" -d orig-uImage patched-uImage
Preencha o arquivo resultante usando o protocolo YModem:
U-Boot > loady
Tentamos inicializar, mas também travamos na fase de descompactar o kernel:
U-Boot > bootm
Era de se esperar o que se poderia esperar aqui. Mas pelo menos eles carregaram o fluxo de trabalho de compartilhamento de arquivos, nada mal.
Tudo o que temos é um arquivo de firmware do site do fabricante , USB560v2_firmware_5.0.573.0.bin
. Supus que esse arquivo contenha uma imagem do kernel, mas seria razoável esperar que o arquivo seja criptografado com pelo menos uma chave simples. Portanto, admito, quebrei e escrevi ao fabricante uma solicitação para fornecer uma uImage
ininterrupta para que eu pudesse carregá-la no dispositivo e inicializá-la e, em seguida, atualizar o dispositivo com um utilitário USB padrão. Ele até se referiu aos termos da GPL (sob a qual o Linux é distribuído), segundo os quais não faria mal fornecer os códigos-fonte do kernel além disso.
Imediatamente após o envio da solicitação, decidi, no entanto, tentar descompactar o arquivo do firmware, como um arquivo simples. E eis que, acabou!
tar -xf USB560v2_firmware_5.0.573.0.bin
Após descompactar, dois arquivos apareceram: uImage
e rootfs.tar.gz
. O que o médico receitou é uma imagem do kernel e um sistema de arquivos raiz.
Resta preencher a uImage
na memória do dispositivo usando o YModem e iniciar, o que eu fiz. O dispositivo inicializado com sucesso no mesmo modo de segurança, desliguei-os. suporte do fabricante e, achando que vou pegar o dispositivo na próxima vez, calmamente fui dormir.
Segunda série
No entanto, no dia seguinte, uma surpresa desagradável me esperava. O dispositivo parou de carregar com sucesso. O que eu simplesmente não tentei, recebi um erro:
INIT: PANIC: segmentation violation! sleeping for 30 seconds.
Log de inicialização longo do kernel Starting kernel ... Uncompressing Linux................................................................................. done, booting thelLinux version 2.6.10_mvl2 CPU: ARM926EJ-Sid(wb) [41069265] revision 5 (ARMv5TEJ) CPU0: D VIVT write-back cache CPU0: I cache: 16384 bytes, associativity 4, 32 byte lines, 128 sets CPU0: D cache: 8192 bytes, associativity 4, 32 byte lines, 64 sets Machine: DaVinci EVM Memory policy: ECC disabled, Data cache writeback Built 1 zonelists Kernel command line: mem=64M console=ttyS0,115200n8 root=/dev/mtdblock3 rw rootfstype=jffs2 ip=off PID hash table entries: 512 (order: 9, 8192 bytes) Console: colour dummy device 80x30 Dentry cache hash table entries: 16384 (order: 4, 65536 bytes) Inode-cache hash table entries: 8192 (order: 3, 32768 bytes) Memory: 64MB = 64MB total Memory: 62080KB available (2118K code, 448K data, 136K init) Mount-cache hash table entries: 512 (order: 0, 4096 bytes) CPU: Testing write buffer coherency: ok spawn_desched_task(00000000) desched cpu_callback 3/00000000 ksoftirqd started up. desched cpu_callback 2/00000000 desched thread 0 started up. NET: Registered protocol family 16 Registering platform device 'nor_davinci.0'. Parent at platform Registering platform device 'nand_davinci.0'. Parent at platform DaVinci I2C DEBUG: 12:46:30 Mar 29 2012 Registering platform device 'i2c'. Parent at platform musb_hdrc: version 2.2a/db-0.4.8 [cppi-dma] [peripheral] [debug=0] Registering platform device 'musb_hdrc'. Parent at platform musb_hdrc: USB Peripheral mode controller at c4800000 using DMA, IRQ 12 JFFS2 version 2.2. (NAND) (C) 2001-2003 Red Hat, Inc. yaffs Mar 29 2012 12:46:15 Installing. Registering platform device 'davincifb.0'. Parent at platform Console: switching to colour frame buffer device 90x30 Serial: 8250/16550 driver $Revision: 1.90 $ 2 ports, IRQ sharing disabled Registering platform device 'serial8250'. Parent at platform ttyS0 at MMIO 0x1c20000 (irq = 40) is a 16550A io scheduler noop registered io scheduler anticipatory registered RAMDISK driver initialized: 1 RAM disks of 32768K size 1024 blocksize Registering platform device 'ti_davinci_emac'. Parent at platform TI DaVinci EMAC: MAC address is 00:00:00:04:12:64 TI DaVinci EMAC Linux version updated 4.0 TI DaVinci EMAC: Installed 1 instances. netconsole: not configured, aborting i2c /dev entries driver elevator: using anticipatory as default io scheduler NAND device: Manufacturer ID: 0x2c, Chip ID: 0xa1 (Unknown NAND 128MiB 1,8V 8-bit) Scanning device for bad blocks Creating 8 MTD partitions on "nand_davinci.0": 0x00000000-0x00020000 : "params" 0x00020000-0x00060000 : "bootloader" 0x00060000-0x00260000 : "safekernel" 0x00260000-0x01260000 : "saferootfs" 0x01260000-0x01460000 : "kernel" 0x01460000-0x02860000 : "rootfs" 0x02860000-0x03860000 : "application" 0x03860000-0x03c60000 : "logging" nand_davinci: hardware revision: 2.1 mice: PS/2 mouse device common for all mice NET: Registered protocol family 2 IP: routing cache hash table of 512 buckets, 4Kbytes TCP: Hash tables configured (established 4096 bind 8192) NET: Registered protocol family 1 NET: Registered protocol family 17 jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x0000016c: 0xffef instead Empty flash at 0x00a237fc ends at 0x00a23800 Empty flash at 0x00c3b7d8 ends at 0x00c3b800 mtd->read(0x1f320 bytes from 0xec0ce0) returned ECC error mtd->read(0x1fb8c bytes from 0xf20474) returned ECC error VFS: Mounted root (jffs2 filesystem). Freeing init memory: 136K mtd->read(0x44 bytes from 0xf39da8) returned ECC error mtd->read(0x988 bytes from 0xf39420) returned ECC error mtd->read(0x44 bytes from 0xed8d20) returned ECC error jffs2_get_inode_nodes(): Data CRC failed on node at 0x00ed8d20: Read 0xa8462b94, calculated 0xa03c90e8 mtd->read(0xa7e bytes from 0xed82a0) returned ECC error jffs2_get_inode_nodes(): Data CRC failed on node at 0x00c3ad78: Read 0x31ac7e30, calculated 0xa52ecb11 jffs2_get_inode_nodes(): Data CRC failed on node at 0x00a22d9c: Read 0x31ac7e30, calculated 0xe9f89c4c mtd->read(0x988 bytes from 0xf39420) returned ECC error mtd->read(0xa7e bytes from 0xed82a0) returned ECC error INIT: version 2.85 booting INIT: PANIC: segmentation violation! sleeping for 30 seconds. jffs2_get_inode_nodes(): Data CRC failed on node at 0x00a2ad10: Read 0x5fa921cc, calculated 0x5282f1d9 INIT: PANIC: segmentation violation! sleeping for 30 seconds.
Concluí que o sistema de arquivos raiz também estava danificado. Bem, então você precisa piscá-lo também.
Primeiro, escreva uImage
para NAND, para não carregá-lo através do UART todas as vezes (devo admitir, a uma velocidade de 115200, um tempo perceptível é carregado mesmo no tamanho de um megabyte). Ao trabalhar com NAND, apenas para o caso, alinhamos o tamanho da imagem com o tamanho da página NAND (eu encontrei essa recomendação em algum lugar) e nosso tamanho de página é 1024 bytes = 0x800 (consulte o primeiro registro).
U-Boot > loady ... U-Boot > nand erase 60000 12DC00 U-Boot > nand write 80700000 60000 12DC00
No log de inicialização do kernel, selecione as informações úteis:
Creating 8 MTD partitions on "nand_davinci.0": 0x00000000-0x00020000 : "params" 0x00020000-0x00060000 : "bootloader" 0x00060000-0x00260000 : "safekernel" 0x00260000-0x01260000 : "saferootfs" 0x01260000-0x01460000 : "kernel" 0x01460000-0x02860000 : "rootfs" 0x02860000-0x03860000 : "application" 0x03860000-0x03c60000 : "logging"
Portanto, o sistema de arquivos raiz deve ser gravado em NAND com um deslocamento de 0x260000. Resta apenas entender em que formato. Recordamos as variáveis de ambiente U-Boot, em particular, esta linha:
setbootargsnand=setenv bootargs mem=64M console=ttyS0,${baudrate}n8 root=${autoroot} rw rootfstype=jffs2 ip=off
Portanto, precisamos converter nosso rootfs.tar.gz
, pescado do arquivo de firmware, no formato JFFS2. No prompt com o Wiki da Texas Instruments, fazemos isso (o sudo
necessário para o tar
, portanto gera erros ao executar o comando mknod
):
mkdir rootfs sudo tar -xf rootfs.tar.gz -C rootfs mkfs.jffs2 -n -r rootfs -e 16 -o rootfs.jffs2
Carregamos o arquivo resultante na memória do dispositivo e o copiamos na seção NAND desejada (o tamanho também é arredondado para a página):
U-Boot > loady ... U-Boot > nand erase 260000 39f000 U-Boot > nand write 80700000 260000 39f000
Cruzamos os dedos, reiniciamos, bem, agora está tudo bem.
Registro completo muito longo de download bem-sucedido TI UBL Version: 1.13, Flash type: NAND Booting PSP Boot Loader PSPBootMode = NAND Starting NAND Copy... Initializing NAND flash... Manufacturer ID = 0x0000002C Device ID = 0x000000A1 Pages Per Block = 0x00000040 Number of Blocks = 0x00000400 Bytes Per Page = 0x00000800 Valid MagicNum found at block 0x00000001, page 0x00000008 NAND Boot success. DONE U-Boot 2010.12 (May 09 2012 - 13:10:23) Cores: ARM 257 MHz, DSP 513 MHz DDR: 162 MHz I2C: ready DRAM: 256 MiB NAND: 128 MiB MMC: Bad block table found at page 65472, version 0x01 Bad block table found at page 65408, version 0x01 In: serial Out: serial Err: serial Read USBID pin : DEVICE Read boot progress legacy : 3 Read boot progress : 10 Write boot progress legacy : 2 Write boot progress : 9 Hit any key to stop autoboot: 0 Loading from NAND 128MiB 1,8V 8-bit, offset 0x1260000 Image Name: Linux-2.6.10_mvl401-xds560 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 1235632 Bytes = 1.2 MiB Load Address: 80008000 Entry Point: 80008000
Posfácio
Sim, o procedimento final acabou não sendo muito complicado; na verdade, não há muita engenharia reversa real aqui. Mas eu pessoalmente aprendi muitas coisas novas sobre coisas de baixo nível durante o processo de inicialização do Linux incorporado, aprendi como trabalhar com o console do U-Boot.
Para proprietários do Blackhawk USB560v2Pode-se ver que os caras não se incomodaram com a proteção. Após a inicialização do Linux, um prompt é exibido no console para efetuar login. O login root
sem senha permite que você efetue login com acesso administrativo e faça qualquer coisa com o dispositivo. O mais interessante está no /usr/local/bin
.
Mas esta é uma história completamente diferente.
Espero que tenha sido interessante.