addi II 0 27 февраля, 2023 Опубликовано 27 февраля, 2023 · Жалоба отладчик у меня но не аппаратный я прошел и в итоге были следующие операции: xPortStartScheduler suspendall resumeall entertaskcritical exittaskcritical xcreatetask memset malloc выделение блока для pxcurrent после vPortStartFirstTask EPC = A5A5A5A5 и далее иду в цикл Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 27 февраля, 2023 Опубликовано 27 февраля, 2023 · Жалоба 16 hours ago, addi II said: после vPortStartFirstTask EPC = A5A5A5A5 Подозреваю что это не адрес главной процедуры таски 🙂 Неправильно проинициализирован стек, проверьте что и как инициализировалось в pxPortInitialiseStack. Соответствует ли это *( pxTopOfStack + _cEPC ) = (StackType_t) pxCode; и то, куда он восстанавливается (pc) Кстати, только сейчас заметил: Quote Вот первый таск LEAF(vPortStartFirstTask) portRESTORE_CONTEXT END(vPortStartFirstTask) А где eret ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 0 27 февраля, 2023 Опубликовано 27 февраля, 2023 · Жалоба 46 minutes ago, xvr said: Подозреваю что это не адрес главной процедуры таски 🙂 Неправильно проинициализирован стек, проверьте что и как инициализировалось в pxPortInitialiseStack. Соответствует ли это *( pxTopOfStack + _cEPC ) = (StackType_t) pxCode; и то, куда он восстанавливается (pc) Кстати, только сейчас заметил: А где eret ? Спасибо, что-то я никак не пойму как правильно в моем случае проинициализировать стек Я брал за основу порт для PIC32MZ, далее немного перекроил для MIPS64 и если брать инициализацию стека от PIC32 то всеравно A5 возникает в EPC и далее рушить я все в RestoreContext, в фунции первого таска Спасибо, добавил eret ******************************************************************/ /* Restore the processor context. */ .macro portRESTORE_CONTEXT dla s6, uxInterruptNesting ld s6, (s6) daddiu s6, s6, -1 bne s6, zero, 1f nop dla s6, uxSavedTaskStackPointer ///REG_L k0, (s6) ld s5, (s6) dla s0, pxCurrentTCB ld s0, (s0) ///REG_L k0, (s0) ld s5, (s0) // Restore the context. ///_gpctx_load 1: ld s7, _cs7(s5) ld s6, _cs6(s5) ld v0, _cv0(s5) ld v1, _cv1(s5) ld a0, _ca0(s5) ld a1, _ca1(s5) ld a2, _ca2(s5) ld a3, _ca3(s5) ld t0, _ct0(s5) ld t1, _ct1(s5) ld t2, _ct2(s5) ld t3, _ct3(s5) ld $12, _ct4(s5) ld $13, _ct5(s5) ld $14, _ct6(s5) ld $15, _ct7(s5) //lw t8, 108(s5) ld t9, _ct9(s5) //lw s8, 116(s5) ld ra, _cra(s5) di ehb dla k0, uxInterruptNesting ld k1, (k0) daddiu k1, k1, -1 sd k1, 0(k0) ld k0, portSTATUS_STACK_LOCATION(s5) ld k1, portEPC_STACK_LOCATION(s5) dadd sp, zero, s5 ld s5, _cs5(sp) /*dla sp, pxCurrentTCB REG_L sp, (sp) REG_L sp, (sp) */ /* dla sp, uxSavedTaskStackPointer REG_L sp, (sp) */ daddu sp, sp, portCONTEXT_SIZE dmtc0 k0, C0_STATUS dmtc0 k1, C0_EPC ehb .endm /////----------////// LEAF(vPortStartFirstTask) portRESTORE_CONTEXT eret nop END(vPortStartFirstTask) StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) { // Ensure 8 byte alignment is maintained when leaving this function. pxTopOfStack--; pxTopOfStack--; *pxTopOfStack = (StackType_t) 0xDEADBEEF; pxTopOfStack--; *pxTopOfStack = (StackType_t) 0x12345678; // Word to which the stack pointer will be left pointing after context restore. pxTopOfStack--; pxTopOfStack -= CTX_SIZE/8; // CTX SIZE HERE *pxTopOfStack = (StackType_t) mips_getcr(); pxTopOfStack--; *pxTopOfStack = (StackType_t) portINITIAL_SR;// CP0_STATUS pxTopOfStack--; *pxTopOfStack = (StackType_t) pxCode; // CP0_EPC pxTopOfStack--; *pxTopOfStack = (StackType_t) portTASK_RETURN_ADDRESS; // ra pxTopOfStack -= 15; return pxTopOfStack; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 0 27 февраля, 2023 Опубликовано 27 февраля, 2023 · Жалоба по поводу eret еще хотел спросить, зачем он там нужен. ведь первый таск это же не прерывание? И что restirecontext в первом таске может туда записать?, ведь ранее не было прерываний и соответственно никаких записей Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 27 февраля, 2023 Опубликовано 27 февраля, 2023 · Жалоба 3 hours ago, addi II said: StackType_t Проверьте его тип - должен быть 64х битный. 1 hour ago, addi II said: по поводу eret еще хотел спросить, зачем он там нужен. ведь первый таск это же не прерывание? Запуск первого таска делается как возврат из прерывания. Заполняется фрейм, и из него делается возврат. Нужен там eret или просто ret зависит от реализации (видел оба варианта) 2 hours ago, addi II said: И что restirecontext в первом таске может туда записать? Ничего. restorecontext не записывает, а читает оттуда. И читает она то, что вы туда записали в pxPortInitialiseStack. Соотвественно содержимое стека должно соотвествовать обоим. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 0 28 февраля, 2023 Опубликовано 28 февраля, 2023 · Жалоба Спасибо!, да уже было так #define portSTACK_TYPE uint64_t #define portBASE_TYPE long typedef portSTACK_TYPE StackType_t; А как pxCode инициализируется? В StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) он как фактический параметр уже приходит Откуда по исходникам не нашел, и почему считается что pxCode = EPC? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 28 февраля, 2023 Опубликовано 28 февраля, 2023 · Жалоба 5 hours ago, addi II said: А как pxCode инициализируется? Это main вашей создаваемой таски 5 hours ago, addi II said: Откуда по исходникам не нашел, и почему считается что pxCode = EPC? Точка входа в таску, это и есть epc при старте таски Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 0 28 февраля, 2023 Опубликовано 28 февраля, 2023 (изменено) · Жалоба Спасибо! Снова возвращаюсь к линкеру поскольку первое знаение EPC получает : ffffffffb502b7d0 <xEnd>: А это относиться к Disassembly of section .bss: Подскажите пожалуйста, правильно ли я выделяю границы bss в линкере: .bss : { /*. = bss_start;*/ _bss_start = ALIGN(8); *(.bss) *(.bss.*) _bss_end = ALIGN(8) ; } То есть я даю возможность определить линкеру самостоятельно диапазон относительно используемых смежных секций И далее я заполняю ее нулями следующим образом: ################################################################## # Clear uninitialized data sections ################################################################## #dla t0,_bss_begin dla t0,_bss_start dla t1,_bss_end dla t1,_bss_end b _bss_check nop _bss_init: sw zero,0x0(t0) sw zero,0x4(t0) sw zero,0x8(t0) sw zero,0xc(t0) addu t0,16 _bss_check: bltu t0,t1,_bss_init nop Изменено 28 февраля, 2023 пользователем addi II Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 28 февраля, 2023 Опубликовано 28 февраля, 2023 · Жалоба 6 hours ago, addi II said: Снова возвращаюсь к линкеру поскольку первое знаение EPC получает : Зто очень странное значение - код никак не может находится в .bss секции. 6 hours ago, addi II said: Подскажите пожалуйста, правильно ли я выделяю границы bss в линкере: У вас заполнение идёт по 16 байт, а align стоит 8. Увеличте до 16 (иначе вы можете затереть 8 байтов после .bss, что скорее всего не имеет значения, но кто знает) В остальном всё вроде ок Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 0 1 марта, 2023 Опубликовано 1 марта, 2023 · Жалоба Спасибо большое! Теперь я кажется начинаю понимать) Вложенные прерывания возникают во время обработчика текущего прерывания, и прерывают его не дожидаясь eret текущего обработчика посредством, в случае MIPS, перехода не другой деневой набор Об этом как раз говорит оригинальная спецификация на MIPS64 r2(то что у меня): NestedException: /* * Nested exceptions typically require saving the EPC, Status,and SRSCtl registers, * setting up the appropriate GPR shadow set for the routine, disabling * the appropriate IM bits in Status to prevent an interrupt loop, putting * the processor in kernel mode, and re-enabling interrupts. The sample code * below can not cover all nuances of this processing and is intended only * to demonstrate the concepts. */ /* Use the current GPR shadow set, and setup software context */ mfc0 k1, C0_Cause /* Read Cause to get RIPL value */ dmfc0 k0, C0_EPC /* Get restart address */ srl k1, k1, S_CauseRIPL /* Right justify RIPL field */ sd k0, EPCSave /* Save in memory */ mfc0 k0, C0_Status /* Get Status value */ sw k0, StatusSave /* Save in memory */ ins k0, k1, S_StatusIPL, 6 /* Set IPL to RIPL in copy of Status */ mfc0 k1, C0_SRSCtl /* Save SRSCtl if changing shadow sets */ sw k1, SRSCtlSave /* If switching shadow sets, write new value to SRSCtlPSS here */ ins k0, zero, S_StatusEXL, (W_StatusKSU+W_StatusERL+W_StatusEXL) /* Clear KSU, ERL, EXL bits in k0 */ mtc0 k0, C0_Status /* Modify IPL, switch to kernel mode, */ /* re-enable interrupts */ /* * If switching shadow sets, clear only KSU above, write target * address to EPC, and do execute an eret to clear EXL, switch * shadow sets, and jump to routine */ /* Process interrupt here, including clearing device interrupt */ /* * The interrupt completion code is identical to that shown for VI mode above. */ Только в рамках переключения контекста FreeRTOS в tickincrement хендлер и yield хендлер не знаю как правильно это вставить И по структуре не могу понять как должно быть в общем Ведь при каждом их этих прерываниях у нас есть для сохранения ISR контекст и контекста задачи Получается при возникновении прерывания tickincrement мы должны сохранить контекст текущего теневого набора куда то(*1) и далее сохранить контекст текущей задачи в стек задачи Далее мы в рамках обработчика tickincrement делаем запрос на программное(yield) прерывание и в случае установки в 0 S_StatusEXL перейдем не дожидаясь eret текущего прерывания в прерывание программное, - yield И тогда по идеи мы должны сохранить ISR программного прерывания из теневого набора для этого второго прерывания куда то и далее еще раз cохранить контекст текущей задачи и после переключения контекста восстановить по CurrentTCB контекст следующей задачи Далее по eret программного прерывания снова вернуться в tickincrement обработчик и по уже его eret перейти по CurrentTCB При этом надо при последующем переключении на исходную задачу как то перейти на ее точку выхода и восстановить ее контекст, который был вот здесь - 1 Получается как то криво, или я что-то путаю? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 1 марта, 2023 Опубликовано 1 марта, 2023 · Жалоба Теневые наборы регистров не очень подходят для вложенных прерываний вообще, а для прерываний FreeRTOS (которые могут переключить контекст в процессе выхода) вообще не подходят. Теневые хорошо работают когда нет вложенных прерываний (или у них ограниченная глубина, и теневых регистров достаточно для хранения всех фреймов) и нет переключения контекста привыходе, т.е. в прерывание с теневыми регистрами входим только из пользовательской нити, и в неё же и выходим. Если можно обойтись без них - лучше обойтись. Иначе придётся спиливать все теневые регистры в память, а за ними и остовные (т.е. весь пользовательский контекст, включая то, что попадает в теневые регистры) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 0 3 марта, 2023 Опубликовано 3 марта, 2023 · Жалоба Спасибо большое за поддержку! Буду проводить изыскание далее до победного) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 187 3 марта, 2023 Опубликовано 3 марта, 2023 · Жалоба В портах ARM7/ARM9 в uCOS все эти обработки вложенных прерываний и переключений контекстов с теневыми регистрами - давно уже есть. Можно там подсмотреть реализацию. Так как доступна в исходниках. Думаю и порт для MIPS там тоже должен быть в исходниках. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться