aboutsummaryrefslogblamecommitdiff
path: root/tamper.c
blob: 477198eb80d832987672e14a0fbee063764a888e (plain) (tree)
1
2
3
4
5
6
7

                                                




                                                                          







                                   











                                                      
                                                    

                                                                     
                                                                      

                                                          
                                                                        













































                                                                     
                                                  

                                                          

                                                                






                                                       

                                                                 











                                                            

                                                            
             

                                                       





                                    


                                                                     
               

                                                   









                      


                                   

                  
                               

                      
                  

 
     





















                                           










                                             






                                                   


                  
                                                                



                                    





















                                                                     
 

                                            


                     





                                                             
 



                                        





                                                           












                                                                     



               






                                  
 

                


                    

                   





                                                                            



           
/* Copyright (c) 2016, NORDUnet A/S. */
/* See LICENSE.txt for licensing information. */

#include <inttypes.h>
#include <avr/io.h> /* -D__AVR_ATtiny828__ will include <avr/iotn828.h> */

/* Mapping of pins to names. */
#define MKM_AVR_CS_N PORTA5
#define MKM_CONTROL_AVR_ENA PORTA6
#define MKM_CONTROL_FPGA_DIS PORTA7

#define MKM_AVR_MOSI PORTD0
#define MKM_AVR_MISO PORTD1
#define MKM_AVR_SCK PORTD3

/* Input pins. */
#define AVR_PANIC_PIN PINA      /* Panic button. */
#define AVR_PANIC_BIT PINA4     /* 0 = panic. */

/* Output ports. */
#define AVR_LED_PORT PORTA
#define AVR_LED_BLUE_BIT PORTA0
#define AVR_LED_RED_BIT PORTA3
#define AVR_LED_YELLOW_BIT PORTA2
#define AVR_LED_GREEN_BIT PORTA1

#define MKM_CS_PORT PORTA       /* MKM chip select. */
#define MKM_CS_BIT MKM_AVR_CS_N /* 0 => selected. */

#define MKM_CONTROL_AVR_PORT PORTA              /* AVR in control. */
#define MKM_CONTROL_AVR_BIT MKM_CONTROL_AVR_ENA /* 0 => in control. */

#define MKM_CONTROL_FPGA_PORT PORTA /* FPGA in control. */
#define MKM_CONTROL_FPGA_BIT MKM_CONTROL_FPGA_DIS /* 0 => in control. */

/* SPI. */
#define MKM_AVR_MOSI_PORT PORTD
#define MKM_AVR_MOSI_BIT MKM_AVR_MOSI /* PD0, Master Out Slave In. */
#define MKM_AVR_MISO_PORT PORTD
#define MKM_AVR_MISO_BIT PORTD1 /* PD1, Master In Slave Out. */
#define MKM_AVR_SCK_PORT PORTD
#define MKM_AVR_SCK_BIT PORTD3  /* PD3, SPI clock. */

/*******/
/* MKM */
static inline void
mkm_chip_select(int select_flag)
{
  if (select_flag)
    MKM_CS_PORT &= ~_BV(MKM_CS_BIT); /* CS low. */
  else
    MKM_CS_PORT |= _BV(MKM_CS_BIT); /* CS high. */
}

static inline void
mkm_grab()
{
  MKM_CONTROL_FPGA_PORT |= _BV(MKM_CONTROL_FPGA_BIT);
  MKM_CONTROL_AVR_PORT &= ~_BV(MKM_CONTROL_AVR_BIT);
}

static inline void
mkm_release()
{
  MKM_CONTROL_AVR_PORT |= _BV(MKM_CONTROL_AVR_BIT);
  MKM_CONTROL_FPGA_PORT &= ~_BV(MKM_CONTROL_FPGA_BIT);
}

/*******/
/* SPI */
#define SPI_SS DDRC0            /* SPI slave select. */

static inline void
spi_setup(int on_flag)
{
  if (on_flag)
    {
      /* Disable SPI power reduction. */
      PRR &= ~_BV(PRSPI);

      /* Configure MOSI and SCK pins as output. */
      DDRD = _BV(MKM_AVR_MOSI_BIT) | _BV(MKM_AVR_SCK_BIT);

      /* Make sure SPI slave select (SS) is configured as output
         before enabling SPI master mode! */
      DDRC |= _BV(SPI_SS);

      /* Enable SPI in master mode, clock rate f/16. */
      SPCR = _BV(SPE) | _BV(MSTR) | _BV(SPR0);
    }
  else
    {
      SPCR &= ~_BV(SPE);        /* Disable SPI. */
      PRR |= _BV(PRSPI);        /* Enable SPI power reduction. */
    }
}

/* SPI commands for MKM (23K640). */
#define SPI_READ 0x03
#define SPI_WRITE 0x02
#define SPI_RDSR 0x05           /* Read status register. */
#define SPI_WRSR 0x01           /* Write status register. */

static inline void
spi_write(uint8_t val)
{
  /* Move the value to be sent to the SPI slave into the SPI
     register. This starts the SPI clock. */
  SPDR = val;

  /* Wait for the byte to be shifted into the slave. */
  loop_until_bit_is_set(SPSR, SPIF);
}

static inline uint8_t
spi_read()
{
  /* Start clocking the SPI slave by moving a dummy byte (0) into the
     SPI register and wait for the byte from the slave to be shifted
     in. */
  spi_write(0);

  /* Read the SPI register and return the value. */
  return SPDR;
}

static inline uint8_t
spi_read_status()
{
  spi_write(SPI_RDSR);
  return SPDR;
}

#define SPI_OPERATION_BYTE 0x00
#define SPI_OPERATION_SEQUENCE 0x40
#define SPI_OPERATION_PAGE 0x80

static inline void
spi_set_operation(uint8_t mode)
{
  spi_write(SPI_WRSR);
  spi_write(mode);
}

#if 0
static void
spi_write_byte(uint16_t addr, uint8_t data)
{
  mkm_chip_select(1);
  spi_write(SPI_WRITE);
  spi_write(addr & 0xff00);
  spi_write(addr & 0x00ff);
  spi_write(data);
  mkm_chip_select(0);
}

static uint8_t
spi_read_byte(uint16_t addr)
{
  mkm_chip_select(1);
  spi_write(SPI_READ);
  spi_write(addr & 0xff00);
  spi_write(addr & 0x00ff);
  uint8_t data = spi_read();
  mkm_chip_select(0);
  return data;
}
#endif

/**********************/
/* Tamper protection. */
#if 0
/* Interrupt handler for tamper pin. */
void
tamper_int(void)  __attribute__ ((interrupt))
{
}
#endif

static inline int
panic_p()
{
  return !bit_is_set(AVR_PANIC_PIN, AVR_PANIC_BIT);
}

static inline void
init_ports()
{
  /* Configure all PORTA pins except the tamper detection pin as
     outputs. */
  DDRA = 0xff & ~_BV(AVR_PANIC_BIT);
}

static void
init_interrupts()
{
  PCMSK0 |= _BV(PCINT4);        /* Set mask bit for PCINT4 */
  PCICR |= _BV(PCIE0);          /* Enable pin change interrupt 0. */
}

static void
init_power_reduction()
{
  /* TBD: Disable everything that we don't need? Note that the effect
     of this should marginal since it's only saving energy when we're
     awaken and actualy wiping memory. */
}

static inline void
mkm_wipe()
{
  AVR_LED_PORT |= _BV(AVR_LED_RED_BIT);

  spi_setup(1);
  mkm_grab();

  mkm_chip_select(1);
  spi_set_operation(SPI_OPERATION_SEQUENCE);
  mkm_chip_select(0);

  mkm_chip_select(1);
  spi_write(SPI_WRITE);
  spi_write(0);                    /* Address, high byte. */
  spi_write(0);                    /* Address, low byte. */
  for (int i = 0; i < 0x1fff; i++) /* 8192 bytes (64Kbit). */
    spi_write(0);
  mkm_chip_select(0);

  mkm_release();
  spi_setup(0);

  AVR_LED_PORT &= ~_BV(AVR_LED_RED_BIT);

  /* Flash blue LED three times to indicate wipe is done */
  for (int x = 0; x < 6; x++) {
    AVR_LED_PORT ^= _BV(AVR_LED_BLUE_BIT);
    for (int i = 0; i < 3200; i++);
  }
}

static inline void
sleep()
{
  SMCR &= ~0x2;               /* Set sleep mode to "power down"... */
  SMCR |= 0x5;                /* ... and enable sleep. */
  asm("sei");                 /* Enable interrupts. */
  asm("sleep");               /* Go to sleep. */

  SMCR &= ~0x1;               /* Disable sleep. */
}

int
main()
{
  init_ports();
  init_power_reduction();
  init_interrupts();

  /* Flash LED's at startup. */
  AVR_LED_PORT |= 0x0f;
  for (int i = 0; i < 16000; i++);
  AVR_LED_PORT &= ~0x0f;

  mkm_release();

  while (1)
    {
      if (panic_p())
        mkm_wipe();

      /* Sleep is not working right at the moment (the AVR seems to be reset
	 when brought out of sleep mode by a press on the panic button).

	 if (!panic_p())
	   sleep();
      */
    }

  return 0;
}