@@ -211,54 +211,125 @@ static int is_core_ready(int core_id)
211211 return (0 != __atomic_load_n (& core_ready [core_id ], __ATOMIC_RELAXED ));
212212}
213213
214- static void set_and_wait_for_ready (word_t hart_id , word_t core_id )
214+ #endif /* CONFIG_MAX_NUM_NODES > 1 */
215+
216+ static NORETURN void boot_hart (word_t hart_id , word_t core_id )
215217{
216- /* Acquire lock to update core ready array */
217- acquire_multicore_lock ();
218- printf ("Hart ID %" PRIu_word " core ID %" PRIu_word "\n" , hart_id , core_id );
218+ /* Caller must hold the multocore lock here. */
219+
220+ if (0 == core_id ) {
221+ printf ("Enabling MMU and paging\n" );
222+ }
223+ enable_virtual_memory ();
224+
225+ #if CONFIG_MAX_NUM_NODES > 1
226+ /* We are ready to hand over control to the kernel on this hart. Sync with
227+ * all other harts before doing this.
228+ */
219229 mark_core_ready (core_id );
220230 release_multicore_lock ();
221-
222- /* Wait until all cores are go */
223231 for (int i = 0 ; i < CONFIG_MAX_NUM_NODES ; i ++ ) {
224232 while (!is_core_ready (i )) {
225233 /* busy waiting loop */
226234 }
227235 }
236+ #endif /* CONFIG_MAX_NUM_NODES > 1 */
237+
238+ if (0 == core_id ) {
239+ printf ("Jumping to kernel-image entry point...\n\n" );
240+ }
241+
242+ /* The hand over interface is the same on all cores. We avoid making
243+ * assumption how the parameters are used. The current seL4 kernel
244+ * implementation only cares about the DTB on the primary core.
245+ */
246+ ((init_riscv_kernel_t )kernel_info .virt_entry )(
247+ user_info .phys_region_start ,
248+ user_info .phys_region_end ,
249+ user_info .phys_virt_offset ,
250+ user_info .virt_entry ,
251+ (word_t )dtb ,
252+ dtb_size
253+ #if CONFIG_MAX_NUM_NODES > 1
254+ ,
255+ hart_id ,
256+ core_id
257+ #endif /* CONFIG_MAX_NUM_NODES > 1 */
258+ );
259+
260+ /* We should never get here. */
261+ printf ("ERROR: back in ELF-loader hart %" PRIu_word " (core ID %" PRIu_word ")\n" ,
262+ hart_id , core_id );
263+ abort ();
264+ UNREACHABLE ();
265+ }
266+
267+ #if CONFIG_MAX_NUM_NODES > 1
268+
269+ NORETURN void secondary_hart_main (word_t hart_id , word_t core_id )
270+ {
271+ block_until_secondary_cores_go ();
272+ acquire_multicore_lock ();
273+ printf ("started hart %" PRIu_word " (core id %" PRIu_word ")\n" ,
274+ hart_id , core_id );
275+
276+ if (core_id >= CONFIG_MAX_NUM_NODES ) {
277+ printf ("ERROR: max number of harts exceeded (%d)\n" ,
278+ (int )CONFIG_MAX_NUM_NODES );
279+ abort ();
280+ UNREACHABLE ();
281+ }
282+
283+ boot_hart (hart_id , core_id );
284+ UNREACHABLE ();
285+
228286}
229287
230288#endif /* CONFIG_MAX_NUM_NODES > 1 */
231289
232- static int run_elfloader ( UNUSED word_t hart_id , void * bootloader_dtb )
290+ void main ( word_t hart_id , void * bootloader_dtb )
233291{
234292 int ret ;
235293
236- /* Unpack ELF images into memory. */
294+ /* Printing uses SBI, so there is no need to initialize any UART. */
295+ printf ("ELF-loader started on (HART %" PRIu_word ") (NODES %d)\n" ,
296+ hart_id , (unsigned int )CONFIG_MAX_NUM_NODES );
297+
298+ printf (" paddr=[%p..%p]\n" , _text , _end - 1 );
299+
300+ /* Load ELF images into memory. */
237301 unsigned int num_apps = 0 ;
238302 ret = load_images (& kernel_info , & user_info , 1 , & num_apps ,
239303 bootloader_dtb , & dtb , & dtb_size );
240304 if (0 != ret ) {
241305 printf ("ERROR: image loading failed, code %d\n" , ret );
242- return -1 ;
306+ abort ();
307+ UNREACHABLE ();
243308 }
244309
245310 if (num_apps != 1 ) {
246311 printf ("ERROR: expected to load just 1 app, actually loaded %u apps\n" ,
247312 num_apps );
248- return -1 ;
313+ abort ();
314+ UNREACHABLE ();
249315 }
250316
317+ /* Setup the MMU tables. */
251318 ret = map_kernel_window (& kernel_info );
252319 if (0 != ret ) {
253320 printf ("ERROR: could not map kernel window, code %d\n" , ret );
254- return -1 ;
321+ abort ();
322+ UNREACHABLE ();
255323 }
256324
257325#if CONFIG_MAX_NUM_NODES > 1
326+
327+ /* Start all secondary cores. Since we take the multicore lock before that,
328+ * the boot process on the primary core continues without concurrency issues
329+ * until things can really run in parallel. Seems the main use case for this
330+ * is printing nicely serialized boot messages,
331+ */
258332 acquire_multicore_lock ();
259- printf ("Main entry hart_id:%" PRIu_word "\n" , hart_id );
260- release_multicore_lock ();
261- /* set global flag that secondary cores can run and bring them up. */
262333 set_secondary_cores_go ();
263334 word_t i = 0 ;
264335 while (i < CONFIG_MAX_NUM_NODES && hsm_exists ) {
@@ -267,78 +338,9 @@ static int run_elfloader(UNUSED word_t hart_id, void *bootloader_dtb)
267338 sbi_hart_start (i , secondary_harts , i );
268339 }
269340 }
270- set_and_wait_for_ready (hart_id , 0 );
271- #endif /* CONFIG_MAX_NUM_NODES > 1 */
272-
273- printf ("Enabling MMU and paging\n" );
274- enable_virtual_memory ();
275-
276- printf ("Jumping to kernel-image entry point...\n\n" );
277- ((init_riscv_kernel_t )kernel_info .virt_entry )(user_info .phys_region_start ,
278- user_info .phys_region_end ,
279- user_info .phys_virt_offset ,
280- user_info .virt_entry ,
281- (word_t )dtb ,
282- dtb_size
283- #if CONFIG_MAX_NUM_NODES > 1
284- ,
285- hart_id ,
286- 0
287- #endif /* CONFIG_MAX_NUM_NODES > 1 */
288- );
289-
290- /* We should never get here. */
291- printf ("ERROR: Kernel returned back to the ELF Loader\n" );
292- return -1 ;
293- }
294-
295- #if CONFIG_MAX_NUM_NODES > 1
296-
297- void secondary_entry (word_t hart_id , word_t core_id )
298- {
299- block_until_secondary_cores_go ();
300- acquire_multicore_lock ();
301- printf ("Secondary entry hart_id:%" PRIu_word " core_id:%" PRIu_word "\n" ,
302- hart_id , core_id );
303- release_multicore_lock ();
304- set_and_wait_for_ready (hart_id , core_id );
305- enable_virtual_memory ();
306- /* If adding or modifying these parameters you will need to update
307- the registers in head.S */
308- ((init_riscv_kernel_t )kernel_info .virt_entry )(user_info .phys_region_start ,
309- user_info .phys_region_end ,
310- user_info .phys_virt_offset ,
311- user_info .virt_entry ,
312- (word_t )dtb ,
313- dtb_size ,
314- hart_id ,
315- core_id
316- );
317- }
318341
319342#endif /* CONFIG_MAX_NUM_NODES > 1 */
320343
321- void main (word_t hart_id , void * bootloader_dtb )
322- {
323- /* Printing uses SBI, so there is no need to initialize any UART. */
324- printf ("ELF-loader started on (HART %" PRIu_word ") (NODES %d)\n" ,
325- hart_id , (unsigned int )CONFIG_MAX_NUM_NODES );
326-
327- printf (" paddr=[%p..%p]\n" , _text , _end - 1 );
328-
329- /* Run the actual ELF loader, this is not expected to return unless there
330- * was an error.
331- */
332- int ret = run_elfloader (hart_id , bootloader_dtb );
333- if (0 != ret ) {
334- printf ("ERROR: ELF-loader failed, code %d\n" , ret );
335- /* There is nothing we can do to recover. */
336- abort ();
337- UNREACHABLE ();
338- }
339-
340- /* We should never get here. */
341- printf ("ERROR: ELF-loader didn't hand over control\n" );
342- abort ();
344+ boot_hart (hart_id , 0 );
343345 UNREACHABLE ();
344346}
0 commit comments