I'd love to be able to write a _start function in Swift and I believe this would be possible with naked functions. Unsafe, but possible.
I have managed to write a Swift _start that compiles equivalent to the hand-written version:
import KernelKit
public import EmbeddedArch
@c(_start) @section(".text.boot")
func _start() {
let reg = get_mpidr_el1()
// read cpu id, stop slave cores
if reg.Aff0 & 0x3 == 0 {
primary()
}
hang()
}
@_transparent
private func primary() {
let elr = get_CurrentEL()
switch elr.el {
case 2:
var hcr = HCR()
hcr.rw = true
set_hcr_el2(hcr)
zero_cntvoff_el2()
var spsr = SPSR()
// EL1h
spsr.m_4_0_ = 5
// mask DAIF
spsr.e = true
spsr.a = true
spsr.i = true
spsr.f = true
// set return level to EL1
set_spsr_el2(spsr)
set_elr_el2(jump_to_main)
isb_eret()
case 3:
var hcr = HCR()
hcr.rw = true
set_hcr_el2(hcr)
var scr = SCR_EL3()
// disable trapping of timer control registers
scr.rw = true
// next lower EL in aarch64
scr.st = true
set_scr_el3(scr)
var spsr = SPSR()
// EL1h
spsr.m_4_0_ = 5
// mask DAIF
spsr.e = true
spsr.a = true
spsr.i = true
spsr.f = true
// set return level to EL1
set_spsr_el3(spsr)
set_elr_el3(jump_to_main)
isb_eret()
default:
break
}
}
@c
private func jump_to_main() {
//FIXME: uses stp fp, lr, [sp, #-0x10]!
set_sp(ImageLayout.topOfStack)
RaspberryPi.main()
hang()
}
But sometimes there are instructions which unfortunately make this completely unviable.
stp fp, lr, [sp, #-0x10]!
mov fp, sp
// Set control registers, stack, exceptions, interrupts, etc.
ldp fp, lr, [sp], #0x10
// Jump to Kernel's main
Sometimes I can get rid of them via refactoring to ensure everything stays in registers.
Sometimes I can't and the very first instruction causes the processor to fall into a trap loop.
I'd like to suggest adding the equivalent of [[gnu::naked]] (also known as __attribute__((naked)) the legacy syntax) in C.
I'm imagining something like @naked in the same vein as @c and @objc.
It could also require the Embedded feature if people think it shouldn't be too easy to reach for in normal Swift code.
Thoughts?
Assembly for the curious
EntryPoint:
0000000000080000 mrs x8, mpidr_el1 ; DATA XREF=sub_8141c+96
0000000000080004 tst x8, #0x3
0000000000080008 b.ne loc_80024
000000000008000c mrs x8, currentel
0000000000080010 ubfx x8, x8, #0x2, #0x2
0000000000080014 cmp x8, #0x3
0000000000080018 b.eq loc_8002c
000000000008001c cmp x8, #0x2
0000000000080020 b.eq loc_80058
loc_80024:
0000000000080024 wfi ; CODE XREF=EntryPoint+8, EntryPoint+40
0000000000080028 b loc_80024
loc_8002c:
000000000008002c mov w8, #0x80000000 ; CODE XREF=EntryPoint+24
0000000000080030 mov w9, #0xc00
0000000000080034 mov w10, #0x3c5
0000000000080038 msr hcr_el2, x8
000000000008003c msr scr_el3, x9
0000000000080040 nop
0000000000080044 adr x8, #0x81e38
0000000000080048 msr spsr_el3, x10
000000000008004c msr elr_el3, x8
0000000000080050 isb
0000000000080054 eret
loc_80058:
0000000000080058 mov w8, #0x80000000 ; CODE XREF=EntryPoint+32
000000000008005c nop
0000000000080060 adr x9, #0x81e38
0000000000080064 mov w10, #0x3c5
0000000000080068 msr hcr_el2, x8
000000000008006c msr cntvoff_el2, xzr
0000000000080070 msr spsr_el2, x10
0000000000080074 msr elr_el2, x9
0000000000080078 isb
000000000008007c eret
sub_81e38:
0000000000081e38 stp fp, lr, [sp, #-0x10]! ; DATA XREF=EntryPoint+68, EntryPoint+96
0000000000081e3c mov fp, sp
0000000000081e40 nop
0000000000081e44 adr x8, #0xa33d0
0000000000081e48 mov sp, x8
0000000000081e4c bl sub_81784 ; sub_81784
loc_81e50:
0000000000081e50 wfi ; CODE XREF=sub_81e38+28
0000000000081e54 b loc_81e50