mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-25 01:43:30 +00:00
使用rust重写了apic的驱动 (#425)
* 使用rust重写了apic的驱动。 * 修正signal和调度器的部分加锁逻辑,增加回退策略。 * 把pcb的flags字段替换为无锁的 * 使用cargo管理apic的编译 * 删除makefile中指定PIC的变量 --------- Co-authored-by: Gou Ngai <ymd7823@outlook.com> Co-authored-by: 櫻井桃華 <89176634+TihayaKousaka@users.noreply.github.com>
This commit is contained in:
79
kernel/src/smp/cpu/c_adapter.rs
Normal file
79
kernel/src/smp/cpu/c_adapter.rs
Normal file
@ -0,0 +1,79 @@
|
||||
use alloc::vec::Vec;
|
||||
use hashbrown::HashSet;
|
||||
|
||||
use crate::{driver::acpi::acpi_manager, kdebug};
|
||||
|
||||
/// 这是一个临时的函数,用于在acpi、cpu模块被正式实现之前,让原本的C写的smp模块能正常运行
|
||||
///
|
||||
/// 请注意!这样写会使得smp模块与x86强耦合。正确的做法是:
|
||||
/// - 在sysfs中新增acpi firmware
|
||||
/// - 在acpi初始化的时候,初始化处理器拓扑信息
|
||||
/// - 初始化cpu模块(加入到sysfs,放置在/sys/devices/system下面)
|
||||
/// - smp模块从cpu模块处,获取到与架构无关的处理器拓扑信息
|
||||
/// - smp根据上述信息,初始化指定的处理器(这部分在arch下面实现)
|
||||
///
|
||||
/// 但是由于acpi、cpu模块还没有被正式实现,所以暂时使用这个函数来代替,接下来会按照上述步骤进行编写代码
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_smp_get_cpus(res: *mut X86CpuInfo) -> usize {
|
||||
let acpi_table = acpi_manager().tables().unwrap();
|
||||
let platform_info = acpi_table
|
||||
.platform_info()
|
||||
.expect("smp_get_cpu_topology(): failed to get platform info");
|
||||
let processor_info = platform_info
|
||||
.processor_info
|
||||
.expect("smp_get_cpu_topology(): failed to get processor info");
|
||||
|
||||
let mut id_set = HashSet::new();
|
||||
let mut cpu_info = processor_info
|
||||
.application_processors
|
||||
.iter()
|
||||
.filter_map(|ap| {
|
||||
if id_set.contains(&ap.local_apic_id) {
|
||||
return None;
|
||||
}
|
||||
let can_boot = ap.state == acpi::platform::ProcessorState::WaitingForSipi;
|
||||
if !can_boot {
|
||||
return None;
|
||||
}
|
||||
|
||||
id_set.insert(ap.local_apic_id);
|
||||
Some(X86CpuInfo::new(
|
||||
ap.local_apic_id,
|
||||
ap.processor_uid,
|
||||
can_boot,
|
||||
))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let bsp_info = X86CpuInfo::new(
|
||||
processor_info.boot_processor.local_apic_id,
|
||||
processor_info.boot_processor.processor_uid,
|
||||
processor_info.boot_processor.state == acpi::platform::ProcessorState::WaitingForSipi,
|
||||
);
|
||||
cpu_info.push(bsp_info);
|
||||
|
||||
cpu_info.sort_by(|a, b| a.apic_id.cmp(&b.apic_id));
|
||||
kdebug!("cpu_info: {:?}", cpu_info);
|
||||
|
||||
res.copy_from_nonoverlapping(cpu_info.as_ptr(), cpu_info.len());
|
||||
return cpu_info.len();
|
||||
}
|
||||
|
||||
/// 这个是临时用于传数据给c版本代码的结构体,请勿用作其他用途
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
struct X86CpuInfo {
|
||||
apic_id: u32,
|
||||
core_id: u32,
|
||||
can_boot: core::ffi::c_char,
|
||||
}
|
||||
|
||||
impl X86CpuInfo {
|
||||
fn new(apic_id: u32, core_id: u32, can_boot: bool) -> Self {
|
||||
Self {
|
||||
apic_id,
|
||||
core_id,
|
||||
can_boot: can_boot as core::ffi::c_char,
|
||||
}
|
||||
}
|
||||
}
|
1
kernel/src/smp/cpu/mod.rs
Normal file
1
kernel/src/smp/cpu/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
mod c_adapter;
|
@ -6,6 +6,7 @@ use crate::{
|
||||
|
||||
pub mod c_adapter;
|
||||
pub mod core;
|
||||
pub mod cpu;
|
||||
|
||||
pub fn kick_cpu(cpu_id: u32) -> Result<(), SystemError> {
|
||||
// todo: 增加对cpu_id的有效性检查
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include <common/cpu.h>
|
||||
#include <common/kprint.h>
|
||||
#include <common/spinlock.h>
|
||||
#include <driver/interrupt/apic/apic.h>
|
||||
#include <exception/gate.h>
|
||||
#include <mm/slab.h>
|
||||
#include <process/process.h>
|
||||
@ -24,7 +23,6 @@ static void __smp__flush_tlb_ipi_handler(uint64_t irq_num, uint64_t param, struc
|
||||
|
||||
static spinlock_t multi_core_starting_lock = {1}; // 多核启动锁
|
||||
|
||||
static struct acpi_Processor_Local_APIC_Structure_t *proc_local_apic_structs[MAX_SUPPORTED_PROCESSOR_NUM];
|
||||
static uint32_t total_processor_num = 0;
|
||||
static int current_starting_cpu = 0;
|
||||
|
||||
@ -32,12 +30,24 @@ int num_cpu_started = 1;
|
||||
|
||||
extern void smp_ap_start();
|
||||
extern uint64_t rs_get_idle_stack_top(uint32_t cpu_id);
|
||||
extern int rs_ipi_send_smp_startup(uint32_t apic_id);
|
||||
extern void rs_ipi_send_smp_init();
|
||||
extern void rs_init_syscall_64();
|
||||
|
||||
// 在head.S中定义的,APU启动时,要加载的页表
|
||||
// 由于内存管理模块初始化的时候,重置了页表,因此我们要把当前的页表传给APU
|
||||
extern uint64_t __APU_START_CR3;
|
||||
|
||||
struct X86CpuInfo
|
||||
{
|
||||
uint32_t apic_id;
|
||||
uint32_t core_id;
|
||||
char can_boot;
|
||||
};
|
||||
|
||||
extern uint64_t rs_smp_get_cpus(struct X86CpuInfo *res);
|
||||
static struct X86CpuInfo __cpu_info[MAX_SUPPORTED_PROCESSOR_NUM] = {0};
|
||||
|
||||
// kick cpu 功能所使用的中断向量号
|
||||
#define KICK_CPU_IRQ_NUM 0xc8
|
||||
#define FLUSH_TLB_IRQ_NUM 0xc9
|
||||
@ -48,16 +58,8 @@ void smp_init()
|
||||
// 设置多核启动时,要加载的页表
|
||||
__APU_START_CR3 = (uint64_t)get_CR3();
|
||||
|
||||
ul tmp_vaddr[MAX_SUPPORTED_PROCESSOR_NUM] = {0};
|
||||
|
||||
apic_get_ics(ACPI_ICS_TYPE_PROCESSOR_LOCAL_APIC, tmp_vaddr, &total_processor_num);
|
||||
|
||||
// kdebug("processor num=%d", total_processor_num);
|
||||
for (int i = 0; i < total_processor_num; ++i)
|
||||
{
|
||||
io_mfence();
|
||||
proc_local_apic_structs[i] = (struct acpi_Processor_Local_APIC_Structure_t *)(tmp_vaddr[i]);
|
||||
}
|
||||
total_processor_num = rs_smp_get_cpus(__cpu_info);
|
||||
|
||||
// 将引导程序复制到物理地址0x20000处
|
||||
memcpy((unsigned char *)phys_2_virt(0x20000), _apu_boot_start,
|
||||
@ -71,7 +73,7 @@ void smp_init()
|
||||
io_mfence();
|
||||
|
||||
io_mfence();
|
||||
ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, 0x00, ICR_INIT, ICR_ALL_EXCLUDE_Self, 0x00);
|
||||
rs_ipi_send_smp_init();
|
||||
|
||||
kdebug("total_processor_num=%d", total_processor_num);
|
||||
// 注册接收kick_cpu功能的处理函数。(向量号200)
|
||||
@ -85,41 +87,42 @@ void smp_init()
|
||||
io_mfence();
|
||||
|
||||
// 跳过BSP
|
||||
kdebug("[core %d] acpi processor UID=%d, APIC ID=%d, flags=%#010lx", i,
|
||||
proc_local_apic_structs[i]->ACPI_Processor_UID, proc_local_apic_structs[i]->local_apic_id,
|
||||
proc_local_apic_structs[i]->flags);
|
||||
if (proc_local_apic_structs[i]->local_apic_id == 0)
|
||||
kdebug("[core %d] acpi processor UID=%d, APIC ID=%d, can_boot=%d", i,
|
||||
__cpu_info[i].core_id, __cpu_info[i].apic_id,
|
||||
__cpu_info[i].can_boot);
|
||||
if (__cpu_info[i].apic_id == 0)
|
||||
{
|
||||
// --total_processor_num;
|
||||
continue;
|
||||
}
|
||||
if (!((proc_local_apic_structs[i]->flags & 0x1) || (proc_local_apic_structs[i]->flags & 0x2)))
|
||||
if (__cpu_info[i].can_boot == false)
|
||||
{
|
||||
// --total_processor_num;
|
||||
kdebug("processor %d cannot be enabled.", proc_local_apic_structs[i]->ACPI_Processor_UID);
|
||||
kdebug("processor %d cannot be enabled.", __cpu_info[i].core_id);
|
||||
continue;
|
||||
}
|
||||
++core_to_start;
|
||||
// continue;
|
||||
io_mfence();
|
||||
spin_lock(&multi_core_starting_lock);
|
||||
rs_preempt_enable(); // 由于ap处理器的pcb与bsp的不同,因此ap处理器放锁时,bsp的自旋锁持有计数不会发生改变,需要手动恢复preempt
|
||||
// count
|
||||
current_starting_cpu = proc_local_apic_structs[i]->ACPI_Processor_UID;
|
||||
spin_lock_no_preempt(&multi_core_starting_lock);
|
||||
current_starting_cpu = __cpu_info[i].apic_id;
|
||||
io_mfence();
|
||||
// 为每个AP处理器分配栈空间
|
||||
cpu_core_info[current_starting_cpu].stack_start = (uint64_t)rs_get_idle_stack_top(current_starting_cpu);
|
||||
|
||||
io_mfence();
|
||||
|
||||
// kdebug("core %d, to send start up", current_starting_cpu);
|
||||
kdebug("core %d, to send start up", __cpu_info[i].apic_id);
|
||||
// 连续发送两次start-up IPI
|
||||
ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, 0x20, ICR_Start_up, ICR_No_Shorthand,
|
||||
proc_local_apic_structs[i]->local_apic_id);
|
||||
|
||||
int r = rs_ipi_send_smp_startup(__cpu_info[i].apic_id);
|
||||
if(r){
|
||||
kerror("Failed to send startup ipi to cpu: %d", __cpu_info[i].apic_id);
|
||||
}
|
||||
io_mfence();
|
||||
rs_ipi_send_smp_startup(__cpu_info[i].apic_id);
|
||||
|
||||
io_mfence();
|
||||
ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, 0x20, ICR_Start_up, ICR_No_Shorthand,
|
||||
proc_local_apic_structs[i]->local_apic_id);
|
||||
// kdebug("core %d, send start up ok", current_starting_cpu);
|
||||
}
|
||||
io_mfence();
|
||||
while (num_cpu_started != (core_to_start + 1))
|
||||
@ -145,7 +148,7 @@ void smp_ap_start_stage2()
|
||||
++num_cpu_started;
|
||||
io_mfence();
|
||||
|
||||
apic_init_ap_core_local_apic();
|
||||
rs_apic_init_ap();
|
||||
|
||||
// ============ 为ap处理器初始化IDLE进程 =============
|
||||
|
||||
|
Reference in New Issue
Block a user