提交 6d26a101 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

CPU核间通讯注解, 多个CPU之间是如何通讯的 ?

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    鸿蒙研究站 | http://weharmonyos.com (国内)
              | https://weharmony.github.io (国外)
    oschina | https://my.oschina.net/weharmony
    博客园 | https://www.cnblogs.com/weharmony/
    知乎 | https://www.zhihu.com/people/weharmonyos
    csdn | https://blog.csdn.net/kuangyufei
    51cto | https://harmonyos.51cto.com/column/34
    掘金 | https://juejin.cn/user/756888642000808
    公众号 | 鸿蒙研究站 (weharmonyos)
上级 587ee0f2
......@@ -125,18 +125,18 @@ UINT64 HalClockGetCycles(VOID)
cntpct = READ_TIMER_REG64(TIMER_REG_CT);
return cntpct;
}
/// 硬时钟初始化,创建硬中断
LITE_OS_SEC_TEXT_INIT VOID HalClockInit(VOID)
{
UINT32 ret;
g_sysClock = HalClockFreqRead();//读取时钟源频率
ret = LOS_HwiCreate(OS_TICK_INT_NUM, MIN_INTERRUPT_PRIORITY, 0, OsTickHandler, 0);
ret = LOS_HwiCreate(OS_TICK_INT_NUM, MIN_INTERRUPT_PRIORITY, 0, OsTickHandler, 0);//创建硬中断
if (ret != LOS_OK) {
PRINT_ERR("%s, %d create tick irq failed, ret:0x%x\n", __FUNCTION__, __LINE__, ret);
}
}
/// 开始硬时钟
LITE_OS_SEC_TEXT_INIT VOID HalClockStart(VOID)
{
UINT32 ret = OsSchedSetTickTimerType(64); /* 64 bit tick timer */
......@@ -146,7 +146,7 @@ LITE_OS_SEC_TEXT_INIT VOID HalClockStart(VOID)
HalIrqUnmask(OS_TICK_INT_NUM);
/* triggle the first tick */
/* triggle the first tick | 触发第一个节拍*/
TimerCtlWrite(0);
TimerTvalWrite(OS_CYCLE_PER_TICK);//递减计时器,使能tick中断,产生周期性tick
TimerCtlWrite(1);
......
......@@ -33,7 +33,7 @@
#include "los_hwi.h"
//节拍初始化
/// 节拍初始化
LITE_OS_SEC_TEXT_INIT UINT32 OsTickInit(UINT32 systemClock, UINT32 tickPerSecond)
{
if ((systemClock == 0) ||
......@@ -45,12 +45,12 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsTickInit(UINT32 systemClock, UINT32 tickPerSecond
return LOS_OK;
}
///启动节拍
/// 启动节拍
LITE_OS_SEC_TEXT_INIT VOID OsTickStart(VOID)
{
HalClockStart();//硬件时钟开始工作
}
///获取自系统启动以来的Cycle数
/// 获取自系统启动以来的Cycle数
LITE_OS_SEC_TEXT_MINOR VOID LOS_GetCpuCycle(UINT32 *highCnt, UINT32 *lowCnt)
{
UINT64 cycle = HalClockGetCycles();
......@@ -58,18 +58,18 @@ LITE_OS_SEC_TEXT_MINOR VOID LOS_GetCpuCycle(UINT32 *highCnt, UINT32 *lowCnt)
*highCnt = cycle >> 32; /* 32: offset 32 bits and retain high bits */
*lowCnt = cycle & 0xFFFFFFFFU;
}
///获取自系统启动以来的纳秒数
/// 获取自系统启动以来的纳秒数
LITE_OS_SEC_TEXT_MINOR UINT64 LOS_CurrNanosec(VOID)
{
UINT64 cycle = HalClockGetCycles();
return (cycle / g_sysClock) * OS_SYS_NS_PER_SECOND + (cycle % g_sysClock) * OS_SYS_NS_PER_SECOND / g_sysClock;
}
///以us为单位的忙等,但可以被优先级更高的任务抢占
/// 以us为单位的忙等,但可以被优先级更高的任务抢占
LITE_OS_SEC_TEXT_MINOR VOID LOS_Udelay(UINT32 usecs)
{
HalDelayUs(usecs);
}
///以ms为单位的忙等,但可以被优先级更高的任务抢占
/// 以ms为单位的忙等,但可以被优先级更高的任务抢占
LITE_OS_SEC_TEXT_MINOR VOID LOS_Mdelay(UINT32 msecs)
{
HalDelayUs(msecs * 1000); /* 1000 : 1ms = 1000us */
......
......@@ -68,12 +68,12 @@ VOID HalIrqSetAffinity(UINT32 vector, UINT32 cpuMask)
GIC_REG_8(GICD_ITARGETSR(offset) + index) = cpuMask;
}
#endif
/// 获取当前中断号
UINT32 HalCurIrqGet(VOID)
{
return g_curIrqNum;
}
/// 屏蔽中断
VOID HalIrqMask(UINT32 vector)
{
if ((vector > OS_USER_HWI_MAX) || (vector < OS_USER_HWI_MIN)) {
......@@ -82,7 +82,7 @@ VOID HalIrqMask(UINT32 vector)
GIC_REG_32(GICD_ICENABLER(vector / 32)) = 1U << (vector % 32);
}
/// 撤销中断屏蔽
VOID HalIrqUnmask(UINT32 vector)
{
if ((vector > OS_USER_HWI_MAX) || (vector < OS_USER_HWI_MIN)) {
......@@ -105,52 +105,52 @@ VOID HalIrqClear(UINT32 vector)
{
GIC_REG_32(GICC_EOIR) = vector;
}
/// 中断控制器与CPU之间的关系初始化
VOID HalIrqInitPercpu(VOID)
{
/* unmask interrupts */
GIC_REG_32(GICC_PMR) = 0xFF;
GIC_REG_32(GICC_PMR) = 0xFF;//写中断优先级屏蔽寄存器,0xFF代表开放所有中断
/* enable gic cpu interface */
GIC_REG_32(GICC_CTLR) = 1;
GIC_REG_32(GICC_CTLR) = 1;//使能GICC_CTLR寄存器,意思是打通控制器和CPU之间的链路
}
/// 中断控制器本身初始化
VOID HalIrqInit(VOID)
{
UINT32 i;
/* set externel interrupts to be level triggered, active low. */
/* set externel interrupts to be level triggered, active low. | 设置外部中断为电平触发,低电平有效。*/
for (i = 32; i < OS_HWI_MAX_NUM; i += 16) {
GIC_REG_32(GICD_ICFGR(i / 16)) = 0;
}
/* set externel interrupts to CPU 0 */
/* set externel interrupts to CPU 0 | 将外部中断设置为 CPU 0*/
for (i = 32; i < OS_HWI_MAX_NUM; i += 4) {
GIC_REG_32(GICD_ITARGETSR(i / 4)) = 0x01010101;
}
/* set priority on all interrupts */
/* set priority on all interrupts | 设置所有中断的优先级*/
for (i = 0; i < OS_HWI_MAX_NUM; i += 4) {
GIC_REG_32(GICD_IPRIORITYR(i / 4)) = GICD_INT_DEF_PRI_X4;
}
/* disable all interrupts. */
/* disable all interrupts. | 禁止所有中断*/
for (i = 0; i < OS_HWI_MAX_NUM; i += 32) {
GIC_REG_32(GICD_ICENABLER(i / 32)) = ~0;
}
HalIrqInitPercpu();
HalIrqInitPercpu();//启动和CPU之间关系
/* enable gic distributor control */
GIC_REG_32(GICD_CTLR) = 1;
GIC_REG_32(GICD_CTLR) = 1;//使能中断分发寄存器
#ifdef LOSCFG_KERNEL_SMP
/* register inter-processor interrupt */
(VOID)LOS_HwiCreate(LOS_MP_IPI_WAKEUP, 0xa0, 0, OsMpWakeHandler, 0);
(VOID)LOS_HwiCreate(LOS_MP_IPI_SCHEDULE, 0xa0, 0, OsMpScheduleHandler, 0);
(VOID)LOS_HwiCreate(LOS_MP_IPI_HALT, 0xa0, 0, OsMpHaltHandler, 0);
#ifdef LOSCFG_KERNEL_SMP //多核情况下会出现CPU核间的通讯
/* register inter-processor interrupt | 注册核间中断*/
(VOID)LOS_HwiCreate(LOS_MP_IPI_WAKEUP, 0xa0, 0, OsMpWakeHandler, 0);//由某CPU去唤醒其他CPU继续工作
(VOID)LOS_HwiCreate(LOS_MP_IPI_SCHEDULE, 0xa0, 0, OsMpScheduleHandler, 0);//由某CPU发起对其他CPU的调度
(VOID)LOS_HwiCreate(LOS_MP_IPI_HALT, 0xa0, 0, OsMpHaltHandler, 0);//由某CPU去暂停其他CPU的工作
#ifdef LOSCFG_KERNEL_SMP_CALL
(VOID)LOS_HwiCreate(LOS_MP_IPI_FUNC_CALL, 0xa0, 0, OsMpFuncCallHandler, 0);
(VOID)LOS_HwiCreate(LOS_MP_IPI_FUNC_CALL, 0xa0, 0, OsMpFuncCallHandler, 0);//触发回调函数
#endif
#endif
}
......
/*!
* @file gic_common.h
* @brief GIC(Generic Interrupt Controller)是ARM公司提供的一个通用的中断控制器
* @link http://weharmonyos.com/blog/44.html
* @verbatim
* @endverbatim
* @version
* @author weharmonyos.com
* @date 2021-11-18
*
* @history
*
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -36,7 +50,7 @@
#include "target_config.h"
#include "los_config.h"
/* gic arch revision */
/* gic arch revision | GIC架构版本*/
enum {
GICV1 = 1,
GICV2,
......@@ -46,15 +60,15 @@ enum {
#define GIC_REV_MASK 0xF0
#define GIC_REV_OFFSET 0x4
/// 前往 http://weharmonyos.com 下载 对应datasheet
#ifdef LOSCFG_ARCH_GIC_V2
#define GICC_CTLR (GICC_OFFSET + 0x00) /* CPU Interface Control Register */
#define GICC_PMR (GICC_OFFSET + 0x04) /* Interrupt Priority Mask Register */
#define GICC_CTLR (GICC_OFFSET + 0x00) /* CPU Interface Control Register | 控制寄存器,控制是否上报中断到处理器 */
#define GICC_PMR (GICC_OFFSET + 0x04) /* Interrupt Priority Mask Register | 中断优先级屏蔽寄存器*/
#define GICC_BPR (GICC_OFFSET + 0x08) /* Binary Point Register */
#define GICC_IAR (GICC_OFFSET + 0x0c) /* Interrupt Acknowledge Register */
#define GICC_EOIR (GICC_OFFSET + 0x10) /* End of Interrupt Register */
#define GICC_RPR (GICC_OFFSET + 0x14) /* Running Priority Register */
#define GICC_HPPIR (GICC_OFFSET + 0x18) /* Highest Priority Pending Interrupt Register */
#define GICC_IAR (GICC_OFFSET + 0x0c) /* Interrupt Acknowledge Register | 中断回应寄存器,处理器会读取此寄存器,用来获取上报的中断号*/
#define GICC_EOIR (GICC_OFFSET + 0x10) /* End of Interrupt Register | 处理器会写这个寄存器来告知CPU interface,此中断已经处理完成*/
#define GICC_RPR (GICC_OFFSET + 0x14) /* Running Priority Register | 运行优先级寄存器,此寄存器的值表示当前CPU interface的运行优先级*/
#define GICC_HPPIR (GICC_OFFSET + 0x18) /* Highest Priority Pending Interrupt Register | 当前pending状态的最高优先级中断号,当在允许中断抢占的情况下,如果此中断的优先级值大于运行优先级寄存器的值的话,就会发生中断抢占*/
#endif
#define GICD_CTLR (GICD_OFFSET + 0x000) /* Distributor Control Register */
......@@ -106,7 +120,7 @@ enum {
#ifndef LOSCFG_ARCH_INTERRUPT_PREEMPTION
#define MAX_BINARY_POINT_VALUE 7
#define PRIORITY_SHIFT 0
#define GIC_MAX_INTERRUPT_PREEMPTION_LEVEL 0U
#define GIC_MAX_INTERRUPT_PREEMPTION_LEVEL 0U ///< 中断最高优先级
#else
#define PRIORITY_SHIFT ((MAX_BINARY_POINT_VALUE + 1) % GIC_PRIORITY_OFFSET)
#define GIC_MAX_INTERRUPT_PREEMPTION_LEVEL ((UINT8)((GIC_PRIORITY_MASK + 1) >> PRIORITY_SHIFT))
......@@ -118,6 +132,6 @@ enum {
* The preemption level is up to 128, and the maximum value corresponding to the interrupt priority is 254 [7:1].
* If the GIC_MAX_INTERRUPT_PREEMPTION_LEVEL is 0, the minimum priority is 0xff.
*/
#define MIN_INTERRUPT_PRIORITY ((UINT8)((GIC_MAX_INTERRUPT_PREEMPTION_LEVEL - 1) << PRIORITY_SHIFT))
#define MIN_INTERRUPT_PRIORITY ((UINT8)((GIC_MAX_INTERRUPT_PREEMPTION_LEVEL - 1) << PRIORITY_SHIFT)) ///< 中断最低优先级
#endif
......@@ -74,7 +74,7 @@ typedef struct {
#ifdef LOSCFG_KERNEL_SMP
UINT32 excFlag; ///< cpu halt or exc flag | cpu 停止或 异常 标志
#ifdef LOSCFG_KERNEL_SMP_CALL
LOS_DL_LIST funcLink; ///< mp function call link | 回调函数
LOS_DL_LIST funcLink; ///< mp function call link | 回调函数链表,由 LOS_MP_IPI_FUNC_CALL 触发
#endif
#endif
} Percpu;
......
......@@ -62,8 +62,8 @@
/* column num of the output info of mem node */
#define OS_MEM_COLUMN_NUM 8
UINT8 *m_aucSysMem0 = NULL; //异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
UINT8 *m_aucSysMem1 = NULL; //系统动态内存池地址的起始地址
UINT8 *m_aucSysMem0 = NULL; ///< 异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
UINT8 *m_aucSysMem1 = NULL; ///< 系统动态内存池地址的起始地址
#ifdef LOSCFG_MEM_MUL_POOL
VOID *g_poolHead = NULL;
......
/*!
* @file los_mp.c
* @brief
* @link
* @verbatim
多CPU核的操作系统3种处理模式(SMP+AMP+BMP) 鸿蒙实现的是 SMP 的方式
非对称多处理(Asymmetric multiprocessing,AMP)每个CPU内核
运行一个独立的操作系统或同一操作系统的独立实例(instantiation)。
对称多处理(Symmetric multiprocessing,SMP)一个操作系统的实例
可以同时管理所有CPU内核,且应用并不绑定某一个内核。
混合多处理(Bound multiprocessing,BMP)一个操作系统的实例可以
同时管理所有CPU内核,但每个应用被锁定于某个指定的核心。
多核多线程处理器的中断
由 PIC(Programmable Interrupt Controller)统一控制。PIC 允许一个
硬件线程中断其他的硬件线程,这种方式被称为核间中断(Inter-Processor Interrupts,IPI)
SGI:软件触发中断(Software Generated Interrupt)。在arm处理器中,
SGI共有16个,硬件中断号分别为ID0~ID15。它通常用于多核间通讯。
* @endverbatim
* @version
* @author weharmonyos.com
* @date 2021-11-18
*
* @history
*
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -35,24 +64,7 @@
#include "los_sched_pri.h"
#include "los_swtmr.h"
#include "los_task_pri.h"
/*******************************************************
多CPU核的操作系统3种处理模式(SMP+AMP+BMP) 鸿蒙实现的是 SMP 的方式
非对称多处理(Asymmetric multiprocessing,AMP)每个CPU内核
运行一个独立的操作系统或同一操作系统的独立实例(instantiation)。
对称多处理(Symmetric multiprocessing,SMP)一个操作系统的实例
可以同时管理所有CPU内核,且应用并不绑定某一个内核。
混合多处理(Bound multiprocessing,BMP)一个操作系统的实例可以
同时管理所有CPU内核,但每个应用被锁定于某个指定的核心。
多核多线程处理器的中断
由 PIC(Programmable Interrupt Controller)统一控制。PIC 允许一个
硬件线程中断其他的硬件线程,这种方式被称为核间中断(Inter-Processor Interrupts,IPI)
SGI:软件触发中断(Software Generated Interrupt)。在arm处理器中,
SGI共有16个,硬件中断号分别为ID0~ID15。它通常用于多核间通讯。
********************************************************/
#ifdef LOSCFG_KERNEL_SMP
//给参数CPU发送调度信号
......@@ -118,6 +130,17 @@ VOID OsMpCollectTasks(VOID)
}
#ifdef LOSCFG_KERNEL_SMP_CALL
/*!
* @brief OsMpFuncCall
* 向指定CPU的funcLink上注册回调函数, 该怎么理解这个函数呢 ? 具体有什么用呢 ?
* \n 可由CPU a核向b核发起一个请求,让b核去执行某个函数, 这是否是分布式调度的底层实现基础 ?
* @param args
* @param func
* @param target
* @return
*
* @see
*/
VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
{
UINT32 index;
......@@ -127,13 +150,13 @@ VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
return;
}
if (!(target & OS_MP_CPU_ALL)) {
if (!(target & OS_MP_CPU_ALL)) {//检查目标CPU是否正确
return;
}
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {//遍历所有核
if (CPUID_TO_AFFI_MASK(index) & target) {
MpCallFunc *mpCallFunc = (MpCallFunc *)LOS_MemAlloc(m_aucSysMem0, sizeof(MpCallFunc));
MpCallFunc *mpCallFunc = (MpCallFunc *)LOS_MemAlloc(m_aucSysMem0, sizeof(MpCallFunc));//从内核空间 分配回调结构体
if (mpCallFunc == NULL) {
PRINT_ERR("smp func call malloc failed\n");
return;
......@@ -142,41 +165,48 @@ VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
mpCallFunc->args = args;
MP_CALL_LOCK(intSave);
LOS_ListAdd(&g_percpu[index].funcLink, &(mpCallFunc->node));
LOS_ListAdd(&g_percpu[index].funcLink, &(mpCallFunc->node));//将回调结构体挂入链表尾部
MP_CALL_UNLOCK(intSave);
}
}
HalIrqSendIpi(target, LOS_MP_IPI_FUNC_CALL);
HalIrqSendIpi(target, LOS_MP_IPI_FUNC_CALL);//向目标CPU发起核间中断
}
/*!
* @brief OsMpFuncCallHandler
* 回调向当前CPU注册过的函数
* @return
*
* @see
*/
VOID OsMpFuncCallHandler(VOID)
{
UINT32 intSave;
UINT32 cpuid = ArchCurrCpuid();
UINT32 cpuid = ArchCurrCpuid();//获取当前CPU
LOS_DL_LIST *list = NULL;
MpCallFunc *mpCallFunc = NULL;
MP_CALL_LOCK(intSave);
while (!LOS_ListEmpty(&g_percpu[cpuid].funcLink)) {
list = LOS_DL_LIST_FIRST(&g_percpu[cpuid].funcLink);
LOS_ListDelete(list);
while (!LOS_ListEmpty(&g_percpu[cpuid].funcLink)) {//遍历回调函数链表,知道为空
list = LOS_DL_LIST_FIRST(&g_percpu[cpuid].funcLink);//获取链表第一个数据
LOS_ListDelete(list);//将自己从链表上摘除
MP_CALL_UNLOCK(intSave);
mpCallFunc = LOS_DL_LIST_ENTRY(list, MpCallFunc, node);
mpCallFunc->func(mpCallFunc->args);
(VOID)LOS_MemFree(m_aucSysMem0, mpCallFunc);
mpCallFunc = LOS_DL_LIST_ENTRY(list, MpCallFunc, node);//获取回调函数
mpCallFunc->func(mpCallFunc->args);//获取参数并回调该函数
(VOID)LOS_MemFree(m_aucSysMem0, mpCallFunc);//释放回调函数内存
MP_CALL_LOCK(intSave);
}
MP_CALL_UNLOCK(intSave);
}
/// CPU层级的回调模块初始化
VOID OsMpFuncCallInit(VOID)
{
UINT32 index;
/* init funclink for each core */
/* init funclink for each core | 为每个CPU核整一个回调函数链表*/
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
LOS_ListInit(&g_percpu[index].funcLink);
LOS_ListInit(&g_percpu[index].funcLink);//链表初始化
}
}
#endif /* LOSCFG_KERNEL_SMP_CALL */
......
......@@ -45,12 +45,13 @@ extern "C" {
#define OS_MP_GC_PERIOD 100 /* ticks */
typedef enum {//核间中断
LOS_MP_IPI_WAKEUP, //唤醒CPU
LOS_MP_IPI_SCHEDULE,//调度CPU
LOS_MP_IPI_HALT, //停止CPU
/// 核间中断
typedef enum {
LOS_MP_IPI_WAKEUP, ///!< 唤醒CPU
LOS_MP_IPI_SCHEDULE, ///!< 调度CPU
LOS_MP_IPI_HALT, ///!< 停止CPU
#ifdef LOSCFG_KERNEL_SMP_CALL
LOS_MP_IPI_FUNC_CALL,
LOS_MP_IPI_FUNC_CALL, ///!< 触发CPU的回调函数,这些回调函数都挂到了cpu的链表上
#endif
} MP_IPI_TYPE;
......@@ -69,11 +70,11 @@ STATIC INLINE VOID LOS_MpSchedule(UINT32 target)
}
#endif
#ifdef LOSCFG_KERNEL_SMP_CALL
#ifdef LOSCFG_KERNEL_SMP_CALL //多核下的回调开关
typedef struct {
LOS_DL_LIST node;
SMP_FUNC_CALL func;
VOID *args;
LOS_DL_LIST node; ///< 链表节点,将挂到 g_percpu[cpuid]上
SMP_FUNC_CALL func; ///< 回调函数地址
VOID *args; ///< 回调函数的参数
} MpCallFunc;
/**
......
git add -A
git commit -m ' 对任务模块更详细的注解
git commit -m ' CPU核间通讯注解, 多个CPU之间是如何通讯的 ?
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
博客输出站点(国内):http://weharmonyos.com
博客输出站点(国外):https://weharmony.github.io
注解文件系统:https://gitee.com/weharmony/third_party_NuttX
注解协议栈:https://gitee.com/weharmony/third_party_lwip
注解编译子系统:https://gitee.com/weharmony/build_lite
鸿蒙研究站 | http://weharmonyos.com (国内)
| https://weharmony.github.io (国外)
oschina | https://my.oschina.net/weharmony
博客园 | https://www.cnblogs.com/weharmony/
知乎 | https://www.zhihu.com/people/weharmonyos
csdn | https://blog.csdn.net/kuangyufei
51cto | https://harmonyos.51cto.com/column/34
掘金 | https://juejin.cn/user/756888642000808
公众号 | 鸿蒙研究站 (weharmonyos)
'
git push origin master
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册