Scan Memory: Checando a integridade da memória Flash no PIC18F47K40

PIC18F47K40

No mundo dos produtos eletrônicos sabe-se que o termo “segurança” deixou há muito tempo de servir apenas de ferramenta de marketing, para tornar-se uma característica essencial na maioria dos dispositivos desenvolvidos com o mínimo de seriedade pelos seus projetistas. Normas reguladoras de produtos estreitam ainda mais essas condições, garantindo que novos produtos sejam lançados no mercado dentro de um limite de segurança aceitável para o consumidor. Neste artigo trataremos sobre um método on running (Scan Memory) para checar a integridade da memória Flash do PIC18F47K40, eliminando, assim, qualquer possibilidade de um sistema corrompido se manter indevidamente operante.

Security Features: Arquitetura Orientada à Segurança

A varredura do conteúdo de todos os endereços da memória Flash de um microcontrolador pode ser uma tarefa um tanto dispendiosa para aplicações em tempo real. Nem todos os microcontroladores são dotados de recursos suficientemente ágeis, para poder realizar tal procedimento dentro de uma performance aceitável. Geralmente o Memory Scan de um microcontrolador é realizado através de técnicas de DMA, necessitando, para isso, uma arquitetura diferenciada, onde um bloco periférico interno do microcontrolador tem acesso ao conteúdo da memória principal sem a participação ativa da CPU. O Memory Scan se enquadra nas chamadas “Security Features”, funcionalidades especialmente desenvolvidas pelos fabricantes de uC’s para contemplar projetos com níveis de segurança mais altos.

O CRC (Cyclic Redundancy Check)

Vídeo 1: Cálculo manual do CRC por um polinômio gerador de 5° Grau.

O CRC é um método matemático que viabiliza o teste da integridade de uma certa cadeia de dados. Basicamente a operação consiste na divisão polinomial binária da cadeia de dados em teste por um polinômio (binário) gerador, sendo o resto da divisão o resultado da operação propriamente dita. Em processos de comunicação o tal “resto” é anexado ao final da mensagem a ser transmitida. O receptor do outro lado, portando o polinômio gerador, realiza a mesma operação sobre a mensagem recebida (incluindo o CRC anexado). Caso o resultado seja nulo, entende-se que a mensagem foi transmitida sem erros.

Slide 1: Demonstração de uma Importante Propriedade do CRC.

O CRC, além de ser muito poderoso na detecção de erros em processos digitais, mostra-se ainda muito leve em implementação via hardware. Isso se deve à natureza das operações binárias realizadas por esse algoritmo. O leitor que estiver familiarizado com álgebra booleana e circuitos sequenciais poderá entender que o circuito da Figura 1, composto de shift register’s e portas XOR’s, realiza o cálculo do CRC utilizando pouquíssimos recursos de hardware. Tendo em vista tamanha elegância, a implementação em software desse algoritmo acaba ficando menos interessante.

Implementação do CRC via Hardware no PIC18F47K40 para Scan Memory
Figura 1: Implementação do CRC via Hardware

CRC no Scan Memory do PIC 18F47K40

Principais características do Módulo CRC do PIC:

  • Implementação em hardware via Linear Feedback Shift Register (Figura 1);
  • Configuração do Polinômio Gerador via software (exceto MSB e LSB, que são fixados por hardware como ‘1’);
  • Configuração da ordem dos bits via software (big-endian/little-endian);
  • Escolha do valor inicial do acumulador do CRC via software (seed value).

Principais características do Módulo Scan Memory do PIC:

  • Configuração do range da memória em teste;
  • Trabalha com interrupções;
  • 4 Modos de checagem da memória:
    • Burst Mode: Paralisa a Operação da CPU para a realização da checagem de toda a memória especificada. (Alto throughput para o processo de scan, com o custo de travar o fluxo do programa principal);
    • Concurrent Mode: De forma análoga ao Burst Mode, também trava o fluxo do programa principal para a execução do scan, contudo permite a CPU retomar suas atividades nos intervalos dos acessos à memória (access cycles);
    • Triggered Mode: Análogo ao Concurrent Mode, contudo o início do Scan Memory se dá por uma fonte de Trigger externa, invés da chamada de uma instrução pela CPU;
    • Peek Mode: Opondo-se ao Burst Mode, no Peek Mode o scan é feito sempre nos intervalos que a CPU não tem acesso à memória não-volátil do micro. (Menor throughput para o processo de scan, com a vantagem de não travar o fluxo do programa principal).

Utilizando o Scan Memory do PIC

Este exemplo foi desenvolvido utilizando-se:

  • Linguagem: C
  • Compilador: xc8
  • IDE: MplabX
  • Calculadora de CRC oferecida pela Microchip
  • Target: PIC18F47K40
  • Ambiente: Windows

A verificação da memória de programa “on running” pode ser implementada através das seguintes etapas:

1°) Codificação da Aplicação: nessa etapa o programador deve implementar o código propriamente dito. Um detalhe importante é a declaração de uma variável const que armazenará o CRC da memória de programa em um local específico da própria memória flash.

//O CRC da Memória de Programa será armazenado na última posição da memória
//Flash (como ainda não sabemos o valor do CRC, carregamos inicialmente um
//valor nulo).

const int CRC_checkValue @ 0x1FFFE=0x0000;

2°) Criação de um .txt com a cadeia de opcodes que formam o programa: após compilar o código fonte, acesse os opcodes gerados para a memória Flash através do seguinte caminho:

Window >> PIC Memory Views >> Program Memory

Acessando os Opcodes da Memória de Programa no MplabX
Figura 2: Acessando os Opcodes da Memória de Programa no MplabX.

Selecione toda a coluna referente aos opcodes e dê um “Ctrl+C”.

Copiando os Opcodes do MplabX
Figura 3: Copiando os Opcodes do MplabX.

Em um editor de texto cole a coluna dos opcodes. Vale lembrar que o último opcode (0x0000) deve ser apagado, pois essa posição de memória armazenará o CRC que iremos calcular. Salve o documento com um nome qualquer.

3°) Cálculo do CRC: possuindo os opcodes sequenciados em um arquivo separado, abra a calculadora de CRC disponibilizada no site da Microchip. Importe o .txt gerado no passo anterior e calcule o CRC da memória de programa (as configurações do cálculo do CRC devem ser as mesmas escolhidas no firmware).

Calculando o CRC do Firmware
Figura 4: Calculando o CRC do Firmware.

4º) Carregue o valor calculado no código fonte: O valor calculado pela aplicação externa será carregado na última posição da memória Flash. Assim, quando o firmware periodicamente checar a memória de programa, os valores devem coincidir, caso contrário a memória estará corrompida.

//O CRC da Memória de Programa será armazenado na última posição da memória
//Flash. (agora sabemos o valor do CRC).

const int CRC_checkValue @ 0x1FFFE=0x189C;

Segue uma implementação do scan memory no modo burst, com o uso de um polinômio gerador 0x1021/CCITT para o módulo CRC:

/*************************************************CONFIG BITS*************************************************************/

#pragma config FEXTOSC = OFF // External Oscillator mode Selection bits->Oscillator not enabled
#pragma config RSTOSC = HFINTOSC_64MHZ // Power-up default value for COSC bits->HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1

// CONFIG1H
#pragma config CLKOUTEN = OFF // Clock Out Enable bit->CLKOUT function is disabled
#pragma config CSWEN = ON // Clock Switch Enable bit->Writing to NOSC and NDIV is allowed
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable bit->Fail-Safe Clock Monitor enabled

// CONFIG2L
#pragma config MCLRE = EXTMCLR // Master Clear Enable bit->If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR
#pragma config PWRTE = OFF // Power-up Timer Enable bit->Power up timer disabled
#pragma config LPBOREN = OFF // Low-power BOR enable bit->ULPBOR disabled
#pragma config BOREN = SBORDIS // Brown-out Reset Enable bits->Brown-out Reset enabled , SBOREN bit is ignored

// CONFIG2H
#pragma config BORV = VBOR_2P45 // Brown Out Reset Voltage selection bits->Brown-out Reset Voltage (VBOR) set to 2.45V
#pragma config ZCD = OFF // ZCD Disable bit->ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
#pragma config PPS1WAY = ON // PPSLOCK bit One-Way Set Enable bit->PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit->Stack full/underflow will cause Reset
#pragma config DEBUG = OFF // Debugger Enable bit->Background debugger disabled
#pragma config XINST = OFF // Extended Instruction Set Enable bit->Extended Instruction Set and Indexed Addressing Mode disabled

// CONFIG3L
#pragma config WDTCPS = WDTCPS_31 // WDT Period Select bits->Divider ratio 1:65536; software control of WDTPS
#pragma config WDTE = OFF // WDT operating mode->WDT Disabled

// CONFIG3H
#pragma config WDTCWS = WDTCWS_7 // WDT Window Select bits->window always open (100%); software control; keyed access not required
#pragma config WDTCCS = SC // WDT input clock selector->Software Control

// CONFIG4L
#pragma config WRT0 = OFF // Write Protection Block 0->Block 0 (000800-003FFFh) not write-protected
#pragma config WRT1 = OFF // Write Protection Block 1->Block 1 (004000-007FFFh) not write-protected
#pragma config WRT2 = OFF // Write Protection Block 2->Block 2 (008000-00BFFFh) not write-protected
#pragma config WRT3 = OFF // Write Protection Block 3->Block 3 (00C000-00FFFFh) not write-protected
#pragma config WRT4 = OFF // Write Protection Block 3->Block 4 (010000-013FFFh) not write-protected
#pragma config WRT5 = OFF // Write Protection Block 3->Block 5 (014000-017FFFh) not write-protected
#pragma config WRT6 = OFF // Write Protection Block 3->Block 6 (018000-01BFFFh) not write-protected
#pragma config WRT7 = OFF // Write Protection Block 3->Block 7 (01C000-01FFFFh) not write-protected

// CONFIG4H
#pragma config WRTC = OFF // Configuration Register Write Protection bit->Configuration registers (300000-30000Bh) not write-protected
#pragma config WRTB = OFF // Boot Block Write Protection bit->Boot Block (000000-0007FFh) not write-protected
#pragma config WRTD = OFF // Data EEPROM Write Protection bit->Data EEPROM not write-protected
#pragma config SCANE = ON // Scanner Enable bit->Scanner module is available for use, SCANMD bit can control the module
#pragma config LVP = ON // Low Voltage Programming Enable bit->Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored

// CONFIG5L
#pragma config CP = OFF // UserNVM Program Memory Code Protection bit->UserNVM code protection disabled
#pragma config CPD = OFF // DataNVM Memory Code Protection bit->DataNVM code protection disabled

// CONFIG6L
#pragma config EBTR0 = OFF // Table Read Protection Block 0->Block 0 (000800-003FFFh) not protected from table reads executed in other blocks
#pragma config EBTR1 = OFF // Table Read Protection Block 1->Block 1 (004000-007FFFh) not protected from table reads executed in other blocks
#pragma config EBTR2 = OFF // Table Read Protection Block 2->Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks
#pragma config EBTR3 = OFF // Table Read Protection Block 3->Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks
#pragma config EBTR4 = OFF // Table Read Protection Block 4->Block 4 (010000-013FFFh) not protected from table reads executed in other blocks
#pragma config EBTR5 = OFF // Table Read Protection Block 5->Block 5 (014000-017FFFh) not protected from table reads executed in other blocks
#pragma config EBTR6 = OFF // Table Read Protection Block 6->Block 6 (018000-01BFFFh) not protected from table reads executed in other blocks
#pragma config EBTR7 = OFF // Table Read Protection Block 7->Block 7 (01C000-01FFFFh) not protected from table reads executed in other blocks

// CONFIG6H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit->Boot Block (000000-0007FFh) not protected from table reads executed in other blocks

/***********************************************DEFINING CONST's*****************************************************************/

#define _XTAL_FREQ 64000000
#define HAL

/********************************************DEFINING PIN's********************************************/

#define LED PORTDbits.RD7

void config_ios();//PORT's Configuration
void config_osc();//Oscillator's Configuration
#include <xc.h>
#ifndef HAL
#include "HAL.h"
#endif

void config_ios()
{
	/*******************************************************************************
	* This function configs the main pin's registers.
	******************************************************************************/

	//PORTA Configuration

	LATA = 0x00;//Latch's set Low
	TRISA = 0xFF;//Tristate sets "In"
	ANSELA = 0xFF;//Analog Inputs Disabled
	WPUA = 0x00;//Internal Weak Pull-ups Disabled
	ODCONA = 0x00;//Open Drain Disabled

	//PORTB Configuration

	LATB = 0x00;//Latch's set Low
	TRISB = 0xFF;//Tristate sets "In"
	ANSELB = 0xFF;//Analog Inputs Disabled
	WPUB = 0x00;//Internal Weak Pull-ups Disabled
	ODCONB = 0x00;//Open Drain Disabled

	//PORTC Configuration

	LATC = 0x00;//Latch's set Low
	TRISC = 0xFF;//Tristate sets "In"
	ANSELC = 0xFF;//Analog Inputs Disabled
	WPUC = 0x00;//Internal Weak Pull-ups Disabled
	ODCONC = 0x00;//Open Drain Disabled

	//PORTD Configuration

	LATD = 0x00;//Latch's set Low
	TRISD = 0xEF;//PIN RD7(LED) -> Out
	ANSELD = 0xFF;//Analog Inputs Disabled
	WPUD = 0x00;//Internal Weak Pull-ups Disabled
	ODCOND = 0x00;//Open Drain Disabled

	//PORTE Configuration

	LATE = 0x00;//Latch's set Low
	TRISE = 0xFF;//Tristate sets "In"
	ANSELE = 0xFF;//Analog Inputs Disabled
	WPUE = 0x00;//Internal Weak Pull-ups Disabled
	ODCONE = 0x00;//Open Drain Disabled

	return;

}

void config_osc()
{
	/*******************************************************************************
	* This function configs the main osc's registers.
	******************************************************************************/

	// NOSC HFINTOSC; NDIV 1;
	OSCCON1 = 0x60;
	// CSWHOLD may proceed; SOSCPWR Low power;
	OSCCON3 = 0x00;
	// MFOEN disabled; LFOEN disabled; ADOEN disabled; SOSCEN disabled; EXTOEN disabled; HFOEN disabled;
	OSCEN = 0x00;
	// HFFRQ 64_MHz;
	OSCFRQ = 0x08;
	// TUN 0;
	OSCTUNE = 0x00;
	return;
}
/*******************************************************************************
Programmer: Caio Cesar Bosco
Date: 28/12/2017
Code: Scan Memory with CRC on PIC18F47K40
* This code do the scan memory in Burst Mode with internal DMA and CRC PIC resources.
* It's just a Microchip Application Note Implementation, for more
* information access:
*
* https://ww1.microchip.com/downloads/en/AppNotes/90003128A.pdf
* https://ww1.microchip.com/downloads/en/AppNotes/00001817A.pdf
*
*
******************************************************************************/

#include <xc.h>
#include "HAL.h"

//******************************************************************************
//The lastest Two address holds Memory's CRC value (computed by a external application).
//Download CRC Calculator on Microchip Site:
// https://www.microchip.com/mymicrochip/filehandler.aspx?ddocname=en572174

const int CRC_checkValue @ 0x1FFFE=0x189C;

//****************************************************************************

void main()
{
	int crc=0;//Receives On Running CRC value.

	config_osc();//Configure Internal Oscillator on 64MHz
	config_ios();//Configure uC pins

	SCANCON0bits.EN=1;//Enable Flash Scan_Memory.
	SCANCON0bits.MODE=1;//Burst Mode - Stop Firmware Flow for Scanning.
	SCANCON0bits.INTM=0;//No interrupts along Scanning Process.

	//***********Selecting Initial Flash Memory Address for Scanning************

	SCANLADRU=0;
	SCANLADRL=0;
	SCANLADRH=0;

	//**************************************************************************

	//***********Selecting Last Flash Memory Address for Scanning************

	SCANHADRU=0x01;
	SCANHADRL=0xFC;
	SCANHADRH=0xFF;

	//Microchip PIC18F47K40's an 8 bits architecture, but opcode's a 16 bits
	//instruction. So the last valid flash address's: 0x1FFFC(opcode MSB)-0x1FFFD(opcode LSB)
	//0x1FFFE - 0x1FFFF holds Flash Memory CRC Value.
	//**************************************************************************

	CRCCON0bits.EN=1;//Enable Internal CRC Module

	CRCACCH=0xFF;//Seeding CRC Accumulator
	CRCACCL=0xFF;//Seeding CRC Accumulator

	//************************16 bit Polynomial CRC-CCITT*************************
	//Polynomial: x^16+x^15+x^5+1
	CRCXORH=0x10;
	CRCXORL=0x21;
	//****************************************************************************

	CRCCON1bits.DLEN=0b0111;//Data Lenght
	CRCCON1bits.PLEN=0b1111;//Polynomial Lenght
	CRCCON0bits.ACCM=1;//Augmented Mode On
	CRCCON0bits.SHIFTM=0;//Big-Endian

	LED=0;//Led off

	while(1)//Super-Loop
	{
		CRCCON0bits.CRCGO=1;//Run CRC Module
		SCANCON0bits.GO=1;//Run Scan Memory

		while(SCANCON0bits.GO);//Waiting Scan
		while(CRCCON0bits.BUSY);//Waiting CRC Module

		crc=CRCACCL+(CRCACCH<<8);//Holds "On Running" CRC value

		if(crc==CRC_checkValue)
		{
			/*******************************************************************
			*If "On Running" memory CRC is the same as the Previously Memory CRC Value,
			toggles LED.
			*******************************************************************/
			LED=~LED;

			/******************************************************************
			(If necessary put a delay routine here).
			******************************************************************/
		}
	}
}

Conclusões

Concluímos que a verificação da memória de programa do PIC pode ser um processo viável a aplicações críticas caso a arquitetura do microcontrolador possuir: acesso direto à memória (DMA – Direct Memory Access) e um módulo de hardware dedicado para o cálculo do CRC. Vimos ainda que existem 4 modos distintos para realizar a checagem da memória, garantindo ao projetista uma significativa liberdade no desenvolvimento do produto.

Espero que o artigo tenha sido útil, qualquer dúvida é só fazer um comentário abaixo.

Saudações e até a próxima!

Saiba mais sobre Segurança em Sistemas Embarcados

O seu dispositivo IoT é seguro?

Webinar Gravado: Segurança em Sistemas Embarcados: Onde, Como e Por quê?

Segurança da Informação – Criptografia AES

Referências

Fonte da Imagem de destaque 

Fonte da Figura 1

Datasheet do PIC18(L)F27/47K40

Computer Interfacing and Protocols

Using a Hardware or Software CRC with Enhanced Core PIC16F1XXX in Class B Applications

Vídeo: How to calculate CRC (Cyclic Redundancy Check)

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
3 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Robson
Robson
20/03/2018 00:26

Ainda não testei essa função CRC, no site mercadolivre, tem o PIC18F46K40 (64k Flash), acho que tem quase tudo que tem no PIC18F47K40 (128k Flash), parece que só muda a capacidade de código da flash, será que esse exemplo roda no 46K40 sem nenhuma alteração?

Encontrei uma tabela de modelos de 8-bits com esta funcionalidade de CRC:
PIC12F1612, PIC16F1613, PIC16F1614, PIC16F1615, PIC16F1618, PIC16F1619, PIC16F18854, PIC16F18855, PIC16F18856, PIC16F18857, PIC16F18875, PIC16F18876, PIC16F18877.

PIC18F24K40, PIC18F24K42, PIC18F24Q10, PIC18F25K40, PIC18F25K42, PIC18F25Q10, PIC18F26K40, PIC18F26K42, PIC18F26Q10, PIC18F27K40, PIC18F27K42, PIC18F27Q10, PIC18F45K40, PIC18F45K42, PIC18F45Q10, PIC18F46K40, PIC18F46K42, PIC18F46Q10, PIC18F47K40, PIC18F47K42, PIC18F47Q10, PIC18F55K42, PIC18F56K42, PIC18F57K42, PIC18F65K40, PIC18F66K40, PIC18F67K40.

Fonte: https://www.microchip.com//wwwAppNotes/AppNotes.aspx?appnote=en573120

Robson
Robson
12/03/2018 12:58

Isso ajuda muito, mas enquanto a fabricante continuar dizendo que o produto deve ser usado por conta e risco do usuário, então a segurança continua duvidosa. Ver datasheet Pg 637: “O uso de dispositivos Microchip em suporte de vida e / ou aplicações de segurança é inteiramente o risco do comprador e o comprador concorda em defender, indenizar e isentar a Microchip de todos e quaisquer danos, reclamações, ações ou despesas decorrentes desse uso.”

Home » Software » Scan Memory: Checando a integridade da memória Flash no PIC18F47K40

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: