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

вложенные прерывания - архитектура

отладчик у меня но не аппаратный

я прошел и в итоге были следующие операции:

xPortStartScheduler

suspendall
resumeall
entertaskcritical
exittaskcritical
xcreatetask
memset

malloc
выделение блока для pxcurrent

после vPortStartFirstTask EPC = A5A5A5A5

и далее иду в цикл

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


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

16 hours ago, addi II said:

после vPortStartFirstTask EPC = A5A5A5A5

Подозреваю что это не адрес главной процедуры таски 🙂 Неправильно проинициализирован стек, проверьте что и как инициализировалось в pxPortInitialiseStack. Соответствует ли это

*( pxTopOfStack + _cEPC ) = (StackType_t) pxCode;

и то, куда он восстанавливается (pc)

Кстати, только сейчас заметил:

Quote

Вот первый таск

LEAF(vPortStartFirstTask)
portRESTORE_CONTEXT
END(vPortStartFirstTask)

А где eret ?

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


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

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

 

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


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

по поводу eret еще хотел спросить, зачем он там нужен. ведь первый таск это же не прерывание?

И что restirecontext в первом таске может туда записать?, ведь ранее не было прерываний и соответственно никаких записей:scratch_one-s_head:

 

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


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

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. Соотвественно содержимое стека должно соотвествовать обоим.

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


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

Спасибо!, да уже было так

#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?

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


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

5 hours ago, addi II said:

А как pxCode инициализируется?

 

Это main вашей создаваемой таски

5 hours ago, addi II said:

Откуда по исходникам не нашел, и почему  считается что pxCode = EPC?

Точка входа в таску, это и есть epc при старте таски

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


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

Спасибо!

Снова возвращаюсь к линкеру поскольку первое знаение 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

 

Изменено пользователем addi II

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


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

6 hours ago, addi II said:

Снова возвращаюсь к линкеру поскольку первое знаение EPC получает :

Зто очень странное значение - код никак не может находится в .bss секции.

6 hours ago, addi II said:

Подскажите пожалуйста, правильно ли я выделяю границы bss в линкере:

У вас заполнение идёт по 16 байт, а align стоит 8. Увеличте до 16 (иначе вы можете затереть 8 байтов после .bss, что скорее всего не имеет значения, но кто знает)

В остальном всё вроде ок

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


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

Спасибо большое!

 

Теперь я кажется начинаю понимать)

Вложенные прерывания возникают во время обработчика текущего прерывания, и прерывают его не дожидаясь 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

Получается как то криво, или я что-то путаю?

 

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


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

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

Теневые хорошо работают когда нет вложенных прерываний (или у них ограниченная глубина, и теневых регистров достаточно для хранения всех фреймов) и нет переключения контекста привыходе, т.е. в прерывание с теневыми регистрами входим только из пользовательской нити, и в неё же и выходим.

Если можно обойтись без них - лучше обойтись. Иначе придётся спиливать все теневые регистры в память, а за ними и остовные (т.е. весь пользовательский контекст, включая то, что попадает в теневые регистры)

 

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


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

В портах ARM7/ARM9 в uCOS все эти обработки вложенных прерываний и переключений контекстов с теневыми регистрами - давно уже есть. Можно там подсмотреть реализацию. Так как доступна в исходниках. Думаю и порт для MIPS там тоже должен быть в исходниках.

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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