Cosworth 0 9 июля, 2015 Опубликовано 9 июля, 2015 · Жалоба А вот интересно, у кого-нибудь получился вот такой трюк: http://www.youtube.com/watch?v=cvKC-4tCRgw ? Решил попробовать на f0-дисковери (контроллер stm32f051). Открыл руководство по бутлодеру: 3 Kbytes starting from address 0x1FFFEC00, contain the bootloader firmware. Сдампил содержимое: 7806 0020 35ee ff1f edec ff1f edec ff1f 00f0 02f8 00f0 40f8 0ca0 30c8 0838 2418 2d18 a246 671e ab46 5446 5d46 ac42 01d1 00f0 32f8 7e46 0f3e 0fcc ... Здорово, первая чиселка 0х20000678 похожа на адрес из рамы, очевидно - указатель куда надо стек поместить. А дальше, с адреса 0x1FFFEC00 + 4 (как раз куда этот чел с видео прыгает) - мура какая-то (0х1FFFEE35), подозреваю, что это некая таблица с адресами. На видео - тоже самое. Дизассемблер видит в этом месте инструкцию arm режима: " mrc 15, 1, r1, cr5, cr15, {7} " - в доках что-то про сопроцессор (какой нафиг сопроцессор?). Вообшем я сделал вывод, что по адресу System Memory + 4 инструкции нету и, тогда вопрос, зачем туда переходить? Ну ладно, думаю, почему не попробовать: void __early_init(void) { uint32_t *key = ( uint32_t * ) SRAM_BASE; void ( *BootLoader )( void ) = ( void ( * )( void ) ) 0x1FFFEC04; if( *key == 0xDEADC0DE ) { *key = 0; __set_PRIMASK( 1 ); __set_MSP( 0x20000678 ); __set_CONTROL( 0 ); BootLoader(); } stm32_clock_init(); } Как и предполагалось - переход по адресу 1FFFEC04 и на этой самой инструкции mrc - провал в хард фолт. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SSerge 6 9 июля, 2015 Опубликовано 9 июля, 2015 · Жалоба Младший бит в адресах переходов - признак Thumb mode, поэтому команду надо было начинать дизассемблировать с адреса 0х1FFFEE34. Кроме передачи управления нужно ещё переключить мэппинг памяти, за это отвечают биты MEM_MODE[1:0] в регистре SYSCFG->CFGR1. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 9 июля, 2015 Опубликовано 9 июля, 2015 · Жалоба Между прочим, в AN2602 написано следующее: In addition to patterns described below, user can execute bootloader by performing a jump to system memory from user code. Before jumping to Bootloader user must: • Disable all peripheral clocks • Disable used PLL • Disable interrupts • Clear pending interrupts Ну и правильно сказал SSerge: нужно добавить 1 к адресу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SSerge 6 9 июля, 2015 Опубликовано 9 июля, 2015 · Жалоба Ну и правильно сказал SSerge: нужно добавить 1 к адресу. Я, наверное, не совсем точно выразился. Во избежание заблуждений надо бы уточнить. Специально ничего добавлять не нужно, линкер об этом уже позаботился и по адресу 0x1FFFEC04 положил адрес перехода с установленным в 1 младшим битом. Сами адреса памяти, по которым будет производится выборка команд, естественно будут чётными. Эту единичку надо учитывать при интерпретации программы "в уме" и при вычислении адресов перехода "вручную" из указателей на память данных. Это всё досталось в наследство от предыдущих ARM, которые имели два набора команд (32-битные ARM и 16-битные Thumb) и младшим битом загружаемого в PC значения указывалось что нужно переключиться в Thumb. У кортексов набор команд только один, Thumb-2, переключать нечего, но установленный младший бит в адресах переходов остался "для совместимости". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Cosworth 0 10 июля, 2015 Опубликовано 10 июля, 2015 (изменено) · Жалоба Младший бит в адресах переходов - признак Thumb mode, поэтому команду надо было начинать дизассемблировать с адреса 0х1FFFEE34. Кроме передачи управления нужно ещё переключить мэппинг памяти, за это отвечают биты MEM_MODE[1:0] в регистре SYSCFG->CFGR1. А, ну точно, надо ж не на 0x1FFFEC04 прыгать, а на адрес, который там хранится. В общем-то, я как делаю: из основной программы по команде выключаю все прерывания, записываю по нулевому адресу рамы ключ, ремаплю нулевой адрес на System Flash (Mem_MODE = 01) и делаю сброс. После сброса - попадаю в __early_init(). Вот поправил указатель: void __early_init(void) { ... void ( *BootLoader )( void ) = ( ( void * )( void ) ) ( *( ( uint32_t * ) 0x1FFFEC04 ) ); ... } Хард флотов больше нет, но контроллер после выполнения BootLoader() прыгает то в ресет то в рандомную функцию и через stlink не прогается - приходится стирать прошивку через бутлоадер. Изменено 10 июля, 2015 пользователем Cosworth Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 10 июля, 2015 Опубликовано 10 июля, 2015 · Жалоба На всякий случай поделюсь своим рецептом перехода на прошивку по произвольному адресу: static const uint16_t jump2fw[] = { 0x6801, // ldr r1, [r0, #0] 0x468D, // mov sp, r1 0x6840, // ldr r0, [r0, #4] 0x4700, // bx r0 }; ((void (*)(int))(1 + (int)jump2fw))(FIRMWARE_ADDRESS); В данном случае FIRMWARE_ADDRESS - это 0, потому что загрузчик, очевидно, ожидает, что его код замапен на нулевой адрес. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 141 10 июля, 2015 Опубликовано 10 июля, 2015 · Жалоба до кучи мой рецепт перехода: extrn "C" void func(); void test() { func(); } // В командную строку линкера добавляем -Wl,--defsym,func=адрес Переход на функцию по указателю (как в вопросе) делал бы так: extern "C" void (*bootloader)(); void test() { bootloader(); } // В командную строку линкера добавляем -Wl,--defsym,bootloader=0x1FFFEC04 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 10 июля, 2015 Опубликовано 10 июля, 2015 · Жалоба до кучи мой рецепт перехода: Я имел в виду переход на начало прошивки с загрузкой указателя стека и точки входа (так, как стартует Cortex). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться