多核唤醒简介
在开始多核BSP开发之前,我们需要思考两个问题:第一个是各个cpu核不管是主核还是从核是如何开始执行指令的,也就是如何唤醒它们让其开始工作;第二个问题是各个cpu核怎么知道它要执行的第一条指令在哪的。下面我们就结合全志R16平台来看看这两个问题。
我们先来看主核的情况,主核被唤醒工作肯定是整个系统被上电了,那么主核执行的第一条指令在哪呢?这个其实是看处理器厂商定义的,全志芯片上电首先会运行固化在芯片内部的BootROM程序,然后再去加载外部程序执行,通过全志R16手册,我们可以知道,BootROM是在0xffff0000起始的区域中,那么R16主核执行的第一条指令就是在这个位置了:
再来看从核的情况,从核是如何被唤醒的呢?这个其实也是取决于处理器厂商的设计,全志R16的从核唤醒之前需要主核对从核和Cache进行复位并使能供电,最后取消复位状态从核就开始运行了。从核运行的第一条指令所在的内存地址需要事先设置在某个寄存器中,这样从核被唤醒后才能知道从哪开始拿指令执行。从核唤醒的步骤在某些厂商的芯片手册中会说明的很清楚,某些则没有说明,只能去参考厂商提供的Linux源码。在SylixOS中,从核与主核都是从内核镜像加载地址处运行:
/* * Start up a secondary CPU core. */ VOID cpuEnable (UINT8 ucCoreNum) { UINT32 uiValue; /* * Exit if the requested core is not available. */ if (ucCoreNum == 0 || ucCoreNum >= MAX_CORE_COUNT) { return; } writel(BSP_CFG_RAM_BASE, R_CPUCFG_BASE + CPUCFG_PRIVATE0_REG); /* Set CPU boot address */ writel(0, R_CPUCFG_BASE + CPUCFG_CPU_RST_CTRL_REG(ucCoreNum)); /* Assert the CPU core in reset*/ uiValue = readl(R_CPUCFG_BASE + CPUCFG_GEN_CTRL_REG); writel(uiValue & ~BIT(ucCoreNum), R_CPUCFG_BASE + CPUCFG_GEN_CTRL_REG); /* Assert the L1 cache in reset*/ uiValue = readl(R_PRCM_BASE + PRCM_CPU_PWROFF_REG); writel(uiValue & ~BIT(ucCoreNum), R_PRCM_BASE + PRCM_CPU_PWROFF_REG); /* Clear CPU power-off gating */ usleep(10); writel(3, R_CPUCFG_BASE + CPUCFG_CPU_RST_CTRL_REG(ucCoreNum)); /* Deassert the CPU core reset */ }
上面的代码移植自Linux,我们可以看出来从核唤醒步骤还是比较简单的,很容易理解。
评论