@@ -14,6 +14,10 @@ static mut BOOT_PT_L0: [A64PTE; 512] = [A64PTE::empty(); 512];
1414#[ unsafe( link_section = ".data.boot_page_table" ) ]
1515static mut BOOT_PT_L1 : [ A64PTE ; 512 ] = [ A64PTE :: empty ( ) ; 512 ] ;
1616
17+ const FLAG_LE : usize = 0b0 ;
18+ const FLAG_PAGE_SIZE_4K : usize = 0b10 ;
19+ const FLAG_ANY_MEM : usize = 0b1000 ;
20+
1721unsafe fn switch_to_el1 ( ) {
1822 SPSel . write ( SPSel :: SP :: ELx ) ;
1923 SP_EL0 . set ( 0 ) ;
@@ -47,11 +51,13 @@ unsafe fn switch_to_el1() {
4751 + SPSR_EL2 :: I :: Masked
4852 + SPSR_EL2 :: F :: Masked ,
4953 ) ;
50- core:: arch:: asm!(
51- "
52- mov x8, sp
53- msr sp_el1, x8"
54- ) ;
54+ unsafe {
55+ core:: arch:: asm!(
56+ "
57+ mov x8, sp
58+ msr sp_el1, x8"
59+ )
60+ } ;
5561 ELR_EL2 . set ( LR . get ( ) ) ;
5662 asm:: eret ( ) ;
5763 }
@@ -100,44 +106,75 @@ unsafe fn init_boot_page_table() {
100106 crate :: platform:: mem:: init_boot_page_table ( addr_of_mut ! ( BOOT_PT_L0 ) , addr_of_mut ! ( BOOT_PT_L1 ) ) ;
101107}
102108
103- /// The earliest entry point for the primary CPU.
109+ /// Kernel entry point with Linux image header.
110+ ///
111+ /// Some bootloaders require this header to be present at the beginning of the
112+ /// kernel image.
113+ ///
114+ /// Documentation: <https://docs.kernel.org/arch/arm64/booting.html>
104115#[ naked]
105116#[ unsafe( no_mangle) ]
106117#[ unsafe( link_section = ".text.boot" ) ]
107118unsafe extern "C" fn _start ( ) -> ! {
108- // PC = 0x8_0000
109- // X0 = dtb
110- core:: arch:: naked_asm!( "
111- mrs x19, mpidr_el1
112- and x19, x19, #0xffffff // get current CPU id
113- mov x20, x0 // save DTB pointer
114-
115- adrp x8, {boot_stack} // setup boot stack
116- add x8, x8, {boot_stack_size}
117- mov sp, x8
118-
119- bl {switch_to_el1} // switch to EL1
120- bl {enable_fp} // enable fp/neon
121- bl {init_boot_page_table}
122- bl {init_mmu} // setup MMU
123-
124- mov x8, {phys_virt_offset} // set SP to the high address
125- add sp, sp, x8
126-
127- mov x0, x19 // call rust_entry(cpu_id, dtb)
128- mov x1, x20
129- ldr x8, ={entry}
130- blr x8
131- b ." ,
132- switch_to_el1 = sym switch_to_el1,
133- init_boot_page_table = sym init_boot_page_table,
134- init_mmu = sym init_mmu,
135- enable_fp = sym enable_fp,
136- boot_stack = sym BOOT_STACK ,
137- boot_stack_size = const TASK_STACK_SIZE ,
138- phys_virt_offset = const PHYS_VIRT_OFFSET ,
139- entry = sym crate :: platform:: rust_entry,
140- )
119+ unsafe {
120+ // PC = bootloader load address
121+ // X0 = dtb
122+ core:: arch:: naked_asm!( "
123+ add x13, x18, #0x16 // 'MZ' magic
124+ b {entry} // Branch to kernel start, magic
125+
126+ .quad 0 // Image load offset from start of RAM, little-endian
127+ .quad _ekernel - _start // Effective size of kernel image, little-endian
128+ .quad {flags} // Kernel flags, little-endian
129+ .quad 0 // reserved
130+ .quad 0 // reserved
131+ .quad 0 // reserved
132+ .ascii \" ARM\\ x64\" // Magic number
133+ .long 0 // reserved (used for PE COFF offset)" ,
134+ flags = const FLAG_LE | FLAG_PAGE_SIZE_4K | FLAG_ANY_MEM ,
135+ entry = sym _start_primary,
136+ )
137+ }
138+ }
139+
140+ /// The earliest entry point for the primary CPU.
141+ #[ naked]
142+ #[ unsafe( link_section = ".text.boot" ) ]
143+ unsafe extern "C" fn _start_primary ( ) -> ! {
144+ unsafe {
145+ // X0 = dtb
146+ core:: arch:: naked_asm!( "
147+ mrs x19, mpidr_el1
148+ and x19, x19, #0xffffff // get current CPU id
149+ mov x20, x0 // save DTB pointer
150+
151+ adrp x8, {boot_stack} // setup boot stack
152+ add x8, x8, {boot_stack_size}
153+ mov sp, x8
154+
155+ bl {switch_to_el1} // switch to EL1
156+ bl {enable_fp} // enable fp/neon
157+ bl {init_boot_page_table}
158+ bl {init_mmu} // setup MMU
159+
160+ mov x8, {phys_virt_offset} // set SP to the high address
161+ add sp, sp, x8
162+
163+ mov x0, x19 // call rust_entry(cpu_id, dtb)
164+ mov x1, x20
165+ ldr x8, ={entry}
166+ blr x8
167+ b ." ,
168+ switch_to_el1 = sym switch_to_el1,
169+ init_boot_page_table = sym init_boot_page_table,
170+ init_mmu = sym init_mmu,
171+ enable_fp = sym enable_fp,
172+ boot_stack = sym BOOT_STACK ,
173+ boot_stack_size = const TASK_STACK_SIZE ,
174+ phys_virt_offset = const PHYS_VIRT_OFFSET ,
175+ entry = sym crate :: platform:: rust_entry,
176+ )
177+ }
141178}
142179
143180/// The earliest entry point for the secondary CPUs.
@@ -146,26 +183,28 @@ unsafe extern "C" fn _start() -> ! {
146183#[ unsafe( no_mangle) ]
147184#[ unsafe( link_section = ".text.boot" ) ]
148185unsafe extern "C" fn _start_secondary ( ) -> ! {
149- core:: arch:: naked_asm!( "
150- mrs x19, mpidr_el1
151- and x19, x19, #0xffffff // get current CPU id
152-
153- mov sp, x0
154- bl {switch_to_el1}
155- bl {init_mmu}
156- bl {enable_fp}
157-
158- mov x8, {phys_virt_offset} // set SP to the high address
159- add sp, sp, x8
160-
161- mov x0, x19 // call rust_entry_secondary(cpu_id)
162- ldr x8, ={entry}
163- blr x8
164- b ." ,
165- switch_to_el1 = sym switch_to_el1,
166- init_mmu = sym init_mmu,
167- enable_fp = sym enable_fp,
168- phys_virt_offset = const PHYS_VIRT_OFFSET ,
169- entry = sym crate :: platform:: rust_entry_secondary,
170- )
186+ unsafe {
187+ core:: arch:: naked_asm!( "
188+ mrs x19, mpidr_el1
189+ and x19, x19, #0xffffff // get current CPU id
190+
191+ mov sp, x0
192+ bl {switch_to_el1}
193+ bl {init_mmu}
194+ bl {enable_fp}
195+
196+ mov x8, {phys_virt_offset} // set SP to the high address
197+ add sp, sp, x8
198+
199+ mov x0, x19 // call rust_entry_secondary(cpu_id)
200+ ldr x8, ={entry}
201+ blr x8
202+ b ." ,
203+ switch_to_el1 = sym switch_to_el1,
204+ init_mmu = sym init_mmu,
205+ enable_fp = sym enable_fp,
206+ phys_virt_offset = const PHYS_VIRT_OFFSET ,
207+ entry = sym crate :: platform:: rust_entry_secondary,
208+ )
209+ }
171210}
0 commit comments