Skip to content

Commit

Permalink
elfloader/risc-v: add helper function boot_hart()
Browse files Browse the repository at this point in the history
Rework boot code flow to simplify it and avoid redundancy.

Signed-off-by: Axel Heider <[email protected]>
  • Loading branch information
axel-h committed Feb 7, 2022
1 parent a377563 commit e773b34
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 85 deletions.
170 changes: 86 additions & 84 deletions elfloader-tool/src/arch-riscv/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,54 +211,125 @@ static int is_core_ready(int core_id)
return (0 != __atomic_load_n(&core_ready[core_id], __ATOMIC_RELAXED));
}

static void set_and_wait_for_ready(word_t hart_id, word_t core_id)
#endif /* CONFIG_MAX_NUM_NODES > 1 */

static NORETURN void boot_hart(word_t hart_id, word_t core_id)
{
/* Acquire lock to update core ready array */
acquire_multicore_lock();
printf("Hart ID %"PRIu_word" core ID %"PRIu_word"\n", hart_id, core_id);
/* Caller must hold the multocore lock here. */

if (0 == core_id) {
printf("Enabling MMU and paging\n");
}
enable_virtual_memory();

#if CONFIG_MAX_NUM_NODES > 1
/* We are ready to hand over control to the kernel on this hart. Sync with
* all other harts before doing this.
*/
mark_core_ready(core_id);
release_multicore_lock();

/* Wait until all cores are go */
for (int i = 0; i < CONFIG_MAX_NUM_NODES; i++) {
while (!is_core_ready(i)) {
/* busy waiting loop */
}
}
#endif /* CONFIG_MAX_NUM_NODES > 1 */

if (0 == core_id) {
printf("Jumping to kernel-image entry point...\n\n");
}

/* The hand over interface is the same on all cores. We avoid making
* assumption how the parameters are used. The current seL4 kernel
* implementation only cares about the DTB on the primary core.
*/
((init_riscv_kernel_t)kernel_info.virt_entry)(
user_info.phys_region_start,
user_info.phys_region_end,
user_info.phys_virt_offset,
user_info.virt_entry,
(word_t)dtb,
dtb_size
#if CONFIG_MAX_NUM_NODES > 1
,
hart_id,
core_id
#endif /* CONFIG_MAX_NUM_NODES > 1 */
);

/* We should never get here. */
printf("ERROR: back in ELF-loader hart %"PRIu_word" (core ID %"PRIu_word")\n",
hart_id, core_id);
abort();
UNREACHABLE();
}

#if CONFIG_MAX_NUM_NODES > 1

NORETURN void secondary_hart_main(word_t hart_id, word_t core_id)
{
block_until_secondary_cores_go();
acquire_multicore_lock();
printf("started hart %"PRIu_word" (core id %"PRIu_word")\n",
hart_id, core_id);

if (core_id >= CONFIG_MAX_NUM_NODES) {
printf("ERROR: max number of harts exceeded (%d)\n",
(int)CONFIG_MAX_NUM_NODES);
abort();
UNREACHABLE();
}

boot_hart(hart_id, core_id);
UNREACHABLE();

}

#endif /* CONFIG_MAX_NUM_NODES > 1 */

static int run_elfloader(UNUSED word_t hart_id, void *bootloader_dtb)
void main(word_t hart_id, void *bootloader_dtb)
{
int ret;

/* Unpack ELF images into memory. */
/* Printing uses SBI, so there is no need to initialize any UART. */
printf("ELF-loader started on (HART %"PRIu_word") (NODES %d)\n",
hart_id, (unsigned int)CONFIG_MAX_NUM_NODES);

printf(" paddr=[%p..%p]\n", _text, _end - 1);

/* Load ELF images into memory. */
unsigned int num_apps = 0;
ret = load_images(&kernel_info, &user_info, 1, &num_apps,
bootloader_dtb, &dtb, &dtb_size);
if (0 != ret) {
printf("ERROR: image loading failed, code %d\n", ret);
return -1;
abort();
UNREACHABLE();
}

if (num_apps != 1) {
printf("ERROR: expected to load just 1 app, actually loaded %u apps\n",
num_apps);
return -1;
abort();
UNREACHABLE();
}

/* Setup the MMU tables. */
ret = map_kernel_window(&kernel_info);
if (0 != ret) {
printf("ERROR: could not map kernel window, code %d\n", ret);
return -1;
abort();
UNREACHABLE();
}

#if CONFIG_MAX_NUM_NODES > 1

/* Start all secondary cores. Since we take the multicore lock before that,
* the boot process on the primary core continues without concurrency issues
* until things can really run in parallel. Seems the main use case for this
* is printing nicely serialized boot messages,
*/
acquire_multicore_lock();
printf("Main entry hart_id:%"PRIu_word"\n", hart_id);
release_multicore_lock();
/* set global flag that secondary cores can run and bring them up. */
set_secondary_cores_go();
word_t i = 0;
while (i < CONFIG_MAX_NUM_NODES && hsm_exists) {
Expand All @@ -267,78 +338,9 @@ static int run_elfloader(UNUSED word_t hart_id, void *bootloader_dtb)
sbi_hart_start(i, secondary_harts, i);
}
}
set_and_wait_for_ready(hart_id, 0);
#endif /* CONFIG_MAX_NUM_NODES > 1 */

printf("Enabling MMU and paging\n");
enable_virtual_memory();

printf("Jumping to kernel-image entry point...\n\n");
((init_riscv_kernel_t)kernel_info.virt_entry)(user_info.phys_region_start,
user_info.phys_region_end,
user_info.phys_virt_offset,
user_info.virt_entry,
(word_t)dtb,
dtb_size
#if CONFIG_MAX_NUM_NODES > 1
,
hart_id,
0
#endif /* CONFIG_MAX_NUM_NODES > 1 */
);

/* We should never get here. */
printf("ERROR: Kernel returned back to the ELF Loader\n");
return -1;
}

#if CONFIG_MAX_NUM_NODES > 1

void secondary_entry(word_t hart_id, word_t core_id)
{
block_until_secondary_cores_go();
acquire_multicore_lock();
printf("Secondary entry hart_id:%"PRIu_word" core_id:%"PRIu_word"\n",
hart_id, core_id);
release_multicore_lock();
set_and_wait_for_ready(hart_id, core_id);
enable_virtual_memory();
/* If adding or modifying these parameters you will need to update
the registers in head.S */
((init_riscv_kernel_t)kernel_info.virt_entry)(user_info.phys_region_start,
user_info.phys_region_end,
user_info.phys_virt_offset,
user_info.virt_entry,
(word_t)dtb,
dtb_size,
hart_id,
core_id
);
}

#endif /* CONFIG_MAX_NUM_NODES > 1 */

void main(word_t hart_id, void *bootloader_dtb)
{
/* Printing uses SBI, so there is no need to initialize any UART. */
printf("ELF-loader started on (HART %"PRIu_word") (NODES %d)\n",
hart_id, (unsigned int)CONFIG_MAX_NUM_NODES);

printf(" paddr=[%p..%p]\n", _text, _end - 1);

/* Run the actual ELF loader, this is not expected to return unless there
* was an error.
*/
int ret = run_elfloader(hart_id, bootloader_dtb);
if (0 != ret) {
printf("ERROR: ELF-loader failed, code %d\n", ret);
/* There is nothing we can do to recover. */
abort();
UNREACHABLE();
}

/* We should never get here. */
printf("ERROR: ELF-loader didn't hand over control\n");
abort();
boot_hart(hart_id, 0);
UNREACHABLE();
}
3 changes: 2 additions & 1 deletion elfloader-tool/src/arch-riscv/crt0.S
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
.extern elfloader_stack
.extern hsm_exists
#if CONFIG_MAX_NUM_NODES > 1
.extern secondary_hart_main
.extern next_logical_core_id
#endif

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

0 comments on commit e773b34

Please sign in to comment.