Skip to content

Conversation

@Tm-C-mT
Copy link
Contributor

@Tm-C-mT Tm-C-mT commented Nov 3, 2025

拉取/合并请求描述:(PR description)

[

为什么提交这份PR (why to submit this PR)

目前qemu-virt64-riscv BSP不支持SMP模式下的运行,想让riscv64支持SMP架构。

这种修改方式是否合理?如不合理,修改后是否有可能被接受?

你的解决方案是什么 (what is your solution)

1、添加SMP架构下的必要接口,详见commit: 6c0a7d1

2、解决使能SMP后,hart为1时的启动挂死问题。添加rt_cpus_lock_status_restore与中断中的调度逻辑。详见commit: 7948f50

3、解决hart=2时的多核启动问题。hartid目前保存在了satp寄存器中,栈区地址根据hartid分配。并实现rt_hw_secondary_cpu_up与secondary_cpu_entry。详见commit: 402ec68

4、实现自旋锁及IPI处理逻辑。详见commit: c7cbe2e8386d29

5、qemu-virt64-riscv BSP根据config配置动态启动。详见commit: 7a770ce

请提供验证的bsp和config (provide the config and bsp)

  • BSP: qemu-virt64-riscv
  • .config: CONFIG_RT_USING_SMP=y、CONFIG_RT_CPUS_NR=2

]

当前拉取/合并请求的状态 Intent for your PR

必须选择一项 Choose one (Mandatory):

  • 本拉取/合并请求是一个草稿版本 This PR is for a code-review and is intended to get feedback
  • 本拉取/合并请求是一个成熟版本 This PR is mature, and ready to be integrated into the repo

代码质量 Code Quality:

我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:

  • 已经仔细查看过代码改动的对比 Already check the difference between PR and old code
  • 代码风格正确,包括缩进空格,命名及其他风格 Style guide is adhered to, including spacing, naming and other styles
  • 没有垃圾代码,代码尽量精简,不包含#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up
  • 所有变更均有原因及合理的,并且不会影响到其他软件组件代码或BSP All modifications are justified and not affect other components or BSP
  • 对难懂代码均提供对应的注释 I've commented appropriately where code is tricky
  • 代码是高质量的 Code in this PR is of high quality
  • 已经使用formatting 等源码格式化工具确保格式符合RT-Thread代码规范 This PR complies with RT-Thread code specification
  • 如果是新增bsp, 已经添加ci检查到.github/ALL_BSP_COMPILE.json 详细请参考链接BSP自查

…ng the SMP architecture.

Currently, the bsp: qemu-virt64-riscv does not support the SMP architecture,
and some necessary interfaces are not implemented.

Solution: Add the interface declarations to make the compilation pass.

Signed-off-by: Mengchen Teng <teng_mengchen@163.com>
…rchitecture.

Tests conducted on bsp: qemu-virt64-riscv. Currently, the command line cannot start normally.
This is because the SMP architecture requires scheduling information update operations;
secondly, it does not yet support context switching operations within interrupts.

Solution: In the two functions (rt_hw_context_switch_to and rt_hw_context_switch)
in context_gcc.S, add a call to rt_cpus_lock_status_restore to update the scheduler information.

For the second issue, if scheduling is triggered in an interrupt, pcpu->irq_switch_flag will
be set to 1; thus, rt_scheduler_do_irq_switch is called in interrupt_gcc.S to determine
whether to perform context switching.

Signed-off-by: Mengchen Teng <teng_mengchen@163.com>
…the spinlock.

The specific implementation of the spinlock is added in risc-v/virt64/interrupt.c.
Due to the need for atomic operations, a new file atomic_riscv.c (copied from the
common directory) is added under risc-v/common64.

Signed-off-by: Mengchen Teng <teng_mengchen@163.com>
…e SMP architecture.

Currently, it does not support operation with two or more cores.

Solution: Since the system runs in S-mode and does not support access to the
mhartid register, the hartid is currently stored in the satp register (this
register is not used when the bsp qemu-virt64-riscv runs RT-Thread). Additionally,
logic for storing boot_hartid and multi-core initialization logic for the sp
pointer have been added in startup_gcc.S. Logic for secondary core wake-up and
entry has been added in cpuport.c.

Signed-off-by: Mengchen Teng <teng_mengchen@163.com>
Add IPI handling logic based on the RISC-V architecture.We
handle IPI-related requests in software interrupts.
Up to this point, the RISC-V 64 architecture can support the 2-core
SMP mode and has passed the SMP Utest.

Signed-off-by: Mengchen Teng <teng_mengchen@163.com>
…figuration.

Add dynamic startup based on core configuration.

It should be noted that to pass the SMP Utest, the maximum
priority needs to be configured to 256.

Signed-off-by: Mengchen Teng <teng_mengchen@163.com>
@github-actions
Copy link

github-actions bot commented Nov 3, 2025

👋 感谢您对 RT-Thread 的贡献!Thank you for your contribution to RT-Thread!

为确保代码符合 RT-Thread 的编码规范,请在你的仓库中执行以下步骤运行代码格式化工作流(如果格式化CI运行失败)。
To ensure your code complies with RT-Thread's coding style, please run the code formatting workflow by following the steps below (If the formatting of CI fails to run).


🛠 操作步骤 | Steps

  1. 前往 Actions 页面 | Go to the Actions page
    点击进入工作流 → | Click to open workflow →

  2. 点击 Run workflow | Click Run workflow

  • 设置需排除的文件/目录(目录请以"/"结尾)
    Set files/directories to exclude (directories should end with "/")
  • 将目标分支设置为 \ Set the target branch to:qemu-virt64-riscv
  • 设置PR number为 \ Set the PR number to:10887
  1. 等待工作流完成 | Wait for the workflow to complete
    格式化后的代码将自动推送至你的分支。
    The formatted code will be automatically pushed to your branch.

完成后,提交将自动更新至 qemu-virt64-riscv 分支,关联的 Pull Request 也会同步更新。
Once completed, commits will be pushed to the qemu-virt64-riscv branch automatically, and the related Pull Request will be updated.

如有问题欢迎联系我们,再次感谢您的贡献!💐
If you have any questions, feel free to reach out. Thanks again for your contribution!

@github-actions github-actions bot added BSP Arch: RISC-V BSP related with risc-v libcpu labels Nov 3, 2025
@github-actions
Copy link

github-actions bot commented Nov 3, 2025

📌 Code Review Assignment

🏷️ Tag: libcpu_riscv

Reviewers: Yaochenger

Changed Files (Click to expand)
  • libcpu/risc-v/common64/atomic_riscv.c
  • libcpu/risc-v/common64/context_gcc.S
  • libcpu/risc-v/common64/cpuport.c
  • libcpu/risc-v/common64/cpuport.h
  • libcpu/risc-v/common64/encoding.h
  • libcpu/risc-v/common64/interrupt_gcc.S
  • libcpu/risc-v/common64/mmu.c
  • libcpu/risc-v/common64/mmu.h
  • libcpu/risc-v/common64/startup_gcc.S
  • libcpu/risc-v/common64/trap.c
  • libcpu/risc-v/virt64/interrupt.c
  • libcpu/risc-v/virt64/interrupt.h

📊 Current Review Status (Last Updated: 2025-11-19 10:26 CST)

  • Yaochenger Pending Review

📝 Review Instructions

  1. 维护者可以通过单击此处来刷新审查状态: 🔄 刷新状态
    Maintainers can refresh the review status by clicking here: 🔄 Refresh Status

  2. 确认审核通过后评论 LGTM/lgtm
    Comment LGTM/lgtm after confirming approval

  3. PR合并前需至少一位维护者确认
    PR must be confirmed by at least one maintainer before merging

ℹ️ 刷新CI状态操作需要具备仓库写入权限。
ℹ️ Refresh CI status operation requires repository Write permission.

@CLAassistant
Copy link

CLAassistant commented Nov 3, 2025

CLA assistant check
All committers have signed the CLA.

@kurisaW kurisaW closed this Nov 4, 2025
@kurisaW kurisaW reopened this Nov 4, 2025
@supperthomas supperthomas reopened this Nov 4, 2025
@unicornx
Copy link
Contributor

unicornx commented Nov 4, 2025

@Tm-C-mT you need sign CLA first.

@Rbb666 Rbb666 requested a review from Copilot November 5, 2025 01:17
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request adds SMP (Symmetric Multi-Processing) support for the RISC-V virt64 BSP. The implementation includes IPI (Inter-Processor Interrupt) handling, spinlock mechanisms, atomic operations, and multi-core initialization.

Key changes:

  • Adds IPI support with dedicated descriptor array and handler functions
  • Implements ticket-based spinlock for SMP synchronization
  • Adds atomic operation primitives using RISC-V AMO instructions
  • Implements secondary CPU initialization and boot-up logic
  • Updates trap handling to support per-CPU nested trap detection

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
libcpu/risc-v/virt64/interrupt.c Adds IPI infrastructure, spinlock implementation, and interrupt priority functions
libcpu/risc-v/common64/trap.c Updates for per-CPU trap nesting detection and IPI handler integration
libcpu/risc-v/common64/startup_gcc.S Adds multi-hart initialization and per-CPU stack setup
libcpu/risc-v/common64/interrupt_gcc.S Adds SMP-specific interrupt handling and local IRQ control
libcpu/risc-v/common64/cpuport.c Adds secondary CPU entry point and context switch for SMP
libcpu/risc-v/common64/context_gcc.S Adds CPU lock status restoration in context switches
libcpu/risc-v/common64/atomic_riscv.c Implements RISC-V atomic operations using AMO instructions
bsp/qemu-virt64-riscv/run.sh Updates to support dynamic SMP core configuration
bsp/qemu-virt64-riscv/qemu-dbg.sh Updates to support dynamic SMP core configuration
bsp/qemu-virt64-riscv/link_cpus.lds Defines the number of CPUs for linker
bsp/qemu-virt64-riscv/link.lds Updates stack allocation for multiple CPUs
bsp/qemu-virt64-riscv/driver/board.c Adds IPI initialization during board setup
bsp/qemu-virt64-riscv/SConstruct Extracts CPU count from rtconfig.h and writes to linker script


void rt_hw_spin_lock_init(rt_hw_spinlock_t *_lock)
{
union rt_hw_spinlock_t *lock = (void *)_lock;
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug/错误: The variable lock is declared but never used in the function. The next line directly uses _lock->slock, making this cast pointless. Either use the lock variable consistently or remove it.

中文: 声明的变量 lock 从未被使用。下一行直接使用了 _lock->slock,使得这个类型转换毫无意义。要么一致地使用 lock 变量,要么删除它。

Suggested change
union rt_hw_spinlock_t *lock = (void *)_lock;

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has been modified according to the content.


void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask)
{
int cpuid = cpu_mask & -cpu_mask; // get the lowest set bit
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug/错误: The logic to extract the CPU ID from cpu_mask is incorrect. The expression cpu_mask & -cpu_mask isolates the lowest set bit (e.g., 0b0100 becomes 0b0100), but this is not the bit position. For example, if cpu_mask = 4 (bit 2), the result is 4, not 2. This will cause an out-of-bounds array access. Use __builtin_ctz(cpu_mask) to get the bit position.

中文: 从 cpu_mask 提取 CPU ID 的逻辑不正确。表达式 cpu_mask & -cpu_mask 会分离出最低位的 1(例如 0b0100 变成 0b0100),但这不是位位置。例如,如果 cpu_mask = 4(第 2 位),结果是 4 而不是 2。这将导致数组越界访问。应使用 __builtin_ctz(cpu_mask) 获取位位置。

Suggested change
int cpuid = cpu_mask & -cpu_mask; // get the lowest set bit
int cpuid = __builtin_ctz(cpu_mask); // get the bit position of the lowest set bit

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has been modified according to the content.

return 0;
#else
/* Currently, the hartid is stored in the satp register. */
uint32_t hart_id;
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug/错误: Using uint32_t for hart_id is problematic on 64-bit systems. The satp CSR is 64-bit on RV64 systems. Using a 32-bit variable will truncate the value, potentially losing important bits. Change to rt_ubase_t or uint64_t.

中文: 使用 uint32_t 作为 hart_id 在 64 位系统上存在问题。在 RV64 系统上,satp CSR 是 64 位的。使用 32 位变量会截断值,可能丢失重要位。应改为 rt_ubase_tuint64_t

Suggested change
uint32_t hart_id;
rt_ubase_t hart_id;

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has been modified according to the content.

li t0, __STACKSIZE__
add sp, sp, t0
#else
csrw satp, a0 /* Currently, the hartid is stored in the satp register. */
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Best Practices/最佳实践: Storing the hartid in the satp register is unconventional and potentially problematic. The satp CSR is designed for address translation control and may be modified by MMU initialization code. Consider using a dedicated memory location or a different CSR (like sscratch temporarily, or a memory-mapped per-CPU data structure).

中文: 将 hartid 存储在 satp 寄存器中是非常规的,且可能存在问题。satp CSR 是为地址转换控制设计的,可能会被 MMU 初始化代码修改。建议使用专用的内存位置或不同的 CSR(如临时使用 sscratch,或使用内存映射的每 CPU 数据结构)。

Suggested change
csrw satp, a0 /* Currently, the hartid is stored in the satp register. */
/* Removed storing hartid in satp register; hartid is stored in boot_hartid memory location. */

Copilot uses AI. Check for mistakes.
Comment on lines 192 to 195
#ifdef RT_USING_SMP
/* ipi init */
rt_hw_ipi_init();
#endif /* RT_USING_SMP */
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintainability/可维护性: Redundant nested #ifdef RT_USING_SMP check inside secondary_cpu_entry() which is already within an #ifdef RT_USING_SMP block (line 159). Remove the inner conditional.

中文: 在 secondary_cpu_entry() 中存在冗余的 #ifdef RT_USING_SMP 嵌套检查,而该函数已经在 #ifdef RT_USING_SMP 块内(第 159 行)。应删除内部的条件编译。

Suggested change
#ifdef RT_USING_SMP
/* ipi init */
rt_hw_ipi_init();
#endif /* RT_USING_SMP */
/* ipi init */
rt_hw_ipi_init();

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has been modified according to the content.

int hart, ret;

/* translate kernel virtual _start to physical address */
entry_pa = (rt_uint64_t)&_start;//(rt_uint64_t)rt_kmem_v2p((void *)&_start);
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintainability/可维护性: Commented-out code should be removed. If virtual-to-physical translation is needed, either implement it or add a TODO comment explaining why it's not needed currently.

中文: 应删除被注释的代码。如果需要虚拟地址到物理地址的转换,要么实现它,要么添加 TODO 注释解释为何当前不需要。

Suggested change
entry_pa = (rt_uint64_t)&_start;//(rt_uint64_t)rt_kmem_v2p((void *)&_start);
entry_pa = (rt_uint64_t)&_start; /* TODO: Virtual-to-physical translation is not needed here because &_start is already a physical address on this platform. */

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has been modified according to the content.

@GuEe-GUI
Copy link
Contributor

GuEe-GUI commented Nov 5, 2025

hartid目前保存在satp寄存器,是asid部分么,如果是这样,smart版本会受影响

@Tm-C-mT
Copy link
Contributor Author

Tm-C-mT commented Nov 5, 2025

@Tm-C-mT you need sign CLA first.

The CLA has now been signed.

#include "encoding.h"
#include "riscv.h"
#include "interrupt.h"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#include "sbi.h"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已添加,一并修复了其他类似问题。

@Tm-C-mT
Copy link
Contributor Author

Tm-C-mT commented Nov 6, 2025

hartid目前保存在satp寄存器,是asid部分么,如果是这样,smart版本会受影响

目前保存在了satp的低位,也就是物理页号(PPN)字段,这应当也会影响smart版本?

那是否能进行宏隔离:#if defined(RT_USING_SMP) && !defined(RT_USING_SMART), 因为对于rtthread-smart版本还没有好的hartid存储方案。但是对于rtthread版本存储在satp里应当不会有影响?
那这份pr就变成了:Qemu-virt64-riscv BSP supports SMP architecture, only for the RT-Thread version. 对于smart版本后续另作修改,这样是否可以?

@GuEe-GUI
Copy link
Contributor

GuEe-GUI commented Nov 6, 2025

道理说 RT-Thread 版本也可能会开启 MMU,所以这么做可能还是会有问题,不过办法有的是。最主要的是 SMP 相关压力测试 OK 吗?

Fix issues with non-standard formatting

Signed-off-by: Mengchen Teng <teng_mengchen@163.com>
@Tm-C-mT
Copy link
Contributor Author

Tm-C-mT commented Nov 6, 2025

道理说 RT-Thread 版本也可能会开启 MMU,所以这么做可能还是会有问题,不过办法有的是。最主要的是 SMP 相关压力测试 OK 吗?

OK的,我应该怎么做以完成压力测试呢

@GuEe-GUI
Copy link
Contributor

GuEe-GUI commented Nov 6, 2025

应该是有 utest 的 SMP 测试,可以选上运行看看 SMP 是否稳定

@Rbb666 Rbb666 linked an issue Nov 9, 2025 that may be closed by this pull request
@Tm-C-mT
Copy link
Contributor Author

Tm-C-mT commented Nov 10, 2025

应该是有 utest 的 SMP 测试,可以选上运行看看 SMP 是否稳定

我看了一下src/utest/smp下的所有单元测试逻辑,也运行了这些单元测试,目前能顺利通过这些单元测试且符合预期。
smart版本还未验证,想请教一下hartid的存储应该怎么做呢

@GuEe-GUI
Copy link
Contributor

应该是有 utest 的 SMP 测试,可以选上运行看看 SMP 是否稳定

我看了一下src/utest/smp下的所有单元测试逻辑,也运行了这些单元测试,目前能顺利通过这些单元测试且符合预期。 smart版本还未验证,想请教一下hartid的存储应该怎么做呢

可以看看之前我这个 PR 的一种思路:#10320

…rt framework/environment

By defining a custom .percpu section and controlling the MMU mapping page table entries,
different cores can access different physical memory when accessing the same virtual
address (percpu_hartid), thereby storing their respective hartids. If the satp register
is not used, the hartid is stored in the satp register.

Signed-off-by: Mengchen Teng <teng_mengchen@163.com>
@Tm-C-mT
Copy link
Contributor Author

Tm-C-mT commented Nov 14, 2025

参考思路 #10320 ,现已支持SMART版本下的smp,详见commit: a59652d

@GuEe-GUI
Copy link
Contributor

测试通过就可以了

Fix issues with non-standard formatting

Signed-off-by: Mengchen Teng <teng_mengchen@163.com>
@Rbb666
Copy link
Member

Rbb666 commented Nov 17, 2025

参考思路 #10320 ,现已支持SMART版本下的smp,详见commit: a59652d

请问Smart也可以正常在SMP模式运行了吗?

@Rbb666
Copy link
Member

Rbb666 commented Nov 17, 2025

作者可以把smp的utest添加到ci看护中,这样出现问题通过CI也可以查看到:https://github.com/RT-Thread/rt-thread/blob/master/.github/workflows/utest_auto_run.yml


#ifndef RT_USING_SMP
//if enable RT_USING_SMP, it will finished by rt_cpus_lock_status_restore.
#ifdef RT_USING_SMART
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这块代码要格式化下,#ifdef前不需要有缩进


percpu_hartid = percpu_ptr;

// from virtual address to physical address
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

注释请统一采用/**/风格

@Rbb666
Copy link
Member

Rbb666 commented Nov 17, 2025

参考思路 #10320 ,现已支持SMART版本下的smp,详见commit: a59652d

请问Smart也可以正常在SMP模式运行了吗?

看起来Smart-SMP模式有问题:

https://github.com/RT-Thread/rt-thread/actions/runs/19415696503/job/55543632031?pr=10887

Copilot finished reviewing on behalf of Rbb666 November 17, 2025 02:52
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 23 comments.

Comment on lines +184 to +186
int cpuid = __builtin_ctz(cpu_mask); // get the bit position of the lowest set bit
ipi_vectors[cpuid] |= (uint8_t)ipi_vector;
sbi_send_ipi((const unsigned long *)&cpu_mask);
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Concurrency/并发问题]: Race condition in IPI vector handling. The ipi_vectors[cpuid] is modified without atomic operations or locking, which can cause lost IPI events in SMP environments.

English: The code reads cpu_mask, extracts cpuid, and then performs a non-atomic OR operation on ipi_vectors[cpuid]. If multiple CPUs send IPIs to the same target CPU simultaneously, updates can be lost due to the read-modify-write race.

中文:代码读取 cpu_mask,提取 cpuid,然后对 ipi_vectors[cpuid] 执行非原子的 OR 操作。如果多个 CPU 同时向同一目标 CPU 发送 IPI,由于读-改-写竞争,更新可能会丢失。

Suggestion/建议: Use atomic OR operation:

rt_hw_atomic_or((volatile rt_atomic_t *)&ipi_vectors[cpuid], (rt_atomic_t)ipi_vector);

Copilot uses AI. Check for mistakes.
Comment on lines 221 to 233

ipi_vector = ipi_vectors[rt_cpu_get_id()];
while (ipi_vector)
{
int bitpos = __builtin_ctz(ipi_vector);
ipi_vector &= ~(1 << bitpos);
if (bitpos < RT_MAX_IPI && ipi_desc[bitpos].handler != RT_NULL)
{
/* call the irq service routine */
ipi_desc[bitpos].handler(bitpos, ipi_desc[bitpos].param);
}
}
ipi_vectors[rt_cpu_get_id()] = 0;
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Concurrency/并发问题]: Race condition in IPI handler. The clearing of ipi_vectors[rt_cpu_get_id()] is not atomic and can race with rt_hw_ipi_send().

English: Line 233 clears the IPI vector without synchronization. If another CPU calls rt_hw_ipi_send() between lines 222-233, the new IPI could be lost when line 233 executes.

中文:第 233 行在没有同步的情况下清除 IPI 向量。如果另一个 CPU 在第 222-233 行之间调用 rt_hw_ipi_send(),当第 233 行执行时,新的 IPI 可能会丢失。

Suggestion/建议: Use atomic operations to clear only the handled bits:

rt_hw_atomic_and((volatile rt_atomic_t *)&ipi_vectors[rt_cpu_get_id()], 
                 (rt_atomic_t)~handled_vectors);

And track which vectors were handled in the loop.

Suggested change
ipi_vector = ipi_vectors[rt_cpu_get_id()];
while (ipi_vector)
{
int bitpos = __builtin_ctz(ipi_vector);
ipi_vector &= ~(1 << bitpos);
if (bitpos < RT_MAX_IPI && ipi_desc[bitpos].handler != RT_NULL)
{
/* call the irq service routine */
ipi_desc[bitpos].handler(bitpos, ipi_desc[bitpos].param);
}
}
ipi_vectors[rt_cpu_get_id()] = 0;
rt_uint32_t handled_vectors = 0;
ipi_vector = ipi_vectors[rt_cpu_get_id()];
while (ipi_vector)
{
int bitpos = __builtin_ctz(ipi_vector);
ipi_vector &= ~(1 << bitpos);
handled_vectors |= (1 << bitpos);
if (bitpos < RT_MAX_IPI && ipi_desc[bitpos].handler != RT_NULL)
{
/* call the irq service routine */
ipi_desc[bitpos].handler(bitpos, ipi_desc[bitpos].param);
}
}
rt_hw_atomic_and((volatile rt_atomic_t *)&ipi_vectors[rt_cpu_get_id()], (rt_atomic_t)~handled_vectors);

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@
RT_CPUS_NR = 8;
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] [Best Practices/最佳实践]: Hardcoded maximum CPUs value in linker script.

English: The value RT_CPUS_NR = 8 is hardcoded in the linker script but may not match the actual RT_CPUS_NR configured in rtconfig.h. While the SConstruct script generates this file, having a default of 8 could be misleading.

中文:值 RT_CPUS_NR = 8 在链接器脚本中硬编码,但可能与 rtconfig.h 中配置的实际 RT_CPUS_NR 不匹配。虽然 SConstruct 脚本生成此文件,但默认值为 8 可能会产生误导。

Suggestion/建议: Add a comment explaining that this file is auto-generated:

/* Auto-generated by SConstruct - do not edit manually */
RT_CPUS_NR = 8;

Or add this to a .gitignore to avoid committing the generated file.

Copilot uses AI. Check for mistakes.
Comment on lines 29 to 35
if grep -q "#define RT_USING_SMP" ./rtconfig.h 2>/dev/null; then
hart_num=$(grep "RT_CPUS_NR = [0-9]*;" ./link_cpus.lds | awk -F'[=;]' '{gsub(/ /, "", $2); print $2}')
if [ -z "$hart_num" ]; then
hart_num=1
fi
QEMU_CMD="$QEMU_CMD -smp $hart_num"
fi
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] [Best Practices/最佳实践]: Missing error handling in shell script.

English: The script uses grep to check for RT_USING_SMP but doesn't handle the case where rtconfig.h doesn't exist (though 2>/dev/null suppresses errors). The awk command could also fail silently if the pattern doesn't match.

中文:脚本使用 grep 检查 RT_USING_SMP,但不处理 rtconfig.h 不存在的情况(尽管 2>/dev/null 抑制了错误)。如果模式不匹配,awk 命令也可能静默失败。

Suggestion/建议: Add validation:

if grep -q "#define RT_USING_SMP" ./rtconfig.h 2>/dev/null; then
    hart_num=$(grep "RT_CPUS_NR = [0-9]*;" ./link_cpus.lds 2>/dev/null | awk -F'[=;]' '{gsub(/ /, "", $2); print $2}')
    if [ -z "$hart_num" ] || [ "$hart_num" -lt 1 ]; then
        echo "Warning: Invalid or missing RT_CPUS_NR, defaulting to 1"
        hart_num=1
    fi
    QEMU_CMD="$QEMU_CMD -smp $hart_num"
fi

Copilot uses AI. Check for mistakes.
Comment on lines 218 to 231
void rt_hw_percpu_hartid_init(rt_ubase_t *percpu_ptr, rt_ubase_t hartid)
{
rt_ubase_t *percpu_hartid_paddr;
rt_size_t percpu_size = (rt_size_t)((rt_ubase_t)&__percpu_end - (rt_ubase_t)&__percpu_start);

percpu_hartid = percpu_ptr;

// from virtual address to physical address
percpu_ptr = (rt_ubase_t *)((rt_ubase_t)percpu_ptr + (rt_ubase_t)rt_kmem_pvoff());
percpu_hartid_paddr = percpu_ptr;

/* Save to the real area */
*(rt_ubase_t *)((void *)percpu_hartid_paddr + hartid * percpu_size) = hartid;
}
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Security/安全问题]: Missing bounds check on hartid parameter.

English: The rt_hw_percpu_hartid_init() function (line 218) uses hartid to calculate an offset without validating that hartid < RT_CPUS_NR. An out-of-bounds hartid could cause buffer overflow when writing to the percpu area.

中文:rt_hw_percpu_hartid_init() 函数(第 218 行)使用 hartid 计算偏移量,而不验证 hartid < RT_CPUS_NR。越界的 hartid 可能会在写入 percpu 区域时导致缓冲区溢出。

Suggestion/建议: Add bounds checking:

void rt_hw_percpu_hartid_init(rt_ubase_t *percpu_ptr, rt_ubase_t hartid)
{
    RT_ASSERT(hartid < RT_CPUS_NR);
    rt_ubase_t *percpu_hartid_paddr;
    rt_size_t percpu_size = (rt_size_t)((rt_ubase_t)&__percpu_end - (rt_ubase_t)&__percpu_start);
    // ... rest of the function
}

Copilot uses AI. Check for mistakes.
Comment on lines 346 to 356
unsigned long get_free_page(void)
{
static unsigned long page_off = 0UL;

if (page_off < ARCH_PAGE_SIZE / sizeof(unsigned long))
{
return (unsigned long)(__init_page_array[page_off++].page);
}

return 0;
}
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] [Performance/性能问题]: Inefficient page allocation in early boot.

English: The get_free_page() function uses a simple linear allocator that doesn't track which pages are freed. Once page_off reaches the limit, no more pages can be allocated even if some were freed.

中文:get_free_page() 函数使用简单的线性分配器,不跟踪哪些页面被释放。一旦 page_off 达到限制,即使某些页面被释放,也无法再分配页面。

Suggestion/建议: Document that this is an early-stage allocator that doesn't support freeing, or implement a proper free list if pages need to be recycled during early boot.

Copilot uses AI. Check for mistakes.
Comment on lines 346 to 356
unsigned long get_free_page(void)
{
static unsigned long page_off = 0UL;

if (page_off < ARCH_PAGE_SIZE / sizeof(unsigned long))
{
return (unsigned long)(__init_page_array[page_off++].page);
}

return 0;
}
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Concurrency/并发问题]: Non-thread-safe static variable in early page allocator.

English: The static variable page_off in get_free_page() (line 348) is modified without synchronization. If multiple CPUs call this function during early boot, they could receive the same page, causing corruption.

中文:get_free_page() 中的静态变量 page_off(第 348 行)在没有同步的情况下被修改。如果多个 CPU 在早期启动期间调用此函数,它们可能会收到相同的页面,导致损坏。

Suggestion/建议: Use atomic increment or ensure this function is only called from the boot CPU during early initialization:

unsigned long get_free_page(void)
{
    static rt_atomic_t page_off = 0;
    
    rt_atomic_t old_off = rt_hw_atomic_add(&page_off, 1);
    if (old_off < ARCH_PAGE_SIZE / sizeof(unsigned long))
    {
        return (unsigned long)(__init_page_array[old_off].page);
    }
    return 0;
}

Copilot uses AI. Check for mistakes.
// if not enable MMU or pvoff==0, read hartid from satp register
rt_ubase_t hartid;
asm volatile("csrr %0, satp" : "=r"(hartid));
return hartid;
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Bug/错误]: Incorrect hartid retrieval in rt_hw_cpu_id() when MMU is disabled.

English: When rt_kmem_pvoff() == 0, the code reads the entire satp register value as hartid (line 90). However, satp is a 64-bit register where only the lower bits should contain the hartid. If the MODE field or other bits are set, this will return an incorrect hartid.

中文:当 rt_kmem_pvoff() == 0 时,代码将整个 satp 寄存器值读取为 hartid(第 90 行)。然而,satp 是一个 64 位寄存器,其中只有低位应该包含 hartid。如果设置了 MODE 字段或其他位,这将返回不正确的 hartid。

Suggestion/建议: Mask the hartid value appropriately:

// if not enable MMU or pvoff==0, read hartid from satp register
rt_ubase_t hartid;
asm volatile("csrr %0, satp" : "=r"(hartid));
return hartid & 0xFFFF;  // Assuming hartid fits in lower 16 bits

Or better yet, document the valid range and add an assertion.

Suggested change
return hartid;
/* Only lower 16 bits of satp are used for hartid; mask to avoid MODE/ASID/PPN bits */
return hartid & 0xFFFF;

Copilot uses AI. Check for mistakes.
Comment on lines 85 to 88
/*
* Pass the previous CPU lock status to
* rt_cpus_lock_status_restore for restoration
*/
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] [Documentation/文档问题]: Comment has trailing whitespace and unclear formatting.

English: The comment spans lines 86-88 with inconsistent indentation and trailing spaces, making it harder to read.

中文:注释跨越第 86-88 行,缩进不一致且有尾随空格,使其难以阅读。

Suggestion/建议: Format the comment consistently:

/* Pass the previous CPU lock status to 
 * rt_cpus_lock_status_restore for restoration */ 

Copilot uses AI. Check for mistakes.
Comment on lines +202 to +215
for (hart = 0; hart < RT_CPUS_NR; hart++)
{
if (hart == boot_hartid)
continue;

ret = sbi_hsm_hart_start((unsigned long)hart,
(unsigned long)entry_pa,
0UL);
if (ret)
{
rt_kprintf("sbi_hsm_hart_start failed for hart %d: %d\n", hart, ret);
}
}
}
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Bug/错误]: Missing validation in rt_hw_secondary_cpu_up().

English: The function iterates through all harts from 0 to RT_CPUS_NR but doesn't validate that the hart IDs are sequential or that boot_hartid < RT_CPUS_NR. If boot_hartid is a large value (e.g., on systems with non-contiguous hart IDs), the comparison on line 204 could be incorrect.

中文:该函数从 0 到 RT_CPUS_NR 迭代所有 hart,但不验证 hart ID 是否连续或 boot_hartid < RT_CPUS_NR。如果 boot_hartid 是一个大值(例如,在具有非连续 hart ID 的系统上),第 204 行的比较可能不正确。

Suggestion/建议: Add validation and document assumptions:

/* Assumes hart IDs are in range [0, RT_CPUS_NR) */
RT_ASSERT(boot_hartid < RT_CPUS_NR);

for (hart = 0; hart < RT_CPUS_NR; hart++)
{
    if (hart == boot_hartid)
        continue;
    // ... rest of loop
}

Copilot uses AI. Check for mistakes.
@Tm-C-mT
Copy link
Contributor Author

Tm-C-mT commented Nov 17, 2025

看起来Smart-SMP模式有问题:

好的,正在排查问题

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@Rbb666
Copy link
Member

Rbb666 commented Nov 19, 2025

我看CI通过了,请问是smart版本也OK了吗?@Tm-C-mT

@Rbb666
Copy link
Member

Rbb666 commented Nov 19, 2025

#10953

我在这个PR里面添加了Virt64的SMP-CI看护,等合并后可以看看效果

@Tm-C-mT
Copy link
Contributor Author

Tm-C-mT commented Nov 19, 2025

我看CI通过了,请问是smart版本也OK了吗?@Tm-C-mT

目前来看是OK了

Fix some potential concurrency issues and code standardization problems.
The .percpu section is only used when both ARCH_MM_MMU and RT_USING_SMP
are enabled. However, there is a certain amount of space waste since no
macro guard is added for it in the link script currently.
The physical memory of QEMU started in CI is 128MB, so RT_HW_PAGE_END is
modified from the original +256MB to +128MB.

Signed-off-by: Mengchen Teng <teng_mengchen@163.com>
@Rbb666
Copy link
Member

Rbb666 commented Nov 19, 2025

@Yaochenger 还请帮忙测试下

@MuChenger
Copy link
Contributor

请移除工程中的重复文件

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: RISC-V BSP related with risc-v BSP libcpu

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] RISC-V TODO LIST

9 participants