Skip to content

Commit e773b34

Browse files
committed
elfloader/risc-v: add helper function boot_hart()
Rework boot code flow to simplify it and avoid redundancy. Signed-off-by: Axel Heider <axelheider@gmx.de>
1 parent a377563 commit e773b34

File tree

2 files changed

+88
-85
lines changed

2 files changed

+88
-85
lines changed

elfloader-tool/src/arch-riscv/boot.c

Lines changed: 86 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

elfloader-tool/src/arch-riscv/crt0.S

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
.extern elfloader_stack
1313
.extern hsm_exists
1414
#if CONFIG_MAX_NUM_NODES > 1
15+
.extern secondary_hart_main
1516
.extern next_logical_core_id
1617
#endif
1718

@@ -152,7 +153,7 @@ secondary_harts:
152153
addi t0, a1, 1 /* increment by one because we need to set sp to the end */
153154
slli t0, t0, CONFIG_KERNEL_STACK_BITS /* t0 = t0 * BIT(CONFIG_KERNEL_STACK_BITS) */
154155
add sp, sp, t0
155-
la s0, secondary_entry
156+
la s0, secondary_hart_main
156157
jr s0
157158
#endif
158159
/* If we get here then the HSM extension exists and the current

0 commit comments

Comments
 (0)