- PVSM.RU - https://www.pvsm.ru -
И снова мы разбираемся как не писать прошивки для микроконтроллеров. Прошлая статья вызвала у людей много эмоций и, мне кажется, осталось мало кем понята и, может быть, мной плохо было объяснено зачем это все вообще затевалось.
Поэтому подготовил пример [1].
Хотя это всего лишь подправленный сэмпл DMA_Polling из Standard Peripherals Library.
Но в этом и преимущество такого подхода, что можно использовать все наработки из кода выполняемого на микроконтроллере, в том числе и библиотеки от производителя МК типа HAL или Standard Peripherals Library. И это должно справедливо быть для любого контроллера, который поддерживает openOCD — хоть STM32, Atmel, PIC32 и прочие по списку [2]. При этом мы можем использовать все библиотеки хостового ПК, а так же пользоваться новыми стандартами языка С++. А если написать обертки, то и вообще можно использовать любой язык. Но я не стал сильно усложнять здесь. Просто решил показать основной функционал и возможности.
В примере, конечно, будем моргать светодиодиком. А так же отсылать данные по UART и по другому UART их принимать с помощью DMA. Использование DMA дает громадный бонус. Зачастую можно будет избавиться от прерываний, которые мы здесь не можем использовать, и поллинга, который из-за моего отладчика работает очень медленно, но тем неменее успевать захватывать данные на интерфейсах. А так же быстро генерировать. Поэтому довольно просто сделать программируемый генератор сигналов и сниффер разнообразных интерфейсов.
Оборудование на котором будем испытывать, осталось со времен первой статьи [3]
Здесь белым проводком соединил Тх UART1 (PA9 pin) c Rx UART2 (PA3 pin).
const 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++) {
/* Send one byte from USARTy to USARTz */
USART_SendData(USARTy, message[i]);
GPIO_SetBits(GPIOC, GPIO_Pin_13);
/* Loop until USARTy DR register is empty */
while (USART_GetFlagStatus(USARTy, USART_FLAG_TXE) == RESET);
printf(".");
fflush(stdout);
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
}
printf("n");
printf("qty of sent bytes %dn", strlen(message));
const uint16_t rec = DMA_GetCurrDataCounter(USARTz_Rx_DMA_Channel);
printf("qty of received byte using DMA : %dn", 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;
}
То можно увидеть, что за исключением нашей ф-ции преобразования адресов и ф-ций из стандратной библиотеки, все остальное взято SPL от ST, впринципе можно было и из HAL ф-ции использовать. Но мне привычнее старый добрый SPL.
Это пример для ПК с Ubuntu 16.04 64-bit:
Для начала нужно скачать Pintool v3.7 [4]
Распаковать куда удобно, дальше можно либо переменную PIN_ROOT определить для сборки PinTool клиента либо просто расположить наш клиент в
pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/
Я делаю вторым способом
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/
git clone git@github.com:ser-mk/AddressIntercept.git
cd AddressIntercept
Дальше потребуется собрать 32-битный клиент
make TARGET=ia32
Бинарник будет лежать здесь obj-ia32/addrIntercept.so. 32-битный требуется, потому как в ARM Сortex такой размер адреса.
Теперь можно собирать и сам пример. Его копирую прям в папку к 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
И получаем в катологе test.elf бинарник. Дальше для простоты эксперимента, положу файл в директорию нашего Pintool клиента AddressIntercept
Перед тем что бы все запускать, нам надо бы создать именованные FIFO для общения с OpenOCD клиентом
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept
mkfifo in.fifo out.fifo
in.fifo out.fifo — названия по умолчанию для наших клиентов, можно дать и другие названия, но тогда их придется указывать явно при запуске клиентов.
Запустим openOCD клиент, в моем случае ему надо передать ip openOCDсервера, это будет 192.168.0.111, порт оставил стандартный 6666, поэтому не указываю его.
Итак запускаем по порядку
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
И вывод должен быть такой:
Надеюсь пример наглядный. Уже вполне получился proof of concept, который можно использовать.
Причем должно все работать в том числе на MacOS и Windows (здесь, возможно, придется подправить работу с named fifo или её заменить на то что есть в "окнах").
Дальше, в следующих статьях, если интересно, можно рассказать про REPL как на гифке из предыдущей статьи и другие способы перехвата адресов, без ограничения платформой Intel.
Автор: ser-mk
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/stm32/303438
Ссылки в тексте:
[1] пример: https://github.com/ser-mk/addrIntercept-example-UART-DMA
[2] списку: http://openocd.org/
[3] первой статьи: https://habr.com/post/402233/
[4] Pintool v3.7: https://software.intel.com/sites/landingpage/pintool/downloads/pin-3.7-97619-g0d0c92f4f-gcc-linux.tar.gz
[5] Источник: https://habr.com/post/434080/?utm_campaign=434080
Нажмите здесь для печати.