
E, novamente, descobrimos como não escrever firmware para microcontroladores. O artigo anterior despertou muitas emoções nas pessoas e, parece-me, poucas pessoas entenderam e, talvez, não me foi explicado por que tudo isso foi iniciado.
Por isso, preparei um exemplo .
Embora seja apenas uma amostra aprimorada de DMA_Polling da Biblioteca de Periféricos Padrão.
Mas esta é a vantagem dessa abordagem: você pode usar todos os desenvolvimentos do código executado no microcontrolador, incluindo bibliotecas do fabricante MK, como HAL ou Standard Peripherals Library. E isso deve ser justo para qualquer controlador que suporte openOCD - pelo menos STM32, Atmel, PIC32 e outros na lista . Ao mesmo tempo, podemos usar todas as bibliotecas do PC host, bem como os novos padrões de linguagem C ++. E se você escrever wrappers, em geral, poderá usar qualquer idioma. Mas não compliquei muito aqui. Eu apenas decidi mostrar as funcionalidades e recursos básicos.
No exemplo, é claro, piscaremos o LED. E também envie dados no UART e em outro UART para recebê-los usando o DMA. Usar o DMA oferece um bônus enorme. Muitas vezes, é possível livrar-se das interrupções que não podemos usar aqui e das pesquisas, que, devido ao meu depurador, são muito lentas, mas ainda menos tempo para capturar dados nas interfaces. E também gerar rapidamente. Portanto, é bastante simples criar um gerador de sinal programável e um sniffer de várias interfaces.
O equipamento no qual testaremos permanece desde o início do primeiro artigo

Aqui, conectei a fiação branca UART1 (pino PA9) com o Rx UART2 (pino PA3).
Se você olhar para o códigoconst char * message = "AddressIntercept PinTool UART DMA example"; int main() { sizeMemoryTranslate_t s = 0; memoryTranslate *p = getMemoryMap(&s); pAddrPERIPH = p[0].start_addr; pAddrSRAM = p[1].start_addr; init(); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef gpio; gpio.GPIO_Pin = GPIO_Pin_13; gpio.GPIO_Speed = GPIO_Speed_50MHz; gpio.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &gpio); const size_t _SIZE_MESSAGE = strlen(message); printf("sending message "); for (int i = 0; i < _SIZE_MESSAGE; i++) { USART_SendData(USARTy, message[i]); GPIO_SetBits(GPIOC, GPIO_Pin_13); while (USART_GetFlagStatus(USARTy, USART_FLAG_TXE) == RESET); printf("."); fflush(stdout); GPIO_ResetBits(GPIOC, GPIO_Pin_13); } printf("\n"); printf("qty of sent bytes %d\n", strlen(message)); const uint16_t rec = DMA_GetCurrDataCounter(USARTz_Rx_DMA_Channel); printf("qty of received byte using DMA : %d\n", sizeDMAbuf - rec); printf("read message from buffer DMA : "); const uint8_t *pM = (uint8_t *)pAddrSRAM; for (int r = 0; r < _SIZE_MESSAGE; r++) { printf("%c", pM[r]); fflush(stdout); } printf("\n"); assert(strncmp(message, (const char *)pM, _SIZE_MESSAGE) == 0); printf("Received and sent bytes are equal!\n"); return 0; }
Você pode ver que, com a exceção da nossa função de converter endereços e funções da biblioteca padrão, todo o resto foi retirado pelo SPL do ST, em princípio era possível usar as funções HAL. Mas estou mais familiarizado com o bom e velho SPL.
Como montar e executar tudo
Este é um exemplo para um PC com Ubuntu 16.04 de 64 bits:
Primeiro você precisa baixar o Pintool v3.7
Descompactar é conveniente, então você pode definir a variável PIN_ROOT para criar o cliente PinTool ou simplesmente localizar nosso cliente em
pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/
Eu faço o segundo caminho
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/ git clone git@github.com:ser-mk/AddressIntercept.git cd AddressIntercept
Em seguida, você precisa criar um cliente de 32 bits
make TARGET=ia32
O binário estará aqui obj-ia32 / addrIntercept.so. É necessário 32 bits, porque no ARM ortex esse tamanho de endereço.
Agora você pode coletar o próprio exemplo. Copio-o diretamente para a pasta no cliente pintool
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept Git clone https://github.com/ser-mk/addrIntercept-example-UART-DMA Cd addrIntercept-example-UART-DMA Make
E nós obtemos o binário no diretório test.elf. Para simplificar o experimento, colocarei o arquivo no diretório do nosso cliente Pintool AddressIntercept
Antes de começar tudo, precisaríamos criar FIFOs nomeados para se comunicar com o cliente OpenOCD
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept mkfifo in.fifo out.fifo
in.fifo out.fifo - nomes padrão para nossos clientes, você pode dar outros nomes, mas eles terão que ser especificados explicitamente ao iniciar clientes.
Vamos iniciar o cliente openOCD, no meu caso eu preciso passar o servidor ip openOCD para ele, será 192.168.0.111, a porta deixará o 6666 padrão, então não o especifico.
Então, corra em ordem
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept python3.5m OCDclient.py -ip 192.168.0.111 & ../../../pin -t obj-ia32/addrIntercept.so -- addrIntercept-example-UART-DMA/test.elf
E a conclusão deve ser assim:

Espero um exemplo ilustrativo. Já é uma prova de conceito que pode ser usada.
E tudo deve funcionar, inclusive no MacOS e no Windows (aqui, você pode precisar ajustar o trabalho com o nome fifo ou substituí-lo pelo que está nas "janelas").
Além disso, nos artigos a seguir, se for interessante, você pode falar sobre o REPL como no GIF do artigo anterior e outras maneiras de interceptar endereços, sem limitar a plataforma Intel.