TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: remi04 en 10 de Septiembre de 2017, 16:15:13

Título: Bootloader
Publicado por: remi04 en 10 de Septiembre de 2017, 16:15:13
Quiero cargar un bootloader de tal forma que el fichero HEX del programa a cargar por el boot solo pueda trabajar con ese bootloader.

  Es decir, que si cargas el hex directo al pic no sea posible, que sea necesario el uso de un bootloader.  Por temas de protección de proyecto.

 ¿sabe alguien qué boot puede hacer eso?.

  el pic es 18f26k20

saludos.
Título: Re:Bootloader
Publicado por: AcoranTf en 10 de Septiembre de 2017, 19:30:59
¿Y no es mas sencillo, practico y efectivo proteger el micro contra lectura?.

Saludos.
Título: Re:Bootloader
Publicado por: planeta9999 en 10 de Septiembre de 2017, 19:46:46
Todos los bootoader funcionan así, el programa a cargar nunca se puede grabar directamente porque está compilado para ejecutarse a partir de una dirección.

Lo importante no es eso, sino que el bootloader esté encriptado, de lo contrario, cualquiera con unos conocimientos muy básicos te lo puede copiar, descompilar o clonar. Date cuenta de que a partir de un binario o HEX (sin encriptar) se puede saber cual es la  dirección de arranque de tu programa, y a partir de ahí cualquiera puede crear una rutina previa que simplemente salte a la ejecución de tu programa, aparte de que tu programa se podrá descompilar y manipular (por ejemplo, parchearlo para que funcione de otra forma, saque unos textos distintos en un display, etc...).

Mira en Google por PIC18 bootloader Github, y seguro que encuentras unos cuantos bootloader, ahora lo importante es que les añadas un sistema de encriptación, por ejemplo XTEA, o si lo encuentras ya hecho, mejor.
Título: Re:Bootloader
Publicado por: elreypic2 en 10 de Septiembre de 2017, 19:52:07
Me ha ganado la respuesta planeta9999.
Para esto existe un bootloader comercial realizado por:
http://www.brushelectronics.com/

Este usa precisamente el algoritmo de encriptado XTEA. Esto tiene un costo de $150.00 USD. Pero creo que si tienes los conocimientos necesarios tu podrás implementarlo basado en alguno que ya exista.

Encontré este otro que es gratuito. Espero te pueda servir:

https://diolan.com/pic-bootloader

Saludos,

elreypic.
Título: Re:Bootloader
Publicado por: AcoranTf en 10 de Septiembre de 2017, 22:37:08
Planeta9999 y elreypic, me gustaria saber que ventajas, a nivel de proteccion del codigo representa poner un bootloader en lugar de simplemente proteger contra lectura el PIC.
Ya se que con un bootloader hay otras ventajas, como no necesitar programador externo y/o poder realizar la carga del codigo por RS232 y/o USB, pero a nivel simplemente de seguridad, no le veo el sentido.

Saludos.
Título: Re:Bootloader
Publicado por: planeta9999 en 10 de Septiembre de 2017, 23:17:55
Planeta9999 y elreypic, me gustaria saber que ventajas, a nivel de proteccion del codigo representa poner un bootloader en lugar de simplemente proteger contra lectura el PIC.
Ya se que con un bootloader hay otras ventajas, como no necesitar programador externo y/o poder realizar la carga del codigo por RS232 y/o USB, pero a nivel simplemente de seguridad, no le veo el sentido.

Saludos.

A nivel de seguridad no hay diferencias. El bootloader se emplea para comercializar productos, para los que quieres poder dar a los clientes, actualizaciones de firmware para corregir bugs, sacar versiones con nuevas prestaciones, crear versiones personalizadas, desactivar placas piratas, etc...

Si tu producto, nunca se va a actualizar, no tiene sentido poner un bootloader, lo grabas con protección de lectura y arreando.

Precisamente hace poco he estado trabajando con el bootloader encriptado uTasker para implementarlo en varios de mis productos con micros Kinetis, y va de maravilla. Así puedo colgar en un Github, actualizaciones del firmware, para que el cliente las descargue y actualice el producto, con total seguridad para mí. Los archivos de actualizaciones que doy están encriptados, si los editas no verás más que garabatos, sin posibilidad alguna de copiarlo o descompilarlo. Una maravilla de bootloader encriptado, que también se puede usar con los STM32, y totalmente gratuito.
Título: Re:Bootloader
Publicado por: AcoranTf en 11 de Septiembre de 2017, 05:55:06
Gracias planeta9999, justamente eso es lo que tenia entendido. Pero con el planteamiento de remo04 me confundio.

Saludos.
Título: Re:Bootloader
Publicado por: planeta9999 en 11 de Septiembre de 2017, 08:02:34


Un bootloader no protege de nada, salvo que esté encriptado.

Que un programa no se pueda cargar si no es a través de un bootloader, no impide que te copien el producto. Simplemente con que te hagan una mini rutina, que en el arranque, salte a la dirección de tu programa, ya está clonado el producto.

Si quiere un bootloader, será porque quiere dar actualizaciones, pero para eso hay que encriptarlo.

Título: Re:Bootloader
Publicado por: remi04 en 11 de Septiembre de 2017, 09:24:11
Exacto eso es. Quiero poder reparar bugs y que el usuario desde su casa pueda actualizarlo con un simple usb y a su vez, proteger el hex para que no se pueda duplicar así por que si.
Título: Re:Bootloader
Publicado por: planeta9999 en 11 de Septiembre de 2017, 09:36:56

Pues tendrás que encriptarlo. Yo hace años me hice uno para PIC32, a partir de una nota aplicativa de Microchip, y le añadí mi propia rutina para desencriptar con XTEA. También me hice un programa en VC++ para encriptar los HEX. Incluso me lo compraron de algunas empresas.

Ahora ya solo trabajo con ARM, y para estos encontré el uTasker, que va de maravilla.
Título: Re:Bootloader
Publicado por: remi04 en 11 de Septiembre de 2017, 18:23:45
Gracias a todos por las respuestas. He estado estudiando bastante toda la info que habéis puesto y de momento al estar muy "verde" en el tema de bootloader pues he empezado por lo mas básico como usar los ejemplos de CCS exbootloader.c

  Por lo menos ya he conseguido cargar el programa a través de este sistema usando el SIOW.exe del ccs.

El problema es que este bootloader no carga los datos de la eeprom interna que están incluidos en el hex del programa.  Sin esos datos no funciona la lcd por que contiene constantes como valores de bias, contraste entre otros muchos datos que deben permanecer no volátiles.

 ¿ como se puede hacer para que el bootloader cargue también la eemprom?
Título: Re:Bootloader
Publicado por: elreypic2 en 11 de Septiembre de 2017, 19:32:05
Que tal remi04,

Puedes usar el "Tiny Multi Bootloader+", este te permite cargar datos en la eeprom como lo necesitas.
Este es el link:

http://tinypicbootload.sourceforge.net/

elreypic.
Título: Re:Bootloader
Publicado por: remi04 en 12 de Septiembre de 2017, 09:34:28
Gracias. Le echaré un vistazo, el problema es que está en asm....  Pero lo veré

  De momento lo he solucionado cargando los datos de la eeprom en el propio bootloader. Es decir, cuando grabo el bootloader en el micro también grabo los datos de la eeprom.

Saludos.
Título: Re:Bootloader
Publicado por: elreypic2 en 12 de Septiembre de 2017, 12:21:45
Gracias. Le echaré un vistazo, el problema es que está en asm....  Pero lo veré

  De momento lo he solucionado cargando los datos de la eeprom en el propio bootloader. Es decir, cuando grabo el bootloader en el micro también grabo los datos de la eeprom.

Saludos.

No veo cual sería el problema de que estuviera en ASM. De hecho este bootloader realmente es muy pequeñito, y comparado con otro que tengas en C, te darás cuenta que tienes mas espacio en memoria de código.

Saludos,

elreypic.
Título: Re:Bootloader
Publicado por: remi04 en 14 de Septiembre de 2017, 05:00:08
Problema en verdad ninguno, salvo que tengo que hacer modificaciones y al intentar compilar el fichero de tiny en mplabx me lanza muchos errores de compilación, algunos diciendo "can´t open the file" de los includes estando la ruta de acceso bien, y de hecho haciendo "control + click" sobre el fichero del include te lo abre perfectamente, pero al compilar dice que no los encuentra.  Ello ocasiona una larga lista de errores.    De todas formas todo lo que pueda hacer directamente en C mucho mejor. El assembler lo leo bien, pero meterme a hacer cosas en asm me da un poco de grima.

  Al margen de todo, he estado estudiando los ejemplos del bootloader del CCS para ver por qué no graba la eeprom y en principio y viendo tambien el datasheet del 18f26k20 entiendo que la eeprom está separada de program memory y de ram. viendo entonces que en el caso de mi cpu, program memory = 65535 bytes (0xFFFF). Entiendo que la eeprom interna debe ser accedida a través de sus registros (funciones en C para ello "read_eeprom(a,d);, write_eeprom(a,d);


  a modo de entender como el compilador incrusta los datos para la eeporm, he compilado un pequeño programa que lleva incrustados 25 bytes de datos en la eeprom. El archivo HEX resultante es este:

   
Código: [Seleccionar]
:1000000002EF00F0F86AD09E700ED36E9B8C9B9E20
:10001000000E7E6EC198C19A7F50E00B7F6E799A78
:0A00200079987A6A7B6AFFD7030023
:0200000400F00A                                                        ; Aquí está el linetype = 04 y los bytes altos de ADDR (00F0) es decir, que la dirección sería 
                                                                                   ; 000000F000000000,   Totalmente fuera de rango. por lo que el loader del exboot ccs lo ignora.
:1000000032463201290E0B01020000010001011AE3     ; Aquí están los primeros 16 bytes de datos a cargar en la eeprom
:09001000015E0000000000000088                              ; Aquí están los otros 9 bytes que van a la eeprom.

:020000040030CA
:0E00000000C81E1E000F81000FC00FE00F4051
:00000001FF
;PIC18F26K20
;CRC=CFE6  CREATED="14-sep.-17 09:10"

   
   Entiendo que lo que puedo hacer es añadir en el cargador un If que detecte esta dirección y grabar el buffer uno a uno usando la función (write_eeprom(address,data)

  ¿ lo veis viable?

¿ se nota que no he tocado bootloader en mi vida?, madre mía lo que se aprende...   La base de todo.  Es lo malo de aprender directo alto nivel, que luego hacen falta cosas asi y empiezan los cortocircuitos cerebrales  :D
Título: Re:Bootloader
Publicado por: elreypic2 en 14 de Septiembre de 2017, 16:25:15
Que tal remi04,

Definitivamente tu idea es viable. No tengo experiencia usando el bootloader de CCS pero con paciencia y dedicación tu modificación sería posible.
En cuanto a lo del tinybootloader no he tratado de ensamblarlo usando MPLABX, lo había intentado satisfactoriamente en las verisiones anteriores del MPLAB. Hoy por la noche lo intento y te comento cual fue el resultado. Yo tengo la versión del MPLABX 3.6 si mal no recuerdo.

En mi opinión creo que tinybootloader es la mejor opción porque el código ya esta listo para grabar los valores de la eeprom como los necesitas. Si el problema es la compilación eso tiene solución. Como te lo comenté voy a intentar ensamblar un bootloader ejemplo (hoy por la noche que llegue a casa) y te comento los resultados.

Saludos,

elreypic.
Título: Re:Bootloader
Publicado por: planeta9999 en 14 de Septiembre de 2017, 21:44:44

Aqui tienes un bootloader encriptado, en C, para Pic18. Para encriptar usa Xtea.

http://www.microchip.com/forums/m/tm.aspx?m=126770&mpage=2&key=&&p=#292501
Título: Re:Bootloader
Publicado por: elreypic2 en 14 de Septiembre de 2017, 22:20:16
Pues lo prometido es deuda.

He tomado uno de los archivos fuentes (en ensamblador) para el tinybootloader y ensamblarlo usando MPLABX V3.6 y los resultados son satisfactorios. No he tenido problema alguno en generar el archivo hex. Aquí una snapshot:

 - Tienes que ingresar para ver archivos adjuntos -

remi04, definitivamente algo estas haciendo mal y por eso no puedes ensamblar el codigo fuente y generar el hexadecimal.

elreypic.
Título: Re:Bootloader
Publicado por: remi04 en 18 de Septiembre de 2017, 17:44:37
Gracias a todos. La verdad es que estoy aprendiendo muchas cositas nuevas y entre toda la info que me habeis puesto, estudiando los ficheros estoy poco a poco desarrollando mi propio bootloader.  Tambien he acabado instalando eclipse con mingw para poder compilar los encriptadores y de paso, aprender mas.

Un saludo.
Título: Re:Bootloader
Publicado por: remi04 en 24 de Septiembre de 2017, 13:15:05
Al final, entre toda la ayuda facilitada y comiendome la cabeza he conseguido elaborar mi propio bootloader con xtea , que aunque no es liviano precisamente cumple para lo que necesito y al ser para propio uso y cargar una aplicación en concreto pues me vale aunque no sea lo más optimo.

  Comparto el codigo con todos por si alguien le puede sacar provecho o para leer sugerencias de como corregir o hacer de otras formas algunos disparates del codigo.  :D :D

 Para encriptar encontré una aplicacion en C++ que se puede compilar con eclipse usando un minigw. También pongo este codigo mas abajo. 

  Un saludo.

Código: C
  1. // erase_size = 64
  2. // write_size = 32
  3. // program_memory = 65536
  4. // Bootloader con XTEA elaborado a partir de ejemplos y otras implementaciones.
  5.  
  6.  
  7. #include<18f26k20.h>
  8. #fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOLVP, NOMCLR, PBADEN,
  9. #use delay(clock=64000000)
  10. #use rs232(baud=115200, xmit=PIN_C6, rcv=PIN_C7,STREAM=TX)                          // Comunicación con el cargador (Coolterm, realterm, etc).
  11. #use rs232(baud=9600,parity=N,xmit=PIN_C7,rcv=PIN_C6,bits=8,FORCE_SW,STREAM=LCD)    // Comunicacion rs232 con la pantalla lcd ascii.
  12. #define PUSH_BUTTON PIN_B4                                                         // pulsador de modo bootloader
  13. #byte OSCCON=getenv("SFR:OSCCON")                                                  // registo de configuración del oscilador.
  14. #bit PLLEN=getenv("BIT:PLLEN")                                                     // registo de configuración del oscilador. PLL
  15. #byte OSCTUNE=getenv("SFR:OSCTUNE")                                                // registo de configuración del oscilador.
  16. #define CLK_16 0x70                                                                 // configuración para oscilador a 16 Mhz.                  
  17. #BIT CREN = 0xfab.4                                                                // control recepción modulo usart
  18.  
  19.  
  20. #define XON    0x11                             // control de flujo datos desde el cargador por sotware
  21. #define XOFF   0x13                             // control de flujo datos desde el cargador por sotware
  22.  
  23. #org 0xc84,0xfffe {}              // a partir de la posicion 0xc80 hasta el final de la flash es para el programa a cargar
  24.                                   // pero permitimos a bootloader escribir hasta 0xc84 para que sobreescriba la función del vector de arranque.
  25.  
  26.  
  27.  
  28. int8  checksum, line_type;                                  //  Control de checksum y almacen del tipo de linea hex respectivamente.
  29. int16 l_addr,h_addr=0;
  30. int32 addr;                                                 // almacena el addres donde hay que cargar el buffer data en la flash
  31. int8  dataidx, i, count;                                  // indice buffer de data, i = control usos multiples, count = almacena numero de bytes de una linea relevante hex.
  32. int8  data[32];                                            // buffer de datos enteros de 8 bits ya convertidos listos para enviar a la flash,
  33. int16 key [4] = {0xface,0xdead,0xbabe,0xd00d};           // clave XTEA
  34.  
  35.  
  36. char encripted_buffer[8];        // buffer de 8 bytes para recibir los primeros 8 caracteres encriptados.
  37. char line [46];                 // buffer para construir una linea hex completa, desde ":" hasta el "CR"
  38. int  buffidx = 0;        // indice para buffer primario (desencriptado))
  39. int  lineidx = 0;        // indice para buffer constructor de lineas
  40. int1 lineconst = 0;      // bool para control de linea en contrucción o linea concluida.
  41.  
  42.  
  43.  
  44.  
  45. unsigned int atoi_b16(char *s);     // conversor de dos caracteres hex en un entero de 8 bits decimal
  46. void buffering();                   // Obtiene un paquete de 8 bytes desencriptados.
  47. void decipher(int32 v[2]);          // recibe 8 bytes encriptados por xtea y devuelve esos 8 bytes desencriptados.
  48. void load_program ();                    // constructor de lineas hex
  49. void graba();                      // procesador de lineas hex y grabación en la flash.
  50.  
  51.  
  52. #org 0xc80,0xc82                  // vector de arranque de la aplicación a cargar. Esto será sobreescrito por el "goto" inicial de la app cargada
  53. void main_program (void) {
  54.      while(1);    
  55. }                                    // fin vector de arranque
  56.  
  57.  
  58. void main(void) {
  59.    OSCCON=CLK_16;                       // configuracion oscilador
  60.    OSCTUNE=0b11000000;                  // fonfig oscilador.  
  61.    PLLEN=TRUE;                          // config oscilador    64 Mhz.
  62.    set_tris_a(0b00111111);              // definidos los puertos segun la configuración de la placa y persiféricos conectados en la cpu donde se va a cargar este bootloader
  63.    set_tris_b(0b10111111);  
  64.    set_tris_c(0b01111101);
  65.    CREN = 0;                           // Deshabilitada la recepción por puerto rs232. ( Si algo envía datos, no nos llena el fifo))
  66.    delay_ms(1000);                    // pausa de 1 segundo para estabilizar arranque, alimentación, osciladores.
  67.    
  68.       fprintf(LCD,"SD2");
  69.       fprintf(LCD,"CL");
  70.    
  71.      
  72.      
  73.      
  74.      
  75.      
  76.      
  77.      
  78.    
  79.    if(!input(PUSH_BUTTON))                          // si está pulsado entramos en modo bootloader.
  80.    {
  81.      
  82.       fprintf(LCD,"TTWaiting for download");        // mensaje en el lcd.
  83.       fputc(0,LCD);                                // caracter null para el lcd (requerido por el lcd);)
  84.       delay_ms(100);                              // espera de tráfico concluido hacia el lcd.
  85.       fputc (XON,TX);                           // purgamos cualquier dato que pueda haber retenido en el cargador coolterm, realterm, etc..
  86.      
  87.       load_program();                                 //  recepcion, procesado y grabación del programa encriptado.
  88.      
  89.      
  90.    }
  91.  
  92.   main_program();                               // si no hemos pulsado saltamos al vector de arranque de la app.
  93. }
  94.  
  95. #int_global
  96. void isr(void) {                  
  97.  jump_to_isr(0x0c88);                     // redirige el vector de interrupción.
  98. }
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106. void load_program () {                   // recepcion, procesado y grabación del programa encriptado.
  107.     lineidx = 0;                       // indice buffer de linea hex a cero.
  108.          
  109.     while(1) {                                // bucle secundario
  110.         while (1) {     //  bucle primario
  111.                  buffering();    // llenamos un buffer de 8 bytes de caracteres desencriptados.
  112.    
  113.                  for (i = 0; i <= 7; i++) {     // recorremos el buffer en busca del inicio de linea (:)
  114.                          if ((encripted_buffer[i] == ':') || (lineconst == 1)) {
  115.                          lineconst = 1;                                          // si lo encontramos indicamos que hay una linea en construcción
  116.                          line[lineidx++] = encripted_buffer[i];              // recorremos el buffer ya desencriptado y lo volcamos sobre el buffer line.
  117.                          if (line[lineidx - 1] == 0x0d) lineconst = 0;      // si en algun momento encontramos el caracter 0x0d cerramos la linea.
  118.                      }
  119.              if (lineconst == 0) break;     // si se ha completado una linea salimos del bucle for y dejamos el buffer actual intacto..
  120.            
  121.         }
  122.           if (lineconst == 0) break;     // si se ha completado una linea salimos del bucle while primario.
  123.              
  124.     }
  125.      
  126.      
  127.      graba();      // mandamos a procesar y a grabar la linea en la flash.
  128.      
  129.      // borrado de linea
  130.      for (i=0; i<=45;i++) line[i] = 255;    // vaciamos completamente la linea a 0xFF.
  131.        
  132.               // el ultimo buffer de 8 bytes, donde habiamos encontrado el 0x0d retorno de carro (fin de linea hex) aun contiene o puede contener mas caracteres
  133.              // que tenemos que utilizar.
  134.      
  135.                   // Por ello, habiéndolo dejado intacto volvemos a escanear el ultimo buffer donde se obtuvo el CR ya que seguramente contendrá el inicio de la linea siguiente..
  136.      lineidx = 0;  // ponemos indice idx de la linea en cero para que empiece a sobreescribirla.
  137.        
  138.      for (i = 0; i <= 7; i++) {     // recorremos el buffer en busca del inicio de la siguiente linea (:)
  139.              
  140.             if ((encripted_buffer[i] == ':') || (lineconst == 1)) {   // si lo encontramos abrimos nueva linea.
  141.             lineconst = 1;                                      
  142.             line[lineidx++] = encripted_buffer[i];    // volcamos el resto del buffer desde donde se ha encontrado ":"  .    
  143.             }
  144.         }  
  145.      
  146.     }    // y volvemos al bucle secundario .
  147.            
  148.           // este proceso se repetirá indefinidamente hasta que se haya completado la descarga.
  149.           // en la función graba();, es donde se detecta el fin de la carga cuando se recibe un tipo de linea = 0.)
  150.     }  
  151.    
  152.    
  153.    
  154.    
  155.  
  156.    
  157.  
  158.  
  159.  
  160.  
  161.  
  162. void graba() {
  163.     h_addr = 0;                     // iniciamos h_addr a cero (16 bits superiores de la dirección de la flash)
  164.     int p = 0;                     // control local de la función.
  165.  
  166.     if (line[0] == ':') {             // comprobamos que el primer caracter sea el inicio de linea (:)
  167.          count = atoi_b16 (&line[1]);  // Cargamos en Count, el numero de bytes que hay que grabar en la flash. (Atoi nos convierte dos caracteres hex en un entero de 8 bits)
  168.          l_addr = make16(atoi_b16(&line[3]),atoi_b16(&line[5]));  // cargamos la direccion de la memoria flash donde hay que grabar estos datos.
  169.          line_type = atoi_b16 (&line[7]);                         // cargamos el tipo de linea al que se refiere.
  170.          addr = make32(h_addr,l_addr);                            // construimos addres de 32 bits para direccionar la flash.
  171.          
  172.          int left = (count * 2) + 9;                         // Count contiene el numero de enteros de 8 bits que hay que grabar, son dos caracteres por entero, por eso multiplicamos su valor por dos.
  173.                                                             //, le sumamos 9 por que son los caracteres del principio de la linea ":",numero de bytes "00", address, "0000", tipo de linea "00", son 9 caracteres
  174.                                                           // Aqui lo usamos para saber el numero de bytes que hay que meter en checksum, mas abajo también es utilizado por el buffer Data
  175.              // ahora Left contiene la posición del primer caracter de checksum.
  176.          
  177.          
  178.          
  179.          int checksum = 0;                             // valor inicial a checksum.
  180.          for (i=1; i<left; i+=2)            // el checksum se verifica con los caracteres desde posicion 1 de la linea, hasta el final excepto los dos ultimos valores (que son el propio checksum). tampoco se tiene en cuenta el LF ni el CR.
  181.             checksum += atoi_b16 (&line[i]);  // concatenamos y sumamos todos los valores arriba indicados.
  182.          checksum = 0xFF - checksum + 1;     // restamos a 255 el valor que nos da la concatenación y le sumamos 1. El resultado ha de coincidir con el entero
  183.                                                 // que suministran los dos ultimos caracteres.
  184.          if (checksum != atoi_b16 (&line[left])){   // comparamos
  185.             fprintf(LCD,"TTChecksum ERROR!\r\n");   // si no coincide cancelamos la operación.
  186.             fputc(0,LCD);              
  187.             delay_ms(10);
  188.            
  189.             for(;;);                               // fin de programa por error de checksum.
  190.            }  
  191.              
  192.                // si checksum es ok continuamos.....
  193.          
  194.          
  195.          if (line_type == 1) {                       // si el tipo de linea es "1" significa que hemos concluido la carga completa del programa.                        
  196.             delay_ms(100);                              
  197.             fprintf(LCD,"TTSuccessfull update!\r\n");    // indicamos fin de carga con éxito.
  198.             fputc(0,LCD);            
  199.             fputc(XON,TX);
  200.             delay_ms(1000);
  201.             reset_cpu();                               // y reiniciamos para que arranque el nuevo programa.
  202.            }  
  203.                
  204.          
  205.          else if (line_type == 4) // si el tipo de linea es "4" es por que tenemos que usar una dirección de más de 16 bits de datos, obtenemos de esta linea los otros 16 bits, y saltamos al final del bucle para pedir la siguiente linea.
  206.                h_addr = make16(atoi_b16(&line[9]), atoi_b16(&line[11]));  // ya tenemos en h_addr los otros 16 bits.
  207.            
  208.            
  209.          else if (line_type == 0) {  // si el tipo de linea es "0", se trata de una linea relevante de datos para la flash.
  210.            
  211.          
  212.              if ((addr >= 0xc80) && (addr < getenv("PROGRAM_MEMORY")))  {        // Solo si la posicion de memoria está comprendida entre la zona reservada grabamos la flash
  213.                                
  214.         for (i = 9,dataidx=0; i < left; i += 2)           // a partir del caracter 9 de una linea, hasta la posicion "left" calculada segun "count" (numero de bytes)
  215.                     data[dataidx++]=atoi_b16(&line[i]);        // cargamos en el bucle DATA los enteros ya convertidos de los caracteres. Aunque no está lleno, data es un array de 32 bytes  
  216.                                                             // debido a que la función write_program_memory en el caso de este cpu, trabaja por bloques de 32 bytes
  217.         write_program_memory(addr, data, count);       // Grabamos en la flash el bloque completo de 32 bytes.
  218.               }                                   // notese que hemos elegido que el programa ocupa a partir de la dirección 0xc80. Es el multiplo de 64 (flash_erase_size" mas cercano)
  219.                                                  // que tengo por encima de lo minimo que ocupa este bootloader + una reserva de espacio por si el dia de mañana tuviese que actualizar el propio bootloader.
  220.           }                                    // de modo que esta función trabajará de forma mas optima por que borrará todo el bloque de 64 bytes en cada operación multiplo  
  221.     }                                        // y eso garantiza que no queden datos residuales de anteriores versiones del programa cargado.
  222. }                                           // Si esto no se cumple, sería prudente efectuar un borrado completo de la zona reservada en flash antes de cargar un programa.
  223.  
  224.  
  225.  
  226.    
  227.    
  228.    
  229.    
  230.  
  231.  
  232. void buffering() {         //  XTEA trabaja por bloques de 8 bytes, recibimos el firmware de 8 en 8 bytes,  
  233.    
  234.     fputc (XON,TX);   //  indicamos al software externo que proceda a enviar datos.  
  235.                             // llenamos el buffer inicial con 8 caracteres desencriptados...
  236.         buffidx = 0;       // indice del buffer de 8 bytes para el XTEA
  237.         CREN = 1;         // habilito la recepción de datos en el modulo usart de la cpu.
  238.        
  239.    
  240.         do {                                        // recibimos el primer bloque de 8 bytes.                  
  241.          encripted_buffer[buffidx] = fgetc(TX);  // con este bucle recibiremos 7 bytes, el octavo lo leeremos justo después del XOFF ya que siempre le da tiempo de enviar un byte mas.
  242.         } while (buffidx++ <= 5);               // ya que al solicitar XOFF a coolterm, siempre le ha dado tiempo a enviar un ultimo byte.
  243.     fputc (XOFF,TX);                       // enviamos solicitud a software externo para que pause el envío de caracteres.
  244.     encripted_buffer[7] = fgetc(TX);      // cogemos el octavo byte que siempre se envía tras la peticion de parada                    
  245.      
  246.     CREN = 0;                              // detenemos el puerto de recepcion del microcontrolador.
  247.      decipher(encripted_buffer);           // desencriptamos por Xtea de 128 bits. Ahora tenemos en el mismo buffer 8 bytes desencriptados.    
  248. }
  249.    
  250.  
  251.  
  252.  
  253. void decipher(int32 v[2]) {                // tiny XTEA 128 bits.
  254.        
  255.         int32 v0 = v[0], v1 = v[1], delta = 0x9E3779B9, sum = delta * 32;     // 32 rondas
  256.    
  257.     for (i = 0; i < 32; i++)
  258.         {
  259.                 v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
  260.                 sum -= delta;
  261.                 v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
  262.         }
  263.       v[0] = v0; v[1] = v1;     // asignamos para cargar en el buffer.
  264. }
  265.  
  266.  
  267. unsigned int atoi_b16(char *s) {    // obtiene un numero entero de 8 bits a partir de dos caracter headecimales.-
  268.    unsigned int result = 0;
  269.    int i;
  270.  
  271.    for (i=0; i<2; i++,s++)  {
  272.           if (*s >= 'A')
  273.                  result = 16*result + (*s) - 'A' + 10;
  274.          else
  275.                  result = 16*result + (*s) - '0';
  276.    }
  277.  
  278.    return(result);
  279. }



 Y aqui para encriptar desde el pc. Para encriptar se escribe en la consola:  xtea fichero.hex -e
y para desencriptar xtea fichero.hex -d

Código: C++
  1. #include <iostream>
  2. #include <fstream>
  3. #include <stdint.h>
  4. #include <string.h>
  5. using namespace std;
  6.  
  7. #define BLOCK_SIZE 8 //XTEA uses 64-bit blocks, 64 bits is 8 bytes
  8.  
  9. unsigned int key[4] = { 0xFACE, 0xDEAD, 0xBABE, 0xD00D };
  10. uint32_t orgval;
  11. uint32_t endval;
  12.  
  13.  
  14.  
  15. //XTEA block cipher - code from Wikipedia
  16. //https://en.wikipedia.org/wiki/XTEA
  17.  
  18. void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
  19. {
  20.         unsigned int i;
  21.         uint32_t v0 = v[0], v1 = v[1], sum = 0, delta = 0x9E3779B9;
  22.         for (i = 0; i < num_rounds; i++)
  23.         {
  24.                 v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
  25.                 sum += delta;
  26.                 v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
  27.         }
  28.         v[0] = v0; v[1] = v1;
  29. }
  30.  
  31. void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
  32. {
  33.         unsigned int i;
  34.         uint32_t v0 = v[0], v1 = v[1], delta = 0x9E3779B9, sum = delta * num_rounds;
  35.         for (i = 0; i < num_rounds; i++)
  36.         {
  37.                 v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
  38.                 sum -= delta;
  39.                 v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
  40.         }
  41.         v[0] = v0; v[1] = v1;
  42. }
  43.  
  44. void convert(uint32_t x[2]) {
  45.         orgval = x[0];
  46.         endval = x[1];
  47.  
  48.  
  49. }
  50.  
  51. void xtea(char filePath[], bool boolEncrypt)
  52. {
  53.         //Open file
  54.         fstream file(filePath, ios::in | ios::out | ios::binary);
  55.         cout << endl << "Opening file: " << filePath << endl;
  56.         if (!file) //Check if file is correctly opened
  57.         {
  58.                 cout << "File " << filePath << " cannot be opened" << endl;
  59.                 return;
  60.         }
  61.  
  62.         cout << "File open" << endl;
  63.         file.seekg(0, ios::end);
  64.         unsigned fileSize = file.tellg(); //Get file size
  65.         cout << "File size: " << fileSize << " bytes" << endl;
  66.         file.seekg(ios::beg);
  67.         file.clear();
  68.  
  69.         //Calculate number of blocks to be encrypted/decrypted
  70.         int blockNumber = fileSize / BLOCK_SIZE;
  71.         if (fileSize % BLOCK_SIZE != 0) { ++blockNumber; }
  72.         cout << "Number of blocks: " << blockNumber << endl;
  73.  
  74.         //Decalre data array for file operations
  75.         unsigned char dataArray[BLOCK_SIZE];
  76.         unsigned filePosition = file.tellg();
  77.  
  78.         if (boolEncrypt) { cout << "Starting encryption" << endl; }
  79.         else { cout << "Starting decryption" << endl; }
  80.         for (int i = 0; i < blockNumber; i++)
  81.         {
  82.                 //Get data from file
  83.                 file.seekg(filePosition);
  84.                 file.read((char*)dataArray, BLOCK_SIZE);
  85.  
  86.      
  87.  
  88.                 //Encrypt/decrypt
  89.                 if (boolEncrypt) { encipher(32, (uint32_t*)dataArray, key); }
  90.                 else { decipher(32, (uint32_t*)dataArray, key); }
  91.  
  92.                 //Write to file
  93.                 file.seekp(filePosition);
  94.                 file.write((char*)dataArray, BLOCK_SIZE);
  95.  
  96.  
  97.  
  98.                 //Zero out the data array and increase the pos counter
  99.                 memset(dataArray, 0, BLOCK_SIZE);
  100.                 filePosition += BLOCK_SIZE;
  101.         }
  102.         //Close file
  103.         file.close();
  104.         cout << "Closing file" << endl;
  105.         if (boolEncrypt) { cout << "File " << filePath << " has been encrypted" << endl; }
  106.         else { cout << "File " << filePath << " has been decrypted" << endl; }
  107. }
  108.  
  109.  
  110.  
  111. int main(int argc, char *argv[])
  112. {
  113.         if (argc != 3)
  114.         {
  115.                 if ((argc == 2) && (string(argv[1]) == "-h"))
  116.                 {
  117.                         cout << endl << "Usage: " << "[" << argv[0] << "]" << " [file] [-e/-d]" << endl;
  118.                         cout << "[file] is path to the file you want to encrypt/decrypt" << endl;
  119.                         cout << "[-e/-d] choose one to encrypt/decrypt" << endl;
  120.                         cout << endl << "Example usage: XTEA.exe photo.jpg -e" << endl;
  121.                 }
  122.                 else { cout << endl << argv[0] << " You have entered invalid number of parameters" << endl; }
  123.                 return 1;
  124.         }
  125.  
  126.         bool encrypt = false;
  127.         if ((string(argv[2]) != "-e") && ((string(argv[2]) != "-d"))) { cout << "Invalid parameter " << argv[2] << endl; return 1; }
  128.         if (string(argv[2]) == "-e") { encrypt = true; }
  129.  
  130.         //Encrypt/decrypt
  131.         xtea(argv[1], encrypt);
  132.         return 0;
  133. }



Título: Re:Bootloader
Publicado por: planeta9999 en 24 de Septiembre de 2017, 13:37:53
 

Yo quitaría el pulsador para entrar en modo boot.

Si es por tarjeta SD, se chequea la existencia de la tarjeta, y que tenga el archivo a cargar, si no lo encuentra salta a la aplicación de usuario, si existe.

Si es por un puerto de comunicaciones, USB, Serie, CAN bus, Ethernet, compruebo comunicaciones durante un lapso de tiempo (10-20 segundos por ejemplo), si no hay comunicación, salto a la aplicación de usuario, si existe. Si hay comunicación se queda en modo boot esperando comandos para cargar el firmware.

Lo del pulsador, siempre me ha parecido algo totalmente prescindible, nunca monto en mis placas un pulsador para entrar en modo actualización, salvo en una placa que diseñé hace tiempo con un STM32 porque esta entraba en modo DFU USB, no era un bootloader de usuario.

Además puedes aprovechar y reservar algunas direcciones de la flash, para guardar datos que identifiquen la placa y el producto. Por ejemplo Número de serie único por placa, Código de producto, Versión de firmware y algún código de protección para bloquear placas piratas, así lo tenía yo en el bootloader que hice para PIC32.

En mi situación actual, que ya solo trabajo con ARM, tanto los Kinetis como los STM32 tienen de fábrica grabado un número de serie único por microcontrolador, y el resto lo tengo todo con el bootloader uTasker.
Título: Re:Bootloader
Publicado por: remi04 en 24 de Septiembre de 2017, 14:30:13
Gracias, planeta9999.

  Lo de esperar una transmision no me es viable por que es una aplicacion que no debe demorar mas de 1 segundo en iniciar. El pulsador lo tiene la aplicacion, ya que se maneja todo, menus, ajustes, etc con un unico pulsador. Por ello lo aprovecho para el boltloader. Aunque sinceramente tampoco soy amigo de usarlo asi. Pero es la opcion mas viable.

  Lo del numero de serie lo cargo en la eeprom interna con el boltloader al cargarlo con el pickit2.  Luego tanto eeprom como el codigo va todo en code protect.

   Eso no aparece en el codigo que he puesto arriba por que para el caso que ocupa es superfluo ponerlo ahi.