Перейти к содержанию
    

Передача управления из бута в программу

Добрый день

 

Вот такой вопрос возник. Управление передается через подобный вызов:

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 - нигде не увидел явной смены режима работы

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...нигде не увидел явной смены режима работы

 

по поводу режима - так-же не видел явно. возможно пока сильно не копал.

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

 

кхм. как то загрузили блин :) надо будет вкурить вопросы получше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

для ядра ARM968E-S значение USER_CODE так же будет (REAL_USER_CODE + 1), как и для CM3?

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

 

Или это нормально, или я что-то не понял и проц нужно перед прыжком переводить в Supervisor режим?

Сколько пересмотрел реализаций бутов для ARM7, CM3 - нигде не увидел явной смены режима работы

В моей реализации большими буквами написано "SWI и xxx_Handler не используется, надо инициализировать только пользовательский стек".

Но вообще-то для универсального бута странно. Это я знаю, что буду грузить своим загрузчиком.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

только ARM

 

В моей реализации большими буквами написано "SWI и xxx_Handler не используется, надо инициализировать только пользовательский стек".

Но вообще-то для универсального бута странно. Это я знаю, что буду грузить своим загрузчиком.

SWI нет, все аборты заткнуты на одну функцию, которая выкидывает в канал связи состояние CPSR и адрес, вызвавший исключение

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сколько пересмотрел реализаций бутов для ARM7, CM3 - нигде не увидел явной смены режима работы

Режимы работы как правило инициализируются в самом загружаемом модуле. То есть типичный скрипт для запуска содержит

строчки где CPSR как раз инициализируется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Режимы работы как правило инициализируются в самом загружаемом модуле. То есть типичный скрипт для запуска содержит

строчки где 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 оказывается размещенным по этому адресу)?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На ResetStart, разумеется: его положение строго фиксировано.

Все, понял. Попадая на ResetStart, мы заносим в PC значение ResetAddr, по которому как раз лежит вызов инициализации стека и дальше как надо.

Остается один вопрос - инициализация обработчиков исключений, ведь этот блок мы просто пропустим, это не аппаратное вычитывание по холодному старту, а, фактически, просто двойной прыжок на ResetAddr

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Остается один вопрос - инициализация обработчиков исключений, ведь этот блок мы просто пропустим, это не аппаратное вычитывание по холодному старту, а, фактически, просто двойной прыжок на ResetAddr

Если приложение не стартует по нулевому адресу (или адресу 0xffff0000 в случае HiVecs), то этот блок можно просто исключить за ненадобностью.

Просто бывает удобно его сохранить, когда приложение собирается как для случая работы с загрузчиком, так и для работы без оного.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

этот блок можно просто исключить за ненадобностью.

это понятно!

непонятно другое - адреса, загруженные при старте, так и останутся адресами п/п бутлоадера. А если есть необходимость обработки их в основной программе?

я могу, конечно, разместить их в RAM по одинаковым адресам и в буте, и в приложении, но ведь это не гуд

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вариантов масса:

- Использовать п/п загрузчика (в случае IRQ или FIQ это зачастую одна инструкция)

- Разместить адреса переходов в RAM

- Сделать remap

- Использовать верхние вектора

- Использовать MMU

Осуществимость последних трёх пунктов зависит от наличия поддержки со стороны ядра/системы.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 своими значениями... и все?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Выходит, все. Только я бы выделил вектора в отдельную секцию и размещал бы её на нулевом адресе штатными средствами (т.е. линкером). Подобные копирования только путаницу вносят.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Выходит, все. Только я бы выделил вектора в отдельную секцию и размещал бы её на нулевом адресе штатными средствами (т.е. линкером). Подобные копирования только путаницу вносят.

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) 
  }
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...в каком месте это сделает ОН? скорее всего, в __main?

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

 

Как-то так?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...