使用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:
LoGin
2023-11-07 20:32:06 +08:00
committed by GitHub
parent 4935c74f32
commit 70a4e5550a
63 changed files with 2638 additions and 1367 deletions

View 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,
}
}
}

View File

@ -0,0 +1 @@
mod c_adapter;

View File

@ -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的有效性检查

View File

@ -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进程 =============