Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Передача управления из бута в программу
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
toweroff
Добрый день

Вот такой вопрос возник. Управление передается через подобный вызов:
Код
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
Цитата(toweroff @ Feb 25 2013, 14:57) *
...нигде не увидел явной смены режима работы


по поводу режима - так-же не видел явно. возможно пока сильно не копал.
по поводу +1 = сам юзаю оверлейность, вычисление точки входа в "модуль" идёт на ран-тайме. управление передаётся на ура без всякой "коррекции" на единицу. объявление, вызов, сами подпрограммы - на сях.

кхм. как то загрузили блин sm.gif надо будет вкурить вопросы получше.
esaulenka
Цитата(toweroff @ Feb 25 2013, 14:57) *
для ядра ARM968E-S значение USER_CODE так же будет (REAL_USER_CODE + 1), как и для CM3?

Значение USER_CODE будет +1 или +0 в зависимости от того, ARM-код это, или THUMB.

Цитата(toweroff @ Feb 25 2013, 14:57) *
Или это нормально, или я что-то не понял и проц нужно перед прыжком переводить в Supervisor режим?
Сколько пересмотрел реализаций бутов для ARM7, CM3 - нигде не увидел явной смены режима работы

В моей реализации большими буквами написано "SWI и xxx_Handler не используется, надо инициализировать только пользовательский стек".
Но вообще-то для универсального бута странно. Это я знаю, что буду грузить своим загрузчиком.
toweroff
Цитата(esaulenka @ Feb 25 2013, 18:05) *
Значение USER_CODE будет +1 или +0 в зависимости от того, ARM-код это, или THUMB.

только ARM

Цитата(esaulenka @ Feb 25 2013, 18:05) *
В моей реализации большими буквами написано "SWI и xxx_Handler не используется, надо инициализировать только пользовательский стек".
Но вообще-то для универсального бута странно. Это я знаю, что буду грузить своим загрузчиком.

SWI нет, все аборты заткнуты на одну функцию, которая выкидывает в канал связи состояние CPSR и адрес, вызвавший исключение
SyncLair
Цитата(toweroff @ Feb 25 2013, 14:57) *
Сколько пересмотрел реализаций бутов для ARM7, CM3 - нигде не увидел явной смены режима работы

Режимы работы как правило инициализируются в самом загружаемом модуле. То есть типичный скрипт для запуска содержит
строчки где CPSR как раз инициализируется.
toweroff
Цитата
Режимы работы как правило инициализируются в самом загружаемом модуле. То есть типичный скрипт для запуска содержит
строчки где 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
На ResetStart, разумеется: его положение строго фиксировано.
toweroff
Цитата(aaarrr @ Feb 25 2013, 18:43) *
На ResetStart, разумеется: его положение строго фиксировано.

Все, понял. Попадая на ResetStart, мы заносим в PC значение ResetAddr, по которому как раз лежит вызов инициализации стека и дальше как надо.
Остается один вопрос - инициализация обработчиков исключений, ведь этот блок мы просто пропустим, это не аппаратное вычитывание по холодному старту, а, фактически, просто двойной прыжок на ResetAddr
aaarrr
Цитата(toweroff @ Feb 25 2013, 19:07) *
Остается один вопрос - инициализация обработчиков исключений, ведь этот блок мы просто пропустим, это не аппаратное вычитывание по холодному старту, а, фактически, просто двойной прыжок на ResetAddr

Если приложение не стартует по нулевому адресу (или адресу 0xffff0000 в случае HiVecs), то этот блок можно просто исключить за ненадобностью.
Просто бывает удобно его сохранить, когда приложение собирается как для случая работы с загрузчиком, так и для работы без оного.
toweroff
Цитата(aaarrr @ Feb 25 2013, 19:21) *
этот блок можно просто исключить за ненадобностью.

это понятно!
непонятно другое - адреса, загруженные при старте, так и останутся адресами п/п бутлоадера. А если есть необходимость обработки их в основной программе?
я могу, конечно, разместить их в RAM по одинаковым адресам и в буте, и в приложении, но ведь это не гуд
aaarrr
Вариантов масса:
- Использовать п/п загрузчика (в случае IRQ или FIQ это зачастую одна инструкция)
- Разместить адреса переходов в RAM
- Сделать remap
- Использовать верхние вектора
- Использовать MMU
Осуществимость последних трёх пунктов зависит от наличия поддержки со стороны ядра/системы.
toweroff
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
Выходит, все. Только я бы выделил вектора в отдельную секцию и размещал бы её на нулевом адресе штатными средствами (т.е. линкером). Подобные копирования только путаницу вносят.
toweroff
Цитата(aaarrr @ Feb 25 2013, 20:55) *
Выходит, все. Только я бы выделил вектора в отдельную секцию и размещал бы её на нулевом адресе штатными средствами (т.е. линкером). Подобные копирования только путаницу вносят.

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
Цитата(toweroff @ Feb 25 2013, 21:45) *
...в каком месте это сделает ОН? скорее всего, в __main?

Да, в __main. До этого нужно настроить память.

Цитата(toweroff @ Feb 25 2013, 21:45) *
Как-то так?

Только вектора - они все же CODE, а не DATA.
toweroff
UPD
Так, становится понятнее

Используются 2 инструкции, исполняемые в Privileged mode - MCR & MRC
Код
MRC p15, 0, <Rd>, c1, c0, 0
MCR p15, 0, <Rd>, c1, c0, 0

Там отключаем ремап или переходим в верхнюю адресацию (но вектора все равно нужно будет скопировать), так что вопрос по скаттеру пока открыт


Цитата(aaarrr @ Feb 25 2013, 22:45) *
Только вектора - они все же CODE, а не DATA.

ээ.. ну да sm.gif

Вы немного опередили, там еще сверху ответ

Еще добавлю скаттер

Вариант 1
Код
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)
  }
}

и меняем использование смаппированной области с AHB на DTCM и ITCM:
Код
    MRC     p15, 0, r4, c1, c0, 0; Read CP15
    ORR     r4, r4, #DTCM_enabled; Enable Data TCM
; At power up, the interrupt vector is mapped to addr. 0 already,
; enabling instruction TCM will wipe out the mirror of the
; vector table. A remap will be performed there after. */
    ORR     r4, r4, #ITCM_enabled; Enable Instruction TCM
    ORR     r4, r4, #WB_enabled; Enable Write Buffer
    MCR     p15, 0, r4, c1, c0, 0; Write CP15


ИЛИ

Вариант 2
Код
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 0xFFFF0000 0xFFFF001C {; Vectors in HI
   *.o (MyVectors)
  }
}

и меняем адреса векторов
Код
VBIT_enabled    EQU    1<<13


    MRC     p15, 0, r4, c1, c0, 0; Read CP15
    ORR     r4, r4, #VBIT_enabled; Enable Vector location bit to 0xFFFF0000
    MCR     p15, 0, r4, c1, c0, 0; Write CP15

вот только посмотреть нужно, этот диапазон адресов для меня RW или RO. Должна быть RW, иначе смысла бы не было biggrin.gif

Кстати, еще добавлю к посту №6 - http://electronix.ru/forum/index.php?showt...t&p=1140378
Ничего там проц не вычитывает при старте, это он по смещению при исключении переходит rolleyes.gif
toweroff
aaarrr, посмотрите, пожалуйста, что я понял не так
пока нужно понимание правильности направления. Для этого ядра нет никаких примеров загрузчиков, сам IAP отработан и проверен, NXP в этом плане все сделала удобно, даже для максимальной частоты ядра, кстати
aaarrr
Вариант 2 не годится, т.к. по адресу 0xffff0000 памяти в вашем случае нет.
То есть план такой:
1. включаем TCM
2. внутри __main копируем вектора (да и прочие скоростные вещи, которые не грех в TCM отправить)
3. разрешаем прерывания

P.S. Только 16кБайт - это 0x4000, а не 0x8000. Можно налететь.
toweroff
Цитата(aaarrr @ Feb 26 2013, 02:38) *
Вариант 2 не годится, т.к. по адресу 0xffff0000 памяти в вашем случае нет.
То есть план такой:
1. включаем TCM
2. внутри __main копируем вектора (да и прочие скоростные вещи, которые не грех в TCM отправить)
3. разрешаем прерывания

P.S. Только 16кБайт - это 0x4000, а не 0x8000. Можно налететь.

спасибо, ждал ответа
сегодня уже к обеду попробую воплотить во что-то рабочее. Кстати, теперь уже и понятие TCM и код, более скоростной, в этой области выполняемый, совсем по-другому смотрится

еще раз спасибо, доброго утра, наверное sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.