2012-02-16 4 views
5

처음 몇 가지 배경. 어떤 이유로 든 펌웨어가 충돌 할 때 (예 : 스택 오버플로, 손상된 함수 포인터 ...) 어딘가로 점프하여 일부 코드 실행을 시작할 수 있습니다. 조만간 워치 독이 재설정 될 것입니다. MCU가 리셋되고 다시 정상적으로 돌아옵니다. 그렇지 않으면 ...우발적 인 펌웨어 덮어 쓰기 방지

플래시 (예 : 부트 로더)에 쓰는 코드는 어떻게됩니까? 이제 우연히 플래시 쓰기 코드로 직접 건너 뛰어 모든 검사를 건너 뛸 수 있습니다. 워치 독이 껍질을 벗기기 전에 손상된 펌웨어로 끝납니다. 이것은 정확히 나에게 일어난 일이다.

이제 어떤 사람들은 우리가 코드 작성에 뛰어 들었던 루트 버그를 수정한다고 말할 수 있습니다. 글쎄, 당신이 개발할 때 당신은 끊임없이 코드를 변경하고 있습니다. 현재 그곳에 그런 버그가 없다고해도 내일이있을 것입니다. 게다가, 어떤 코드도 버그가 없다 - 적어도 내 것이 아니다.

그래서 지금 나는 어떤 종류의 교차 검사를하고 있습니다. 나는 'wen'이라는 변수를 가지고 있는데 보통의 수표 (예 : 목적지가 유효한지 확인) 전에 0xa5로 설정합니다. 그런 다음 실제 지우기 또는 쓰기를 수행하기 전에 'wen'이 실제로 0xa5로 설정되어 있는지 확인합니다. 그렇지 않으면 우리가 실수로 글쓰기 코드로 뛰어 들었음을 의미합니다. 쓰기가 완료되면 'wen'이 지워집니다. C에서이 작업을 수행했으며 제대로 작동했습니다. 그러나 SPMCR 레지스터에 쓸 때까지 'wen'에 대한 최종 점검에서 나온 지침이 거의 없기 때문에 약간의 이론적 인 기회가 발생할 수 있습니다.

이제 SPMCR에 대한 쓰기와 SPM 명령어 사이에이 검사를 어셈블리에 넣음으로써이 기능을 향상시키고 싶습니다.

__asm__ __volatile__ 
( 
    "lds __zero_reg__, %0\n\t" 
    "out %1, %2\n\t" 
    "ldi r25, %3\n\t" 
    "add __zero_reg__, r25\n\t" 
    "brne spm_fail\n\t" 
    "spm\n\t" 
    "rjmp spm_done\n\t" 
    "spm_fail: clr __zero_reg__\n\t" 
    "call __assert\n\t" 
    "spm_done:" 
    : 
    : "i" ((uint16_t)(&wen)), 
     "I" (_SFR_IO_ADDR(__SPM_REG)), 
     "r" ((uint8_t)(__BOOT_PAGE_ERASE)), 
     "M" ((uint8_t)(-ACK)), 
     "z" ((uint16_t)(adr)) 
    : "r25" 
); 

내일은 코드를 사용해 본적이 없습니다. 어떤 문제가 보이니? 어떻게 그런 문제를 해결할 수 있습니까?

답변

3

내가 본 한 기술은 플래시 쓰기 루틴이 일종의 워치 독 시간 초과를 트리거하거나 프로세서를 재설정하기 직전에 바이트를 확인하는 것입니다. 그렇게하면 플래시 쓰기 기능으로 이어진 무작위 데이터를 실행할 수 없으며 함수에 "빠져들"뿐입니다.

지침을 올바르게 해석하려면 재설정하기 전에 일부 NOP가 필요할 수 있습니다.

쓰기가 완료되면 wen 변수를 지우면 함수가 처음부터 실행되었는지 확인하는 방법이 좋은 것으로 보입니다.

+0

예, 쓰기가 완료되면 wen이 지워집니다. 이 __assert를 호출하면 실제로는 워치 독 재설정이 트리거되고 (트리거 된 내용에 대한 정보가 기록됩니다). 사람들이 실제로 그런 접근법을 사용한다는 소식을 듣고 기쁜 마음입니다. – Stefan

2

부트 로더에서 플래시에 쓸 수있는 기능이 필요한 이유가 확실하지 않습니다. 우리의 부트 로더는 시리얼 포트를 통해 응용 프로그램을 업데이트 할 수 있기 때문에 그렇게합니다. 따라서 우리는 로더가 플래시에 쓰는 코드를 포함하지 않도록함으로써 우발적 인 쓰기의 가능성을 제거합니다. 해당 코드는 다운로드 할 이미지가 들어있는 동일한 패키지의 헤더입니다. 온보드 이미지에는 프로그래밍 알고리즘의 체크섬이 저장되어 있으며이를 실행하기 전에 확인합니다.

내부적으로 생성 된 것을 쓰고 있다면 하드웨어 관련 인터록을 살펴볼 것입니다. 이전에 특정 이산 출력 핀을 ON으로 설정 한 경우에만 쓰기를 허용합니다. "IP가 수표를 뛰어 넘으면 어떻게 될까?"라는 문제에 답하기 위해서? 당신은 2 부분으로 그것을 할 수 있습니다. 먼저 알고리즘에 대한 몇 가지 중요한 변수를 설정하십시오. (쓰기 주소 예를 들어 - 무효 메모리로 초기화 유지하고 쓰기 전에 작성된 별도의 호출에서만 올바르게 설정 한 다음 HW 인터록을 확인하도록하십시오. 인터럽트에서 사용 가능 단계 중 하나를 수행하십시오. 또는 타이머에 대한 응답으로 불량 IP가있는 경우 정확한 순서로 히트되지 않을 수도 있습니다.

IP가 실제로 점프 할 수 있으면 실수로 쓰기를 막는 것이 불가능할 수 있습니다. 최선을 다하는 것은 성공할 수있는 유일한 길을 보장하여 성공적인 작성을 위해 필요한 모든 것을 설정할 수 있다는 것입니다.

+0

동일한 일을하고 있습니다 (UART를 통해 업데이트). 응용 프로그램과 부트 로더에 코드가 작성됩니다. 그래서 그들은 서로를 상호 업데이트 할 수 있고, 또한 플래시에 몇 가지 구성을 저장합니다. 당신은 가지고있는 것이 무엇인지 모르지만, 가지고있는 코드는 RAM에서 실행할 수 없으므로, 쓰기 용 코드를 업로드하는 것은 옵션이 아닙니다. 실제로 HW 인터록으로 설명한 것과 비슷한 절차를 사용하고 있습니다. 이것은 내가 질문을 설정할 때 설명하려고했던 것입니다 ... 제가 나쁜 일을 한 것 같습니다 :) – Stefan

+0

@Stefan : 응용 프로그램에서 부트 로더를 업데이트하는 데주의하십시오. 지우기와 쓰기 사이의 전력 손실은 어떻게됩니까? 죄송합니다. 부트 로더가 없어져서 기기를 벽돌에 넣었습니다. Freescale HCS08 프로젝트 중 하나 인 부트 로더는 실제로 CPU 레지스터를 덮어 쓰지 않도록 보호하기 위해 CPU 레지스터를 설정합니다. 따라서 응용 프로그램이 플래시의 해당 페이지에 쓸 수 없습니다. 안전한. – tomlogic

+0

@tomlogic : 필자는 애플리케이션 및 부트 로더에 2 개의 코드를 작성하고 서로 업데이트 할 수 있습니다. 기본적으로 uC는 응용 프로그램 코드로 돌아옵니다. 부트 로더를 업데이트하지 못하면 응용 프로그램으로 돌아와 재 시도 할 수 있습니다. 그리고 부트 로더는 트릭을 사용합니다. 최상위 페이지에서 가장 낮은 페이지로 응용 프로그램 코드를 씁니다. 첫 번째 (실제로는 최고) 페이지를 작성하기 전에 페이지 0에 '부트 로더로 건너 뛰기'라고 씁니다. 이제는 마지막 페이지 (페이지 0)를 작성하는 데 실패하지 않아야합니다. 따라서 복구 할 수없는 플래시로 끝날 확률은 극히 적습니다. – Stefan