aboutsummaryrefslogtreecommitdiff
path: root/tamper.c
blob: e2b21275147fabc4b9a63da4c8668e6e5d0d2114 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
/* 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);
}

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;
}