
Y nuevamente, descubrimos cómo no escribir firmware para microcontroladores. El artículo anterior despertó muchas emociones en las personas y, según me parece, pocas personas entendieron y, tal vez, me explicaron mal por qué se inició todo esto.
Por lo tanto, preparé un ejemplo .
Aunque esto es solo una muestra ajustada de DMA_Polling de la Biblioteca de periféricos estándar.
Pero esta es la ventaja de tal enfoque que puede utilizar todos los desarrollos del código ejecutado en el microcontrolador, incluidas las bibliotecas del fabricante del MK tipo HAL o la Biblioteca de periféricos estándar. Y esto debería ser justo para cualquier controlador que admita openOCD, al menos STM32, Atmel, PIC32 y otros en la lista . Al mismo tiempo, podemos usar todas las bibliotecas de la PC host, así como también usar los nuevos estándares de lenguaje C ++. Y si escribe envoltorios, en general puede usar cualquier idioma. Pero no he complicado mucho aquí. Simplemente decidí mostrar la funcionalidad y características básicas.
En el ejemplo, por supuesto, parpadearemos el LED. Y también envíe datos en UART y en otro UART para recibirlos usando DMA. Usar DMA da una gran ventaja. A menudo será posible deshacerse de las interrupciones que no podemos usar aquí, y las encuestas, que, debido a mi depurador, son muy lentas, pero aún menos tiempo para capturar datos en las interfaces. Y también generar rápidamente. Por lo tanto, es bastante simple hacer un generador de señal programable y un sniffer de varias interfaces.
El equipo en el que probaremos permanece desde el momento del primer artículo.

Aquí conecté el cableado blanco UART1 (pin PA9) con Rx UART2 (pin PA3).
Si miras el 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; }
Puede ver que, con la excepción de nuestra función de convertir direcciones y funciones de la biblioteca estándar, todo lo demás se toma del SPL de ST, en principio, fue posible usarlo desde la función HAL. Pero estoy más familiarizado con el buen viejo SPL.
Cómo armar y ejecutar todo
Este es un ejemplo para una PC con Ubuntu 16.04 de 64 bits:
Primero necesitas descargar Pintool v3.7
Desempacar es conveniente, puede definir la variable PIN_ROOT para construir el cliente PinTool o simplemente ubicar a nuestro cliente en
pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/
Hago la segunda manera
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/ git clone git@github.com:ser-mk/AddressIntercept.git cd AddressIntercept
A continuación, debe crear un cliente de 32 bits.
make TARGET=ia32
El binario estará aquí obj-ia32 / addrIntercept.so. Se requiere 32 bits, porque en ARM ortex tal tamaño de dirección.
Ahora puede recopilar el ejemplo en sí. Lo copio directamente a la carpeta al 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
Y obtenemos el binario en el directorio test.elf. Además, para simplificar el experimento, colocaré el archivo en el directorio de nuestro cliente de Pintool AddressIntercept
Antes de comenzar todo, necesitaríamos crear FIFO con nombre para comunicarnos con el cliente OpenOCD
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept mkfifo in.fifo out.fifo
in.fifo out.fifo - nombres predeterminados para nuestros clientes, puede dar otros nombres, pero luego deberán especificarse explícitamente al iniciar clientes.
Ejecute el cliente openOCD, en mi caso necesita pasar la ip del servidor openOCD ip, será 192.168.0.111, el puerto dejará el 6666 estándar, así que no lo especifico.
Entonces, corre en orden
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
Y la conclusión debería ser así:

Espero un ejemplo ilustrativo. Ya es una gran prueba de concepto que se puede utilizar.
Además, todo debería funcionar, incluso en MacOS y Windows (aquí, puede que tenga que modificar el trabajo con el nombre de Fifo o reemplazarlo con lo que está en las "ventanas").
Además, en los siguientes artículos, si es interesante, puede hablar sobre REPL como en el GIF del artículo anterior y otras formas de interceptar direcciones, sin limitar la plataforma Intel.