Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
SMP
文件系统学习营
RT-Thread SMP核弹与树莓派碰撞(新)
发布于 2019-08-13 21:17:19 浏览:652
订阅该版
[tocm] 本帖主要描述raspi 3b上SMP实现,该实现主要基于现有raspi2 bsp代码基础上添加相关SMP支持,所需支持的功能主要包括: - 多核启动 - 多核通信 - 多核时钟 - 多核中断上下文切换 - 其它rt-thread SMP必要接口 ## 多核启动 rt-thread启动过程中,bootrom会让主核之外的其它核处于等待状态,直至主核将地址写入其它核对应的MAILBOX3寄存器中。 当前实现中,Raspi3b 多核从同一个入口:_reset 开始进行CPU核初始化。总体初始化流程如下: 1. 首先判断当前CPU是否为主核(默认CPU0为主核): ``` mrc p15, 0, r0, c0, c0, 5 //read cpu id ubfx r0, r0, #0, #2 cmp r0, #0 ``` 2. 如果非主核,进入非主核初始化操作(该操作在主核唤醒非主核后执行): ``` bl secondary_cpu_start b . ``` 3. 如果是主核,那么对各模式下栈指针,中断向量表,MMU,调度,组件等进行初始化,设置IPI中断处理函数,使能多核IPI通信中断,启动应用,并开始调度。除初始化MMU,设置IPI中断函数,使能IPI中断外,其它基本为原raspi2单核启动内容。需要注意的是:MMU数据内存类型需要带SHARED属性(以支持后续spin_lock功能实现): ``` #define SHARED (1<<16) /* shareable */ ``` 4. 主核在启动应用时会调用rt_hw_secondary_cpu_up接口,BSP需要将其它核启动地址写入对应核的MAILBOX3寄存器中唤醒其它核(当前启动地址和主核保持一致:`_reset)`: ```c void rt_hw_secondary_cpu_up(void) { rt_cpu_dcache_clean_flush(); rt_cpu_icache_flush(); int i; int retry,val; //for(i=1; i< RT_CPUS_NR; i++ ) for(i=RT_CPUS_NR-1; i>0; i-- ) { rt_kprintf("boot cpu:%d
", i); CORE_MAILBOX3_SET(i) = _reset; __SEV(); __DSB(); __ISB(); retry = 10; rt_thread_delay(RT_TICK_PER_SECOND/1000); do { val = CORE_MAILBOX3_CLEAR(i); if(val == 0){ rt_kprintf("start OK: CPU %d
",i); break; } rt_thread_delay(RT_TICK_PER_SECOND); retry --; if(retry <= 0) { rt_kprintf("can't start for CPU %d
",i); break; } }while(1); } __DSB(); __SEV(); } ``` 5. 其它核对各模式下栈指针,MMU,中断向量表进行设置,开启时钟,使能多核IPI通信中断,并开始调度。当前实现中MMU和中断向量表与主核保持一致: ```c rt_hw_timer_init(); rt_hw_vector_init(); COREMB_INTCTL(rt_hw_cpu_id()) = IPI_MAILBOX_INT_MASK; //使能IPI中断 rt_hw_spin_lock(&_cpus_lock); rt_system_scheduler_start(); ``` ## 多核通信 多核通信接口为:rt_hw_ipi_send。本实现中主要通过MAILBOX机制利用MAILBOX0寄存器来实现多核通信: ```c void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask) { __DSB(); if(cpu_mask&0x1) { IPI_MAILBOX_SET(0) = 1 << ipi_vector; } if(cpu_mask&0x2) { IPI_MAILBOX_SET(1) = 1 << ipi_vector; } if(cpu_mask&0x4) { IPI_MAILBOX_SET(2) = 1 << ipi_vector; } if(cpu_mask&0x8) { IPI_MAILBOX_SET(3) = 1 << ipi_vector; } __DSB(); } ``` 在Raspi 3b中,如果使能了对应MAILBOX中断,当MAILBOX寄存器值不为0时,可以触发对应核的IRQ中断。 当前多核通信主要实现多核调度功能:对于未绑定CPU的新线程开始执行或者未绑定CPU的线程从某个核调度出来时,会调用IPI接口通知其它核进行调度:该功能主要利用了MAILBOX中断机制,通过写其它核MAILBOX0寄存器触发对应核IRQ中断,进入MAILBOX中断处理,然后调用rt_scheduler_ipi_handler接口来触发对应核进行调度。 ```c #define IRQ_ARM_MAILBOX 65 ``` board.c: ```c rt_hw_ipi_handler_install(IRQ_ARM_MAILBOX, ipi_handler); rt_hw_interrupt_umask(IRQ_ARM_MAILBOX); ``` trap.c: ```c uint32_t int_source = CORE_IRQSOURCE(cpu_id); if (int_source & 0xf0) { /*it's a ipi interrupt*/ if (mailbox_data & 0x1){ /* clear mailbox */ IPI_MAILBOX_CLEAR(cpu_id) = mailbox_data; isr_func = isr_table[IRQ_ARM_MAILBOX].handler; #ifdef RT_USING_INTERRUPT_INFO isr_table[IRQ_ARM_MAILBOX].counter++; #endif if (isr_func) { param = isr_table[IRQ_ARM_MAILBOX].param; isr_func(IRQ_ARM_MAILBOX, param); } } else CORE_MAILBOX3_CLEAR(cpu_id) = mailbox_data; } ``` ## 多核时钟 多核时钟实现主要是对单核时钟实现rt_hw_timer_init以及rt_hw_timer_isr进行了修改,每个核都利用自身的时钟进行核和线程相关tick更新,进而实现时间片调度功能: ```c int rt_hw_timer_init() { #ifndef RT_USING_SMP /* timer_clock = apb_clock/(pre_divider + 1) */ ARM_TIMER_PREDIV = (250 - 1); ARM_TIMER_RELOAD = 0; ARM_TIMER_LOAD = 0; ARM_TIMER_IRQCLR = 0; ARM_TIMER_CTRL = 0; ARM_TIMER_RELOAD = 10000; ARM_TIMER_LOAD = 10000; /* 23-bit counter, enable interrupt, enable timer */ ARM_TIMER_CTRL = (1 << 1) | (1 << 5) | (1 << 7); #else __DSB(); cntfrq = read_cntfrq(); cntfrq = cntfrq/(RT_TICK_PER_SECOND*10); write_cntv_tval(cntfrq); enable_cntv(); __DSB(); CORETIMER_INTCTL(rt_hw_cpu_id()) = 0x8; #endif rt_hw_interrupt_install(IRQ_ARM_TIMER, rt_hw_timer_isr, RT_NULL, "tick"); rt_hw_interrupt_umask(IRQ_ARM_TIMER); return 0; } void rt_hw_timer_isr(int vector, void *parameter) { #ifndef RT_USING_SMP ARM_TIMER_IRQCLR = 0; #else mask_cntv(); __DSB(); write_cntv_tval(cntfrq); __DSB(); unmask_cntv(); __DSB(); #endif rt_tick_increase(); } ``` ## 多核中断上下文切换 该功能相关代码出自libcpu cortex-a代码,每个CPU核都需要单独维护自身的中断上下文、中断嵌套等信息。 ```c #ifdef RT_USING_SMP #define rt_interrupt_nest rt_cpu_self()->irq_nest #else extern volatile rt_uint8_t rt_interrupt_nest; #endif ``` ## 其它rt-thread SMP必要接口 - `rt_hw_local_irq_enable/rt_hw_local_irq_disable` 这两个接口实现中断使能和静止,在rasp3b中和单核中断使能/禁止无区别: ```c #ifdef RT_USING_SMP #define rt_hw_interrupt_disable rt_hw_local_irq_disable #define rt_hw_interrupt_enable rt_hw_local_irq_enable #endif ``` - `rt_hw_cpu_id` 该接口获取当前CPU的cpu id: ```c int rt_hw_cpu_id(void) { int cpu_id; __asm__ volatile ( "mrc p15, 0, %0, c0, c0, 5" :"=r"(cpu_id) ); cpu_id &= 0xf; return cpu_id; }; ``` - `rt_hw_spin_lock/rt_hw_spin_unlock` 这两个接口实现多核间互斥锁功能,主要利用ARM的ldrex/strex机制来实现: ``` __asm__ __volatile__( "1: ldrex %0, [%3]
" " add %1, %0, %4
" " strex %2, %1, [%3]
" " teq %2, #0
" " bne 1b" : "=&r" (lockval), "=&r" (newval), "=&r" (tmp) : "r" (&lock->slock), "I" (1 << 16) : "cc") ``` - `rt_hw_secondary_cpu_idle_exec` 该接口主要实现其它(非主)核idle线程执行的功能: ```c void rt_hw_secondary_cpu_idle_exec(void) { __WFE(); } ```
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
droid_angell
这家伙很懒,什么也没写!
文章
1
回答
1
被采纳
0
关注TA
发私信
相关文章
1
【文件系统学习】+DMY+任务1sample例程
2
【文件系统学习】skawu的文件系统跑起来了
3
【文件系统学习】bin5219在qemu-vexpress-a9 中运行一个.c
4
【文件系统学习】skawu之文件匹配学习
5
【文件系统学习】+海中陆地+成功运行文件系统,并运行文...
6
【文件系统学习】+清石+运行文件系统sample例程
7
【文件系统学习】+小燕+运行文件系统sample例程
8
【文件系统学习】+阿暖+运行文件系统 sample 例程
9
【文件系统学习】+小燕+一系列文件中找出指定文件
10
【文件系统学习】+小燕+文件数据替换
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
张世争
8
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
KunYi
6
个答案
1
次被采纳
本月文章贡献
程序员阿伟
6
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部