Opensbi初始化分析:设备初始化

本文详细分析了OpenSBI设备初始化过程,包括冷启动初始化、 hart初始化、中断控制器初始化、IPI初始化、TLB初始化和时钟初始化等。在冷启动中,涉及了 hart状态管理、安全启动、平台特定操作等。此外,文章还介绍了PMP配置、系统调用初始化以及域的最终设置。OpenSBI在初始化完成后,准备进入更高阶段的引导,如U-boot或Linux。
摘要由CSDN通过智能技术生成

设备初始化

紧接_start_warm,接下来将正式进入C阶段,调用到sbi_init,这里也会在终端出经典的Opensbi界面。

sbi_init函数

这个函数传入的参数为sbi_scratch结构体,也就是在前面的汇编阶段初始化的scratch空间,CSR_MSCRATCH存储着起始地址。

  • 首先需要判断启动模式
  • 随机选择满足条件的hart执行clodboot,其余的hart执行warmboot
    注意:Opensbi中的coolboot和warmboot不是传统意义上的冷启动和热启动,而是完全初始化和部分初始化的意思
/**
 * Initialize OpenSBI library for current HART and jump to next
 * booting stage.
 *
 * The function expects following:
 * 1. The 'mscratch' CSR is pointing to sbi_scratch of current HART
 * 2. Stack pointer (SP) is setup for current HART
 * 3. Interrupts are disabled in MSTATUS CSR
 * 4. All interrupts are disabled in MIE CSR
 *
 * @param scratch pointer to sbi_scratch of current HART
 */
void __noreturn sbi_init(struct sbi_scratch *scratch)
{
   
	bool next_mode_supported	= FALSE;
	bool coldboot			= FALSE;
	u32 hartid			= current_hartid();
	const struct sbi_platform *plat = sbi_platform_ptr(scratch);

	if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
	    sbi_platform_hart_invalid(plat, hartid))
		sbi_hart_hang();

	switch (scratch->next_mode) {
   
	case PRV_M:
		next_mode_supported = TRUE;
		break;
	case PRV_S:
		if (misa_extension('S'))
			next_mode_supported = TRUE;
		break;
	case PRV_U:
		if (misa_extension('U'))
			next_mode_supported = TRUE;
		break;
	default:
		sbi_hart_hang();
	}

	/*
	 * Only the HART supporting privilege mode specified in the
	 * scratch->next_mode should be allowed to become the coldboot
	 * HART because the coldboot HART will be directly jumping to
	 * the next booting stage.
	 *
	 * We use a lottery mechanism to select coldboot HART among
	 * HARTs which satisfy above condition.
	 */

	if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
		coldboot = TRUE;

	if (coldboot)
		init_coldboot(scratch, hartid);
	else
		init_warmboot(scratch, hartid);
}
coldinit,冷启动初始化

这个函数执行的是冷启动初始化:传入的参数为scratch结构体和hartid,主要做了下面几件事:

  • 初始化scratch空间
  • 初始化domain加载的镜像模块
  • hsm\paltfrom早期\hart\console\中断控制器\核间中断\初始化
  • MMU的tlb初始化
  • timer初始化
  • ecall初始化:注册系统调用
  • 发出软中断,唤醒其他warmboot的核
  • 准备下一级的bootloader
static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
   
	int rc;
	unsigned long *init_count;
	const struct sbi_platform *plat = sbi_platform_ptr(scratch);

	/* Note: This has to be first thing in coldboot init sequence */
	rc = sbi_scratch_init(scratch);
	if (rc)
		sbi_hart_hang();

	/* Note: This has to be second thing in coldboot init sequence */
	rc = sbi_domain_init(scratch, hartid);
	if (rc)
		sbi_hart_hang();

	init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
						     "INIT_COUNT");
	if (!init_count_offset)
		sbi_hart_hang();

	rc = sbi_hsm_init(scratch, hartid, TRUE);
	if (rc)
		sbi_hart_hang();

	rc = sbi_platform_early_init(plat, TRUE);
	if (rc)
		sbi_hart_hang();

	rc = sbi_hart_init(scratch, TRUE);
	if (rc)
		sbi_hart_hang();

	rc = sbi_console_init(scratch);
	if (rc)
		sbi_hart_hang();

	sbi_boot_print_banner(scratch);

	rc = sbi_platform_irqchip_init(plat, TRUE);
	if (rc) {
   
		sbi_printf("%s: platform irqchip init failed (error %d)\n",
			   __func__, rc);
		sbi_hart_hang();
	}

	rc = sbi_ipi_init(scratch, TRUE);
	if (rc) {
   
		sbi_printf("%s: ipi init failed (error %d)\n", __func__, rc);
		sbi_hart_hang();
	}

	rc = sbi_tlb_init(scratch, TRUE);
	if (rc) {
   
		sbi_printf("%s: tlb init failed (error %d)\n", __func__, rc);
		sbi_hart_hang();
	}

	rc = sbi_timer_init(scratch, TRUE);
	if (rc) {
   
		sbi_printf("%s: timer init failed (error %d)\n", __func__, rc);
		sbi_hart_hang();
	}

	rc = sbi_ecall_init();
	if (rc) {
   
		sbi_printf("%s: ecall init failed (error %d)\n", __func__, rc);
		sbi_hart_hang();
	}

	sbi_boot_print_general(scratch);

	/*
	 * Note: Finalize domains after HSM initialization so that we
	 * can startup non-root domains.
	 * Note: Finalize domains before HART PMP configuration so
	 * that we use correct domain for configuring PMP.
	 */
	rc = sbi_domain_finalize(scratch, hartid);
	if (rc) {
   
		sbi_printf("%s: domain finalize failed (error %d)\n",
			   __func__, rc);
		sbi_hart_hang();
	}

	sbi_boot_print_domains(scratch);

	rc = sbi_hart_pmp_configure(scratch);
	if (rc) {
   
		sbi_printf("%s: PMP configure failed (error %d)\n",
			   __func__, rc);
		sbi_hart_hang();
	}

	/*
	 * Note: Platform final initialization should be last so that
	 * it sees correct domain assignment and PMP configuration.
	 */
	rc = sbi_platform_final_init(plat, TRUE);
	if (rc) {
   
		sbi_printf("%s: platform final init failed (error %d)\n",
			   __func__, rc);
		sbi_hart_hang();
	}

	sbi_boot_print_hart(scratch, hartid);

	wake_coldboot_harts(scratch, hartid);

	init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
	(*init_count)++;

	sbi_hsm_prepare_next_jump(scratch, hartid);
	sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
			     scratch->next_mode, FALSE);
}

sbi_scratch_init函数

在这里插入图片描述

这个函数的主要作用:根据hart id和scratch结构的映射关系,初始化hartid_to_scratch_table这个数组。值得注意的是它记住了最后一个hart。

int sbi_scratch_init(struct sbi_scratch *scratch)
{
   
	u32 i;
	const struct sbi_platform *plat = sbi_platform_ptr(scratch);

	for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
   
		if (sbi_platform_hart_invalid(plat, i))
			continue;
		hartid_to_scratch_table[i] =
			((hartid2scratch)scratch->hartid_to_scratch)(i,
					sbi_platform_hart_index(plat, i));
		if (hartid_to_scratch_table[i])
			last_hartid_having_scratch = i;
	}

	return 0;
}
sbi_domain_init函数

这个函数本质是初始化动态加载的镜像模块,首先会初始化一个ROOT的内存域,最后会将root域注册到opensbi的西欧统中

int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
{
   
	u32 i;
	struct sbi_domain_memregion *memregs;
	const struct sbi_platform *plat = sbi_platform_ptr(scratch);

	/* Root domain firmware memory region */
	root_memregs[ROOT_FW_REGION].order = log2roundup(scratch->fw_size);
	root_memregs[ROOT_FW_REGION].base = scratch->fw_start &
				~((1UL << root_memregs[0].order) - 1UL);
	root_memregs[ROOT_FW_REGION].flags = 0;

	/* Root domain allow everything memory region */
	root_memregs[ROOT_ALL_REGION].order = __riscv_xlen;
	root_memregs[ROOT_ALL_REGION].base = 0
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值