org 0xA0900000
code32
b start
DB "SIEMENS_BOOTCODE"
DW 0x00000003
DW 115200
DW 0, 0, 0, 0 ; тут, по-идее, boot key должен быть
start:
ADR SP, start
MRS R0, CPSR
BIC R0, R0, #0xFF ; &= ~11111111
ORR R0, R0, #0xC0 ; |= 11000000
MSR CPSR_c, R0
; adr SP, start
;
; mrs r1, cpsr ;/* R1 = CPSR */
; bic r1, r1, #0x1F ;/* R1 &= ~0x1F (11111) */
; orr r1, r1, #0xD3 ;/* R1 |= 0xD3 (11010011) */
; msr cpsr_cf, r1 ;/* CPSR = R1 */
; /* R0 = 0x50078 F B 7 3 */
; mov r0, 0x00050000
; add r0, r0, 0x78
; mcr p15, 0, r0, c1, c0 ; /* Sets MMU to (0101 0000 0000 0111 1000) */
; Enable write to einit-protected registers
mov r0, #0
bl set_einit
; Disable first watchdog
bl disable_fist_watchdog
; Disable write to einit-protected registers
mov r0, #1
bl set_einit
; Init watchdog
bl init_watchdog
; Установим скорость по умолчанию (115200)
mov r0, #1
bl uart_set_speed
; Сразу шлём ответ на пинг
b cmd_ping
main_loop:
; Читаем команду
bl uart_rx_byte
cmp r0, #0x51 ; 'Q' - Выход
beq cmd_quit
cmp r0, #0x45 ; 'E' - Приём и запуск бинарника
beq cmd_exec_bin
cmp r0, #0x2E ; '.' - keep alive
beq cmd_keep_alive
cmp r0, #0x41 ; 'A' - ping
beq cmd_ping
cmp r0, #0x53 ; 'S' - Установить скорость
beq cmd_set_speed
; bl serve_watchdog ; Сбросим ватчдог
b main_loop
; Fast power-off
cmd_quit:
bl switch_watchdog
bl switch_watchdog
q_l: b q_l
; Задать скорость
cmd_set_speed:
bl uart_rx_byte ; Принимаем номер скорости
bl uart_set_speed ; Задаём скорость
b main_loop ; Возвращаемся в main_loop
; Пинг
cmd_ping:
mov r0, #0x4f ; 'O'
bl uart_tx_byte ; Шлём ответ на пинг
b main_loop
; Keep alive
cmd_keep_alive:
bl serve_watchdog
b main_loop
; Приём и запуск бинарника
cmd_exec_bin:
; r0 - Текущий принятый байт
; r6 - вычисляемая чексумма бинарника (XOR)
; r7 - Размер бинарника
; r8 - Адрес следующего байта для записи в раме
; r9 - Адрес в раме, куда пишется наш бинарник
mov r0, 0xDE
mov r1, 0xA8000000
;add r1, r1, 0x00100000
strb r0, [r1]
;sub r1, r1, #1
;ldrb r0, [r1], #1
bl serve_watchdog
bl serve_watchdog
bl serve_watchdog
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
b cmd_quit
bl uart_rx_word ; Принимаем размер
mov r7, r0 ; Запишем размер в r2
mov r9, #0xA8000000 ; Адрес в раме, куда будем писать бинарник
mov r8, r9 ; Запишем начальный адрес байта для записи в r3
; Принимаем бинарник
bl serve_watchdog ; Watchdog
cmd_exec_bin_receiver_loop:
bl uart_rx_byte ; Принимаем байт
strb r0, [r8], #1 ; Запишем байт в память
SUB r8, r8, #1
bl serve_watchdog ; Watchdog
ldrb r0, [r8], #1
eor r6, r6, r0 ; Посчитаем контрольную сумму. r1 = r1 ^ r0
bl serve_watchdog ; Watchdog
subs r7, r7, #1 ; Отнимем 1 от размера
bne cmd_exec_bin_receiver_loop ; Продолжаем цикл до тех пор, пока не примем всё (size = 0)
bl serve_watchdog ; Watchdog
bl uart_rx_byte ; Примем контрольную сумму
cmp r0, r6 ; Проверим чексумму
beq cmd_exec_bin_success
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
mov r0, #0x45 ; 'E'
bl uart_tx_byte ; Отправим сообщение об ошибке
bl serve_watchdog ; Сбросим watchdog
b cmd_quit ; Вернёмся в main_loop
; Если успешно приняли и чексумма сошлась (o_O)
cmd_exec_bin_success:
mov r0, #0x4f ; 'O'
bl uart_tx_byte ; Отправим сообщение об успешной записи
bl serve_watchdog ; Сбросим watchdog
blx r9 ; Пробуем запустить принятый код..
mov r0, #0x4f ; 'O'
bl uart_tx_byte ; Отправим сообщение об успешной записи
; Сюда никогда не дойдёт.. наверное
b cmd_quit
; --------------------------------------------------
; Watchdog
; --------------------------------------------------
; void disable_fist_watchdog()
disable_fist_watchdog:
add r1, pc, WATCH_DOG-$-8
ldr r1, [r1]
ldr r0, [r1, #0x7C] ; SCU_ROMAMCR
bic r0, r0, #1
str r0, [r1, #0x7C] ; SCU_ROMAMCR
mov r0, #8
str r0, [r1, #0x28] ; SCU_ROMAMCR
bx lr
; -------------------------
; void set_einit(r0=on/off)
; uses r0, r1, r2, r3
set_einit:
add r3, pc, WATCH_DOG-$-8
ldr r3, [r3]
ldr r1, [r3, #0x24] ; SCU_WDTCON0
bic r1, r1, #0x0e
orr r1, r1, #0xf0
ldr r2, [r3, #0x28] ; SCU_WDTCON1
and r2, r2, #0x0c
orr r1, r1, r2
str r1, [r3, #0x24] ; SCU_WDTCON0
bic r1, r1, #0x0d
orr r1, r1, #2
orr r0, r0, r1
str r0, [r3, #0x24] ; SCU_WDTCON0
bx lr
; -------------------------
; void init_watchdog()
; uses r0, r1, r2, r3, r4
init_watchdog:
add r0, pc, WATCH_DOG-$-8
ldr r0, [r0]
LDR R0, [R0, #0x60] ; SCU_CHIPID
MOV R0, R0, LSR#8
AND R0, R0, #0xff
add r1, pc, PCL_62-$-8 ; PCL_62
ldr r1, [r1]
sub r2, r1, #0xcc
cmp r0, #0x14
bne iwd_1a
add r1, r1, #0x60
add r2, r2, #0x04
iwd_1a:
add r3, r2, #0x4
sub r4, r3, #0x0c
mov r12, r1
MOV R0, #1
STR R0, [R2]
MOV R0, #0x10
STR R0, [R3]
MOV R0, #0x500
STR R0, [R1]
MOV R0, #0x4000
ORR R0, R0, #0x510
STR R0, [R4]
add r1, pc, STM_4-$-8 ; STM_4
ldr r1, [r1]
LDR r11, [R1]
b switch_watchdog
; -------------------------
; void serve_watchdog()
; uses r0, r1, r2
serve_watchdog:
; read timer
add r2, pc, STM_4-$-8 ; STM_4
ldr r2, [r2]
ldr r0, [r2]
sub r1, r0, r11
cmp r1, #0x200
bcc swd_exit
; Save timer value
mov r11, r0
; ------------------------
; void switch_watchdog()
; uses r0, r1, r2
switch_watchdog:
LDR R0, [R12]
MOV R0, R0,LSL#22
LDR R2, [R12]
MVN R0, R0,LSR#31
BIC R2, R2, #0x200
AND R0, R0, #1
ORR R0, R2, R0,LSL#9
STR R0, [R12]
swd_exit:
BX LR
; --------------------------------------------------
; USART
; --------------------------------------------------
; set_usart_speed(r0)
; 0=57600, 1=115200, 2=230400, 3=460800, 4=614400, 5=921600, 6=1228800, 7=1600000
uart_set_speed:
adr r1, usart_speeds
ldr r1, [r1, r0, LSL#2]
mov r2, #0xf1000000 ; USART0_CLC
mov r0, r1, LSR#16
str r0, [r2, #0x14] ; USART0_BG
mov r0, r1, LSL#16
mov r0, r0, LSR#16
str r0, [r2, #0x18] ; USART0_FDV
bx lr
; -------------------------
; uart_tx_byte(r0=byte)
; uses r0, r1, r2
uart_tx_byte:
mov r2, #0xf1000000 ; USART0_CLC
ldr r1, [r2, #0x20] ; USART0_TXB
bic r1, r1, #0xff
orr r1, r0, r1
str r1, [r2, #0x20] ; USART0_TXB
tx_w:
ldr r1, [r2, #0x68] ; USART0_FCSTAT
ands r1, r1, #0x02
beq tx_w
ldr r1, [r2, #0x70] ; USART0_ICR
orr r1, r1, #2
str r1, [r2, #0x70]
b serve_watchdog
; -------------------------
; byte uart_rx_byte()
; uses r0, r1, r2
uart_rx_byte:
rx_loop:
mov r1, #0xf1000000
ldr r0, [r1, #0x68] ; USART0_FCSTAT
ands r0, r0, #0x04
beq rx_loop
rx_c:
ldr r0, [r1, #0x70] ; USART0_ICR
orr r0, r0, #4
str r0, [r1, #0x70]
ldr r0, [r1, #0x24] ; USART0_RXB
and r0, r0, #0xff
bx lr
; ------------------------
; word uart_rx_word()
; uses r0, r1, r2, r3, r4, r5
uart_rx_word:
mov r5, lr
bl uart_rx_byte
mov r4, r0, LSL#24
bl uart_rx_byte
orr r4, r4, r0, LSL#16
bl uart_rx_byte
orr r4, r4, r0, LSL#8
bl uart_rx_byte
orr r0, r4, r0
bx r5
; ----------------------------
usart_speeds:
DW 0x001901d8 ; 57600 / 0x1d8 = 122.033898 * 0x1a = 3172.881348
DW 0x000c01d8 ; 115200 / 0x1d8 = 244.067797 * 13 = 3172.881361
DW 0x000501b4 ; 230400 / 0x1b4 = 528.440367 * 0x6 = 3170.642202
DW 0x00000092 ; 460800 / 0x92 = 3156.164384
DW 0x000000c3 ; 614400 / 0xc3 = 3150.769231
DW 0x00000127 ; 921600 / 0x127 = 3124.067797
DW 0x0000018a ; 1228800 / 0x18a = 3118.781726
DW 0x00000000 ; 1600000 / 0x200 = 3125
DW 0x000001d0 ; 1500000 / 0x1d0 = 3232.758621
; -------------------------
WATCH_DOG DW 0xF4400000
PCL_62 DW 0xF4300118
STM_4 DW 0xF4B00020