Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум разработчиков электроники ELECTRONIX.ru _ Операционные системы _ вызов супервизора SVCall в STM32

Автор: FFFF Aug 31 2018, 10:27

В cortex M есть команда вызова системных функций, SVC
при исполнении этой команды процессор переходит в обработчик исключения супервизора.

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

как правильно должно это все работать по задумкам разработчиков?

Автор: AlexandrY Aug 31 2018, 11:27

Цитата(FFFF @ Aug 31 2018, 13:27) *
как правильно должно это все работать по задумкам разработчиков?

Если выйти из обработчика, то кончится и привилегированный режим.
Поэтому обработчик вызывает функцию, она возвращается в обработчик и обработчик закрывается, а если надо, то перед этим сделает переключение контекста.
Смотрите как сделано в Mbed OS.

Автор: x893 Aug 31 2018, 11:44

Как это сделано в любой RTOS.

Автор: FFFF Aug 31 2018, 11:51

спасибо.
и как это сделано в любой rtos? системная функция вызывается прямо в обработчике исключения и возвращается в него?

я с Си плохо знаком, пробираться в дебрях rtos для меня мучение

Автор: x893 Aug 31 2018, 11:54

Там в основном ассемблер. Для изучения сильно помогает Source Insight.

Автор: AlexandrY Aug 31 2018, 12:13

Цитата(x893 @ Aug 31 2018, 14:44) *
Как это сделано в любой RTOS.

Не в любой. Зависит от порта.

Автор: jcxz Aug 31 2018, 12:17

Цитата(FFFF @ Aug 31 2018, 13:27) *
что должно происходить в обработчике исключения супервизора, вызов системной функции прямо в обработчике?
как то странно это. логичнее на мой взгляд было бы выйти из обработчика передав управление вызываемой функции в привилегированном режиме. незнаю как только реализовать это попроще

Как душе угодно: можно прям оттуда вызвать, можно оттуда только программно активировать другое прерывание или задачу, где всё и свершить.

Цитата(x893 @ Aug 31 2018, 14:44) *
Как это сделано в любой RTOS.

Видимо uCOS-II - не любая. Так как вообще никак не использует SVC.

Автор: Arlleex Sep 1 2018, 13:44

Цитата(jcxz @ Aug 31 2018, 15:17) *
Видимо uCOS-II - не любая. Так как вообще никак не использует SVC.

А во FreeRTOS вообще плохо поступили - SVC используется один раз в жизни -только при запуске первой задачи crying.gif Но это дело можно под себя перепилить, если что, как мне кажется.

Автор: Arlleex Sep 1 2018, 14:48

Открыл вот порт FreeRTOS на Cortex-M4.
В этой RTOS переключатель контекста построен по следующей модели:
1. Сохранить контекст прерванной задачи;
2. Переключить указатель на контекст новой задачи;
3. Восстановить регистры из этого контекста.

Все 3 пункта выполняются в обработчике исключения PendSV.
Для того, чтобы начать выполнение, нужно как-то запустить первую задачу.
FreeRTOS предлагает решение на исключении SVC

Код
__asm void prvStartFirstTask( void )
{
    PRESERVE8

    /* Use the NVIC offset register to locate the stack. */
    ldr r0, =0xE000ED08
    ldr r0, [r0]
    ldr r0, [r0]
    /* Set the msp back to the start of the stack. */
    msr msp, r0
    /* Clear the bit that indicates the FPU is in use in case the FPU was used
    before the scheduler was started - which would otherwise result in the
    unnecessary leaving of space in the SVC stack for lazy saving of FPU
    registers. */
    mov r0, #0
    msr control, r0
    /* Globally enable interrupts. */
    cpsie i
    cpsie f
    dsb
    isb
    /* Call SVC to start the first task. */
    svc 0
    nop
    nop
}

Сам обработчик
Код
__asm void vPortSVCHandler( void )
{
    PRESERVE8

    /* Get the location of the current TCB. */
    ldr    r3, =pxCurrentTCB
    ldr r1, [r3]
    ldr r0, [r1]
    /* Pop the core registers. */
    ldmia r0!, {r4-r11, r14}
    msr psp, r0
    isb
    mov r0, #0
    msr    basepri, r0
    bx r14
}


А меня жаба душит транжирить SVC на такое... Вообще не хочу, чтобы FreeRTOS использовала SVC.
Есть идея сделать почти все то же самое, что в обработчике, но вызовом функции: только вместо bx r14 перевести процессор на использование PSP + непривилегированный режим. Ну и регистры все восстановить, потому как не в прерывании находимся. И это будет возможно сделать, поскольку после сброса CPU находится в привилегированном режиме, соответственно все системные функции работы с регистрами специального назначения ему разрешены.
Нужно попробовать, но хотелось бы выслушать критику... Работать будет?

Итого, что-то типа
Код
__asm void prvStartFirstTask( void )
{
    PRESERVE8

    /* Use the NVIC offset register to locate the stack. */
    ldr r0, =0xE000ED08
    ldr r0, [r0]
    ldr r0, [r0]
    /* Set the msp back to the start of the stack. */
    msr msp, r0
    /* Clear the bit that indicates the FPU is in use in case the FPU was used
    before the scheduler was started - which would otherwise result in the
    unnecessary leaving of space in the SVC stack for lazy saving of FPU
    registers. */
    mov r0, #0
    msr control, r0
    /* Globally enable interrupts. */
    cpsie i
    cpsie f
    dsb
    isb

        // Финт ушами

        /* Get the location of the current TCB. */
    ldr    r3, =pxCurrentTCB
    ldr r1, [r3]
    ldr r0, [r1]
    // восстановить контекст первой задачи в нужной последовательности
    ldmia r0!, {тут список регистров R0-R12, LR, XPSR в правильном порядке}
    msr psp, r0
    isb
    mov r0, #0
    msr    basepri, r0
        // а тут восстановить PC и поехали
}

Автор: FFFF Sep 1 2018, 15:21

А меня жаба душит транжирить SVC на такое... Вообще не хочу, чтобы FreeRTOS использовала SVC.

а Вы как бы распорядились SVC?

Автор: jcxz Sep 1 2018, 16:27

Цитата(Arlleex @ Sep 1 2018, 17:48) *
ldr r0, =0xE000ED08
ldr r0, [r0]
ldr r0, [r0]
msr msp, r0

Что-то у Вас мухи с котлетами намешаны wink.gif
Зачем ещё и указатель стека прерываний на начало стека из таблицы прерываний ставить?
Это вобщем-то не относится к данной задаче. Хотя конечно хозяин - барин.

Цитата(Arlleex @ Sep 1 2018, 17:48) *
mov r0, #0
msr control, r0

Опять мухи с котлетами. Тогда сюда ещё до кучи и инициализацию пинов впендюрить можно. laughing.gif
Да и вроде - невозможно так записать что-то в CONTROL. Нужно юзать EXC_RETURN.

Цитата(Arlleex @ Sep 1 2018, 17:48) *
dsb
isb

Зачем?

Цитата(Arlleex @ Sep 1 2018, 17:48) *
ldmia r0!, {тут список регистров R0-R12, LR, XPSR в правильном порядке}

Ну вообще-то тут R0-R3,R12,LR,XPSR совершенно лишние.
Вроде как достаточно восстановить R4-R11, занести в LR нужное значение и сделать BX LR (сымитировать возврат из прерывания с переключением на нужный стек и в нужный режим).

Цитата(Arlleex @ Sep 1 2018, 17:48) *
msr psp, r0
isb
mov r0, #0
msr basepri, r0
// а тут восстановить PC и поехали

В результате режим процессора Вы не переключили и он остался в handler-режиме.
Для переключения нужно юзать BX LR с правильным значением в нём.
И опять же - ISB тут лишняя.

В uCOS вообще не заморачиваются: они изначально заносят в PSP=0, а потом просто программно возбуждают PendSV (как для любого программного переключения контекста), а в ISR PendSV делают проверку если PSP==0 (начальный старт первой задачи) - просто пропускают сохранение контекста сразу переходя к восстановлению контекста самой приоритетной задачи.
Конечно при этом в переключатель контекста добавляется одна лишняя команда, но имхо - это несущественно.

PS: Да и, как видно по приведённому Вами коду, FreeRTOS использует не всю SVC, а только SVC 0. Остальные 255 - свободны. Неужто Вам 255 не хватит? Для чего???

Автор: FFFF Sep 2 2018, 06:03

если передавать номер функции в регистре перед вызовом SVC то можно и больше чем 256

еще и быстрее будет. надо лишь в регистр ввести значение необходимой функции. 2 команды если число больше 255, не придется доставать значение из SVC в обработчике

Автор: AlexandrY Sep 2 2018, 06:38

Цитата(FFFF @ Sep 2 2018, 09:03) *
если передавать номер функции в регистре перед вызовом SVC то можно и больше чем 256
еще и быстрее будет. надо лишь в регистр ввести значение необходимой функции. 2 команды если число больше 255, не придется доставать значение из SVC в обработчике

Цитируя давайте ссылки на первоисточник:
http://electronix.ru/redirect.php?https://github.com/Indemsys/Mbed_led_blinky_MKE18F/blob/master/mbed-os/rtos/TARGET_CORTEX/rtx5/RTX/Source/rtx_kernel.c


Автор: FFFF Sep 2 2018, 06:49

собственно я сам до этого дошел, думаю это лежит на поверхности

я Си не знаю, 516 строка для меня темный лес

Автор: Arlleex Sep 2 2018, 08:50

Цитата(FFFF @ Sep 1 2018, 18:21) *
А меня жаба душит транжирить SVC на такое... Вообще не хочу, чтобы FreeRTOS использовала SVC.

а Вы как бы распорядились SVC?

Сам факт того, что это прерывание используется только 1 раз... Ужас.
Даже если оно мне не нужно - у меня внутренний когнитивный диссонанс biggrin.gif

Цитата(jcxz @ Sep 1 2018, 19:27) *
Что-то у Вас мухи с котлетами намешаны wink.gif
Зачем ещё и указатель стека прерываний на начало стека из таблицы прерываний ставить?
Это вобщем-то не относится к данной задаче. Хотя конечно хозяин - барин.

...

Опять мухи с котлетами. Тогда сюда ещё до кучи и инициализацию пинов впендюрить можно. laughing.gif

...

Зачем?

Не мое. Это я сейчас порт на Cortex-M4 открыл и сюда вставил laughing.gif Нужно оно там или не нужно - это другой вопрос, конечно же.

Цитата
Да и вроде - невозможно так записать что-то в CONTROL. Нужно юзать EXC_RETURN.

В привилегированном режиме можно. EXC_RETURN используется при входе в прерывание и выходе из него.

Цитата
Ну вообще-то тут R0-R3,R12,LR,XPSR совершенно лишние.
Вроде как достаточно восстановить R4-R11, занести в LR нужное значение и сделать BX LR (сымитировать возврат из прерывания с переключением на нужный стек и в нужный режим).

В этом и фишка, что я хочу полностью избавиться от SVC, передать управление на первую задачу без использования прерывания. Поэтому я и предложил восстановить весь регистровый стек, потому как мы не в прерывании еще находимся, поэтому R0-R3, R12, LR, XPSR восстановить нужно будет.
Интересно вот, что будет если в привилегированном режиме потока записать EXC_RETURN в LR со значениями (PSP + Thread Mode) и сделать BX LR... Какой-нибудь Usage Fault, скорее всего.

Цитата
В результате режим процессора Вы не переключили и он остался в handler-режиме.
Для переключения нужно юзать BX LR с правильным значением в нём.
И опять же - ISB тут лишняя.

Повторюсь, что режим процессора должен оставаться в Thread. Если бы прерывание было - как в исходном примере, то я не задался бы целью обойти использование SVC sad.gif
ISB лишняя, да... Там весь порт кривущий, но работает. Вычищаю потихоньку, что нужно мне. Вот и решил заморочиться, избавившись от такого не очень, на мой взгляд, разумного использования SVC. Я еще понимаю, если бы оно вызывалось раз в день. Но тут только при старте приложения...

Цитата
PS: Да и, как видно по приведённому Вами коду, FreeRTOS использует не всю SVC, а только SVC 0. Остальные 255 - свободны. Неужто Вам 255 не хватит? Для чего???

Мне-то хватит. Просто хочу свои SVC как можно короче сделать, без лишних телодвижений. А подход, предложенный индусами-портировщиками, мне не очень нравится. Поэтому и гадаю, как красиво сделать wink.gif

Цитата
В uCOS вообще не заморачиваются: они изначально заносят в PSP=0, а потом просто программно возбуждают PendSV (как для любого программного переключения контекста), а в ISR PendSV делают проверку если PSP==0 (начальный старт первой задачи) - просто пропускают сохранение контекста сразу переходя к восстановлению контекста самой приоритетной задачи.
Конечно при этом в переключатель контекста добавляется одна лишняя команда, но имхо - это несущественно.

Воот. Вот это уже другое дело. Я тоже рассматривал такой вариант, но как раз лишние пару инструкций проверки травят душу перфекциониста biggrin.gif
Вот и думаю, что это сделать, скорее всего, можно без прерываний и лишних телодвижений в переключателе контекста (я хотел бы, чтобы он был как можно короче и быстрее). Просто нужно исхитриться и восстановить весь контекст выполнения первой запускаемой задачи.

Автор: jcxz Sep 2 2018, 10:04

Цитата(Arlleex @ Sep 2 2018, 11:50) *
В привилегированном режиме можно. EXC_RETURN используется при входе в прерывание и выходе из него.

А в непривилегированном? В каком режиме (и с какими привилегиями) находится ядро Cortex-M после сброса - мы знаем из мануала, а в каком режиме и с какими привилегиями оно будет находиться после завершения выполнения ROM-boot на любом МК - Вы знаете? rolleyes.gif
А в каком режиме будет находиться CPU после смены регистра SP через запись в CONTROL - Handler или Thread? Также изменит режим согласно SP или нет?
И по Вашему коду неясно - в каком изначальном режиме и с какими привилегиями ядро находится перед выполнением этого кода, поэтому я и написал что в общем случае - это не будет работать.
В то же время мануал на ядро говорит:
Handler mode always uses the MSP, so the processor ignores explicit writes to the active stack
pointer bit of the CONTROL register when in Handler mode. The exception entry and return
mechanisms automatically update the CONTROL register based on the EXC_RETURN value

Из чего я заключаю, что самый надёжный способ установки SP и режима CPU - через EXC_RETURN. Кстати - uCOS нигде не пишет в биты 0,1 CONTROL напрямую - везде только через EXC_RETURN. А она написана грамотно и для многих МК.

Цитата(Arlleex @ Sep 2 2018, 11:50) *
В этом и фишка, что я хочу полностью избавиться от SVC, передать управление на первую задачу без использования прерывания. Поэтому я и предложил восстановить весь регистровый стек, потому как мы не в прерывании еще находимся, поэтому R0-R3, R12, LR, XPSR восстановить нужно будет.

а я Вам предлагал войти в любое прерывание и сделать выход оттуда с помощью нужного значения EXC_RETURN. Неужто у Вас нет ни одного свободного вектора прерывания? Не обязательно SVC. К тому же весь - Вы его всё равно не восстановите, регистры нужны для работы, и к тому же формат хранения контекста задачи удобно сделать совместимым с аппаратным порядком сохранения регистров по прерыванию.

Цитата(Arlleex @ Sep 2 2018, 11:50) *
Интересно вот, что будет если в привилегированном режиме потока записать EXC_RETURN в LR со значениями (PSP + Thread Mode) и сделать BX LR... Какой-нибудь Usage Fault, скорее всего.

Может и так, а может и сработает. Пробовать нужно.

Цитата(Arlleex @ Sep 2 2018, 11:50) *
Мне-то хватит. Просто хочу свои SVC как можно короче сделать, без лишних телодвижений.

Так можно любой другой вектор использовать. Их обычно полно неиспользуемых в МК.

Цитата(Arlleex @ Sep 2 2018, 11:50) *
но как раз лишние пару инструкций проверки травят душу перфекциониста biggrin.gif

Я же писал - не пара, а только одна лишняя.

Автор: jcxz Sep 2 2018, 21:19

Цитата(Arlleex @ Sep 2 2018, 11:50) *
Воот. Вот это уже другое дело. Я тоже рассматривал такой вариант, но как раз лишние пару инструкций проверки травят душу перфекциониста biggrin.gif

Вобщем - разбередили Вы мне душу... biggrin.gif
Взялся я за свой uCOS-II и доработал его переключатель контекста и процедуру старта многозадачности. Теперь работает без занесения спец.значения в PSP и проверки его при каждом вызове PendSV. Ну и ещё много что почистил, оптимизировал.
Стартует теперь очень просто - без всяких доп.прерываний и спец.значений. Просто внутри ISR PendSV делается ORR LR, LR, #4 и всё. cool.gif
Хотя надо будет ещё тщательнее всё проверить....

Автор: Arlleex Sep 3 2018, 04:57

Цитата(jcxz @ Sep 3 2018, 00:19) *
Вобщем - разбередили Вы мне душу... biggrin.gif
Взялся я за свой uCOS-II и доработал его переключатель контекста и процедуру старта многозадачности. Теперь работает без занесения спец.значения в PSP и проверки его при каждом вызове PendSV. Ну и ещё много что почистил, оптимизировал.
Стартует теперь очень просто - без всяких доп.прерываний и спец.значений. Просто внутри ISR PendSV делается ORR LR, LR, #4 и всё. cool.gif
Хотя надо будет ещё тщательнее всё проверить....

Зато внутренний перфекционист ликует теперь biggrin.gif
Сегодня-завтра поковыряю свой переключатель контекста и процедуру старта...

Автор: Arlleex Sep 3 2018, 08:05

В общем, выделил часок на свои изыскания и, определенно, пришел к некоторому успеху.
Повторюсь, что я хотел сделать.
Имеется FreeRTOS v10.0.0, компилятор ARMCCv5 Keil.
В системе есть 2 задачи:

CODE
xTaskHandle Task1Handle;
xTaskHandle Task2Handle;

void Task1(void *Parameters)
{
while(1)
{
HW_LED_TOGGLE(GPIO_LED1);

vTaskDelay(1000);
}
}

void Task2(void *Parameters)
{
while(1)
{
HW_LED_TOGGLE(GPIO_LED2);

vTaskDelay(500);
}
}

int main(void)
{
HW_MCUInit();

xTaskCreate(&Task1, "Task1", 128, NULL, 1, &Task1Handle);
xTaskCreate(&Task2, "Task2", 128, NULL, 1, &Task2Handle);

vTaskStartScheduler();

return 0;
}

Моя цель была в том, чтобы избавиться от единожды используемого прерывания SVC, которую индусы задействовали для запуска первой задачи. Для этого:
  1. Удалил обработчик SVC.
  2. Скорректировал функцию запуска первой задачи следующим образом:
Код
__asm void prvStartFirstTask(void)
{
    PRESERVE8
    
    // установка MSP
    ldr r0, =0xE000ED08
    ldr r0, [r0]
    ldr r0, [r0]
    msr msp, r0
    
    dsb
    
    // получение указателя на стековый фрейм задачи
    ldr r3, =pxCurrentTCB
    ldr r1, [r3]
    ldr r0, [r1]
    
    // последовательная загрузка контекста
    ldmia r0!, {r4-r11, r14} // загрузка R4-R11, LR (LR здесь уже, по сути, является аттавизмом)
    msr psp, r0              // установка PSP
    
    dsb
    
    // перевод CPU на использование стека PSP
    mov r0, #2
    msr control, r0
    
    dsb
    
    // извлечение XPSR из стекового фрейма
    mrs r1, psp
    add r1, r1, #28
    ldr r0, [r1]
    msr xpsr, r0
    
    // извлечение оставшихся регистров
    pop {r0-r3, r12, r14}
    
    // корректировка бита 0 регистра PC
    push {r0, r1}
    
    mrs r0, psp
    add r0, r0, #8
    ldr r1, [r0]
    orr r1, r1, #1
    str r1, [r0]
    
    pop {r0, r1}
    
    // переход на активную задачу
    pop {r15}
}

Примечания:
  1. Как видно в конце ассемблерного кода, я подменяю в памяти адрес задачи на тот же, только с установленным 0-м битом. И он останется там, в то время, как адреса других задач будут иметь 0 в этом бите. Можно и тут заморочиться и исправить, но я пока не стал. Большой проблемы это не доставит, т.к. этот адрес является адресом начала задачи, а при переключении контекста там будет уже другой адрес (чуть ниже точки входа в задачу).
  2. Поставил DSB в местах, где меняется SP, а также после записи в CONTROL (как рекомендует ARM). Хотелось бы выслушать мнение насчет расстановки DSB, желательно аргументированно rolleyes.gif ISB убрал полностью, ибо не вижу в них смысла здесь.
  3. Подразумевается, что в системе нет загрузчика, или загрузчик, после выполнения своего кода и перехода на пользовательское приложение, привел все регистры в состояние после сброса, а также режим работы CPU и активный SP.
В общем-то проверил - работает, и я рад, что оно получилось 08.gif

Автор: AlexandrY Sep 3 2018, 08:10

Цитата(Arlleex @ Sep 3 2018, 11:05) *
[/list]В общем-то проверил - работает, и я рад, что оно получилось 08.gif

Тяжело же вам придется скоро.
Все переходят на http://electronix.ru/redirect.php?https://www.arm.com/company/news/2018/02/psa-next-steps-toward-a-common-industry-framework-for-secure-iot
А там каждый чих через SVC.

Автор: Arlleex Sep 3 2018, 09:46

Цитата(AlexandrY @ Sep 3 2018, 12:10) *
Тяжело же вам придется скоро.
Все переходят на http://electronix.ru/redirect.php?https://www.arm.com/company/news/2018/02/psa-next-steps-toward-a-common-industry-framework-for-secure-iot
А там каждый чих через SVC.

Там, где это действительно нужно, пусть остается. Там, где это как собаке пятая нога - я чищу smile3046.gif

Автор: jcxz Sep 3 2018, 10:01

Цитата(Arlleex @ Sep 3 2018, 11:05) *
[*]Как видно в конце ассемблерного кода, я подменяю в памяти адрес задачи на тот же, только с установленным 0-м битом.

Зачем?

Цитата(Arlleex @ Sep 3 2018, 11:05) *
[*]Поставил DSB в местах, где меняется SP, а также после записи в CONTROL (как рекомендует ARM). Хотелось бы выслушать мнение насчет расстановки DSB, желательно аргументированно rolleyes.gif ISB убрал полностью, ибо не вижу в них смысла здесь.

Зачем DSB после записи в SP? А в программе в куче мест где делается PUSH ... или ADD/SUB SP, ... тоже будете DSB расставлять? biggrin.gif
DSB задерживает выполнение последующих после неё команд пока не завершатся все текущие/отложенные доступы к памяти как я понимаю.
Зачем её ставить после пересылки в SP если эта загрузка никак к памяти не обращается?
Хотя она конечно не помешает, но сэкономив на пуговицах Вы добавили кучу лишних команд, перфекционист должен негодовать biggrin.gif

После модификации CONTROL DSB тоже лишняя. Я вижу - Вы не запрещаете прерывания на время всех манипуляций. Подумайте что будет если между модификацией CONTROL и DSB произойдёт прерывание? Это показывает - что DSB неэффективна тут.
Да и вообще - такие манипуляции с CONTROL я бы не рисковал делать при разрешённых прерываниях. В uCOS-II например не только никак не обращаются к CONTROL, но и все манипуляции с переключениями стеков и пр. делают при запрещённых прерываниях.

Цитата(Arlleex @ Sep 3 2018, 11:05) *
[*]Подразумевается, что в системе нет загрузчика, или загрузчик, после выполнения своего кода и перехода на пользовательское приложение, привел все регистры в состояние после сброса, а также режим работы CPU и активный SP.

А если это загрузчик в ROM и его никак не изменить?

PS: Когда на на ARM9 в CCS сталкивался с тем, что штатный стартап-код (цепляемый штатным CCS) переводил CPU в непривилегированный режим. И все операции с привилегированными ресурсами вызывали fault-ы. Писателями этого стартапа подразумевалось видимо, что работать с такими ресурсами следует только из обработчика SVC. Пришлось найти исходники стартапа и исправить их мнение - только так. rolleyes.gif
Боюсь представить если также будут думать разработчики ROM-бута в каком-то МК.

PPS: Кстати - не вижу в Вашем коде никаких манипуляций с FPU, хотя вроде писали что он для Cortex-M4.

Автор: Arlleex Sep 3 2018, 11:08

Цитата(jcxz @ Sep 3 2018, 14:01) *
Зачем?

При явной работе с PC адрес инструкции, записываемой в этот регистр, должен быть с установленным 0-м битом, указывающим на Thumb-режим.

Цитата
Зачем её ставить после пересылки в SP если эта загрузка никак к памяти не обращается?
Хотя она конечно не помешает, но сэкономив на пуговицах Вы добавили кучу лишних команд, перфекционист должен негодовать biggrin.gif

Тут мне следует почитать специальный pdf-документ на эту тему, т.к. не до конца понимаю когда их ставить. В общем-то, действительно, тут вообще они не нужны. Я посчитал, что после смены активного указателя стека может что-то измениться в плохую сторону без барьерных инструкций, это не есть гуд. Перфекционист негодует biggrin.gif
Кстати, http://electronix.ru/redirect.php?http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CHDBIBGJ.html прямо пишут
Цитата
Note
When changing the stack pointer, software must use an ISB instruction immediately after the MSR instruction. This ensures that instructions after the ISB instruction execute using the new stack pointer. See ISB

Так что ISB надо вставлять. Выглядит даже логично - действительно конвейер надо сбросить, т.к. SP может наадресовать чего-нибудь не того в конвейверной обработке...

Цитата
А если это загрузчик в ROM и его никак не изменить?
...
Боюсь представить если также будут думать разработчики ROM-бута в каком-то МК.

Будет очень плохо, конечно же sad.gif По-хорошему, такого быть не должно...

Цитата
PPS: Кстати - не вижу в Вашем коде никаких манипуляций с FPU, хотя вроде писали что он для Cortex-M4.

А вот с этим я еще пока разбираюсь.
Есть регистр FPCCR, в нем биты ASPEN и LSPEN. А есть еще CONTROL с его FPCA. Причем все они взаимосвязаны и надо переварить, как именно. В примере от индусов (старый порт RTOS) в бит FPCA CONTROL пишется 0 и вызывается SVC. При этом предварительно биты ASPEN, LSPEN в FPCCR установлены в 1, а FPU-сопроцессор, естественно, включен.

Автор: jcxz Sep 3 2018, 11:44

Цитата(Arlleex @ Sep 3 2018, 14:08) *
При явной работе с PC адрес инструкции, записываемой в этот регистр, должен быть с установленным 0-м битом, указывающим на Thumb-режим.

А как она туда (в стек) попадёт с 0 в мл.бите? Если только специально постараться. laughing.gif

Цитата(Arlleex @ Sep 3 2018, 14:08) *
Кстати, http://electronix.ru/redirect.php?http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CHDBIBGJ.html прямо пишут
Так что ISB надо вставлять. Выглядит даже логично - действительно конвейер надо сбросить, т.к. SP может наадресовать чего-нибудь не того в конвейверной обработке...

Вы похоже не поняли того, что сами процитировали..... biggrin.gif
Эта фраза дана после рекомендации как правильно менять CONTROL.SPSEL. И относится именно к этому изменению.
Подумайте сами логически: если-б ISB нужно менять после любой модификации SP, то компилятор генерил бы ISB во всех случаях когда генерит PUSH/POP/ADD SP/SUB SP. А также ему пришлось бы обрамлять запретами прерываний все такие места. Загляните в листинги.
А также из этой фразы и того что перед ней следует что Вы в своём примере неправильно меняете SPSEL. Там же указано:
Код
By default, Thread mode uses the MSP. To switch the stack pointer used in Thread mode to the
PSP, either:
• use the MSR instruction to set the Active stack pointer bit to 1, see MSR on page 3-164.
• perform an exception return to Thread mode with the appropriate EXC_RETURN value,
see Table 2-17 on page 2-28.

А где у Вас exception return с правильным EXC_RETURN? Каково вообще значение LR при ближайшем входе в ISR? Я что-то подозреваю что оно неверное. rolleyes.gif
Я ещё неск. сообщений назад говорил, что решается это одной командой ORR LR, LR, #4. Да и вообще сам старт многозадачности он много проще чем у Вас тут наворочено.
Также из этой фразы следует что и изменение CONTROL.SPSEL нужно делать при запрещённых прерываниях, чего у Вас нет. Понятно что Вам везёт и у Вас просто сейчас не попадает туда прерывание. Но завтра попадёт. laughing.gif

Цитата(Arlleex @ Sep 3 2018, 14:08) *
В примере от индусов (старый порт RTOS) в бит FPCA CONTROL пишется 0 и вызывается SVC.

Не нужно индусов и SVC. uCOS-II всё это делает без них. laughing.gif
Приведу пример переключателя контекста и запускателя многозадачности из uCOS-II оптимизированного мной:
CODE
;**********************************************************************
**********************************
; START MULTITASKING
; void OSStartHighRdy(void)
;
; Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause
; the first task to start.
;
; 2) OSStartHighRdy() MUST:
; a) Setup PendSV exception priority to lowest;
; cool.gif Set initial PSP to 0, to tell context switcher this is first run;
; c) Set the main stack to end of OS_CPU_ExceptStk
; d) Set OSRunning to TRUE;
; e) Trigger PendSV exception;
; f) Enable interrupts (tasks will run with interrupts enabled).
;*******************************************************************************
*************************

THUMB
OSStartHighRdy LDR R0, =NVIC_SYSPRI14 ;Set the PendSV exception priority
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0]
LDR R1, stkBase ;Initialize the MSP to the end of OS_CPU_ExceptStk
MSR MSP, R1
LDR R0, =OSRunning ;OSRunning = TRUE
MOVS R1, #1
STRB R1, [R0]
BL OSCtxSw
LDR R3, =OSGlobalV
LDRB R2, [R3, #OSPrioHighRdy] ;OSPrioHighRdy
STRB R2, [R3, #OSPrioCur] ;OSPrioCur = OSPrioHighRdy
LDR R2, [R3, #OSTCBHighRdy] ;OSTCBHighRdy
STR R2, [R3, #OSTCBCur] ;OSTCBCur = OSTCBHighRdy;
LDR R0, [R2, #OSTCBStkPtr] ;R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
#ifdef __ARMVFP__
LDRH R1, [R2, #OSTCBOpt] ;OSTCBHighRdy->OSTCBOpt
LSLS R1, R1, #31 - OS_TASK_OPT_SAVE_FP_BIT
ITTT MI
VLDMIAMI R0!, {S0-S31}
LDMIAMI R0!, {R1}
VMSRMI FPSCR, R1
#endif
LDMFD R0!, {R4-R11} ;Restore r4-11 from new process stack
MSR PSP, R0 ;Load PSP with new process SP
CPSIE I ;Exception return will restore remaining context
startHR_01: B startHR_01

DATA
stkBase DC32 OS_CPU_ExceptStk + OS_CPU_EXCEPT_STK_SIZE * 4

здесь Notes 2b более недействительно - я изменил порядок старта многозадачности перенеся часть переключателя контекста в эту функцию. Так что PSP=0 больше не нужно.
На входе в функцию прерывания должны быть запрещены!
Функция OSCtxSw просто возбуждает прерывание PendSV. Которое сработает после CPSIE I.

Переключатель контекста:
CODE
;**********************************************************************
**********************************
; HANDLE PendSV EXCEPTION
; void OS_CPU_PendSVHandler(void)
;
; Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing
; context switches with Cortex-M3. This is because the Cortex-M3 auto-saves half of the
; processor context on any exception, and restores same on return from exception. So only
; saving of R4-R11 is required and fixing up the stack pointers. Using the PendSV exception
; this way means that context saving and restoring is identical whether it is initiated from
; a thread or occurs due to an interrupt or exception.
;
; 2) Pseudo-code is:
; a) Get the process SP, if 0 then skip (goto d) the saving part (first context switch);
; cool.gif Save remaining regs r4-r11 on process stack;
; c) Save the process SP in its TCB, OSTCBCur->OSTCBStkPtr = SP;
; d) Call OSTaskSwHook();
; e) Get current high priority, OSPrioCur = OSPrioHighRdy;
; f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy;
; g) Get new process SP from TCB, SP = OSTCBHighRdy->OSTCBStkPtr;
; h) Restore R4-R11 from new process stack;
; i) Perform exception return which will restore remaining context.
;
; 3) On entry into PendSV handler:
; a) The following have been saved on the process stack (by processor):
; xPSR, PC, LR, R12, R0-R3
; cool.gif Processor mode is switched to Handler mode (from Thread mode)
; c) Stack is Main stack (switched from Process stack)
; d) OSTCBCur points to the OS_TCB of the task to suspend
; OSTCBHighRdy points to the OS_TCB of the task to resume
;
; 4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we
; know that it will only be run when no other exception or interrupt is active, and
; therefore safe to assume that context being switched out was using the process stack (PSP).
;*******************************************************************************
*************************

THUMB
OS_CPU_PendSVHandler:
CPSID I ;Prevent interruption during context switch
MRS R0, PSP ;PSP is process stack pointer
LDR R3, =OSGlobalV
STMFD R0!, {R4-R11} ;Save remaining regs r4-11 on process stack
LDR R2, [R3, #OSTCBCur] ;OSTCBCur
#ifdef __ARMVFP__
LDRH R1, [R2, #OSTCBOpt] ;OSTCBCur->OSTCBOpt
LSLS R1, R1, #31 - OS_TASK_OPT_SAVE_FP_BIT
ITTT MI
VMRSMI R1, FPSCR
STRMI R1, [R0, #-4]!
VSTMDBMI R0!, {S0-S31}
STR R0, [R2, #OSTCBStkPtr] ;OSTCBCur->OSTCBStkPtr = SP;
LDR R2, [R3, #OSTCBHighRdy] ;OSTCBHighRdy
STR R2, [R3, #OSTCBCur] ;OSTCBCur = OSTCBHighRdy;
LDR R0, [R2, #OSTCBStkPtr] ;R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
LDRH R1, [R2, #OSTCBOpt] ;OSTCBHighRdy->OSTCBOpt
LSLS R1, R1, #31 - OS_TASK_OPT_SAVE_FP_BIT
ITTT MI
VLDMIAMI R0!, {S0-S31}
LDMIAMI R0!, {R1}
VMSRMI FPSCR, R1
#else
STR R0, [R2, #OSTCBStkPtr] ;OSTCBCur->OSTCBStkPtr = SP;
LDR R0, [R3, #OSTCBHighRdy] ;OSTCBHighRdy
STR R0, [R3, #OSTCBCur] ;OSTCBCur = OSTCBHighRdy;
LDR R0, [R0, #OSTCBStkPtr] ;R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
#endif
LDRB R1, [R3, #OSPrioHighRdy] ;OSPrioCur = OSPrioHighRdy;
STRB R1, [R3, #OSPrioCur]
ORR LR, LR, #4 ;Ensure exception return uses process stack
LDMFD R0!, {R4-R11} ;Restore r4-11 from new process stack
MSR PSP, R0 ;Load PSP with new process SP
CPSIE I
BX LR ;Exception return will restore remaining context


Замечу что при переключении контекста OSTCBHighRdy (TCB - task control block) - готовой к выполнению самой приоритетной задачи должен быть переписан на место OSTCBCur - TCB текущей активной задачи. И то же самое для OSPrioHighRdy и OSPrioCur (это приоритеты задач, являются в uCOS-II собственно идентификаторами задач).
Также замечу что код по веткам #ifndef __ARMVFP__ я не тестировал - тестил только на CM4 с программой имеющей задачи использующие FPU.
И поясню, что в OSTCBOpt TCB бит OS_TASK_OPT_SAVE_FP_BIT - это флаг о том что задача использует FPU и его контекст нужно тоже сохранять/восстанавливать.

Как видите - нигде нет манипуляций с регистром CONTROL. В нём предполагаются исходные значения == 0 или 4.

Также добавлю описание формата хранения контекста задач в uCOS (для задач с FPU и без):
CODE
+------------+ +------------+
| xPSR | | xPSR |
+------------+ +------------+
|Return Addr | |Return Addr |
+------------+ +------------+
| LR(R14) | | LR(R14) |
+------------+ +------------+
| R12 | | R12 |
+------------+ +------------+
| R3 | | R3 |
+------------+ +------------+
| R2 | | R0 |
+------------+ +------------+
| R1 | | R1 |
+------------+ +------------+
| R0 | | R0 |
+------------+ +------------+
| R11 | | R11 |
+------------+ +------------+
| R10 | | R10 |
+------------+ +------------+
| R9 | | R9 |
+------------+ +------------+
| R8 | | R8 |
+------------+ +------------+
| R7 | | R7 |
+------------+ +------------+
| R6 | | R6 |
+------------+ +------------+
| R5 | | R5 |
+------------+ +------------+
| R4 | | R4 |
+------------+ +------------+
(a) | FPSCR |
+------------+
| S31 |
+------------+
.
.
.
+------------+
| S1 |
+------------+
| S0 |
+------------+

Верхние 8 слов соответствуют аппаратному сохранению контекста в Cortex-M.

Автор: Arlleex Sep 3 2018, 12:00

Цитата
А как она туда (в стек) попадёт с 0 в мл.бите? Если только специально постараться

А вот и не правда. При аппаратном сохранении в стек R0-R3, R12, LR, PC, XPSR значение PC туда укладывается со сброшенным 0-м битом. Можете проверить laughing.gif

Цитата
Эта фраза дана после рекомендации как правильно менять CONTROL.SPSEL. И относится именно к этому изменению.

Так все правильно я понял. Как раз после смены активного SP нужно ставить ISB. А не при смене самого числа, записанного в указателе стека. Это разные вещи.

Цитата
Подумайте сами логически: если-б ISB нужно менять после любой модификации SP, то компилятор генерил бы ISB во всех случаях когда генерит PUSH/POP/ADD SP/SUB SP. А также ему пришлось бы обрамлять запретами прерываний все такие места. Загляните в листинги.

Это не тот случай. Повторюсь: изменение активного SP путем выбора его в CONTROL и любая модификация значения уже активного SP - это различные понятия и действия. Во втором случае, разумеется, никакие барьеры не нужны. А вот в первом - еще как нужны.

Цитата
А также из этой фразы и того что перед ней следует что Вы в своём примере неправильно меняете SPSEL. Там же указано:
By default, Thread mode uses the MSP. To switch the stack pointer used in Thread mode to the
PSP, either:
• use the MSR instruction to set the Active stack pointer bit to 1, see MSR on page 3-164.
• perform an exception return to Thread mode with the appropriate EXC_RETURN value,
see Table 2-17 on page 2-28.

Ключевое слово "либо/одно из двух": либо ручками записать в CONTROL, будучи в привилегированном режиме ядра, либо при помощи исключения с механизмом EXC_RETURN.

Насчет запрета прерываний тоже сомнительно. Раз я сделал все без прерываний, значит ничего не испортит значения регистров в моей последовательности. А на работу барьерных инструкций это не повлияет.

Ваш порт поизучаю для себя, спасибо rolleyes.gif

Автор: jcxz Sep 3 2018, 12:26

Цитата(Arlleex @ Sep 3 2018, 15:00) *
А вот и не правда. При аппаратном сохранении в стек R0-R3, R12, LR, PC, XPSR значение PC туда укладывается со сброшенным 0-м битом. Можете проверить laughing.gif

Проверил: выполнил PUSH {R4, LR} в стеке появилось 0x000000B, 0x1FFF7C5B как и следовало ожидать. Может у Вас CPU какой-то неправильный? cool.gif
Вы бы хоть в листинги сделанные компилятором заглянули и сделали поиск по ним строк POP {....,PC} прежде чем писать. Если следовать Вашим доводам, то всё это ПО в принципе не должно работать никогда. laughing.gif

Цитата(Arlleex @ Sep 3 2018, 15:00) *
Так все правильно я понял. Как раз после смены активного SP нужно ставить ISB. А не при смене самого числа, записанного в указателе стека. Это разные вещи.

Вы не совсем правы: при смене записью в регистр CONTROL. А не при любой смене.
Так почему тогда Вы не следуете этой рекомендации в своём коде?

Цитата(Arlleex @ Sep 3 2018, 15:00) *
Это не тот случай.

Это тот случай, потому что у Вас нет запрета прерываний на время этой смены.

Цитата(Arlleex @ Sep 3 2018, 15:00) *
Ключевое слово "либо/одно из двух":

Гуглопереводчик не так однозначен в переводе этого слова. Поэтому лучше проверить.
Так какое значение в LR у Вас при первом входе в ISR после этой функции?

Цитата(Arlleex @ Sep 3 2018, 15:00) *
Насчет запрета прерываний тоже сомнительно. Раз я сделал все без прерываний, значит ничего не испортит значения регистров в моей последовательности. А на работу барьерных инструкций это не повлияет.

Вы сами себе противоречите. Только что Выше сами писали:
Цитата(Arlleex @ Sep 3 2018, 15:00) *
Так все правильно я понял. Как раз после смены активного SP нужно ставить ISB.

а теперь утверждаете обратное...
Я Вам уже писал выше, но видимо Вы невнимательно читали: Что будет если прерывание произойдёт между записью в CONTROL и ISB? Какую инструкцию CPU выполнит тогда после записи CONTROL?

Автор: Arlleex Sep 3 2018, 13:02

Цитата(jcxz @ Sep 3 2018, 16:26) *
Проверил: выполнил PUSH {R4, LR} в стеке появилось 0x000000B, 0x1FFF7C5B как и следовало ожидать. Может у Вас CPU какой-то неправильный?

Речь идет об аппаратном сохранении в стек при входе в прерывание. Потому что задачи изначально сделаны так, чтобы переключатель контекста восстанавливал PC аппаратно, при выходе из прерывания. А поскольку это так, то при подготовке задачи ей предварительно сбрасывается 0-й бит.
Поскольку моя процедура старта избавлена от прерывания, мне нужно обратно установить 1 в 0-й бит.

Цитата(jcxz @ Sep 3 2018, 16:26) *
Вы не совсем правы: при смене записью в регистр CONTROL. А не при любой смене.
Так почему тогда Вы не следуете этой рекомендации в своём коде?

Сейчас, после записи SPSEL в CONTROL, у меня выполняется ISB.

Цитата
Это тот случай, потому что у Вас нет запрета прерываний на время этой смены.

Так что произойдет-то?

Цитата
Гуглопереводчик не так однозначен в переводе этого слова. Поэтому лучше проверить.
Так какое значение в LR у Вас при первом входе в ISR после этой функции?

Вполне однозначно. Раз мне удалось записать в CONTROL, будучи не в прерывании.
0xFFFFFFFD в LR. Также, как указывалось при создании задачи (в ее стеке).

Цитата
Я Вам уже писал выше, но видимо Вы невнимательно читали: Что будет если прерывание произойдёт между записью в CONTROL и ISB? Какую инструкцию CPU выполнит тогда после записи CONTROL?

Ну, здесь Ваша правда. Не ясно, что будет. Но я покопаюсь в этой каше и докопаюсь до истины biggrin.gif

Автор: jcxz Sep 3 2018, 13:26

Цитата(Arlleex @ Sep 3 2018, 16:02) *
Сейчас, после записи SPSEL в CONTROL, у меня выполняется ISB.
Так что произойдет-то?

После записи в CONTROL не будет выполнена ISB, а будет выполнена видимо первая команда ISR. laughing.gif

Цитата(Arlleex @ Sep 3 2018, 16:02) *
Вполне однозначно. Раз мне удалось записать в CONTROL, будучи не в прерывании.
0xFFFFFFFD в LR. Также, как указывалось при создании задачи (в ее стеке).

Ну тогда ок. Я просто сомневаюсь что это будет выполняться всегда, и на всех ядрах Cortex-M любого производителя. Очень уж меня сомнения берут, почему тогда порт Cortex-M uCOS нигде не пишет в CONTROL напрямую? Думаю - неспроста. Ведь она на очень многие ядра рассчитана....
Содержимое LR для стека задачи тут как бы вообще не при чём.

Цитата(AlexandrY @ Sep 3 2018, 11:10) *
Все переходят на

Отучайтесь говорить за всех!

Русская версия Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)