sunxi-tools/thunks/fel-to-spl-thunk.S
2023-10-20 19:54:56 +08:00

163 lines
4.6 KiB
ArmAsm

/*
* Copyright © 2015 Siarhei Siamashka <siarhei.siamashka@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
.arm
BUF1 .req r0
BUF2 .req r1
TMP1 .req r2
TMP2 .req r3
SWAPTBL .req r4
FULLSIZE .req r5
BUFSIZE .req r6
CHECKSUM .req r7
SPL_ADDR .req r8
entry_point:
b setup_stack
stack_begin:
.space 32, 0xff
stack_end:
nop
/* A function, which walks the table and swaps all buffers */
swap_all_buffers:
adr SWAPTBL, appended_data + 4
swap_next_buffer:
ldr BUF1, [SWAPTBL], #4
ldr BUF2, [SWAPTBL], #4
ldr BUFSIZE, [SWAPTBL], #4
cmp BUFSIZE, #0
bxeq lr
swap_next_word:
ldr TMP1, [BUF1]
ldr TMP2, [BUF2]
subs BUFSIZE, BUFSIZE, #4
str TMP1, [BUF2], #4
str TMP2, [BUF1], #4
bne swap_next_word
b swap_next_buffer
setup_stack: /* Save the original SP, LR and CPSR to stack */
ldr SPL_ADDR, appended_data
adr BUF1, stack_end
str sp, [BUF1, #-4]!
mov sp, BUF1
mrs TMP1, cpsr
push {TMP1, lr}
/* Disable IRQ and FIQ */
orr TMP1, #0xc0
msr cpsr_c, TMP1
/* Check if the instructions or data cache is enabled */
mrc p15, 0, TMP1, c1, c0, 0
tst TMP1, #(1 << 2)
tsteq TMP1, #(1 << 12)
bne cache_is_unsupported
bl swap_all_buffers
verify_checksum:
ldr CHECKSUM, checksum_seed
mov BUF1, SPL_ADDR
ldr FULLSIZE, [BUF1, #16]
check_next_word:
ldr TMP1, [BUF1], #4
subs FULLSIZE, FULLSIZE, #4
add CHECKSUM, CHECKSUM, TMP1
bne check_next_word
ldr TMP1, [SPL_ADDR, #12]
subs CHECKSUM, CHECKSUM, TMP1, lsl #1
bne checksum_is_bad
/* Change 'eGON.BT0' -> 'eGON.FEL' */
ldr TMP1, egon_fel_str
str TMP1, [SPL_ADDR, #8]
/*
* Call the SPL code, but before that make sure the CPU sees the
* recently uploaded code. This requires a DSB and ISB.
* The "dsb" and "isb" *instructions* are not available in ARMv5TE,
* but at least for DSB we can use the CP15 register encoding. This
* works for ARMv7 and v8 as well, because we have checked our SCTLR
* before (in fel.c), so we know that CP15BEN is set.
* The ARM926 core does not implement ISB, instead the TRM recommends
* just a branch to achieve the same "flush the pipeline" effect.
* As just this is not sufficient for later cores, check the MIDR
* register, and do the DSB only for ARMv6 or later.
* The input register for the CP15 instruction is ignored.
*/
mcr p15, 0, TMP1, c7, c10, 4 /* CP15DSB */
mrc p15, 0, TMP1, c0, c0, 0 /* read MIDR */
and TMP1, TMP1, #(0xf << 16) /* architecture */
cmp TMP1, #(0x6 << 16) /* ARMv5TEJ */
mcrgt p15, 0, TMP1, c7, c5, 4 /* CP15ISB, if > ARMv5TEJ */
blx SPL_ADDR
/* Return back to FEL */
b return_to_fel
cache_is_unsupported:
/* Bail out if cache is enabled and change 'eGON.BT0' -> 'eGON.???' */
ldr TMP1, cache_enabled_str
str TMP1, [SPL_ADDR, #8]
b return_to_fel_noswap
checksum_is_bad:
/* The checksum test failed, so change 'eGON.BT0' -> 'eGON.BAD' */
ldr TMP1, checksum_failed_str
str TMP1, [SPL_ADDR, #8]
return_to_fel:
bl swap_all_buffers
return_to_fel_noswap:
pop {TMP1, lr}
msr cpsr_c, TMP1 /* Restore the original CPSR */
ldr sp, [sp]
bx lr
checksum_seed:
.word 0x5f0a6c39
egon_fel_str:
.ascii ".FEL"
cache_enabled_str:
.ascii ".???"
checksum_failed_str:
.ascii ".BAD"
appended_data:
/*
* The appended data uses the following format:
*
* struct {
* uint32_t spl_addr;
* sram_swap_buffers swaptbl[];
* };
*
* More details about the 'spl_addr' variable and the 'sram_swap_buffers'
* struct can be found in the 'fel.c' source file.
*/