Add source code from Gnuk 1.0.1
[gnuk/neug.git] / src / sys.c
1 /*
2  * sys.c - system services at the first flash ROM blocks
3  *
4  * Copyright (C) 2012 Free Software Initiative of Japan
5  * Author: NIIBE Yutaka <gniibe@fsij.org>
6  *
7  * This file is a part of Gnuk, a GnuPG USB Token implementation.
8  *
9  * Gnuk is free software: you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Gnuk is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "config.h"
25 #include "ch.h"
26 #include "hal.h"
27 #include "board.h"
28 #include "usb_lld.h"
29
30 extern uint8_t __flash_start__, __flash_end__;
31
32
33 static void
34 usb_cable_config (int enable)
35 {
36 #if defined(SET_USB_CONDITION)
37   if (SET_USB_CONDITION (enable))
38     palSetPad (IOPORT_USB, GPIO_USB);
39   else
40     palClearPad (IOPORT_USB, GPIO_USB);
41 #else
42   (void)enable;
43 #endif
44 }
45
46 static void
47 set_led (int on)
48 {
49   if (SET_LED_CONDITION (on))
50     palSetPad (IOPORT_LED, GPIO_LED);
51   else
52     palClearPad (IOPORT_LED, GPIO_LED);
53 }
54
55
56 #define FLASH_KEY1               0x45670123UL
57 #define FLASH_KEY2               0xCDEF89ABUL
58
59 static void
60 flash_unlock (void)
61 {
62   FLASH->KEYR = FLASH_KEY1;
63   FLASH->KEYR = FLASH_KEY2;
64 }
65
66
67 static int
68 flash_wait_for_last_operation (uint32_t timeout)
69 {
70   int status;
71
72   do
73     {
74       status = FLASH->SR;
75       if (--timeout == 0)
76         break;
77     }
78   while ((status & FLASH_SR_BSY) != 0);
79
80   return status & (FLASH_SR_BSY|FLASH_SR_PGERR|FLASH_SR_WRPRTERR);
81 }
82
83 #define FLASH_PROGRAM_TIMEOUT 0x00010000
84 #define FLASH_ERASE_TIMEOUT   0x01000000
85
86 static int
87 flash_program_halfword (uint32_t addr, uint16_t data)
88 {
89   int status;
90
91   status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
92
93   port_disable ();
94   if (status == 0)
95     {
96       FLASH->CR |= FLASH_CR_PG;
97
98       *(volatile uint16_t *)addr = data;
99
100       status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
101       FLASH->CR &= ~FLASH_CR_PG;
102     }
103   port_enable ();
104
105   return status;
106 }
107
108 static int
109 flash_erase_page (uint32_t addr)
110 {
111   int status;
112
113   status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
114
115   port_disable ();
116   if (status == 0)
117     {
118       FLASH->CR |= FLASH_CR_PER;
119       FLASH->AR = addr;
120       FLASH->CR |= FLASH_CR_STRT;
121
122       status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
123       FLASH->CR &= ~FLASH_CR_PER;
124     }
125   port_enable ();
126
127   return status;
128 }
129
130 static int
131 flash_check_blank (const uint8_t *p_start, size_t size)
132 {
133   const uint8_t *p;
134
135   for (p = p_start; p < p_start + size; p++)
136     if (*p != 0xff)
137       return 0;
138
139   return 1;
140 }
141
142 static int
143 flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
144 {
145   int status;
146   uint32_t flash_start = (uint32_t)&__flash_start__;
147   uint32_t flash_end = (uint32_t)&__flash_end__;
148
149   if (dst_addr < flash_start || dst_addr + len > flash_end)
150     return 0;
151
152   while (len)
153     {
154       uint16_t hw = *src++;
155
156       hw |= (*src++ << 8);
157       status = flash_program_halfword (dst_addr, hw);
158       if (status != 0)
159         return 0;               /* error return */
160
161       dst_addr += 2;
162       len -= 2;
163     }
164
165   return 1;
166 }
167
168 #define OPTION_BYTES_ADDR 0x1ffff800
169
170 static int
171 flash_protect (void)
172 {
173   int status;
174   uint32_t option_bytes_value;
175
176   status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
177
178   port_disable ();
179   if (status == 0)
180     {
181       FLASH->OPTKEYR = FLASH_KEY1;
182       FLASH->OPTKEYR = FLASH_KEY2;
183
184       FLASH->CR |= FLASH_CR_OPTER;
185       FLASH->CR |= FLASH_CR_STRT;
186
187       status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
188       FLASH->CR &= ~FLASH_CR_OPTER;
189     }
190   port_enable ();
191
192   if (status != 0)
193     return 0;
194
195   option_bytes_value = *(uint32_t *)OPTION_BYTES_ADDR;
196   return (option_bytes_value & 0xff) == 0xff ? 1 : 0;
197 }
198
199
200 static void __attribute__((naked))
201 flash_erase_all_and_exec (void (*entry)(void))
202 {
203   uint32_t addr = (uint32_t)&__flash_start__;
204   uint32_t end = (uint32_t)&__flash_end__;
205   int r;
206
207   while (addr < end)
208     {
209       r = flash_erase_page (addr);
210       if (r != 0)
211         break;
212
213       addr += FLASH_PAGE_SIZE;
214     }
215
216   if (addr >= end)
217     (*entry) ();
218
219   for (;;);
220 }
221
222 static void
223 nvic_enable_vector (uint32_t n, uint32_t prio)
224 {
225   unsigned int sh = (n & 3) << 3;
226
227   NVIC_IPR (n >> 2) = (NVIC_IPR(n >> 2) & ~(0xFF << sh)) | (prio << sh);
228   NVIC_ICPR (n >> 5) = 1 << (n & 0x1F);
229   NVIC_ISER (n >> 5) = 1 << (n & 0x1F);
230 }
231
232 static void
233 usb_lld_sys_init (void)
234 {
235   RCC->APB1ENR |= RCC_APB1ENR_USBEN;
236   nvic_enable_vector (USB_LP_CAN1_RX0_IRQn,
237                       CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY));
238   /*
239    * Note that we also have other IRQ(s):
240    *    USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous)
241    *    USBWakeUp_IRQn (suspend/resume)
242    */
243   RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
244   RCC->APB1RSTR = 0;
245
246   usb_cable_config (1);
247 }
248
249 static void
250 usb_lld_sys_shutdown (void)
251 {
252   RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
253   usb_cable_config (0);
254 }
255
256 #define SYSRESETREQ 0x04
257 static void
258 nvic_system_reset (void)
259 {
260   SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SYSRESETREQ);
261   asm volatile ("dsb");
262 }
263
264 static void __attribute__ ((naked))
265 reset (void)
266 {
267   asm volatile ("cpsid  i\n\t"          /* Mask all interrupts. */
268                 "mov.w  r0, #0xed00\n\t" /* r0 = SCR */
269                 "movt   r0, #0xe000\n\t"
270                 "mov    r1, pc\n\t"      /* r1 = (PC + 0x1000) & ~0x0fff */
271                 "mov    r2, #0x1000\n\t"
272                 "add    r1, r1, r2\n\t"
273                 "sub    r2, r2, #1\n\t"
274                 "bic    r1, r1, r2\n\t"
275                 "str    r1, [r0, #8]\n\t"       /* Set SCR->VCR */
276                 "ldr    r0, [r1], #4\n\t"
277                 "msr    MSP, r0\n\t"    /* Main (exception handler) stack. */
278                 "ldr    r0, [r1]\n\t"   /* Reset handler.                  */
279                 "bx     r0\n"
280                 : /* no output */ : /* no input */ : "memory");
281 }
282
283 typedef void (*handler)(void);
284 extern uint8_t __ram_end__;
285
286 handler vector[] __attribute__ ((section(".vectors"))) = {
287   (handler)&__ram_end__,
288   reset,
289   (handler)set_led,
290   flash_unlock,
291   (handler)flash_program_halfword,
292   (handler)flash_erase_page,
293   (handler)flash_check_blank,
294   (handler)flash_write,
295   (handler)flash_protect,
296   (handler)flash_erase_all_and_exec,
297   usb_lld_sys_init,
298   usb_lld_sys_shutdown,
299   nvic_system_reset,
300 };
301
302 const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
303   3*2+2,             /* bLength */
304   0x03,              /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE*/
305   /* sys version: "1.0" */
306   '1', 0, '.', 0, '0', 0,
307 };