-
Notifications
You must be signed in to change notification settings - Fork 3
/
bootloader.asm
360 lines (295 loc) · 7.1 KB
/
bootloader.asm
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
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
; Bootloader
; (C) 2007-2011 Marek Wodzinski
;
; Changelog:
; 2007.11.16 - first code
; 2007.11.17 - xmodem and flash programming done
; 2007.11.18 - decrypting
; 2007.11.23 - fixed hang when there is a constant stream of data coming from rs
; - removed other options, corrected banners
; - changed a little decrypting algoryth
; 2007.11.24 - final changes in decryption algo
; 2011.07.01 - compute uart divider instead of hardcoding values
; - make crypt optional
.include "m8def.inc"
;.define use_crypt ;comment it out if no encryption is needed
.ifndef temp
.def temp=r16
.def temp2=r17
.endif
.def rblock=r2
.def rblocki=r3
.def rcksum=r4
.def cksum=r18
.def block=r19
.def spmcrval=r20
.def response=r21
.def looplo=r24
.def loophi=r25
;.equ ZEGAR=8000000 ;CLK
.equ ZEGAR=7372800
.equ UART_RATE=9600
.equ RAM_START=0x100 ;ram start
.equ REC_BUF=RAM_START ;receive buffer
.equ WRITE_BUF=REC_BUF+256 ;write buffer
.equ boot_rx_timeout=ZEGAR/641 ;wait about 2s for char from UART
.equ xmodem_SOH=0x01 ;xmodem definitions
.equ xmodem_EOT=0x04
.equ xmodem_ACK=0x06
.equ xmodem_NAK=0x15
.equ xmodem_CAN=0x18
.equ xmodem_C=0x45
.equ mieszacz=79
.equ poczatek=0x39
.cseg
.org 0
reset:
.org SECONDBOOTSTART
boot_start:
;disable interrupts
cli
;initialize stack
ldi temp,low(RAMEND)
out SPL,temp
ldi temp,high(RAMEND)
out SPH,temp
;initialize UART
cbi DDRD,PD0 ;rx: input
sbi DDRD,PD1 ;tx: output
ldi temp,0 ;no x2 speed, no multiprocessor comm.
out UCSRA,temp
ldi temp,(1<<RXEN)+(1<<TXEN) ;enable rx and tx
out UCSRB,temp
ldi temp,(1<<URSEL)+(1<<UCSZ1)+(1<<UCSZ0) ;8 bit
out UCSRC,temp
ldi temp,0
out UBRRH,temp
ldi temp,ZEGAR/16/UART_RATE-1 ;speed: 9600 (47 for 7.3728, 51 for 8M)
out UBRRL,temp
in temp,UDR ;flush receiver
in temp,UDR
in temp,UDR
;print banner
ldi ZL,low(boot_banner1<<1)
ldi ZH,high(boot_banner1<<1)
rcall boot_print
;wait for keypress
boot_wait:
rcall boot_rx_char ;get char from uart
brcs boot_end ;go to end if timeout
cpi temp,'B' ;B?
brne boot_end ;no second chance
boot_menu: ;menu
ldi ZL,low(boot_banner3<<1)
ldi ZH,high(boot_banner3<<1)
rcall boot_print
boot_menu1:
sbis UCSRA,RXC ;wait for char
rjmp boot_menu1
in temp,UDR ;read char
cpi temp,'P'
brne boot_end
;
; ########## upload new firmware #########
; #
boot_firmware:
;upload new firmware
clr ZL ;set FLASH address to 0
clr ZH
ldi block,1 ;set block counter
xmodem_start:
;start xmodem transmission
ldi response,xmodem_NAK ;send initial NAK
xmodem_start1:
mov temp,response
rcall boot_tx_char
rcall boot_rx_char ;wait for char
brcs xmodem_start1 ;time out - wait again
cpi temp,xmodem_SOH ;check for start of header
breq xmodem_receive
cpi temp,xmodem_EOT ;check for end of transmission
breq xmodem_end
rjmp xmodem_start1
xmodem_receive:
;get packet
rcall boot_rx_char ;get block number
mov rblock,temp
rcall boot_rx_char ;get inverse block number
mov rblocki,temp
ldi YL,low(REC_BUF) ;prepare buffer address
ldi YH,high(REC_BUF)
clr cksum ;clear checksum counter
ldi temp2,128 ;prepare to receive 128 chars
xmodem_receive1:
rcall boot_rx_char ;receive byte
st Y+,temp ;store in ram
add cksum,temp ;checksum
dec temp2
brne xmodem_receive1
rcall boot_rx_char ;get checksum
;checks
cp temp,cksum ;check checksum
brne xmodem_start
cp block,rblock ;check for block number
brne xmodem_start
com rblocki ;check for block and 255-block fields
cp rblocki,rblock
brne xmodem_start
;block received ok
rcall boot_block_process ;do something
inc block ;get next block
ldi response,xmodem_ACK ;send ACK
rjmp xmodem_start1
xmodem_end:
ldi temp,xmodem_ACK
rcall boot_tx_char
rjmp boot_menu
; ### end of new firmware
;
boot_end:
;time out - boot original application
ldi ZL,low(boot_banner2<<1)
ldi ZH,high(boot_banner2<<1)
rcall boot_print
rjmp reset ;end of bootloader
;
; ########## subroutines ###########
; #
;
; send chars stored in flash to UART
boot_print:
lpm temp,Z+
tst temp
breq boot_print1
rcall boot_tx_char
rjmp boot_print
boot_print1:
ret
;
;
; transmit char from temp to UART
boot_tx_char:
sbis UCSRA,UDRE ;wait for empty buffer
rjmp boot_tx_char
out UDR,temp
ret
;
;
; # wait for char (about 1s timeout)
boot_rx_char:
push temp2
ldi looplo,low(boot_rx_timeout) ;maximum time to wait
ldi loophi,high(boot_rx_timeout)
clr temp2 ;second wait loop
boot_rx_char1:
sbic UCSRA,RXC ;skip if nothing to read ;2
rjmp boot_rx_char2
dec temp2 ;end of small loop ;1
brne boot_rx_char1 ;2/1 (5*256)
sbiw looplo,1 ;end of main loop ;2
brne boot_rx_char1 ;2
sec ;set carry=1 : time out
rjmp boot_rx_char3
boot_rx_char2:
in temp,UDR
clc ;clear carry, temp<-char received
boot_rx_char3:
pop temp2
ret
;
;
; Make something with 128B of data in RAM
boot_block_process:
.ifdef use_crypt
rcall boot_decrypt
ldi YL,low(WRITE_BUF) ;prepare buffer address
ldi YH,high(WRITE_BUF)
.else
ldi YL,low(REC_BUF)
ldi YH,high(REC_BUF)
.endif
ldi temp,128 ;how many bytes are to write
rcall boot_block_write
ret
;
;
; # write blocks to flash
; - Z : flash address
; - Y : ram address
; - temp : number of bytes to write
boot_block_write:
;page erase
ldi spmcrval,(1<<PGERS)+(1<<SPMEN)
rcall boot_spm
;reenable RWW section
ldi spmcrval,(1<<RWWSRE)+(1<<SPMEN)
rcall boot_spm
;transfer data from RAM to FLASH buffer
ldi looplo,PAGESIZE ;number of WORDS in page to write
boot_block_write1:
ld r0,Y+
ld r1,Y+
ldi spmcrval,(1<<SPMEN)
rcall boot_spm
adiw ZL,2
subi temp,2
dec looplo
brne boot_block_write1
;write page from buffer to FLASH
subi ZL,(PAGESIZE<<1) ;step back
sbci ZH,0
ldi spmcrval,(1<<PGWRT)+(1<<SPMEN) ;write page
rcall boot_spm
ldi spmcrval,(PAGESIZE<<1)
add ZL,spmcrval ;restore Z
ldi spmcrval,0 ;temporary
adc ZH,spmcrval ;for adding only carry
;reenable RWW section
ldi spmcrval,(1<<RWWSRE)+(1<<SPMEN)
rcall boot_spm
tst temp ;all bytes saved?
brne boot_block_write
ret
;
;
; # make real spm
boot_spm:
in temp2,SPMCR ;wait for previous spm complete
sbrc temp2,SPMEN
rjmp boot_spm
out SPMCR,spmcrval
spm
ret
;
;
; # decrypt
boot_decrypt:
ldi YL,low(WRITE_BUF) ;destination buffer
ldi YH,high(WRITE_BUF)
ldi XL,low(REC_BUF) ;source buffer
ldi XH,high(REC_BUF) ;it's 0...
ldi temp2,128 ;bytes count
ldi spmcrval,poczatek ;seed for xor
boot_decrypt1:
;calculate new address
subi XL,-mieszacz ;add XL,mieszacz!
andi XL,0x7F ;modulo 128
ld temp,X ;get byte
eor spmcrval,temp ;decrypt xor
st Y+,spmcrval ;store decrypted information
mov spmcrval,temp ;new seed (last value)
swap spmcrval
dec temp2
brne boot_decrypt1
ret
;
;
; ########## static data ###########
; #
boot_banner1:
.db "Bootloader v.1.3 (C) Marek Wodzinski",13,10
.db "Press B for options or wait 2s for normal boot.",13,10,0
boot_banner2:
.db "timed out... booting...",13,10,0
boot_banner3:
.db "Press P for firmware update (XMODEM) or any other key to continue booting",13,10,0