This is from linux source arch/arm64/kernel/head.S showing the kernel start. The code first calls preserve_boot_args
and next calls el2_setup
using bl
(branch and link). I showed the procedure preserve_boot_args
also.
SYM_CODE_START(primary_entry)
bl preserve_boot_args
bl el2_setup // Drop to EL1, w0=cpu_boot_mode
adrp x23, __PHYS_OFFSET
and x23, x23, MIN_KIMG_ALIGN - 1 // KASLR offset, defaults to 0
bl set_cpu_boot_mode_flag
bl __create_page_tables
/*
* The following calls CPU setup code, see arch/arm64/mm/proc.S for
* details.
* On return, the CPU will be ready for the MMU to be turned on and
* the TCR will have been set.
*/
bl __cpu_setup // initialise processor
b __primary_switch
SYM_CODE_END(primary_entry)
SYM_CODE_START_LOCAL(preserve_boot_args)
mov x21, x0 // x21=FDT
adr_l x0, boot_args // record the contents of
stp x21, x1, [x0] // x0 .. x3 at kernel entry
stp x2, x3, [x0, #16]
dmb sy // needed before dc ivac with
// MMU off
mov x1, #0x20 // 4 x 8 bytes
b __inval_dcache_area // tail call
SYM_CODE_END(preserve_boot_args)
As I understand, bl
is for calling procedure (after procedure, return to the address kept in the lr - link register, x30) and b
is just going to the labeled address not returning. But in procedure preserve_boot_args
above, just at the end, there is b __inval_dcache_area
instruction which just goes to __inval_dcache_area
without returning. Then how does it return to the original code (where bl el2_setup
is)? And how does a procedure ends itself? The definition of SYM_CODE_END is like this :
#define SYM_END(name, sym_type) \
.type name sym_type ASM_NL \
.size name, .-name
#endif
I can't understand how this code makes it return to the address in lr
. Shouldn't we do something like mv pc, lr
?