mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 22:36:48 +00:00
重写SMP模块 (#633)
* 修复cpumask的迭代器的错误。 * 能进系统(AP核心还没有初始化自身) * 初始化ap core * 修改percpu * 删除无用的cpu.c * riscv64编译通过
This commit is contained in:
parent
1d37ca6d17
commit
8cb2e9b344
@ -36,7 +36,7 @@ export ASFLAGS := --64
|
|||||||
LD_LIST := ""
|
LD_LIST := ""
|
||||||
|
|
||||||
|
|
||||||
kernel_subdirs := common driver debug smp syscall libs time
|
kernel_subdirs := common driver debug syscall libs time
|
||||||
|
|
||||||
|
|
||||||
kernel_rust:
|
kernel_rust:
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::smp::SMPArch;
|
use crate::smp::{
|
||||||
|
cpu::{CpuHpCpuState, ProcessorId},
|
||||||
|
SMPArch,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct RiscV64SMPArch;
|
pub struct RiscV64SMPArch;
|
||||||
|
|
||||||
@ -10,7 +13,7 @@ impl SMPArch for RiscV64SMPArch {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init() -> Result<(), SystemError> {
|
fn start_cpu(cpu_id: ProcessorId, hp_state: &CpuHpCpuState) -> Result<(), SystemError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,8 @@ impl TimeArch for RiscV64TimeArch {
|
|||||||
fn get_cycles() -> usize {
|
fn get_cycles() -> usize {
|
||||||
riscv::register::cycle::read()
|
riscv::register::cycle::read()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cal_expire_cycles(ns: usize) -> usize {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ _apu_boot_base = .
|
|||||||
|
|
||||||
// 设置栈指针
|
// 设置栈指针
|
||||||
movl $(_apu_boot_tmp_stack_end - _apu_boot_base), %esp
|
movl $(_apu_boot_tmp_stack_end - _apu_boot_base), %esp
|
||||||
|
|
||||||
// 计算ap处理器引导程序的基地址
|
// 计算ap处理器引导程序的基地址
|
||||||
mov %cs, %ax
|
mov %cs, %ax
|
||||||
movzx %ax, %esi
|
movzx %ax, %esi
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
use crate::{sched::SchedArch, time::TimeArch};
|
|
||||||
|
|
||||||
use super::{driver::tsc::TSCManager, syscall::init_syscall_64, CurrentSchedArch, CurrentTimeArch};
|
|
||||||
|
|
||||||
/// 获取当前的时间戳
|
|
||||||
#[no_mangle]
|
|
||||||
unsafe extern "C" fn rs_get_cycles() -> u64 {
|
|
||||||
return CurrentTimeArch::get_cycles() as u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
unsafe extern "C" fn rs_tsc_get_cpu_khz() -> u64 {
|
|
||||||
return TSCManager::cpu_khz();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// syscall指令初始化
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn rs_init_syscall_64() {
|
|
||||||
init_syscall_64();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
unsafe extern "C" fn rs_init_current_core_sched() {
|
|
||||||
CurrentSchedArch::initial_setup_sched_local();
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
use x86::cpuid::{cpuid, CpuIdResult};
|
use x86::cpuid::{cpuid, CpuIdResult};
|
||||||
|
|
||||||
use crate::smp::cpu::{ProcessorId, SmpCpuManager};
|
use crate::smp::cpu::ProcessorId;
|
||||||
|
|
||||||
/// 获取当前cpu的apic id
|
/// 获取当前cpu的apic id
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -16,7 +16,3 @@ pub unsafe fn cpu_reset() -> ! {
|
|||||||
unsafe { x86::io::outb(0x64, 0xfe) };
|
unsafe { x86::io::outb(0x64, 0xfe) };
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SmpCpuManager {
|
|
||||||
pub fn arch_init(_boot_cpu: ProcessorId) {}
|
|
||||||
}
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by longjin on 2022/1/20.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <common/cpu.h>
|
|
||||||
|
|
||||||
|
|
||||||
void __init_set_cpu_stack_start(uint32_t cpu, uint64_t stack_start)
|
|
||||||
{
|
|
||||||
cpu_core_info[cpu].stack_start = stack_start;
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ use x86::dtables::DescriptorTablePointer;
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::{interrupt::trap::arch_trap_init, process::table::TSSManager},
|
arch::{interrupt::trap::arch_trap_init, process::table::TSSManager},
|
||||||
driver::pci::pci::pci_init,
|
driver::pci::pci::pci_init,
|
||||||
include::bindings::bindings::cpu_init,
|
|
||||||
init::init::start_kernel,
|
init::init::start_kernel,
|
||||||
kdebug,
|
kdebug,
|
||||||
mm::{MemoryManagementArch, PhysAddr},
|
mm::{MemoryManagementArch, PhysAddr},
|
||||||
@ -33,7 +32,6 @@ extern "C" {
|
|||||||
fn head_stack_start();
|
fn head_stack_start();
|
||||||
|
|
||||||
fn multiboot2_init(mb2_info: u64, mb2_magic: u32) -> bool;
|
fn multiboot2_init(mb2_info: u64, mb2_magic: u32) -> bool;
|
||||||
fn __init_set_cpu_stack_start(cpu: u32, stack_start: u64);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -81,7 +79,6 @@ pub fn early_setup_arch() -> Result<(), SystemError> {
|
|||||||
|
|
||||||
set_current_core_tss(stack_start, 0);
|
set_current_core_tss(stack_start, 0);
|
||||||
unsafe { TSSManager::load_tr() };
|
unsafe { TSSManager::load_tr() };
|
||||||
unsafe { __init_set_cpu_stack_start(0, stack_start as u64) };
|
|
||||||
arch_trap_init().expect("arch_trap_init failed");
|
arch_trap_init().expect("arch_trap_init failed");
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -90,10 +87,6 @@ pub fn early_setup_arch() -> Result<(), SystemError> {
|
|||||||
/// 架构相关的初始化
|
/// 架构相关的初始化
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn setup_arch() -> Result<(), SystemError> {
|
pub fn setup_arch() -> Result<(), SystemError> {
|
||||||
unsafe {
|
|
||||||
cpu_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: 将来pci接入设备驱动模型之后,删掉这里。
|
// todo: 将来pci接入设备驱动模型之后,删掉这里。
|
||||||
pci_init();
|
pci_init();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
use crate::smp::cpu::ProcessorId;
|
|
||||||
|
|
||||||
use super::ipi::{ipi_send_smp_init, ipi_send_smp_startup};
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
unsafe extern "C" fn rs_ipi_send_smp_init() -> i32 {
|
|
||||||
return ipi_send_smp_init()
|
|
||||||
.map(|_| 0)
|
|
||||||
.unwrap_or_else(|e| e.to_posix_errno());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
unsafe extern "C" fn rs_ipi_send_smp_startup(target_cpu: u32) -> i32 {
|
|
||||||
return ipi_send_smp_startup(ProcessorId::new(target_cpu))
|
|
||||||
.map(|_| 0)
|
|
||||||
.unwrap_or_else(|e| e.to_posix_errno());
|
|
||||||
}
|
|
@ -160,7 +160,7 @@ pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 发送smp初始化IPI
|
/// 发送smp初始化IPI
|
||||||
pub fn ipi_send_smp_init() -> Result<(), SystemError> {
|
pub fn ipi_send_smp_init() {
|
||||||
let target = ArchIpiTarget::Other;
|
let target = ArchIpiTarget::Other;
|
||||||
let icr = if CurrentApic.x2apic_enabled() {
|
let icr = if CurrentApic.x2apic_enabled() {
|
||||||
x86::apic::Icr::for_x2apic(
|
x86::apic::Icr::for_x2apic(
|
||||||
@ -186,7 +186,6 @@ pub fn ipi_send_smp_init() -> Result<(), SystemError> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
CurrentApic.write_icr(icr);
|
CurrentApic.write_icr(icr);
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 发送smp启动IPI
|
/// 发送smp启动IPI
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
mod c_adapter;
|
|
||||||
pub(super) mod entry;
|
pub(super) mod entry;
|
||||||
mod handle;
|
mod handle;
|
||||||
pub mod ipi;
|
pub mod ipi;
|
||||||
@ -93,6 +92,14 @@ impl InterruptArch for X86_64InterruptArch {
|
|||||||
fn arch_early_irq_init() -> Result<(), SystemError> {
|
fn arch_early_irq_init() -> Result<(), SystemError> {
|
||||||
arch_early_irq_init()
|
arch_early_irq_init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn arch_ap_early_irq_init() -> Result<(), SystemError> {
|
||||||
|
if !CurrentApic.init_current_cpu() {
|
||||||
|
return Err(SystemError::ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 中断栈帧结构体
|
/// 中断栈帧结构体
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
use super::LowAddressRemapping;
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
unsafe extern "C" fn rs_unmap_at_low_addr() -> usize {
|
|
||||||
LowAddressRemapping::unmap_at_low_address(true);
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
pub mod barrier;
|
pub mod barrier;
|
||||||
pub mod bump;
|
pub mod bump;
|
||||||
mod c_adapter;
|
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
@ -159,6 +158,7 @@ impl MemoryManagementArch for X86_64MMArch {
|
|||||||
|
|
||||||
// 初始化内存管理器
|
// 初始化内存管理器
|
||||||
unsafe { allocator_init() };
|
unsafe { allocator_init() };
|
||||||
|
|
||||||
send_to_default_serial8250_port("x86 64 init done\n\0".as_bytes());
|
send_to_default_serial8250_port("x86 64 init done\n\0".as_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,11 +181,10 @@ impl MemoryManagementArch for X86_64MMArch {
|
|||||||
unsafe fn table(table_kind: PageTableKind) -> PhysAddr {
|
unsafe fn table(table_kind: PageTableKind) -> PhysAddr {
|
||||||
match table_kind {
|
match table_kind {
|
||||||
PageTableKind::Kernel | PageTableKind::User => {
|
PageTableKind::Kernel | PageTableKind::User => {
|
||||||
let paddr: usize;
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
asm!("mov {}, cr3", out(reg) paddr, options(nomem, nostack, preserves_flags));
|
let cr3 = x86::controlregs::cr3() as usize;
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
return PhysAddr::new(paddr);
|
return PhysAddr::new(cr3);
|
||||||
}
|
}
|
||||||
PageTableKind::EPT => {
|
PageTableKind::EPT => {
|
||||||
let eptp =
|
let eptp =
|
||||||
@ -461,9 +460,6 @@ unsafe fn allocator_init() {
|
|||||||
flusher.ignore();
|
flusher.ignore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加低地址的映射(在smp完成初始化之前,需要使用低地址的映射.初始化之后需要取消这一段映射)
|
|
||||||
LowAddressRemapping::remap_at_low_address(&mut mapper);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -659,9 +655,7 @@ impl LowAddressRemapping {
|
|||||||
// 映射64M
|
// 映射64M
|
||||||
const REMAP_SIZE: usize = 64 * 1024 * 1024;
|
const REMAP_SIZE: usize = 64 * 1024 * 1024;
|
||||||
|
|
||||||
pub unsafe fn remap_at_low_address(
|
pub unsafe fn remap_at_low_address(mapper: &mut PageMapper) {
|
||||||
mapper: &mut crate::mm::page::PageMapper<MMArch, &mut BumpAllocator<MMArch>>,
|
|
||||||
) {
|
|
||||||
for i in 0..(Self::REMAP_SIZE / MMArch::PAGE_SIZE) {
|
for i in 0..(Self::REMAP_SIZE / MMArch::PAGE_SIZE) {
|
||||||
let paddr = PhysAddr::new(i * MMArch::PAGE_SIZE);
|
let paddr = PhysAddr::new(i * MMArch::PAGE_SIZE);
|
||||||
let vaddr = VirtAddr::new(i * MMArch::PAGE_SIZE);
|
let vaddr = VirtAddr::new(i * MMArch::PAGE_SIZE);
|
||||||
@ -676,14 +670,10 @@ impl LowAddressRemapping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 取消低地址的映射
|
/// 取消低地址的映射
|
||||||
pub unsafe fn unmap_at_low_address(flush: bool) {
|
pub unsafe fn unmap_at_low_address(mapper: &mut PageMapper, flush: bool) {
|
||||||
let mut mapper = KernelMapper::lock();
|
|
||||||
assert!(mapper.as_mut().is_some());
|
|
||||||
for i in 0..(Self::REMAP_SIZE / MMArch::PAGE_SIZE) {
|
for i in 0..(Self::REMAP_SIZE / MMArch::PAGE_SIZE) {
|
||||||
let vaddr = VirtAddr::new(i * MMArch::PAGE_SIZE);
|
let vaddr = VirtAddr::new(i * MMArch::PAGE_SIZE);
|
||||||
let (_, _, flusher) = mapper
|
let (_, _, flusher) = mapper
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.unmap_phys(vaddr, true)
|
.unmap_phys(vaddr, true)
|
||||||
.expect("Failed to unmap frame");
|
.expect("Failed to unmap frame");
|
||||||
if flush == false {
|
if flush == false {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod asm;
|
pub mod asm;
|
||||||
mod acpi;
|
mod acpi;
|
||||||
mod c_adapter;
|
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
pub mod driver;
|
pub mod driver;
|
||||||
pub mod elf;
|
pub mod elf;
|
||||||
|
@ -1,27 +1,38 @@
|
|||||||
use core::{
|
use core::{
|
||||||
arch::asm,
|
arch::asm,
|
||||||
hint::spin_loop,
|
hint::spin_loop,
|
||||||
sync::atomic::{compiler_fence, AtomicBool, Ordering},
|
sync::atomic::{compiler_fence, fence, AtomicBool, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
use kdepends::memoffset::offset_of;
|
use kdepends::memoffset::offset_of;
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::process::table::TSSManager,
|
arch::{mm::LowAddressRemapping, process::table::TSSManager, MMArch},
|
||||||
exception::InterruptArch,
|
exception::InterruptArch,
|
||||||
include::bindings::bindings::{cpu_core_info, smp_init},
|
|
||||||
kdebug,
|
kdebug,
|
||||||
libs::rwlock::RwLock,
|
libs::{cpumask::CpuMask, rwlock::RwLock},
|
||||||
mm::percpu::PerCpu,
|
mm::{percpu::PerCpu, MemoryManagementArch, PhysAddr, VirtAddr, IDLE_PROCESS_ADDRESS_SPACE},
|
||||||
process::ProcessManager,
|
process::ProcessManager,
|
||||||
smp::{core::smp_get_processor_id, cpu::ProcessorId, SMPArch},
|
smp::{
|
||||||
|
core::smp_get_processor_id,
|
||||||
|
cpu::{smp_cpu_manager, CpuHpCpuState, ProcessorId, SmpCpuManager},
|
||||||
|
init::smp_ap_start_stage2,
|
||||||
|
SMPArch,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{acpi::early_acpi_boot_init, CurrentIrqArch};
|
use super::{
|
||||||
|
acpi::early_acpi_boot_init,
|
||||||
|
interrupt::ipi::{ipi_send_smp_init, ipi_send_smp_startup},
|
||||||
|
CurrentIrqArch,
|
||||||
|
};
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn smp_ap_start_stage2();
|
/// AP处理器启动时,会将CR3设置为这个值
|
||||||
|
pub static mut __APU_START_CR3: u64;
|
||||||
|
fn _apu_boot_start();
|
||||||
|
fn _apu_boot_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) static X86_64_SMP_MANAGER: X86_64SmpManager = X86_64SmpManager::new();
|
pub(super) static X86_64_SMP_MANAGER: X86_64SmpManager = X86_64SmpManager::new();
|
||||||
@ -35,7 +46,17 @@ struct ApStartStackInfo {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn smp_ap_start() -> ! {
|
unsafe extern "C" fn smp_ap_start() -> ! {
|
||||||
CurrentIrqArch::interrupt_disable();
|
CurrentIrqArch::interrupt_disable();
|
||||||
let vaddr = cpu_core_info[smp_get_processor_id().data() as usize].stack_start as usize;
|
let vaddr = if let Some(t) = smp_cpu_manager()
|
||||||
|
.cpuhp_state(smp_get_processor_id())
|
||||||
|
.thread()
|
||||||
|
{
|
||||||
|
t.kernel_stack().stack_max_address().data() - 16
|
||||||
|
} else {
|
||||||
|
// 没有设置ap核心的栈,那么就进入死循环。
|
||||||
|
loop {
|
||||||
|
spin_loop();
|
||||||
|
}
|
||||||
|
};
|
||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||||
let v = ApStartStackInfo { vaddr };
|
let v = ApStartStackInfo { vaddr };
|
||||||
smp_init_switch_stack(&v);
|
smp_init_switch_stack(&v);
|
||||||
@ -49,7 +70,7 @@ unsafe extern "sysv64" fn smp_init_switch_stack(st: &ApStartStackInfo) -> ! {
|
|||||||
jmp {stage1}
|
jmp {stage1}
|
||||||
"),
|
"),
|
||||||
off_rsp = const(offset_of!(ApStartStackInfo, vaddr)),
|
off_rsp = const(offset_of!(ApStartStackInfo, vaddr)),
|
||||||
stage1 = sym smp_ap_start_stage1,
|
stage1 = sym smp_ap_start_stage1,
|
||||||
options(noreturn));
|
options(noreturn));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,10 +87,9 @@ unsafe extern "C" fn smp_ap_start_stage1() -> ! {
|
|||||||
);
|
);
|
||||||
TSSManager::load_tr();
|
TSSManager::load_tr();
|
||||||
|
|
||||||
|
CurrentIrqArch::arch_ap_early_irq_init().expect("arch_ap_early_irq_init failed");
|
||||||
|
|
||||||
smp_ap_start_stage2();
|
smp_ap_start_stage2();
|
||||||
loop {
|
|
||||||
spin_loop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 多核的数据
|
/// 多核的数据
|
||||||
@ -141,10 +161,34 @@ impl X86_64SmpManager {
|
|||||||
pub fn build_cpu_map(&self) -> Result<(), SystemError> {
|
pub fn build_cpu_map(&self) -> Result<(), SystemError> {
|
||||||
// 参考:https://code.dragonos.org.cn/xref/linux-6.1.9/arch/ia64/kernel/smpboot.c?fi=smp_build_cpu_map#496
|
// 参考:https://code.dragonos.org.cn/xref/linux-6.1.9/arch/ia64/kernel/smpboot.c?fi=smp_build_cpu_map#496
|
||||||
// todo!("build_cpu_map")
|
// todo!("build_cpu_map")
|
||||||
|
unsafe {
|
||||||
|
smp_cpu_manager().set_possible_cpu(ProcessorId::new(0), true);
|
||||||
|
smp_cpu_manager().set_present_cpu(ProcessorId::new(0), true);
|
||||||
|
smp_cpu_manager().set_online_cpu(ProcessorId::new(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for cpu in 1..SMP_BOOT_DATA.cpu_count() {
|
||||||
|
unsafe {
|
||||||
|
smp_cpu_manager().set_possible_cpu(ProcessorId::new(cpu as u32), true);
|
||||||
|
smp_cpu_manager().set_present_cpu(ProcessorId::new(cpu as u32), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_cpus("possible", smp_cpu_manager().possible_cpus());
|
||||||
|
print_cpus("present", smp_cpu_manager().present_cpus());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_cpus(s: &str, mask: &CpuMask) {
|
||||||
|
let mut v = vec![];
|
||||||
|
for cpu in mask.iter_cpu() {
|
||||||
|
v.push(cpu.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
kdebug!("{s}: cpus: {v:?}\n");
|
||||||
|
}
|
||||||
|
|
||||||
pub struct X86_64SMPArch;
|
pub struct X86_64SMPArch;
|
||||||
|
|
||||||
impl SMPArch for X86_64SMPArch {
|
impl SMPArch for X86_64SMPArch {
|
||||||
@ -155,11 +199,87 @@ impl SMPArch for X86_64SMPArch {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
fn post_init() -> Result<(), SystemError> {
|
||||||
fn init() -> Result<(), SystemError> {
|
// AP核心启动完毕,取消低地址映射
|
||||||
x86::fence::mfence();
|
unsafe {
|
||||||
unsafe { smp_init() };
|
LowAddressRemapping::unmap_at_low_address(
|
||||||
x86::fence::mfence();
|
&mut IDLE_PROCESS_ADDRESS_SPACE()
|
||||||
|
.write_irqsave()
|
||||||
|
.user_mapper
|
||||||
|
.utable,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_cpu(cpu_id: ProcessorId, _cpu_hpstate: &CpuHpCpuState) -> Result<(), SystemError> {
|
||||||
|
kdebug!("start_cpu: cpu_id: {:#x}\n", cpu_id.data());
|
||||||
|
|
||||||
|
Self::copy_smp_start_code();
|
||||||
|
|
||||||
|
ipi_send_smp_init();
|
||||||
|
fence(Ordering::SeqCst);
|
||||||
|
ipi_send_smp_startup(cpu_id)?;
|
||||||
|
fence(Ordering::SeqCst);
|
||||||
|
ipi_send_smp_startup(cpu_id)?;
|
||||||
|
fence(Ordering::SeqCst);
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl X86_64SMPArch {
|
||||||
|
const SMP_CODE_START: usize = 0x20000;
|
||||||
|
/// 复制SMP启动代码到0x20000处
|
||||||
|
fn copy_smp_start_code() -> (VirtAddr, usize) {
|
||||||
|
let apu_boot_size = Self::start_code_size();
|
||||||
|
|
||||||
|
fence(Ordering::SeqCst);
|
||||||
|
unsafe {
|
||||||
|
core::ptr::copy(
|
||||||
|
_apu_boot_start as *const u8,
|
||||||
|
Self::SMP_CODE_START as *mut u8,
|
||||||
|
apu_boot_size,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
return (VirtAddr::new(Self::SMP_CODE_START), apu_boot_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_code_size() -> usize {
|
||||||
|
let apu_boot_start = _apu_boot_start as usize;
|
||||||
|
let apu_boot_end = _apu_boot_end as usize;
|
||||||
|
let apu_boot_size = apu_boot_end - apu_boot_start;
|
||||||
|
return apu_boot_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SmpCpuManager {
|
||||||
|
pub fn arch_init(_boot_cpu: ProcessorId) {
|
||||||
|
assert!(smp_get_processor_id().data() == 0);
|
||||||
|
// 写入APU_START_CR3,这个值会在AP处理器启动时设置到CR3寄存器
|
||||||
|
let addr = IDLE_PROCESS_ADDRESS_SPACE()
|
||||||
|
.read_irqsave()
|
||||||
|
.user_mapper
|
||||||
|
.utable
|
||||||
|
.table()
|
||||||
|
.phys();
|
||||||
|
let vaddr = unsafe {
|
||||||
|
MMArch::phys_2_virt(PhysAddr::new(&mut __APU_START_CR3 as *mut u64 as usize)).unwrap()
|
||||||
|
};
|
||||||
|
let ptr = vaddr.data() as *mut u64;
|
||||||
|
unsafe { *ptr = addr.data() as u64 };
|
||||||
|
|
||||||
|
// 添加低地址映射
|
||||||
|
unsafe {
|
||||||
|
LowAddressRemapping::remap_at_low_address(
|
||||||
|
&mut IDLE_PROCESS_ADDRESS_SPACE()
|
||||||
|
.write_irqsave()
|
||||||
|
.user_mapper
|
||||||
|
.utable,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
use crate::time::TimeArch;
|
use crate::time::TimeArch;
|
||||||
|
|
||||||
|
use super::driver::tsc::TSCManager;
|
||||||
|
|
||||||
pub struct X86_64TimeArch;
|
pub struct X86_64TimeArch;
|
||||||
|
|
||||||
impl TimeArch for X86_64TimeArch {
|
impl TimeArch for X86_64TimeArch {
|
||||||
fn get_cycles() -> usize {
|
fn get_cycles() -> usize {
|
||||||
unsafe { x86::time::rdtsc() as usize }
|
unsafe { x86::time::rdtsc() as usize }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cal_expire_cycles(ns: usize) -> usize {
|
||||||
|
Self::get_cycles() + ns * TSCManager::cpu_khz() as usize / 1000000
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "glib.h"
|
|
||||||
|
|
||||||
#define MAX_CPU_NUM 32 // 操作系统支持的最大处理器数量
|
|
||||||
|
|
||||||
// cpu支持的最大cpuid指令的基础主功能号
|
|
||||||
extern uint32_t Cpu_cpuid_max_Basic_mop;
|
|
||||||
// cpu支持的最大cpuid指令的扩展主功能号
|
|
||||||
extern uint32_t Cpu_cpuid_max_Extended_mop;
|
|
||||||
// cpu制造商信息
|
|
||||||
extern char Cpu_Manufacturer_Name[17];
|
|
||||||
// 处理器名称信息
|
|
||||||
extern char Cpu_BrandName[49];
|
|
||||||
// 处理器家族ID
|
|
||||||
extern uint32_t Cpu_Family_ID;
|
|
||||||
// 处理器扩展家族ID
|
|
||||||
extern uint32_t Cpu_Extended_Family_ID;
|
|
||||||
// 处理器模式ID
|
|
||||||
extern uint32_t Cpu_Model_ID;
|
|
||||||
// 处理器扩展模式ID
|
|
||||||
extern uint32_t Cpu_Extended_Model_ID;
|
|
||||||
// 处理器步进ID
|
|
||||||
extern uint32_t Cpu_Stepping_ID;
|
|
||||||
// 处理器类型
|
|
||||||
extern uint32_t Cpu_Processor_Type;
|
|
||||||
// 处理器支持的最大物理地址可寻址地址线宽度
|
|
||||||
extern uint32_t Cpu_max_phys_addrline_size;
|
|
||||||
// 处理器支持的最大线性地址可寻址地址线宽度
|
|
||||||
extern uint32_t Cpu_max_linear_addrline_size;
|
|
||||||
|
|
||||||
// 处理器的tsc频率(单位:hz)(HPET定时器在测定apic频率时,顺便测定了这个值)
|
|
||||||
extern uint64_t Cpu_tsc_freq;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 执行cpuid指令
|
|
||||||
*
|
|
||||||
* @param mop 主功能号
|
|
||||||
* @param sop 子功能号
|
|
||||||
* @param eax 结果的eax值
|
|
||||||
* @param ebx 结果的ebx值
|
|
||||||
* @param ecx 结果的ecx值
|
|
||||||
* @param edx 结果的edx值
|
|
||||||
*
|
|
||||||
* cpuid指令参考英特尔开发手册卷2A Chapter3 3.2 Instruction
|
|
||||||
*/
|
|
||||||
void cpu_cpuid(uint32_t mop, uint32_t sop, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 初始化获取处理器信息模块
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void cpu_init(void);
|
|
||||||
|
|
||||||
struct cpu_core_info_t
|
|
||||||
{
|
|
||||||
uint64_t stack_start; // 栈基地址
|
|
||||||
uint64_t ist_stack_start; // IST栈基地址
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct cpu_core_info_t cpu_core_info[MAX_CPU_NUM];
|
|
@ -181,7 +181,7 @@ impl IrqHandler for Ps2KeyboardIrqHandler {
|
|||||||
let status = unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_STATUS.into()) };
|
let status = unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_STATUS.into()) };
|
||||||
let status = Ps2StatusRegister::from(status);
|
let status = Ps2StatusRegister::from(status);
|
||||||
if !status.outbuf_full() {
|
if !status.outbuf_full() {
|
||||||
return Ok(IrqReturn::NotHandled);
|
return Ok(IrqReturn::Handled);
|
||||||
}
|
}
|
||||||
|
|
||||||
let input = unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_DATA.into()) };
|
let input = unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_DATA.into()) };
|
||||||
|
@ -183,7 +183,6 @@ impl TtyOperation for TtyConsoleDriverInner {
|
|||||||
let mut window_size = window_size.upgrade();
|
let mut window_size = window_size.upgrade();
|
||||||
window_size.col = vc_data.cols as u16;
|
window_size.col = vc_data.cols as u16;
|
||||||
window_size.row = vc_data.rows as u16;
|
window_size.row = vc_data.rows as u16;
|
||||||
kerror!("window_size {:?}", *window_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if vc_data.utf {
|
if vc_data.utf {
|
||||||
|
@ -40,6 +40,11 @@ pub trait InterruptArch: Send + Sync {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ap启动时的中断初始化
|
||||||
|
fn arch_ap_early_irq_init() -> Result<(), SystemError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// 响应未注册的中断
|
/// 响应未注册的中断
|
||||||
fn ack_bad_irq(irq: IrqNumber);
|
fn ack_bad_irq(irq: IrqNumber);
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,6 @@
|
|||||||
#include <mm/slab.h>
|
#include <mm/slab.h>
|
||||||
#include <process/process.h>
|
#include <process/process.h>
|
||||||
#include <sched/sched.h>
|
#include <sched/sched.h>
|
||||||
#include <smp/smp.h>
|
|
||||||
#include <time/clocksource.h>
|
#include <time/clocksource.h>
|
||||||
#include <time/sleep.h>
|
#include <time/sleep.h>
|
||||||
#include <common/errno.h>
|
#include <common/errno.h>
|
||||||
#include <common/cpu.h>
|
|
||||||
|
@ -59,13 +59,12 @@ fn do_start_kernel() {
|
|||||||
unsafe {
|
unsafe {
|
||||||
acpi_init()
|
acpi_init()
|
||||||
};
|
};
|
||||||
|
process_init();
|
||||||
early_smp_init().expect("early smp init failed");
|
early_smp_init().expect("early smp init failed");
|
||||||
irq_init().expect("irq init failed");
|
irq_init().expect("irq init failed");
|
||||||
setup_arch().expect("setup_arch failed");
|
setup_arch().expect("setup_arch failed");
|
||||||
CurrentSMPArch::prepare_cpus().expect("prepare_cpus failed");
|
CurrentSMPArch::prepare_cpus().expect("prepare_cpus failed");
|
||||||
|
|
||||||
process_init();
|
|
||||||
sched_init();
|
sched_init();
|
||||||
softirq_init().expect("softirq init failed");
|
softirq_init().expect("softirq init failed");
|
||||||
Syscall::init().expect("syscall init failed");
|
Syscall::init().expect("syscall init failed");
|
||||||
@ -74,9 +73,6 @@ fn do_start_kernel() {
|
|||||||
kthread_init();
|
kthread_init();
|
||||||
clocksource_boot_finish();
|
clocksource_boot_finish();
|
||||||
|
|
||||||
CurrentSMPArch::init().expect("smp init failed");
|
|
||||||
// SMP初始化有可能会开中断,所以这里再次检查中断是否关闭
|
|
||||||
assert_eq!(CurrentIrqArch::is_irq_enabled(), false);
|
|
||||||
Futex::init();
|
Futex::init();
|
||||||
|
|
||||||
setup_arch_post().expect("setup_arch_post failed");
|
setup_arch_post().expect("setup_arch_post failed");
|
||||||
|
@ -12,6 +12,7 @@ use crate::{
|
|||||||
kdebug, kerror,
|
kdebug, kerror,
|
||||||
net::net_core::net_init,
|
net::net_core::net_init,
|
||||||
process::{kthread::KernelThreadMechanism, process::stdio_init},
|
process::{kthread::KernelThreadMechanism, process::stdio_init},
|
||||||
|
smp::smp_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::initcall::do_initcalls;
|
use super::initcall::do_initcalls;
|
||||||
@ -55,6 +56,8 @@ fn kenrel_init_freeable() -> Result<(), SystemError> {
|
|||||||
panic!("Failed to initialize subsystems: {:?}", err);
|
panic!("Failed to initialize subsystems: {:?}", err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
smp_init();
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
#include <common/cpu.h>
|
|
||||||
#include <common/kprint.h>
|
|
||||||
#include <common/printk.h>
|
|
||||||
// #pragma GCC optimize("O0")
|
|
||||||
// cpu支持的最大cpuid指令的基础主功能号
|
|
||||||
uint Cpu_cpuid_max_Basic_mop;
|
|
||||||
// cpu支持的最大cpuid指令的扩展主功能号
|
|
||||||
uint Cpu_cpuid_max_Extended_mop;
|
|
||||||
// cpu制造商信息
|
|
||||||
char Cpu_Manufacturer_Name[17] = {0};
|
|
||||||
// 处理器名称信息
|
|
||||||
char Cpu_BrandName[49] = {0};
|
|
||||||
// 处理器家族ID
|
|
||||||
uint Cpu_Family_ID;
|
|
||||||
// 处理器扩展家族ID
|
|
||||||
uint Cpu_Extended_Family_ID;
|
|
||||||
// 处理器模式ID
|
|
||||||
uint Cpu_Model_ID;
|
|
||||||
// 处理器扩展模式ID
|
|
||||||
uint Cpu_Extended_Model_ID;
|
|
||||||
// 处理器步进ID
|
|
||||||
uint Cpu_Stepping_ID;
|
|
||||||
// 处理器类型
|
|
||||||
uint Cpu_Processor_Type;
|
|
||||||
// 处理器支持的最大物理地址可寻址地址线宽度
|
|
||||||
uint Cpu_max_phys_addrline_size;
|
|
||||||
// 处理器支持的最大线性地址可寻址地址线宽度
|
|
||||||
uint Cpu_max_linear_addrline_size;
|
|
||||||
// 处理器的tsc频率(单位:hz)(HPET定时器在测定apic频率时,顺便测定了这个值)
|
|
||||||
uint64_t Cpu_tsc_freq = 0;
|
|
||||||
|
|
||||||
struct cpu_core_info_t cpu_core_info[MAX_CPU_NUM];
|
|
||||||
|
|
||||||
#if ARCH(I386) || ARCH(X86_64)
|
|
||||||
|
|
||||||
void cpu_init(void)
|
|
||||||
{
|
|
||||||
// 获取处理器制造商信息
|
|
||||||
uint tmp_info[4] = {0};
|
|
||||||
cpu_cpuid(0, 0, &tmp_info[0], &tmp_info[1], &tmp_info[2], &tmp_info[3]);
|
|
||||||
|
|
||||||
// 保存CPU支持的最大cpuid指令主功能号
|
|
||||||
Cpu_cpuid_max_Basic_mop = tmp_info[0];
|
|
||||||
// 保存制造商名称
|
|
||||||
*(uint *)&Cpu_Manufacturer_Name[0] = tmp_info[1];
|
|
||||||
*(uint *)&Cpu_Manufacturer_Name[4] = tmp_info[3];
|
|
||||||
*(uint *)&Cpu_Manufacturer_Name[8] = tmp_info[2];
|
|
||||||
Cpu_Manufacturer_Name[12] = '\0';
|
|
||||||
kinfo("CPU manufacturer: %s", Cpu_Manufacturer_Name);
|
|
||||||
|
|
||||||
// 获取处理器型号信息
|
|
||||||
int count = 0;
|
|
||||||
for (uint i = 0x80000002; i < 0x80000005; ++i)
|
|
||||||
{
|
|
||||||
cpu_cpuid(i, 0, &tmp_info[0], &tmp_info[1], &tmp_info[2], &tmp_info[3]);
|
|
||||||
for (int j = 0; j <= 3; ++j)
|
|
||||||
{
|
|
||||||
*(uint *)&Cpu_BrandName[4 * count] = tmp_info[j];
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Cpu_BrandName[48] = '\0';
|
|
||||||
|
|
||||||
kinfo("CPU Brand Name: %s", Cpu_BrandName);
|
|
||||||
|
|
||||||
// 使用cpuid主功能号0x01进行查询(未保存ebx ecx edx的信息,具体参见白皮书)
|
|
||||||
cpu_cpuid(1, 0, &tmp_info[0], &tmp_info[1], &tmp_info[2], &tmp_info[3]);
|
|
||||||
|
|
||||||
// EAX中包含 Version Informatin Type,Family,Model,and Stepping ID
|
|
||||||
Cpu_Stepping_ID = tmp_info[0] & 0xf;
|
|
||||||
Cpu_Model_ID = (tmp_info[0] >> 4) & 0xf;
|
|
||||||
Cpu_Family_ID = (tmp_info[0] >> 8) & 0xf;
|
|
||||||
Cpu_Processor_Type = (tmp_info[0] >> 12) & 0x3;
|
|
||||||
// 14-15位保留
|
|
||||||
Cpu_Extended_Model_ID = (tmp_info[0] >> 16) & 0xf;
|
|
||||||
Cpu_Extended_Family_ID = (tmp_info[0] >> 20) & 0xff;
|
|
||||||
// 31-25位保留
|
|
||||||
kinfo("Family ID=%#03lx\t Extended Family ID=%#03lx\t Processor Type=%#03lx\t", Cpu_Family_ID, Cpu_Extended_Family_ID, Cpu_Processor_Type);
|
|
||||||
kinfo("Model ID=%#03lx\t Extended Model ID=%#03lx\tStepping ID=%#03lx\t", Cpu_Model_ID, Cpu_Extended_Model_ID, Cpu_Stepping_ID);
|
|
||||||
|
|
||||||
// 使用0x80000008主功能号,查询处理器支持的最大可寻址地址线宽度
|
|
||||||
cpu_cpuid(0x80000008, 0, &tmp_info[0], &tmp_info[1], &tmp_info[2], &tmp_info[3]);
|
|
||||||
Cpu_max_phys_addrline_size = tmp_info[0] & 0xff;
|
|
||||||
Cpu_max_linear_addrline_size = (tmp_info[0] >> 8) & 0xff;
|
|
||||||
|
|
||||||
kinfo("Cpu_max_phys_addrline_size = %d", Cpu_max_phys_addrline_size);
|
|
||||||
kinfo("Cpu_max_linear_addrline_size = %d", Cpu_max_linear_addrline_size);
|
|
||||||
|
|
||||||
cpu_cpuid(0x80000000, 0, &tmp_info[0], &tmp_info[1], &tmp_info[2], &tmp_info[3]);
|
|
||||||
Cpu_cpuid_max_Extended_mop = tmp_info[0];
|
|
||||||
|
|
||||||
kinfo("Max basic mop=%#05lx", Cpu_cpuid_max_Basic_mop);
|
|
||||||
kinfo("Max extended mop=%#05lx", Cpu_cpuid_max_Extended_mop);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_cpuid(uint32_t mop, uint32_t sop, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
|
|
||||||
{
|
|
||||||
// 向eax和ecx分别输入主功能号和子功能号
|
|
||||||
// 结果输出到eax, ebx, ecx, edx
|
|
||||||
__asm__ __volatile__("cpuid \n\t"
|
|
||||||
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
|
|
||||||
: "0"(mop), "2"(sop)
|
|
||||||
: "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
void cpu_init(void){}
|
|
||||||
#endif
|
|
@ -65,8 +65,9 @@ impl CpuMask {
|
|||||||
pub fn iter_cpu(&self) -> CpuMaskIter {
|
pub fn iter_cpu(&self) -> CpuMaskIter {
|
||||||
CpuMaskIter {
|
CpuMaskIter {
|
||||||
mask: self,
|
mask: self,
|
||||||
index: ProcessorId::new(0),
|
index: None,
|
||||||
set: true,
|
set: true,
|
||||||
|
begin: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,36 +75,41 @@ impl CpuMask {
|
|||||||
pub fn iter_zero_cpu(&self) -> CpuMaskIter {
|
pub fn iter_zero_cpu(&self) -> CpuMaskIter {
|
||||||
CpuMaskIter {
|
CpuMaskIter {
|
||||||
mask: self,
|
mask: self,
|
||||||
index: ProcessorId::new(0),
|
index: None,
|
||||||
set: false,
|
set: false,
|
||||||
|
begin: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CpuMaskIter<'a> {
|
pub struct CpuMaskIter<'a> {
|
||||||
mask: &'a CpuMask,
|
mask: &'a CpuMask,
|
||||||
index: ProcessorId,
|
index: Option<ProcessorId>,
|
||||||
set: bool,
|
set: bool,
|
||||||
|
begin: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for CpuMaskIter<'a> {
|
impl<'a> Iterator for CpuMaskIter<'a> {
|
||||||
type Item = ProcessorId;
|
type Item = ProcessorId;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<ProcessorId> {
|
fn next(&mut self) -> Option<ProcessorId> {
|
||||||
if self.index.data() == 0 {
|
if self.index.is_none() && self.begin {
|
||||||
if self.set {
|
if self.set {
|
||||||
self.index = self.mask.first()?;
|
self.index = self.mask.first();
|
||||||
} else {
|
} else {
|
||||||
self.index = self.mask.first_zero()?;
|
self.index = self.mask.first_zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.begin = false;
|
||||||
|
}
|
||||||
|
let result = self.index;
|
||||||
|
if self.set {
|
||||||
|
self.index = self.mask.next_index(self.index?);
|
||||||
|
} else {
|
||||||
|
self.index = self.mask.next_zero_index(self.index?);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.set {
|
result
|
||||||
self.index = self.mask.next_index(self.index)?;
|
|
||||||
} else {
|
|
||||||
self.index = self.mask.next_zero_index(self.index)?;
|
|
||||||
}
|
|
||||||
Some(self.index)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ impl WaitQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn sleep_without_schedule_uninterruptible(&self) {
|
pub unsafe fn sleep_without_schedule_uninterruptible(&self) {
|
||||||
before_sleep_check(0);
|
before_sleep_check(1);
|
||||||
// 安全检查:确保当前处于中断禁止状态
|
// 安全检查:确保当前处于中断禁止状态
|
||||||
assert!(CurrentIrqArch::is_irq_enabled() == false);
|
assert!(CurrentIrqArch::is_irq_enabled() == false);
|
||||||
let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
|
let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
|
||||||
@ -264,7 +264,7 @@ fn before_sleep_check(max_preempt: usize) {
|
|||||||
if unlikely(pcb.preempt_count() > max_preempt) {
|
if unlikely(pcb.preempt_count() > max_preempt) {
|
||||||
kwarn!(
|
kwarn!(
|
||||||
"Process {:?}: Try to sleep when preempt count is {}",
|
"Process {:?}: Try to sleep when preempt count is {}",
|
||||||
pcb.pid(),
|
pcb.pid().data(),
|
||||||
pcb.preempt_count()
|
pcb.preempt_count()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ pub mod syscall;
|
|||||||
pub mod ucontext;
|
pub mod ucontext;
|
||||||
|
|
||||||
/// 内核INIT进程的用户地址空间结构体(仅在process_init中初始化)
|
/// 内核INIT进程的用户地址空间结构体(仅在process_init中初始化)
|
||||||
static mut __INITIAL_PROCESS_ADDRESS_SPACE: Option<Arc<AddressSpace>> = None;
|
static mut __IDLE_PROCESS_ADDRESS_SPACE: Option<Arc<AddressSpace>> = None;
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Virtual memory flags
|
/// Virtual memory flags
|
||||||
@ -74,29 +74,29 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 获取内核INIT进程的用户地址空间结构体
|
/// 获取内核IDLE进程的用户地址空间结构体
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn INITIAL_PROCESS_ADDRESS_SPACE() -> Arc<AddressSpace> {
|
pub fn IDLE_PROCESS_ADDRESS_SPACE() -> Arc<AddressSpace> {
|
||||||
unsafe {
|
unsafe {
|
||||||
return __INITIAL_PROCESS_ADDRESS_SPACE
|
return __IDLE_PROCESS_ADDRESS_SPACE
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("INITIAL_PROCESS_ADDRESS_SPACE is null")
|
.expect("IDLE_PROCESS_ADDRESS_SPACE is null")
|
||||||
.clone();
|
.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 设置内核INIT进程的用户地址空间结构体全局变量
|
/// 设置内核IDLE进程的用户地址空间结构体全局变量
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub unsafe fn set_INITIAL_PROCESS_ADDRESS_SPACE(address_space: Arc<AddressSpace>) {
|
pub unsafe fn set_IDLE_PROCESS_ADDRESS_SPACE(address_space: Arc<AddressSpace>) {
|
||||||
static INITIALIZED: AtomicBool = AtomicBool::new(false);
|
static INITIALIZED: AtomicBool = AtomicBool::new(false);
|
||||||
if INITIALIZED
|
if INITIALIZED
|
||||||
.compare_exchange(false, true, Ordering::SeqCst, Ordering::Acquire)
|
.compare_exchange(false, true, Ordering::SeqCst, Ordering::Acquire)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
panic!("INITIAL_PROCESS_ADDRESS_SPACE is already initialized");
|
panic!("IDLE_PROCESS_ADDRESS_SPACE is already initialized");
|
||||||
}
|
}
|
||||||
__INITIAL_PROCESS_ADDRESS_SPACE = Some(address_space);
|
__IDLE_PROCESS_ADDRESS_SPACE = Some(address_space);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief 将内核空间的虚拟地址转换为物理地址
|
/// @brief 将内核空间的虚拟地址转换为物理地址
|
||||||
|
@ -3,9 +3,11 @@ use core::sync::atomic::AtomicU32;
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
include::bindings::bindings::smp_get_total_cpu,
|
|
||||||
libs::lazy_init::Lazy,
|
libs::lazy_init::Lazy,
|
||||||
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
smp::{
|
||||||
|
core::smp_get_processor_id,
|
||||||
|
cpu::{smp_cpu_manager, ProcessorId},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 系统中的CPU数量
|
/// 系统中的CPU数量
|
||||||
@ -29,8 +31,9 @@ impl PerCpu {
|
|||||||
if CPU_NUM.load(core::sync::atomic::Ordering::SeqCst) != 0 {
|
if CPU_NUM.load(core::sync::atomic::Ordering::SeqCst) != 0 {
|
||||||
panic!("PerCpu::init() called twice");
|
panic!("PerCpu::init() called twice");
|
||||||
}
|
}
|
||||||
let cpus = unsafe { smp_get_total_cpu() };
|
let cpus = smp_cpu_manager().present_cpus_count();
|
||||||
assert!(cpus > 0, "PerCpu::init(): smp_get_total_cpu() returned 0");
|
assert!(cpus > 0, "PerCpu::init(): present_cpus_count() returned 0");
|
||||||
|
|
||||||
CPU_NUM.store(cpus, core::sync::atomic::Ordering::SeqCst);
|
CPU_NUM.store(cpus, core::sync::atomic::Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,17 +83,19 @@ impl<T> PerCpuVar<T> {
|
|||||||
&self.inner[cpu_id.data() as usize]
|
&self.inner[cpu_id.data() as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(&mut self) -> &mut T {
|
pub fn get_mut(&self) -> &mut T {
|
||||||
let cpu_id = smp_get_processor_id();
|
let cpu_id = smp_get_processor_id();
|
||||||
&mut self.inner[cpu_id.data() as usize]
|
unsafe {
|
||||||
|
&mut (self as *const Self as *mut Self).as_mut().unwrap().inner[cpu_id.data() as usize]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn force_get(&self, cpu_id: ProcessorId) -> &T {
|
pub unsafe fn force_get(&self, cpu_id: ProcessorId) -> &T {
|
||||||
&self.inner[cpu_id.data() as usize]
|
&self.inner[cpu_id.data() as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn force_get_mut(&mut self, cpu_id: ProcessorId) -> &mut T {
|
pub unsafe fn force_get_mut(&self, cpu_id: ProcessorId) -> &mut T {
|
||||||
&mut self.inner[cpu_id.data() as usize]
|
&mut (self as *const Self as *mut Self).as_mut().unwrap().inner[cpu_id.data() as usize]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ use core::{
|
|||||||
use alloc::{sync::Arc, vec::Vec};
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mm::{percpu::PerCpu, VirtAddr, INITIAL_PROCESS_ADDRESS_SPACE},
|
mm::{percpu::PerCpu, VirtAddr, IDLE_PROCESS_ADDRESS_SPACE},
|
||||||
process::KernelStack,
|
process::KernelStack,
|
||||||
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
||||||
};
|
};
|
||||||
@ -53,7 +53,7 @@ impl ProcessManager {
|
|||||||
unsafe {
|
unsafe {
|
||||||
idle_pcb
|
idle_pcb
|
||||||
.basic_mut()
|
.basic_mut()
|
||||||
.set_user_vm(Some(INITIAL_PROCESS_ADDRESS_SPACE()))
|
.set_user_vm(Some(IDLE_PROCESS_ADDRESS_SPACE()))
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(idle_pcb.sched_info().on_cpu().is_none());
|
assert!(idle_pcb.sched_info().on_cpu().is_none());
|
||||||
|
@ -41,7 +41,7 @@ use crate::{
|
|||||||
spinlock::{SpinLock, SpinLockGuard},
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
wait_queue::WaitQueue,
|
wait_queue::WaitQueue,
|
||||||
},
|
},
|
||||||
mm::{percpu::PerCpuVar, set_INITIAL_PROCESS_ADDRESS_SPACE, ucontext::AddressSpace, VirtAddr},
|
mm::{percpu::PerCpuVar, set_IDLE_PROCESS_ADDRESS_SPACE, ucontext::AddressSpace, VirtAddr},
|
||||||
net::socket::SocketInode,
|
net::socket::SocketInode,
|
||||||
sched::{
|
sched::{
|
||||||
completion::Completion,
|
completion::Completion,
|
||||||
@ -109,7 +109,7 @@ impl ProcessManager {
|
|||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
kdebug!("To create address space for INIT process.");
|
kdebug!("To create address space for INIT process.");
|
||||||
// test_buddy();
|
// test_buddy();
|
||||||
set_INITIAL_PROCESS_ADDRESS_SPACE(
|
set_IDLE_PROCESS_ADDRESS_SPACE(
|
||||||
AddressSpace::new(true).expect("Failed to create address space for INIT process."),
|
AddressSpace::new(true).expect("Failed to create address space for INIT process."),
|
||||||
);
|
);
|
||||||
kdebug!("INIT process address space created.");
|
kdebug!("INIT process address space created.");
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "ptrace.h"
|
#include "ptrace.h"
|
||||||
#include <common/cpu.h>
|
|
||||||
#include <common/errno.h>
|
#include <common/errno.h>
|
||||||
#include <common/glib.h>
|
#include <common/glib.h>
|
||||||
#include <syscall/syscall.h>
|
#include <syscall/syscall.h>
|
||||||
|
@ -5,12 +5,12 @@ use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::CurrentIrqArch,
|
arch::CurrentIrqArch,
|
||||||
exception::InterruptArch,
|
exception::InterruptArch,
|
||||||
include::bindings::bindings::MAX_CPU_NUM,
|
|
||||||
kBUG,
|
kBUG,
|
||||||
libs::{
|
libs::{
|
||||||
rbtree::RBTree,
|
rbtree::RBTree,
|
||||||
spinlock::{SpinLock, SpinLockGuard},
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
},
|
},
|
||||||
|
mm::percpu::PerCpu,
|
||||||
process::{
|
process::{
|
||||||
ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSchedulerInfo, ProcessState,
|
ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSchedulerInfo, ProcessState,
|
||||||
},
|
},
|
||||||
@ -122,7 +122,7 @@ impl SchedulerCFS {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 为每个cpu核心创建队列,进程重构后可以直接初始化Idle_pcb?
|
// 为每个cpu核心创建队列,进程重构后可以直接初始化Idle_pcb?
|
||||||
for i in 0..MAX_CPU_NUM {
|
for i in 0..PerCpu::MAX_CPU_NUM {
|
||||||
let idle_pcb = ProcessManager::idle_pcb()[i as usize].clone();
|
let idle_pcb = ProcessManager::idle_pcb()[i as usize].clone();
|
||||||
result
|
result
|
||||||
.cpu_queue
|
.cpu_queue
|
||||||
|
@ -4,9 +4,9 @@ use alloc::{boxed::Box, collections::LinkedList, sync::Arc, vec::Vec};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::cpu::current_cpu_id,
|
arch::cpu::current_cpu_id,
|
||||||
include::bindings::bindings::MAX_CPU_NUM,
|
|
||||||
kBUG, kdebug,
|
kBUG, kdebug,
|
||||||
libs::spinlock::SpinLock,
|
libs::spinlock::SpinLock,
|
||||||
|
mm::percpu::PerCpu,
|
||||||
process::{ProcessControlBlock, ProcessFlags, ProcessManager},
|
process::{ProcessControlBlock, ProcessFlags, ProcessManager},
|
||||||
smp::cpu::ProcessorId,
|
smp::cpu::ProcessorId,
|
||||||
};
|
};
|
||||||
@ -108,7 +108,7 @@ impl SchedulerRT {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 为每个cpu核心创建队列
|
// 为每个cpu核心创建队列
|
||||||
for cpu_id in 0..MAX_CPU_NUM {
|
for cpu_id in 0..PerCpu::MAX_CPU_NUM {
|
||||||
result.cpu_queue.push(Vec::new());
|
result.cpu_queue.push(Vec::new());
|
||||||
// 每个CPU有MAX_RT_PRIO个优先级队列
|
// 每个CPU有MAX_RT_PRIO个优先级队列
|
||||||
for _ in 0..SchedulerRT::MAX_RT_PRIO {
|
for _ in 0..SchedulerRT::MAX_RT_PRIO {
|
||||||
@ -116,7 +116,7 @@ impl SchedulerRT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 为每个cpu核心创建负载统计队列
|
// 为每个cpu核心创建负载统计队列
|
||||||
for _ in 0..MAX_CPU_NUM {
|
for _ in 0..PerCpu::MAX_CPU_NUM {
|
||||||
result
|
result
|
||||||
.load_list
|
.load_list
|
||||||
.push(Box::leak(Box::new(LinkedList::new())));
|
.push(Box::leak(Box::new(LinkedList::new())));
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
CFLAGS += -I .
|
|
||||||
|
|
||||||
|
|
||||||
all: smp.o
|
|
||||||
|
|
||||||
smp.o: smp.c
|
|
||||||
$(CC) $(CFLAGS) -c smp.c -o smp.o
|
|
@ -1,13 +0,0 @@
|
|||||||
use super::{core::smp_get_processor_id, cpu::ProcessorId, kick_cpu};
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn rs_kick_cpu(cpu_id: u32) -> usize {
|
|
||||||
return kick_cpu(ProcessorId::new(cpu_id))
|
|
||||||
.map(|_| 0usize)
|
|
||||||
.unwrap_or_else(|e| e.to_posix_errno() as usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn rs_current_cpu_id() -> i32 {
|
|
||||||
return smp_get_processor_id().data() as i32;
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
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,8 +1,17 @@
|
|||||||
use core::sync::atomic::AtomicU32;
|
use core::sync::atomic::AtomicU32;
|
||||||
|
|
||||||
use crate::libs::cpumask::CpuMask;
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
mod c_adapter;
|
use crate::{
|
||||||
|
arch::CurrentSMPArch,
|
||||||
|
libs::cpumask::CpuMask,
|
||||||
|
mm::percpu::{PerCpu, PerCpuVar},
|
||||||
|
process::{ProcessControlBlock, ProcessManager},
|
||||||
|
sched::completion::Completion,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{core::smp_get_processor_id, SMPArch};
|
||||||
|
|
||||||
int_like!(ProcessorId, AtomicProcessorId, u32, AtomicU32);
|
int_like!(ProcessorId, AtomicProcessorId, u32, AtomicU32);
|
||||||
|
|
||||||
@ -17,14 +26,81 @@ pub fn smp_cpu_manager() -> &'static SmpCpuManager {
|
|||||||
unsafe { SMP_CPU_MANAGER.as_ref().unwrap() }
|
unsafe { SMP_CPU_MANAGER.as_ref().unwrap() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum CpuHpState {
|
||||||
|
/// 启动阈值
|
||||||
|
ThresholdBringUp = 0,
|
||||||
|
|
||||||
|
/// 该CPU是离线的
|
||||||
|
Offline,
|
||||||
|
|
||||||
|
/// 该CPU是在线的
|
||||||
|
Online,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Per-Cpu Cpu的热插拔状态
|
||||||
|
pub struct CpuHpCpuState {
|
||||||
|
/// 当前状态
|
||||||
|
state: CpuHpState,
|
||||||
|
/// 目标状态
|
||||||
|
target_state: CpuHpState,
|
||||||
|
/// 指向热插拔的线程的PCB
|
||||||
|
thread: Option<Arc<ProcessControlBlock>>,
|
||||||
|
|
||||||
|
/// 当前是否为启动流程
|
||||||
|
bringup: bool,
|
||||||
|
/// 启动完成的信号
|
||||||
|
comp_done_up: Completion,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CpuHpCpuState {
|
||||||
|
const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
state: CpuHpState::Offline,
|
||||||
|
target_state: CpuHpState::Offline,
|
||||||
|
thread: None,
|
||||||
|
bringup: false,
|
||||||
|
comp_done_up: Completion::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn thread(&self) -> &Option<Arc<ProcessControlBlock>> {
|
||||||
|
&self.thread
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SmpCpuManager {
|
pub struct SmpCpuManager {
|
||||||
|
/// 可用的CPU
|
||||||
possible_cpus: CpuMask,
|
possible_cpus: CpuMask,
|
||||||
|
/// 出现的CPU
|
||||||
|
present_cpus: CpuMask,
|
||||||
|
/// 出现在系统中的CPU的数量
|
||||||
|
present_cnt: AtomicU32,
|
||||||
|
/// 可用的CPU的数量
|
||||||
|
possible_cnt: AtomicU32,
|
||||||
|
/// CPU的状态
|
||||||
|
cpuhp_state: PerCpuVar<CpuHpCpuState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SmpCpuManager {
|
impl SmpCpuManager {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let possible_cpus = CpuMask::new();
|
let possible_cpus = CpuMask::new();
|
||||||
Self { possible_cpus }
|
let present_cpus = CpuMask::new();
|
||||||
|
let mut data = Vec::with_capacity(PerCpu::MAX_CPU_NUM as usize);
|
||||||
|
for i in 0..PerCpu::MAX_CPU_NUM {
|
||||||
|
let mut hpstate = CpuHpCpuState::new();
|
||||||
|
hpstate.thread = Some(ProcessManager::idle_pcb()[i as usize].clone());
|
||||||
|
data.push(hpstate);
|
||||||
|
}
|
||||||
|
let cpuhp_state = PerCpuVar::new(data).unwrap();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
possible_cpus,
|
||||||
|
present_cpus,
|
||||||
|
cpuhp_state,
|
||||||
|
present_cnt: AtomicU32::new(0),
|
||||||
|
possible_cnt: AtomicU32::new(0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 设置可用的CPU
|
/// 设置可用的CPU
|
||||||
@ -38,14 +114,184 @@ impl SmpCpuManager {
|
|||||||
// 强制获取mut引用,因为该函数只能在初始化阶段调用
|
// 强制获取mut引用,因为该函数只能在初始化阶段调用
|
||||||
let p = (self as *const Self as *mut Self).as_mut().unwrap();
|
let p = (self as *const Self as *mut Self).as_mut().unwrap();
|
||||||
|
|
||||||
p.possible_cpus.set(cpu, value);
|
if let Some(prev) = p.possible_cpus.set(cpu, value) {
|
||||||
|
if prev != value {
|
||||||
|
if value {
|
||||||
|
p.possible_cnt
|
||||||
|
.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
p.possible_cnt
|
||||||
|
.fetch_sub(1, core::sync::atomic::Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 获取可用的CPU
|
/// 获取可用的CPU
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn possible_cpus(&self) -> &CpuMask {
|
pub fn possible_cpus(&self) -> &CpuMask {
|
||||||
&self.possible_cpus
|
&self.possible_cpus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn possible_cpus_count(&self) -> u32 {
|
||||||
|
self.possible_cnt.load(core::sync::atomic::Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn present_cpus_count(&self) -> u32 {
|
||||||
|
self.present_cnt.load(core::sync::atomic::Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn set_present_cpu(&self, cpu: ProcessorId, value: bool) {
|
||||||
|
// 强制获取mut引用,因为该函数只能在初始化阶段调用
|
||||||
|
let p = (self as *const Self as *mut Self).as_mut().unwrap();
|
||||||
|
|
||||||
|
if let Some(prev) = p.present_cpus.set(cpu, value) {
|
||||||
|
if prev != value {
|
||||||
|
if value {
|
||||||
|
p.present_cnt
|
||||||
|
.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
|
||||||
|
} else {
|
||||||
|
p.present_cnt
|
||||||
|
.fetch_sub(1, core::sync::atomic::Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取CPU的状态
|
||||||
|
pub fn cpuhp_state(&self, cpu_id: ProcessorId) -> &CpuHpCpuState {
|
||||||
|
unsafe { self.cpuhp_state.force_get(cpu_id) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cpuhp_state_mut(&self, cpu_id: ProcessorId) -> &mut CpuHpCpuState {
|
||||||
|
unsafe { self.cpuhp_state.force_get_mut(cpu_id) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 设置CPU的状态, 返回旧的状态
|
||||||
|
pub unsafe fn set_cpuhp_state(
|
||||||
|
&self,
|
||||||
|
cpu_id: ProcessorId,
|
||||||
|
target_state: CpuHpState,
|
||||||
|
) -> CpuHpState {
|
||||||
|
let p = self.cpuhp_state.force_get_mut(cpu_id);
|
||||||
|
let old_state = p.state;
|
||||||
|
|
||||||
|
let bringup = target_state > p.state;
|
||||||
|
p.target_state = target_state;
|
||||||
|
p.bringup = bringup;
|
||||||
|
|
||||||
|
return old_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_online_cpu(&self, cpu_id: ProcessorId) {
|
||||||
|
unsafe { self.set_cpuhp_state(cpu_id, CpuHpState::Online) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取出现在系统中的CPU
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn present_cpus(&self) -> &CpuMask {
|
||||||
|
&self.present_cpus
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 启动bsp以外的CPU
|
||||||
|
pub(super) fn bringup_nonboot_cpus(&self) {
|
||||||
|
for cpu_id in self.present_cpus().iter_cpu() {
|
||||||
|
if cpu_id == smp_get_processor_id() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kdebug!("Bring up CPU {}", cpu_id.data());
|
||||||
|
|
||||||
|
if let Err(e) = self.cpu_up(cpu_id, CpuHpState::Online) {
|
||||||
|
kerror!("Failed to bring up CPU {}: {:?}", cpu_id.data(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kinfo!("All non-boot CPUs have been brought up");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cpu_up(&self, cpu_id: ProcessorId, target_state: CpuHpState) -> Result<(), SystemError> {
|
||||||
|
if !self.possible_cpus().get(cpu_id).unwrap_or(false) {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cpu_state = self.cpuhp_state(cpu_id).state;
|
||||||
|
kdebug!(
|
||||||
|
"cpu_up: cpu_id: {}, cpu_state: {:?}, target_state: {:?}",
|
||||||
|
cpu_id.data(),
|
||||||
|
cpu_state,
|
||||||
|
target_state
|
||||||
|
);
|
||||||
|
// 如果CPU的状态已经达到或者超过目标状态,则直接返回
|
||||||
|
if cpu_state >= target_state {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { self.set_cpuhp_state(cpu_id, target_state) };
|
||||||
|
let cpu_state = self.cpuhp_state(cpu_id).state;
|
||||||
|
if cpu_state > CpuHpState::ThresholdBringUp {
|
||||||
|
self.cpuhp_kick_ap(cpu_id, target_state)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cpuhp_kick_ap(
|
||||||
|
&self,
|
||||||
|
cpu_id: ProcessorId,
|
||||||
|
target_state: CpuHpState,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
let prev_state = unsafe { self.set_cpuhp_state(cpu_id, target_state) };
|
||||||
|
let hpstate = self.cpuhp_state_mut(cpu_id);
|
||||||
|
if let Err(e) = self.do_cpuhp_kick_ap(hpstate) {
|
||||||
|
self.cpuhp_reset_state(hpstate, prev_state);
|
||||||
|
self.do_cpuhp_kick_ap(hpstate).ok();
|
||||||
|
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_cpuhp_kick_ap(&self, cpu_state: &mut CpuHpCpuState) -> Result<(), SystemError> {
|
||||||
|
let pcb = cpu_state.thread.as_ref().ok_or(SystemError::EINVAL)?;
|
||||||
|
let cpu_id = pcb.sched_info().on_cpu().ok_or(SystemError::EINVAL)?;
|
||||||
|
|
||||||
|
// todo: 等待CPU启动完成
|
||||||
|
|
||||||
|
ProcessManager::wakeup(cpu_state.thread.as_ref().unwrap())?;
|
||||||
|
CurrentSMPArch::start_cpu(cpu_id, cpu_state)?;
|
||||||
|
assert_eq!(ProcessManager::current_pcb().preempt_count(), 0);
|
||||||
|
self.wait_for_ap_thread(cpu_state, cpu_state.bringup);
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_for_ap_thread(&self, cpu_state: &mut CpuHpCpuState, bringup: bool) {
|
||||||
|
if bringup {
|
||||||
|
cpu_state.comp_done_up.wait_for_completion().ok();
|
||||||
|
} else {
|
||||||
|
todo!("wait_for_ap_thread")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 完成AP的启动
|
||||||
|
pub fn complete_ap_thread(&self, bringup: bool) {
|
||||||
|
let cpu_id = smp_get_processor_id();
|
||||||
|
let cpu_state = self.cpuhp_state_mut(cpu_id);
|
||||||
|
if bringup {
|
||||||
|
cpu_state.comp_done_up.complete();
|
||||||
|
} else {
|
||||||
|
todo!("complete_ap_thread")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cpuhp_reset_state(&self, st: &mut CpuHpCpuState, prev_state: CpuHpState) {
|
||||||
|
let bringup = !st.bringup;
|
||||||
|
st.target_state = prev_state;
|
||||||
|
|
||||||
|
st.bringup = bringup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn smp_cpu_manager_init(boot_cpu: ProcessorId) {
|
pub fn smp_cpu_manager_init(boot_cpu: ProcessorId) {
|
||||||
|
27
kernel/src/smp/init.rs
Normal file
27
kernel/src/smp/init.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use crate::{
|
||||||
|
arch::{syscall::arch_syscall_init, CurrentIrqArch, CurrentSchedArch},
|
||||||
|
exception::InterruptArch,
|
||||||
|
process::ProcessManager,
|
||||||
|
sched::SchedArch,
|
||||||
|
smp::{core::smp_get_processor_id, cpu::smp_cpu_manager},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn smp_ap_start_stage2() -> ! {
|
||||||
|
assert_eq!(CurrentIrqArch::is_irq_enabled(), false);
|
||||||
|
|
||||||
|
smp_cpu_manager().complete_ap_thread(true);
|
||||||
|
|
||||||
|
do_ap_start_stage2();
|
||||||
|
|
||||||
|
CurrentSchedArch::initial_setup_sched_local();
|
||||||
|
|
||||||
|
CurrentSchedArch::enable_sched_local();
|
||||||
|
ProcessManager::arch_idle_func();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
fn do_ap_start_stage2() {
|
||||||
|
kinfo!("Successfully started AP {}", smp_get_processor_id().data());
|
||||||
|
arch_syscall_init().expect("AP core failed to initialize syscall");
|
||||||
|
}
|
@ -1,18 +1,18 @@
|
|||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::interrupt::ipi::send_ipi,
|
arch::{interrupt::ipi::send_ipi, CurrentSMPArch},
|
||||||
exception::ipi::{IpiKind, IpiTarget},
|
exception::ipi::{IpiKind, IpiTarget},
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
core::smp_get_processor_id,
|
core::smp_get_processor_id,
|
||||||
cpu::{smp_cpu_manager_init, ProcessorId},
|
cpu::{smp_cpu_manager, smp_cpu_manager_init, CpuHpCpuState, ProcessorId},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod c_adapter;
|
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
|
pub mod init;
|
||||||
|
|
||||||
pub fn kick_cpu(cpu_id: ProcessorId) -> Result<(), SystemError> {
|
pub fn kick_cpu(cpu_id: ProcessorId) -> Result<(), SystemError> {
|
||||||
// todo: 增加对cpu_id的有效性检查
|
// todo: 增加对cpu_id的有效性检查
|
||||||
@ -27,10 +27,17 @@ pub trait SMPArch {
|
|||||||
/// 该函数需要标记为 `#[inline(never)]`
|
/// 该函数需要标记为 `#[inline(never)]`
|
||||||
fn prepare_cpus() -> Result<(), SystemError>;
|
fn prepare_cpus() -> Result<(), SystemError>;
|
||||||
|
|
||||||
/// 初始化SMP
|
/// 在smp初始化结束后,执行一些必要的操作
|
||||||
///
|
///
|
||||||
/// 该函数需要标记为 `#[inline(never)]`
|
/// 该函数需要标记为 `#[inline(never)]`
|
||||||
fn init() -> Result<(), SystemError>;
|
fn post_init() -> Result<(), SystemError> {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 向目标CPU发送启动信号
|
||||||
|
///
|
||||||
|
/// 如果目标CPU已经启动,返回Ok。
|
||||||
|
fn start_cpu(cpu_id: ProcessorId, hp_state: &CpuHpCpuState) -> Result<(), SystemError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 早期SMP初始化
|
/// 早期SMP初始化
|
||||||
@ -40,3 +47,10 @@ pub fn early_smp_init() -> Result<(), SystemError> {
|
|||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn smp_init() {
|
||||||
|
smp_cpu_manager().bringup_nonboot_cpus();
|
||||||
|
|
||||||
|
CurrentSMPArch::post_init().expect("SMP post init failed");
|
||||||
|
}
|
||||||
|
@ -1,182 +0,0 @@
|
|||||||
#include "smp.h"
|
|
||||||
#include <common/cpu.h>
|
|
||||||
#include <common/kprint.h>
|
|
||||||
#include <common/spinlock.h>
|
|
||||||
#include <mm/slab.h>
|
|
||||||
#include <process/process.h>
|
|
||||||
|
|
||||||
#include <process/preempt.h>
|
|
||||||
#include <sched/sched.h>
|
|
||||||
#include <driver/acpi/acpi.h>
|
|
||||||
#include <arch/arch.h>
|
|
||||||
|
|
||||||
/* x86-64 specific MSRs */
|
|
||||||
#define MSR_EFER 0xc0000080 /* extended feature register */
|
|
||||||
#define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */
|
|
||||||
#define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */
|
|
||||||
#define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */
|
|
||||||
|
|
||||||
static spinlock_t multi_core_starting_lock = {1}; // 多核启动锁
|
|
||||||
|
|
||||||
static uint32_t total_processor_num = 0;
|
|
||||||
static int current_starting_cpu = 0;
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
void smp_init()
|
|
||||||
{
|
|
||||||
spin_init(&multi_core_starting_lock); // 初始化多核启动锁
|
|
||||||
#if ARCH(I386) || ARCH(X86_64)
|
|
||||||
// 设置多核启动时,要加载的页表
|
|
||||||
__APU_START_CR3 = (uint64_t)get_CR3();
|
|
||||||
|
|
||||||
// kdebug("processor num=%d", total_processor_num);
|
|
||||||
total_processor_num = rs_smp_get_cpus(__cpu_info);
|
|
||||||
|
|
||||||
// 将引导程序复制到物理地址0x20000处
|
|
||||||
memcpy((unsigned char *)phys_2_virt(0x20000), _apu_boot_start,
|
|
||||||
(unsigned long)&_apu_boot_end - (unsigned long)&_apu_boot_start);
|
|
||||||
io_mfence();
|
|
||||||
|
|
||||||
|
|
||||||
io_mfence();
|
|
||||||
|
|
||||||
io_mfence();
|
|
||||||
rs_ipi_send_smp_init();
|
|
||||||
|
|
||||||
kdebug("total_processor_num=%d", total_processor_num);
|
|
||||||
|
|
||||||
int core_to_start = 0;
|
|
||||||
// total_processor_num = 3;
|
|
||||||
for (int i = 0; i < total_processor_num; ++i) // i从1开始,不初始化bsp
|
|
||||||
{
|
|
||||||
io_mfence();
|
|
||||||
|
|
||||||
// 跳过BSP
|
|
||||||
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 (__cpu_info[i].can_boot == false)
|
|
||||||
{
|
|
||||||
// --total_processor_num;
|
|
||||||
kdebug("processor %d cannot be enabled.", __cpu_info[i].core_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++core_to_start;
|
|
||||||
// continue;
|
|
||||||
io_mfence();
|
|
||||||
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", __cpu_info[i].apic_id);
|
|
||||||
// 连续发送两次start-up IPI
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
io_mfence();
|
|
||||||
while (num_cpu_started != (core_to_start + 1))
|
|
||||||
pause();
|
|
||||||
|
|
||||||
kinfo("Cleaning page table remapping...\n");
|
|
||||||
|
|
||||||
// 由于ap处理器初始化过程需要用到0x00处的地址,因此初始化完毕后才取消内存地址的重映射
|
|
||||||
rs_unmap_at_low_addr();
|
|
||||||
kinfo("Successfully cleaned page table remapping!\n");
|
|
||||||
#endif
|
|
||||||
io_mfence();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AP处理器启动后执行的第一个函数
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void smp_ap_start_stage2()
|
|
||||||
{
|
|
||||||
|
|
||||||
ksuccess("AP core %d successfully started!", current_starting_cpu);
|
|
||||||
io_mfence();
|
|
||||||
++num_cpu_started;
|
|
||||||
io_mfence();
|
|
||||||
#if ARCH(I386) || ARCH(X86_64)
|
|
||||||
rs_apic_init_ap();
|
|
||||||
|
|
||||||
// ============ 为ap处理器初始化IDLE进程 =============
|
|
||||||
|
|
||||||
barrier();
|
|
||||||
|
|
||||||
io_mfence();
|
|
||||||
spin_unlock_no_preempt(&multi_core_starting_lock);
|
|
||||||
|
|
||||||
rs_init_syscall_64();
|
|
||||||
|
|
||||||
rs_init_current_core_sched();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sti();
|
|
||||||
sched();
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
// kdebug("123");
|
|
||||||
hlt();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
printk_color(BLACK, WHITE, "CPU:%d IDLE process.\n", rs_current_cpu_id());
|
|
||||||
}
|
|
||||||
while (1) // 这里要循环hlt,原因是当收到中断后,核心会被唤醒,处理完中断之后不会自动hlt
|
|
||||||
hlt();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取当前全部的cpu数目
|
|
||||||
*
|
|
||||||
* @return uint32_t
|
|
||||||
*/
|
|
||||||
uint32_t smp_get_total_cpu()
|
|
||||||
{
|
|
||||||
return num_cpu_started;
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <common/glib.h>
|
|
||||||
#include <common/stddef.h>
|
|
||||||
#include <common/asm.h>
|
|
||||||
|
|
||||||
#define MAX_SUPPORTED_PROCESSOR_NUM 1024
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern uchar _apu_boot_start[];
|
|
||||||
extern uchar _apu_boot_end[];
|
|
||||||
/**
|
|
||||||
* @brief 初始化对称多核处理器
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void smp_init();
|
|
||||||
|
|
||||||
extern int64_t rs_kick_cpu(uint32_t cpu_id);
|
|
||||||
|
|
||||||
uint32_t smp_get_total_cpu();
|
|
||||||
|
|
||||||
extern void set_current_core_tss(uint64_t stack_start, uint64_t ist0);
|
|
||||||
extern void rs_load_current_core_tss();
|
|
@ -425,4 +425,15 @@ impl From<Duration> for smoltcp::time::Duration {
|
|||||||
pub trait TimeArch {
|
pub trait TimeArch {
|
||||||
/// Get CPU cycles (Read from register)
|
/// Get CPU cycles (Read from register)
|
||||||
fn get_cycles() -> usize;
|
fn get_cycles() -> usize;
|
||||||
|
|
||||||
|
/// Calculate expire cycles
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `ns` - The time to expire in nanoseconds
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// The expire cycles
|
||||||
|
fn cal_expire_cycles(ns: usize) -> usize;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use system_error::SystemError;
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::{sched::sched, CurrentIrqArch, CurrentTimeArch},
|
arch::{sched::sched, CurrentIrqArch, CurrentTimeArch},
|
||||||
exception::InterruptArch,
|
exception::InterruptArch,
|
||||||
include::bindings::bindings::{useconds_t, Cpu_tsc_freq},
|
include::bindings::bindings::useconds_t,
|
||||||
process::ProcessManager,
|
process::ProcessManager,
|
||||||
time::timekeeping::getnstimeofday,
|
time::timekeeping::getnstimeofday,
|
||||||
};
|
};
|
||||||
@ -29,11 +29,8 @@ pub fn nanosleep(sleep_time: TimeSpec) -> Result<TimeSpec, SystemError> {
|
|||||||
}
|
}
|
||||||
// 对于小于500us的时间,使用spin/rdtsc来进行定时
|
// 对于小于500us的时间,使用spin/rdtsc来进行定时
|
||||||
if sleep_time.tv_nsec < 500000 && sleep_time.tv_sec == 0 {
|
if sleep_time.tv_nsec < 500000 && sleep_time.tv_sec == 0 {
|
||||||
let expired_tsc: u64 = unsafe {
|
let expired_tsc: usize = CurrentTimeArch::cal_expire_cycles(sleep_time.tv_nsec as usize);
|
||||||
CurrentTimeArch::get_cycles() as u64
|
while CurrentTimeArch::get_cycles() < expired_tsc {
|
||||||
+ (sleep_time.tv_nsec as u64 * Cpu_tsc_freq) / 1000000000
|
|
||||||
};
|
|
||||||
while (CurrentTimeArch::get_cycles() as u64) < expired_tsc {
|
|
||||||
spin_loop()
|
spin_loop()
|
||||||
}
|
}
|
||||||
return Ok(TimeSpec {
|
return Ok(TimeSpec {
|
||||||
|
@ -262,7 +262,9 @@ pub fn next_n_us_timer_jiffies(expire_us: u64) -> u64 {
|
|||||||
pub fn schedule_timeout(mut timeout: i64) -> Result<i64, SystemError> {
|
pub fn schedule_timeout(mut timeout: i64) -> Result<i64, SystemError> {
|
||||||
// kdebug!("schedule_timeout");
|
// kdebug!("schedule_timeout");
|
||||||
if timeout == MAX_TIMEOUT {
|
if timeout == MAX_TIMEOUT {
|
||||||
|
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||||
ProcessManager::mark_sleep(true).ok();
|
ProcessManager::mark_sleep(true).ok();
|
||||||
|
drop(irq_guard);
|
||||||
sched();
|
sched();
|
||||||
return Ok(MAX_TIMEOUT);
|
return Ok(MAX_TIMEOUT);
|
||||||
} else if timeout < 0 {
|
} else if timeout < 0 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user