toweroff 1 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба Добрый день Вот такой вопрос возник. Управление передается через подобный вызов: void (*Entry_Point)(void); Entry_Point = (void(*)(void))(USER_CODE); Entry_Point(); кстати, еще вопрос сразу - для ядра ARM968E-S значение USER_CODE так же будет (REAL_USER_CODE + 1), как и для CM3? Потом управление передается по адресу, указанному в линкере как ENTRY_POINT Но вопрос вот какой. При старте процессора, он находится в Supervisor режиме, когда грузит все регистры, а из бута он попадет на точку входа приложения уже в User/System Или это нормально, или я что-то не понял и проц нужно перед прыжком переводить в Supervisor режим? Сколько пересмотрел реализаций бутов для ARM7, CM3 - нигде не увидел явной смены режима работы Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kolobok0 0 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба ...нигде не увидел явной смены режима работы по поводу режима - так-же не видел явно. возможно пока сильно не копал. по поводу +1 = сам юзаю оверлейность, вычисление точки входа в "модуль" идёт на ран-тайме. управление передаётся на ура без всякой "коррекции" на единицу. объявление, вызов, сами подпрограммы - на сях. кхм. как то загрузили блин :) надо будет вкурить вопросы получше. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба для ядра ARM968E-S значение USER_CODE так же будет (REAL_USER_CODE + 1), как и для CM3? Значение USER_CODE будет +1 или +0 в зависимости от того, ARM-код это, или THUMB. Или это нормально, или я что-то не понял и проц нужно перед прыжком переводить в Supervisor режим? Сколько пересмотрел реализаций бутов для ARM7, CM3 - нигде не увидел явной смены режима работы В моей реализации большими буквами написано "SWI и xxx_Handler не используется, надо инициализировать только пользовательский стек". Но вообще-то для универсального бута странно. Это я знаю, что буду грузить своим загрузчиком. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба Значение USER_CODE будет +1 или +0 в зависимости от того, ARM-код это, или THUMB. только ARM В моей реализации большими буквами написано "SWI и xxx_Handler не используется, надо инициализировать только пользовательский стек". Но вообще-то для универсального бута странно. Это я знаю, что буду грузить своим загрузчиком. SWI нет, все аборты заткнуты на одну функцию, которая выкидывает в канал связи состояние CPSR и адрес, вызвавший исключение Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SyncLair 0 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба Сколько пересмотрел реализаций бутов для ARM7, CM3 - нигде не увидел явной смены режима работы Режимы работы как правило инициализируются в самом загружаемом модуле. То есть типичный скрипт для запуска содержит строчки где CPSR как раз инициализируется. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба Режимы работы как правило инициализируются в самом загружаемом модуле. То есть типичный скрипт для запуска содержит строчки где CPSR как раз инициализируется. ок, согласен. Но бут, как минимум, должен прерывания отключить, если он их использовал тогда мне непонятен такой момент На холодном старте проц вычитывает со стартового адреса ResetStart LDR PC, ResetAddr LDR PC, UndefinedAddr LDR PC, SWI_Addr LDR PC, PrefetchAddr LDR PC, DataAbortAddr LDR PC, ReservedAddr LDR PC, IRQ_Addr LDR PC, FIQ_Addr далее инициализируются стеки (вызывается эта функция): InitStack MOV R0, LR ;Build the SVC stack MSR CPSR_c, #SVC32Mode :OR: I_BIT :OR: F_BIT LDR SP, StackSvc ;Build the IRQ stack MSR CPSR_c, #IRQ32Mode :OR: I_BIT :OR: F_BIT LDR SP, StackIrq ;Build the FIQ stack MSR CPSR_c, #FIQ32Mode :OR: I_BIT :OR: F_BIT LDR SP, StackFiq ;Build the DATAABORT stack MSR CPSR_c, #ABT32Mode :OR: I_BIT :OR: F_BIT LDR SP, StackAbt ;Build the UDF stack MSR CPSR_c, #UDF32Mode :OR: I_BIT :OR: F_BIT LDR SP, StackUnd ;Build the SYS stack MSR CPSR_c, #SYS32Mode :OR: I_BIT :OR: F_BIT LDR SP, =StackUsr MSR CPSR_c, #SYS32Mode BX R0 после чего прыгаем на __main параметр __entry у линкера указывает именно на ResetStart Так вот. Куда нужно прыгать? На сам ResetStart, или, все-таки, на точку вызова InitStack (точнее, на ResetStart+(4*8), ибо там может быть что-то еще, это у меня сразу стеки инициализируются и вызов InitStack оказывается размещенным по этому адресу)? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба На ResetStart, разумеется: его положение строго фиксировано. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба На ResetStart, разумеется: его положение строго фиксировано. Все, понял. Попадая на ResetStart, мы заносим в PC значение ResetAddr, по которому как раз лежит вызов инициализации стека и дальше как надо. Остается один вопрос - инициализация обработчиков исключений, ведь этот блок мы просто пропустим, это не аппаратное вычитывание по холодному старту, а, фактически, просто двойной прыжок на ResetAddr Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба Остается один вопрос - инициализация обработчиков исключений, ведь этот блок мы просто пропустим, это не аппаратное вычитывание по холодному старту, а, фактически, просто двойной прыжок на ResetAddr Если приложение не стартует по нулевому адресу (или адресу 0xffff0000 в случае HiVecs), то этот блок можно просто исключить за ненадобностью. Просто бывает удобно его сохранить, когда приложение собирается как для случая работы с загрузчиком, так и для работы без оного. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба этот блок можно просто исключить за ненадобностью. это понятно! непонятно другое - адреса, загруженные при старте, так и останутся адресами п/п бутлоадера. А если есть необходимость обработки их в основной программе? я могу, конечно, разместить их в RAM по одинаковым адресам и в буте, и в приложении, но ведь это не гуд Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба Вариантов масса: - Использовать п/п загрузчика (в случае IRQ или FIQ это зачастую одна инструкция) - Разместить адреса переходов в RAM - Сделать remap - Использовать верхние вектора - Использовать MMU Осуществимость последних трёх пунктов зависит от наличия поддержки со стороны ядра/системы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба aaarrr, спасибо, пойду разбираться Вот что накопал Вектора располагаются в TCM памяти, когторая смаппирована на 0x00000000 То, что идет в примерай кейла, содержит вот такой ремап: PRESERVE8 VECTOR_RAM_SRC EQU 0x80000000 VECTOR_FLASH_SRC EQU 0x20000000 VECTOR_DST EQU 0x00000000 EXPORT VectorRemap AREA BlockCopy, CODE, READONLY ; name this block of code VectorRemap STMFD sp!, {r0, r1, r4-r11}; save registers IF :DEF: REMAP_RAM LDR r0, =VECTOR_RAM_SRC ELSE LDR r0, =VECTOR_FLASH_SRC; r0 = pointer to source block ENDIF LDR r1, =VECTOR_DST ; r1 = pointer to destination block LDMIA r0!, {r4-r11} ; remap first 16 words from 0x20000000 STMIA r1!, {r4-r11} ; to address 0x00000000 for interrupt LDMIA r0!, {r4-r11} ; exception handler STMIA r1!, {r4-r11} LDMFD sp!, {r0, r1, r4-r11}; restore registers END таким образом, в основной программе я могу переписать значения векторов в области 0x00000000 - 0x0000001F своими значениями... и все? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба Выходит, все. Только я бы выделил вектора в отдельную секцию и размещал бы её на нулевом адресе штатными средствами (т.е. линкером). Подобные копирования только путаницу вносят. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба Выходит, все. Только я бы выделил вектора в отдельную секцию и размещал бы её на нулевом адресе штатными средствами (т.е. линкером). Подобные копирования только путаницу вносят. Embedded Flash по умолчанию маппируется из 0x20000000 на 0x00000000 Программа у меня собирается по физическому адресу. Фактически, хоть программа и "бегает" по реальным адресам, вектора лежат в маппированной области Сейчас нужно разобраться, как вернуть отображение TCM памяти на свое реальное место и не очень понятно, как заставить линкер "положить" вектора в область нулевую Точнее, КАК - это да, указать регион, но вот в каком месте это сделает ОН? скорее всего, в __main? Потому что копировать в отображаемую Flash не получится без отката ремапа Да, вот еще вопрос какой. Как в кейле, в ASM файле указать регион, прописанный в скаттере? Как-то так? AREA MyVectors, DATA, NOINIT, ALIGN=4 и в скаттере: LR_IROM1 0x20000000 0x00080000 { ; load region size_region ER_IROM1 0x20000000 0x00080000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x80000000 0x0000E000 { ; RW data *.o (RAMFUNC) .ANY (+RW +ZI) } RW_IRAM2 0x00000000 0x00008000 {; 16 KB TCM memory *.o (MyVectors) } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 25 февраля, 2013 Опубликовано 25 февраля, 2013 · Жалоба ...в каком месте это сделает ОН? скорее всего, в __main? Да, в __main. До этого нужно настроить память. Как-то так? Только вектора - они все же CODE, а не DATA. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться