2012-02-16 14 views
5

Primero algunos antecedentes. Cuando el firmware por cualquier motivo se bloquea (por ejemplo, desbordamiento de pila, puntero de función dañada ...) puede suceder que salte a algún lado y comience a ejecutar algún código. Esto tarde o temprano dará como resultado el reinicio del perro guardián. MCU se reiniciará y volvemos a la pista. A menos que ...Evitar la sobrescritura accidental del firmware

¿Qué sucede cuando tenemos un código que escribe en flash (por ejemplo, gestor de arranque)? Ahora puede suceder que saltemos accidentalmente directamente al código de escritura flash, omitiendo todas las comprobaciones. Antes de que watchdog ladre, terminará con firmware dañado. Esto es exactamente lo que me estaba pasando.

Ahora dirán algunos: solucione el error de raíz que provocó que incluso saltáramos al código de escritura. Bueno, cuando estás desarrollando estás constantemente cambiando el código. Incluso si no hay tal error en este momento, puede haber mañana. Además, ningún código está libre de errores, o al menos no es mío.

Así que ahora estoy haciendo algún tipo de comprobación cruzada. Tengo una variable llamada 'wen' que establecí en 0xa5 antes de las comprobaciones habituales (por ejemplo, verificar para asegurarse de que el destino sea válido). Entonces, justo antes de hacer el borrado real o escribir, verifico si 'wen' realmente está configurado a 0xa5. De lo contrario, esto significa que de alguna manera accidentalmente saltamos al código de escritura. Después de escribir con éxito, 'wen' se borra. He hecho esto en C y funcionó bien. Pero todavía hay una ligera probabilidad teórica de que la corrupción ocurra, porque hay pocas instrucciones de esta verificación final de 'wen' hasta que se escriba en el registro de SPMCR.

Ahora quiero mejorar esto poniendo esta verificación en el ensamblaje, entre la escritura en las instrucciones SPMCR y 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" 
); 

No he probado el código todavía, lo haremos mañana. ¿Ves algún problema? ¿Cómo resolvería usted/tal problema?

Respuesta

3

Una técnica que he visto es asegurarse de que los bytes inmediatamente antes de las rutinas de escritura flash activen algún tipo de tiempo de espera del perro guardián, o reinicie el procesador. De esta forma, no es posible ejecutar datos aleatorios hasta la función de escritura flash y simplemente "caer" en la función.

Es posible que deba tener algunos NOP antes de su restablecimiento para garantizar que las instrucciones se interpretan correctamente.

Su técnica de verificar que la función se ha ejecutado desde el principio, parece una buena, suponiendo que borre la variable wen una vez que haya hecho la escritura.

+0

Sí, wen se borra después de escribir con éxito. Esta llamada a __assert realmente desencadena el restablecimiento de watchdog (además de que registra algo de información sobre lo que lo activó). Me alegra oír que las personas realmente usan tales enfoques :) – Stefan

2

No estoy seguro de por qué necesita tener la capacidad de escribir en flash en su gestor de arranque. Nuestro gestor de arranque sí lo hace, porque puede actualizar el programa de aplicación a través del puerto serie. Por lo tanto, eliminamos el potencial de escrituras inadvertidas al asegurarnos de que el cargador no contenga ninguno de los códigos que escribe en flash. El código que se descarga es un encabezado en el mismo paquete que contiene la imagen que se escribirá. La imagen incorporada tiene la suma de comprobación del algoritmo de programación almacenado y lo verifica antes de ejecutarlo.

Si está escribiendo cosas que se generan internamente, entonces vería los enclavamientos relacionados con el hardware. Solo permita escrituras si previamente ha establecido un pin de salida discreta en ON. Para responder al problema de "¿y si el IP salta los controles"? puedes hacerlo en 2 partes Primero establece algunas variables críticas para el algoritmo. (la dirección para escribir, por ejemplo, mantener esa memoria inicializada en memoria no válida, y solo configurarla correctamente en una llamada separada realizada antes de la escritura. Luego, haga que la función de escritura compruebe su enclavamiento HW. Realice uno de los pasos habilitados en una interrupción, o en respuesta a un temporizador, algo que es poco probable que se golpee en la secuencia correcta si tienes una IP deshonesta.

Si su IP realmente puede saltar a cualquier parte, puede ser imposible evitar una escritura inadvertida. Lo mejor que puede esperar es que se asegure de que el único camino para llegar allí también configure todo lo demás necesario para una escritura exitosa.

+0

Estoy haciendo lo mismo (actualización a través de UART). Hay un código de escritura en la aplicación y en el gestor de arranque. Para que puedan actualizarse mutuamente, y también almaceno alguna configuración en flash. No sé qué UC tiene, pero el que tengo no puede ejecutar el código de la RAM, por lo que cargar un código para escribir no es una opción. En realidad estoy usando un procedimiento similar al descrito con el enclavamiento HW. Esto es lo que traté de explicar cuando hice la pregunta ... parece que hice un mal trabajo :) – Stefan

+0

@Stefan: tenga cuidado al actualizar su gestor de arranque desde su aplicación. ¿Qué sucede con la pérdida de potencia entre el borrado y la escritura? Vaya, tu gestor de arranque no está y has bloqueado tu dispositivo. Uno, un proyecto Freescale HCS08, el gestor de arranque realmente establece los registros de la CPU para evitar que se sobrescriba, y es imposible para la aplicación escribir en esas páginas en el flash. Cuidate. – tomlogic

+0

@tomlogic: Tengo 2 códigos de escritura, en la aplicación y en el gestor de arranque, y pueden actualizarse mutuamente. uC se activa por defecto en el código de la aplicación. Si no actualizo el gestor de arranque, sigo activando la aplicación y puedo volver a intentarlo. Y el gestor de arranque usa un truco. Escribe el código de la aplicación desde la página más alta a la más baja. Antes de escribir la primera página (que en realidad es la más alta), escribe "saltar al gestor de arranque" en la página 0. Ahora, la única preocupación es que no debe dejar de escribir la última página (página 0). Entonces las posibilidades son extremadamente pequeñas para terminar con flash no recuperable. – Stefan

Cuestiones relacionadas