使用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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 2638 additions and 1367 deletions

View File

@ -183,4 +183,8 @@
"./kernel/Cargo.toml",
"./kernel/src/libs/ida/Cargo.toml"
],
"rust-analyzer.check.overrideCommand": [
"make",
"check"
],
}

View File

@ -21,6 +21,7 @@ backtrace = []
[dependencies]
x86 = "0.52.0"
x86_64 = "0.14.10"
bit_field = "0.10"
bitflags = "1.3.2"
bitfield-struct = "0.5.3"
virtio-drivers = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/virtio-drivers.git", rev = "f1d1cbb" }

View File

@ -11,3 +11,7 @@ clean:
.PHONY: fmt
fmt:
cargo fmt --all $(FMT_CHECK)
check:
cargo +nightly-2023-01-21 check --workspace --message-format=json --target ./src/arch/x86_64/x86_64-unknown-none.json

View File

@ -91,7 +91,6 @@ impl CFilesBuilder {
c.define("__x86_64__", None);
}
c.define("PIC", "_INTR_APIC_");
}
fn setup_global_include_dir(c: &mut Build) {
@ -105,6 +104,76 @@ impl CFilesBuilder {
/// 设置需要编译的文件
fn setup_files(c: &mut Build) {
c.file("src/arch/x86_64/driver/hpet.c");
let mut files = Vec::new();
#[cfg(target_arch = "x86_64")]
Self::setup_files_x86_64(&mut files);
Self::set_rerun_if_files_changed(&files);
c.files(files.as_slice());
}
/// 设置x86_64架构下需要编译的C文件
fn setup_files_x86_64(files: &mut Vec<PathBuf>) {
files.push(PathBuf::from("src/arch/x86_64/driver/hpet.c"));
// 获取`kernel/src/arch/x86_64/driver/apic`下的所有C文件
files.append(&mut FileUtils::list_all_files(
&PathBuf::from("src/arch/x86_64/driver/apic"),
Some("c"),
true,
));
}
/// 设置Cargo对文件更改的监听
fn set_rerun_if_files_changed(files: &Vec<PathBuf>) {
for f in files {
println!("cargo:rerun-if-changed={}", f.to_str().unwrap());
}
}
}
struct FileUtils;
impl FileUtils {
/// 列出指定目录下的所有文件
///
/// ## 参数
///
/// - `path` - 指定的目录
/// - `ext_name` - 文件的扩展名如果为None则列出所有文件
/// - `recursive` - 是否递归列出所有文件
pub fn list_all_files(path: &PathBuf, ext_name: Option<&str>, recursive: bool) -> Vec<PathBuf> {
let mut queue: Vec<PathBuf> = Vec::new();
let mut result = Vec::new();
queue.push(path.clone());
while !queue.is_empty() {
let path = queue.pop().unwrap();
let d = std::fs::read_dir(path);
if d.is_err() {
continue;
}
let d = d.unwrap();
d.for_each(|ent| {
if let Ok(ent) = ent {
if let Ok(file_type) = ent.file_type() {
if file_type.is_file() {
if let Some(e) = ext_name {
if let Some(ext) = ent.path().extension() {
if ext == e {
result.push(ent.path());
}
}
}
} else if file_type.is_dir() && recursive {
queue.push(ent.path());
}
}
}
});
}
return result;
}
}

View File

@ -8,9 +8,6 @@ lib_patterns := *.a
LIB_FILES := $(foreach DIR,$(DIR_LIB),$(addprefix $(DIR)/,$(lib_patterns)))
# 控制操作系统使用的中断控制器 _INTR_8259A_ _INTR_APIC_
PIC := _INTR_APIC_
# unwind/backtrace related
UNWIND_ENABLE ?= yes
CFLAGS_UNWIND =
@ -22,14 +19,14 @@ ifeq ($(UNWIND_ENABLE), yes)
RUSTFLAGS_UNWIND = -Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld
endif
CFLAGS = $(GLOBAL_CFLAGS) -fno-pie $(CFLAGS_UNWIND) -D $(PIC) -I $(shell pwd) -I $(shell pwd)/include -I $(shell pwd)/arch/x86_64/include
CFLAGS = $(GLOBAL_CFLAGS) -fno-pie $(CFLAGS_UNWIND) -I $(shell pwd) -I $(shell pwd)/include -I $(shell pwd)/arch/x86_64/include
export ASFLAGS := --64
LD_LIST := head.o
kernel_subdirs := common driver debug arch exception smp sched syscall ktest libs time
kernel_subdirs := common driver debug arch exception smp syscall ktest libs time
head.o: head.S
@ -43,9 +40,8 @@ main.o: main.c
$(CC) $(CFLAGS) -c main.c -o main.o
kernel_rust:
rustup default nightly
RUSTFLAGS="$(RUSTFLAGS_UNWIND)" cargo +nightly-2023-01-21 build --release --target ./arch/x86_64/x86_64-unknown-none.json
all: kernel
@echo "Linking kernel..."
@ -78,7 +74,7 @@ ECHO:
$(kernel_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)" kernel_root_path="$(shell pwd)"
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" kernel_root_path="$(shell pwd)"
kernel: head.o main.o $(kernel_subdirs) kernel_rust

View File

@ -9,7 +9,7 @@ all:
@list='$(kernel_arch_subdirs)'; for subdir in $$list; do \
echo "make all in $$subdir";\
cd $$subdir;\
$(MAKE) all CFLAGS="$(CFLAGS)" PIC="$(PIC)";\
$(MAKE) all CFLAGS="$(CFLAGS)" ;\
cd ..;\
done

View File

@ -13,7 +13,7 @@ $(kernel_arch_x86_64_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
$(kernel_arch_x86_64_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)"
all: $(kernel_arch_x86_64_objs) $(kernel_arch_x86_64_subdirs)

View File

@ -13,7 +13,7 @@ $(kernel_arch_x86_64_asm_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
# $(kernel_arch_x86_64_asm_subdirs): ECHO
# $(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
# $(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)"
all: $(kernel_arch_x86_64_asm_objs)

View File

@ -0,0 +1,228 @@
#include "apic.h"
#include "apic_timer.h"
#include <common/cpu.h>
#include <common/glib.h>
#include <common/kprint.h>
#include <common/printk.h>
#include <driver/acpi/acpi.h>
#include <exception/gate.h>
#include <exception/softirq.h>
#include <process/process.h>
#include <sched/sched.h>
#pragma GCC push_options
#pragma GCC optimize("O0")
// 导出定义在irq.c中的中段门表
extern void (*interrupt_table[26])(void);
extern uint32_t rs_current_pcb_preempt_count();
extern uint32_t rs_current_pcb_pid();
extern uint32_t rs_current_pcb_flags();
extern void rs_apic_init_bsp();
extern void rs_apic_local_apic_edge_ack(uint8_t irq_num);
extern int rs_ioapic_install(uint8_t vector, uint8_t dest, bool level_triggered, bool active_high, bool dest_logical);
extern void rs_ioapic_uninstall(uint8_t irq_num);
extern void rs_ioapic_enable(uint8_t irq_num);
extern void rs_ioapic_disable(uint8_t irq_num);
/**
* @brief apic控制器
*
*/
int apic_init()
{
cli();
kinfo("Initializing APIC...");
// 初始化中断门, 中断使用rsp0防止在软中断时发生嵌套然后处理器重新加载导致数据被抹掉
for (int i = 32; i <= 57; ++i)
set_intr_gate(i, 0, interrupt_table[i - 32]);
// 设置local apic中断门
for (int i = 150; i < 160; ++i)
set_intr_gate(i, 0, local_apic_interrupt_table[i - 150]);
// 初始化BSP的APIC
rs_apic_init_bsp();
kinfo("APIC initialized.");
// sti();
return 0;
}
/**
* @brief
*
* @param rsp
* @param number
*/
void do_IRQ(struct pt_regs *rsp, ul number)
{
if((rsp->cs & 0x3) == 3)
{
asm volatile("swapgs":::"memory");
}
if (number < 0x80 && number >= 32) // 以0x80为界限低于0x80的是外部中断控制器高于0x80的是Local APIC
{
// ==========外部中断控制器========
irq_desc_t *irq = &interrupt_desc[number - 32];
// 执行中断上半部处理程序
if (irq != NULL && irq->handler != NULL)
irq->handler(number, irq->parameter, rsp);
else
kwarn("Intr vector [%d] does not have a handler!");
// 向中断控制器发送应答消息
// if (irq->controller != NULL && irq->controller->ack != NULL)
// irq->controller->ack(number);
// else
// rs_apic_local_apic_edge_ack(number);
rs_apic_local_apic_edge_ack(number);
}
else if (number >= 200)
{
rs_apic_local_apic_edge_ack(number);
{
irq_desc_t *irq = &SMP_IPI_desc[number - 200];
if (irq->handler != NULL)
irq->handler(number, irq->parameter, rsp);
}
}
else if (number >= 150 && number < 200)
{
irq_desc_t *irq = &local_apic_interrupt_desc[number - 150];
// 执行中断上半部处理程序
if (irq != NULL && irq->handler != NULL)
irq->handler(number, irq->parameter, rsp);
else
kwarn("Intr vector [%d] does not have a handler!");
// 向中断控制器发送应答消息
// if (irq->controller != NULL && irq->controller->ack != NULL)
// irq->controller->ack(number);
// else
// rs_apic_local_apic_edge_ack(number);
rs_apic_local_apic_edge_ack(number);
}
else
{
kwarn("do IRQ receive: %d", number);
// 忽略未知中断
return;
}
// kdebug("before softirq");
// 进入软中断处理程序
rs_do_softirq();
// kdebug("after softirq");
// 检测当前进程是否持有自旋锁,若持有自旋锁,则不进行抢占式的进程调度
if (rs_current_pcb_preempt_count() > 0)
{
return;
}
else if ((int32_t)rs_current_pcb_preempt_count() < 0)
kBUG("current_pcb->preempt_count<0! pid=%d", rs_current_pcb_pid()); // should not be here
// 检测当前进程是否可被调度
if ((rs_current_pcb_flags() & PF_NEED_SCHED) && number == APIC_TIMER_IRQ_NUM)
{
io_mfence();
sched();
}
}
// =========== 中断控制操作接口 ============
void apic_ioapic_enable(ul irq_num)
{
rs_ioapic_enable(irq_num);
}
void apic_ioapic_disable(ul irq_num)
{
rs_ioapic_disable(irq_num);
}
ul apic_ioapic_install(ul irq_num, void *arg)
{
struct apic_IO_APIC_RTE_entry *entry = (struct apic_IO_APIC_RTE_entry *)arg;
uint8_t dest = 0;
if (entry->dest_mode)
{
dest = entry->destination.logical.logical_dest;
}
else
{
dest = entry->destination.physical.phy_dest;
}
return rs_ioapic_install(entry->vector, dest, entry->trigger_mode, entry->polarity, entry->dest_mode);
}
void apic_ioapic_uninstall(ul irq_num)
{
rs_ioapic_uninstall(irq_num);
}
void apic_ioapic_edge_ack(ul irq_num) // 边沿触发
{
rs_apic_local_apic_edge_ack(irq_num);
}
/**
* @brief local apic 沿
*
* @param irq_num
*/
void apic_local_apic_edge_ack(ul irq_num)
{
rs_apic_local_apic_edge_ack(irq_num);
}
/**
* @brief RTE Entry结构体
*
* @param entry
* @param vector
* @param deliver_mode
* @param dest_mode
* @param deliver_status
* @param polarity
* @param irr IRR标志位
* @param trigger
* @param mask 0 1
* @param dest_apicID apicID
*/
void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, uint8_t deliver_mode, uint8_t dest_mode,
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask,
uint8_t dest_apicID)
{
entry->vector = vector;
entry->deliver_mode = deliver_mode;
entry->dest_mode = dest_mode;
entry->deliver_status = deliver_status;
entry->polarity = polarity;
entry->remote_IRR = irr;
entry->trigger_mode = trigger;
entry->mask = mask;
entry->reserved = 0;
if (dest_mode == DEST_PHYSICAL)
{
entry->destination.physical.phy_dest = dest_apicID;
entry->destination.physical.reserved1 = 0;
entry->destination.physical.reserved2 = 0;
}
else
{
entry->destination.logical.logical_dest = dest_apicID;
entry->destination.logical.reserved1 = 0;
}
}
#pragma GCC pop_options

View File

@ -8,12 +8,6 @@
#pragma GCC push_options
#pragma GCC optimize("O0")
#define APIC_SUCCESS 0
#define APIC_E_NOTFOUND 1
#define APIC_IO_APIC_VIRT_BASE_ADDR SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + IO_APIC_MAPPING_OFFSET
#define APIC_LOCAL_APIC_VIRT_BASE_ADDR SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + LOCAL_APIC_MAPPING_OFFSET
// 当前apic启用状态标志
extern uint8_t __apic_enable_state;
#define APIC_XAPIC_ENABLED 0
@ -113,36 +107,6 @@ struct apic_LVT
} __attribute((packed)); // 取消结构体的align
/*
ICR
*/
struct INT_CMD_REG
{
unsigned int vector : 8, // 0~7
deliver_mode : 3, // 8~10
dest_mode : 1, // 11
deliver_status : 1, // 12
res_1 : 1, // 13
level : 1, // 14
trigger : 1, // 15
res_2 : 2, // 16~17
dest_shorthand : 2, // 18~19
res_3 : 12; // 20~31
union
{
struct
{
unsigned int res_4 : 24, // 32~55
dest_field : 8; // 56~63
} apic_destination;
unsigned int x2apic_destination; // 32~63
} destination;
} __attribute__((packed));
/**
* @brief I/O APIC
*
@ -243,18 +207,6 @@ struct apic_IO_APIC_RTE_entry
#define POLARITY_HIGH 0
#define POLARITY_LOW 1
struct apic_IO_APIC_map
{
// 间接访问寄存器的物理基地址
uint addr_phys;
// 索引寄存器虚拟地址
unsigned char *virtual_index_addr;
// 数据寄存器虚拟地址
uint *virtual_data_addr;
// EOI寄存器虚拟地址
uint *virtual_EOI_addr;
} apic_ioapic_map;
/**
* @brief
*
@ -262,28 +214,7 @@ struct apic_IO_APIC_map
* @param number
*/
void do_IRQ(struct pt_regs *rsp, ul number);
/**
* @brief RTE寄存器
*
* @param index
* @return ul
*/
ul apic_ioapic_read_rte(unsigned char index);
/**
* @brief RTE寄存器
*
* @param index
* @param value
*/
void apic_ioapic_write_rte(unsigned char index, ul value);
/**
* @brief AP处理器的Local apic
*
*/
void apic_init_ap_core_local_apic();
void rs_apic_init_ap();
/**
* @brief apic控制器
@ -291,22 +222,11 @@ void apic_init_ap_core_local_apic();
*/
int apic_init();
/**
* @brief Interrupt Control Structure
*
* @param type ics的类型
* @param ret_vaddr ICS的虚拟地址数组
* @param total
* @return uint
*/
uint apic_get_ics(const uint type, ul ret_vaddr[], uint *total);
// =========== 中断控制操作接口 ============
void apic_ioapic_enable(ul irq_num);
void apic_ioapic_disable(ul irq_num);
ul apic_ioapic_install(ul irq_num, void *arg);
void apic_ioapic_uninstall(ul irq_num);
void apic_ioapic_level_ack(ul irq_num); // ioapic电平触发 应答
void apic_ioapic_edge_ack(ul irq_num); // ioapic边沿触发 应答
// void apic_local_apic_level_ack(ul irq_num);// local apic电平触发 应答
@ -329,7 +249,4 @@ void apic_local_apic_edge_ack(ul irq_num); // local apic边沿触发 应答
void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, uint8_t deliver_mode, uint8_t dest_mode,
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask, uint8_t dest_apicID);
uint32_t apic_get_local_apic_id();
void apic_write_icr(uint64_t value);
bool apic_x2apic_enabled();
#pragma GCC pop_options

View File

@ -4,15 +4,15 @@
#include <process/process.h>
#include <sched/sched.h>
// #pragma GCC push_options
// #pragma GCC optimize("O0")
uint64_t apic_timer_ticks_result = 0;
static spinlock_t apic_timer_init_lock = {1};
// bsp 是否已经完成apic时钟初始化
static bool bsp_initialized = false;
extern uint64_t rs_get_cycles();
extern uint64_t rs_tsc_get_cpu_khz();
extern void rs_apic_timer_install(int irq_num);
extern void rs_apic_timer_uninstall(int irq_num);
extern void rs_apic_timer_enable(int irq_num);
extern void rs_apic_timer_disable(int irq_num);
extern int rs_apic_timer_handle_irq();
/**
* @brief AP核的apic时钟
@ -30,19 +30,12 @@ void apic_timer_ap_core_init()
void apic_timer_enable(uint64_t irq_num)
{
// 启动apic定时器
io_mfence();
uint64_t val = apic_timer_get_LVT();
io_mfence();
val &= (~APIC_LVT_INT_MASKED);
io_mfence();
apic_timer_write_LVT(val);
io_mfence();
rs_apic_timer_enable(irq_num);
}
void apic_timer_disable(uint64_t irq_num)
{
apic_timer_stop();
rs_apic_timer_disable(irq_num);
}
/**
@ -54,33 +47,14 @@ void apic_timer_disable(uint64_t irq_num)
*/
uint64_t apic_timer_install(ul irq_num, void *arg)
{
// 设置div16
io_mfence();
apic_timer_stop();
io_mfence();
apic_timer_set_div(APIC_TIMER_DIVISOR);
io_mfence();
// 设置初始计数
uint64_t cpu_khz = rs_tsc_get_cpu_khz();
// 疑惑这里使用khz吗
// 我觉得应该是hz但是由于旧的代码是测量出initcnt的而不是计算的
// 然后我发现使用hz会导致计算出来的initcnt太大导致系统卡顿而khz的却能跑
// TODO 这里需要进一步研究
uint64_t init_cnt = cpu_khz * APIC_TIMER_INTERVAL / (1000 * APIC_TIMER_DIVISOR);
kdebug("cpu_khz: %ld, init_cnt: %ld", cpu_khz, init_cnt);
apic_timer_set_init_cnt(init_cnt);
io_mfence();
// 填写LVT
apic_timer_set_LVT(APIC_TIMER_IRQ_NUM, 1, APIC_LVT_Timer_Periodic);
io_mfence();
rs_apic_timer_install(irq_num);
return 0;
}
void apic_timer_uninstall(ul irq_num)
{
apic_timer_write_LVT(APIC_LVT_INT_MASKED);
io_mfence();
rs_apic_timer_uninstall(irq_num);
}
hardware_intr_controller apic_timer_intr_controller = {
@ -100,9 +74,7 @@ hardware_intr_controller apic_timer_intr_controller = {
*/
void apic_timer_handler(uint64_t number, uint64_t param, struct pt_regs *regs)
{
io_mfence();
sched_update_jiffies();
io_mfence();
rs_apic_timer_handle_irq();
}
/**
@ -111,9 +83,6 @@ void apic_timer_handler(uint64_t number, uint64_t param, struct pt_regs *regs)
*/
void apic_timer_init()
{
uint64_t flags = 0;
spin_lock_irqsave(&apic_timer_init_lock, flags);
kinfo("Initializing apic timer for cpu %d", rs_current_pcb_cpuid());
io_mfence();
irq_register(APIC_TIMER_IRQ_NUM, NULL, &apic_timer_handler, 0, &apic_timer_intr_controller,
@ -124,5 +93,4 @@ void apic_timer_init()
bsp_initialized = true;
}
kdebug("apic timer init done for cpu %d", rs_current_pcb_cpuid());
spin_unlock_irqrestore(&apic_timer_init_lock, flags);
}

View File

@ -0,0 +1,14 @@
#pragma once
#include <common/unistd.h>
#include "apic.h"
#define APIC_TIMER_IRQ_NUM 151
/**
* @brief local APIC定时器
*
*/
void apic_timer_init();
void apic_timer_ap_core_init();

View File

@ -0,0 +1,257 @@
use core::cell::RefCell;
use crate::arch::driver::tsc::TSCManager;
use crate::include::bindings::bindings::APIC_TIMER_IRQ_NUM;
use crate::kdebug;
use crate::mm::percpu::PerCpu;
use crate::sched::core::sched_update_jiffies;
use crate::smp::core::smp_get_processor_id;
use crate::syscall::SystemError;
pub use drop;
use x86::cpuid::cpuid;
use x86::msr::{wrmsr, IA32_X2APIC_DIV_CONF, IA32_X2APIC_INIT_COUNT};
use super::xapic::XApicOffset;
use super::{CurrentApic, LVTRegister, LocalAPIC, LVT};
static mut LOCAL_APIC_TIMERS: [RefCell<LocalApicTimer>; PerCpu::MAX_CPU_NUM] =
[const { RefCell::new(LocalApicTimer::new()) }; PerCpu::MAX_CPU_NUM];
#[inline(always)]
pub(super) fn local_apic_timer_instance(cpu_id: u32) -> core::cell::Ref<'static, LocalApicTimer> {
unsafe { LOCAL_APIC_TIMERS[cpu_id as usize].borrow() }
}
#[inline(always)]
pub(super) fn local_apic_timer_instance_mut(
cpu_id: u32,
) -> core::cell::RefMut<'static, LocalApicTimer> {
unsafe { LOCAL_APIC_TIMERS[cpu_id as usize].borrow_mut() }
}
/// 初始化BSP的APIC定时器
///
fn init_bsp_apic_timer() {
kdebug!("init_bsp_apic_timer");
assert!(smp_get_processor_id() == 0);
let mut local_apic_timer = local_apic_timer_instance_mut(0);
local_apic_timer.init(
LocalApicTimerMode::Periodic,
LocalApicTimer::periodic_default_initial_count(),
LocalApicTimer::DIVISOR as u32,
);
kdebug!("init_bsp_apic_timer done");
}
fn init_ap_apic_timer() {
kdebug!("init_ap_apic_timer");
let cpu_id = smp_get_processor_id();
assert!(cpu_id != 0);
let mut local_apic_timer = local_apic_timer_instance_mut(cpu_id);
local_apic_timer.init(
LocalApicTimerMode::Periodic,
LocalApicTimer::periodic_default_initial_count(),
LocalApicTimer::DIVISOR as u32,
);
kdebug!("init_ap_apic_timer done");
}
pub(super) struct LocalApicTimerIntrController;
impl LocalApicTimerIntrController {
pub(super) fn install(&self, _irq_num: u8) {
kdebug!("LocalApicTimerIntrController::install");
if smp_get_processor_id() == 0 {
init_bsp_apic_timer();
} else {
init_ap_apic_timer();
}
}
pub(super) fn uninstall(&self) {
let cpu_id = smp_get_processor_id();
let local_apic_timer = local_apic_timer_instance(cpu_id);
local_apic_timer.stop_current();
}
pub(super) fn enable(&self) {
kdebug!("LocalApicTimerIntrController::enable");
let cpu_id = smp_get_processor_id();
let mut local_apic_timer = local_apic_timer_instance_mut(cpu_id);
local_apic_timer.start_current();
}
pub(super) fn disable(&self) {
let cpu_id = smp_get_processor_id();
let local_apic_timer = local_apic_timer_instance_mut(cpu_id);
local_apic_timer.stop_current();
}
}
#[derive(Debug, Copy, Clone)]
pub struct LocalApicTimer {
mode: LocalApicTimerMode,
/// IntialCount
initial_count: u64,
divisor: u32,
/// 是否已经触发oneshot模式
triggered: bool,
}
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
pub enum LocalApicTimerMode {
Oneshot = 0,
Periodic = 1,
Deadline = 2,
}
impl LocalApicTimer {
/// 定时器中断的间隔
pub const INTERVAL_MS: u64 = 5;
pub const DIVISOR: u64 = 3;
/// IoApicManager 初值为0或false
pub const fn new() -> Self {
LocalApicTimer {
mode: LocalApicTimerMode::Periodic,
initial_count: 0,
divisor: 0,
triggered: false,
}
}
/// 周期模式下的默认初始值
pub fn periodic_default_initial_count() -> u64 {
let cpu_khz = TSCManager::cpu_khz();
// 疑惑这里使用khz吗
// 我觉得应该是hz但是由于旧的代码是测量出initcnt的而不是计算的
// 然后我发现使用hz会导致计算出来的initcnt太大导致系统卡顿而khz的却能跑
let count = cpu_khz * Self::INTERVAL_MS / (1000 * Self::DIVISOR);
return count;
}
/// Init this manager.
///
/// At this time, it does nothing.
fn init(&mut self, mode: LocalApicTimerMode, initial_count: u64, divisor: u32) {
self.stop_current();
self.triggered = false;
match mode {
LocalApicTimerMode::Periodic => self.install_periodic_mode(initial_count, divisor),
LocalApicTimerMode::Oneshot => todo!(),
LocalApicTimerMode::Deadline => todo!(),
}
}
fn install_periodic_mode(&mut self, initial_count: u64, divisor: u32) {
kdebug!(
"install_periodic_mode: initial_count = {}, divisor = {}",
initial_count,
divisor
);
self.mode = LocalApicTimerMode::Periodic;
self.set_divisor(divisor);
self.set_initial_cnt(initial_count);
self.setup_lvt(APIC_TIMER_IRQ_NUM as u8, true, LocalApicTimerMode::Periodic);
}
fn setup_lvt(&mut self, vector: u8, mask: bool, mode: LocalApicTimerMode) {
let mode: u32 = mode as u32;
let data = (mode << 17) | (vector as u32) | (if mask { 1 << 16 } else { 0 });
let lvt = LVT::new(LVTRegister::Timer, data).unwrap();
CurrentApic.set_lvt(lvt);
}
fn set_divisor(&mut self, divisor: u32) {
self.divisor = divisor;
CurrentApic.set_timer_divisor(divisor as u32);
}
fn set_initial_cnt(&mut self, initial_count: u64) {
self.initial_count = initial_count;
CurrentApic.set_timer_initial_count(initial_count);
}
fn start_current(&mut self) {
let mut lvt = CurrentApic.read_lvt(LVTRegister::Timer);
lvt.set_mask(false);
CurrentApic.set_lvt(lvt);
}
fn stop_current(&self) {
let mut lvt = CurrentApic.read_lvt(LVTRegister::Timer);
lvt.set_mask(true);
CurrentApic.set_lvt(lvt);
}
/// 检查是否支持TSC-Deadline
///
/// 此函数调用cpuid请避免多次调用此函数。
/// 如果支持TSC-Deadline模式则除非TSC为常数否则不会启用该模式。
#[allow(dead_code)]
pub fn is_deadline_mode_supported(&self) -> bool {
let res = cpuid!(1);
return (res.ecx & (1 << 24)) != 0;
}
pub(super) fn handle_irq() -> Result<(), SystemError> {
sched_update_jiffies();
return Ok(());
}
}
impl TryFrom<u8> for LocalApicTimerMode {
type Error = SystemError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0b00 => {
return Ok(LocalApicTimerMode::Oneshot);
}
0b01 => {
return Ok(LocalApicTimerMode::Periodic);
}
0b10 => {
return Ok(LocalApicTimerMode::Deadline);
}
_ => {
return Err(SystemError::EINVAL);
}
}
}
}
impl CurrentApic {
fn set_timer_divisor(&self, divisor: u32) {
if self.x2apic_enabled() {
unsafe { wrmsr(IA32_X2APIC_DIV_CONF, divisor.into()) };
} else {
unsafe {
self.write_xapic_register(
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_CLKDIV,
divisor.into(),
)
};
}
}
fn set_timer_initial_count(&self, initial_count: u64) {
if self.x2apic_enabled() {
unsafe {
wrmsr(IA32_X2APIC_INIT_COUNT.into(), initial_count);
}
} else {
unsafe {
self.write_xapic_register(
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG,
initial_count as u32,
)
};
}
}
}

View File

@ -0,0 +1,84 @@
use super::{
apic_timer::{LocalApicTimer, LocalApicTimerIntrController},
ioapic::{ioapic_disable, ioapic_enable, ioapic_install, ioapic_uninstall},
CurrentApic, LocalAPIC,
};
#[no_mangle]
unsafe extern "C" fn rs_apic_timer_install(irq_num: u8) {
LocalApicTimerIntrController.install(irq_num);
}
#[no_mangle]
unsafe extern "C" fn rs_apic_timer_uninstall(_irq_num: u8) {
LocalApicTimerIntrController.uninstall();
}
#[no_mangle]
unsafe extern "C" fn rs_apic_timer_enable(_irq_num: u8) {
LocalApicTimerIntrController.enable();
}
#[no_mangle]
unsafe extern "C" fn rs_apic_timer_disable(_irq_num: u8) {
LocalApicTimerIntrController.disable();
}
#[no_mangle]
unsafe extern "C" fn rs_apic_local_apic_edge_ack(_irq_num: u8) {
CurrentApic.send_eoi();
}
/// 初始化bsp处理器的apic
#[no_mangle]
pub extern "C" fn rs_apic_init_bsp() -> i32 {
if CurrentApic.init_current_cpu() {
return 0;
}
return -1;
}
#[no_mangle]
pub extern "C" fn rs_apic_init_ap() -> i32 {
if CurrentApic.init_current_cpu() {
return 0;
}
return -1;
}
#[no_mangle]
unsafe extern "C" fn rs_ioapic_install(
vector: u8,
dest: u8,
level_triggered: bool,
active_high: bool,
dest_logic: bool,
) -> i32 {
return ioapic_install(vector, dest, level_triggered, active_high, dest_logic)
.map(|_| 0)
.unwrap_or_else(|e| e.to_posix_errno());
}
#[no_mangle]
unsafe extern "C" fn rs_ioapic_uninstall(vector: u8) {
ioapic_uninstall(vector);
}
#[no_mangle]
unsafe extern "C" fn rs_ioapic_enable(vector: u8) {
ioapic_enable(vector);
}
#[no_mangle]
unsafe extern "C" fn rs_ioapic_disable(vector: u8) {
ioapic_disable(vector);
}
#[no_mangle]
unsafe extern "C" fn rs_apic_timer_handle_irq(_irq_num: u8) -> i32 {
return LocalApicTimer::handle_irq()
.map(|_| 0)
.unwrap_or_else(|e| e.to_posix_errno());
}

View File

@ -0,0 +1,364 @@
use core::ptr::NonNull;
use acpi::madt::Madt;
use bit_field::BitField;
use bitflags::bitflags;
use crate::{
driver::acpi::acpi_manager,
kdebug, kinfo,
libs::{
once::Once,
spinlock::SpinLock,
volatile::{volwrite, Volatile},
},
mm::{
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
PhysAddr,
},
syscall::SystemError,
};
use super::{CurrentApic, LocalAPIC};
static mut __IOAPIC: Option<SpinLock<IoApic>> = None;
#[allow(non_snake_case)]
fn IOAPIC() -> &'static SpinLock<IoApic> {
unsafe { __IOAPIC.as_ref().unwrap() }
}
#[allow(dead_code)]
pub struct IoApic {
reg: *mut u32,
data: *mut u32,
virt_eoi: *mut u32,
phys_base: PhysAddr,
mmio_guard: MMIOSpaceGuard,
}
impl IoApic {
/// IO APIC的中断向量号从32开始
pub const VECTOR_BASE: u8 = 32;
/// Create a new IOAPIC.
///
/// # Safety
///
/// You must provide a valid address.
pub unsafe fn new() -> Self {
static INIT_STATE: Once = Once::new();
assert!(!INIT_STATE.is_completed());
let mut result: Option<IoApic> = None;
INIT_STATE.call_once(|| {
kinfo!("Initializing ioapic...");
// get ioapic base from acpi
let madt = acpi_manager()
.tables()
.unwrap()
.find_table::<Madt>()
.expect("IoApic::new(): failed to find MADT");
let io_apic_paddr = madt
.entries()
.find(|x| {
if let acpi::madt::MadtEntry::IoApic(_x) = x {
return true;
}
return false;
})
.map(|x| {
if let acpi::madt::MadtEntry::IoApic(x) = x {
Some(x.io_apic_address)
} else {
None
}
})
.flatten()
.unwrap();
let phys_base = PhysAddr::new(io_apic_paddr as usize);
let mmio_guard = mmio_pool()
.create_mmio(0x1000)
.expect("IoApic::new(): failed to create mmio");
assert!(
mmio_guard.map_phys(phys_base, 0x1000).is_ok(),
"IoApic::new(): failed to map phys"
);
kdebug!("Ioapic map ok");
let reg = mmio_guard.vaddr();
result = Some(IoApic {
reg: reg.data() as *mut u32,
data: (reg + 0x10).data() as *mut u32,
virt_eoi: (reg + 0x40).data() as *mut u32,
phys_base,
mmio_guard,
});
kdebug!("IOAPIC: to mask all RTE");
// 屏蔽所有的RTE
let res_mut = result.as_mut().unwrap();
for i in 0..res_mut.supported_interrupts() {
res_mut.write_rte(i, 0x20 + i, RedirectionEntry::DISABLED, 0);
}
kdebug!("Ioapic init done");
});
assert!(
result.is_some(),
"Failed to init ioapic, maybe this is a double initialization bug?"
);
return result.unwrap();
}
/// Disable all interrupts.
#[allow(dead_code)]
pub fn disable_all(&mut self) {
// Mark all interrupts edge-triggered, active high, disabled,
// and not routed to any CPUs.
for i in 0..self.supported_interrupts() {
self.disable(i);
}
}
unsafe fn read(&mut self, reg: u8) -> u32 {
assert!(!(0x3..REG_TABLE).contains(&reg));
self.reg.write_volatile(reg as u32);
self.data.read_volatile()
}
/// 直接写入REG_TABLE内的寄存器
///
/// ## 参数
///
/// * `reg` - 寄存器下标
/// * `data` - 寄存器数据
unsafe fn write(&mut self, reg: u8, data: u32) {
// 0x1 & 0x2 are read-only regs
assert!(!(0x1..REG_TABLE).contains(&reg));
self.reg.write_volatile(reg as u32);
self.data.write_volatile(data);
}
fn write_rte(&mut self, rte_index: u8, vector: u8, flags: RedirectionEntry, dest: u8) {
unsafe {
self.write(REG_TABLE + 2 * rte_index, vector as u32 | flags.bits());
self.write(REG_TABLE + 2 * rte_index + 1, (dest as u32) << 24);
}
}
/// 标记中断边沿触发、高电平有效、
/// 启用并路由到给定的 cpunum即是是该 cpu 的 APIC ID不是cpuid
pub fn enable(&mut self, rte_index: u8) {
let mut val = unsafe { self.read(REG_TABLE + 2 * rte_index) };
val &= !RedirectionEntry::DISABLED.bits();
unsafe { self.write(REG_TABLE + 2 * rte_index, val) };
}
pub fn disable(&mut self, rte_index: u8) {
let reg = REG_TABLE + 2 * rte_index;
let mut val = unsafe { self.read(reg) };
val |= RedirectionEntry::DISABLED.bits();
unsafe { self.write(reg, val) };
}
/// 安装中断
///
/// ## 参数
///
/// * `rte_index` - RTE下标
/// * `vector` - 中断向量号
/// * `dest` - 目标CPU的APIC ID
/// * `level_triggered` - 是否为电平触发
/// * `active_high` - 是否为高电平有效
/// * `dest_logic` - 是否为逻辑模式
/// * `mask` - 是否屏蔽
pub fn install(
&mut self,
rte_index: u8,
vector: u8,
dest: u8,
level_triggered: bool,
active_high: bool,
dest_logic: bool,
mut mask: bool,
) -> Result<(), SystemError> {
// 重定向表从 REG_TABLE 开始,使用两个寄存器来配置每个中断。
// 一对中的第一个低位寄存器包含配置位。32bit
// 第二个(高)寄存器包含一个位掩码,告诉哪些 CPU 可以服务该中断。
// level_triggered如果为真表示中断触发方式为电平触发level-triggered则将RedirectionEntry::LEVEL标志位设置在flags中。
// active_high如果为假表示中断的极性为低电平有效active-low则将RedirectionEntry::ACTIVELOW标志位设置在flags中。
// dest_logic如果为真表示中断目标为逻辑模式logical mode则将RedirectionEntry::LOGICAL标志位设置在flags中。
// !(0x20..=0xef).contains(&vector)判断中断向量号vector是否在范围0x20到0xef之外如果是则表示中断无效将mask标志位设置为真。
// mask如果为真表示中断被屏蔽masked将RedirectionEntry::DISABLED标志位设置在flags中。
let mut flags = RedirectionEntry::NONE;
if level_triggered {
flags |= RedirectionEntry::LEVEL;
}
if !active_high {
flags |= RedirectionEntry::ACTIVELOW;
}
if dest_logic {
flags |= RedirectionEntry::LOGICAL;
}
if !(0x20..=0xef).contains(&vector) {
mask = true;
}
if mask {
flags |= RedirectionEntry::DISABLED;
}
self.write_rte(rte_index, vector, flags, dest);
return Ok(());
}
/// Get the vector number for the given IRQ.
#[allow(dead_code)]
pub fn irq_vector(&mut self, irq: u8) -> u8 {
unsafe { self.read(REG_TABLE + 2 * irq).get_bits(0..8) as u8 }
}
/// Set the vector number for the given IRQ.
#[allow(dead_code)]
pub fn set_irq_vector(&mut self, irq: u8, vector: u8) {
let mut old = unsafe { self.read(REG_TABLE + 2 * irq) };
let old_vector = old.get_bits(0..8);
if !(0x20..=0xfe).contains(&old_vector) {
old |= RedirectionEntry::DISABLED.bits();
}
unsafe {
self.write(REG_TABLE + 2 * irq, *old.set_bits(0..8, vector as u32));
}
}
#[allow(dead_code)]
pub fn id(&mut self) -> u8 {
unsafe { self.read(REG_ID).get_bits(24..28) as u8 }
}
/// IO APIC Version
#[allow(dead_code)]
pub fn version(&mut self) -> u8 {
unsafe { self.read(REG_VER).get_bits(0..8) as u8 }
}
/// Number of supported interrupts by this IO APIC.
///
/// Max Redirection Entry = "how many IRQs can this I/O APIC handle - 1"
/// The -1 is silly so we add one back to it.
pub fn supported_interrupts(&mut self) -> u8 {
unsafe { (self.read(REG_VER).get_bits(16..24) + 1) as u8 }
}
fn vector_rte_index(irq_num: u8) -> u8 {
assert!(irq_num >= Self::VECTOR_BASE);
irq_num - Self::VECTOR_BASE
}
/// 电平响应
#[allow(dead_code)]
fn level_ack(&mut self, irq_num: u8) {
#[repr(C)]
struct LevelAck {
virt_eoi: Volatile<u32>,
}
let p = NonNull::new(self.virt_eoi as *mut LevelAck).unwrap();
unsafe {
volwrite!(p, virt_eoi, irq_num as u32);
}
}
/// 边沿响应
#[allow(dead_code)]
fn edge_ack(&mut self, _irq_num: u8) {
CurrentApic.send_eoi();
}
}
/// Register index: ID
const REG_ID: u8 = 0x00;
/// 获取IO APIC Version
const REG_VER: u8 = 0x01;
/// Redirection table base
const REG_TABLE: u8 = 0x10;
bitflags! {
/// The redirection table starts at REG_TABLE and uses
/// two registers to configure each interrupt.
/// The first (low) register in a pair contains configuration bits.
/// The second (high) register contains a bitmask telling which
/// CPUs can serve that interrupt.
struct RedirectionEntry: u32 {
/// Interrupt disabled
const DISABLED = 0x00010000;
/// Level-triggered (vs edge-)
const LEVEL = 0x00008000;
/// Active low (vs high)
const ACTIVELOW = 0x00002000;
/// Destination is CPU id (vs APIC ID)
const LOGICAL = 0x00000800;
/// None
const NONE = 0x00000000;
}
}
pub fn ioapic_init() {
kinfo!("Initializing ioapic...");
let ioapic = unsafe { IoApic::new() };
unsafe {
__IOAPIC = Some(SpinLock::new(ioapic));
}
kinfo!("IO Apic initialized.");
}
/// 安装中断
///
/// ## 参数
///
/// * `vector` - 中断向量号
/// * `dest` - 目标CPU的APIC ID
/// * `level_triggered` - 是否为电平触发
/// * `active_high` - 是否为高电平有效
/// * `dest_logic` - 是否为逻辑模式
/// * `mask` - 是否屏蔽
pub(super) fn ioapic_install(
vector: u8,
dest: u8,
level_triggered: bool,
active_high: bool,
dest_logic: bool,
) -> Result<(), SystemError> {
let rte_index = IoApic::vector_rte_index(vector);
return IOAPIC().lock_irqsave().install(
rte_index,
vector,
dest,
level_triggered,
active_high,
dest_logic,
true,
);
}
/// 卸载中断
pub(super) fn ioapic_uninstall(vector: u8) {
let rte_index = IoApic::vector_rte_index(vector);
IOAPIC().lock_irqsave().disable(rte_index);
}
/// 使能中断
pub(super) fn ioapic_enable(vector: u8) {
let rte_index = IoApic::vector_rte_index(vector);
IOAPIC().lock_irqsave().enable(rte_index);
}
/// 禁用中断
pub(super) fn ioapic_disable(vector: u8) {
let rte_index = IoApic::vector_rte_index(vector);
IOAPIC().lock_irqsave().disable(rte_index);
}

View File

@ -0,0 +1,623 @@
use core::sync::atomic::Ordering;
use atomic_enum::atomic_enum;
use x86::{apic::Icr, msr::IA32_APIC_BASE};
use crate::{
arch::{
driver::apic::{ioapic::ioapic_init, x2apic::X2Apic, xapic::XApic},
io::PortIOArch,
CurrentPortIOArch,
},
kdebug, kinfo,
mm::PhysAddr,
smp::core::smp_get_processor_id,
syscall::SystemError,
};
use self::{
apic_timer::LocalApicTimerMode,
xapic::{current_xapic_instance, XApicOffset},
};
pub mod apic_timer;
mod c_adapter;
pub mod ioapic;
pub mod x2apic;
pub mod xapic;
/// 当前启用的APIC类型
#[atomic_enum]
#[derive(PartialEq, Eq)]
pub enum LocalApicEnableType {
XApic,
X2Apic,
}
static LOCAL_APIC_ENABLE_TYPE: AtomicLocalApicEnableType =
AtomicLocalApicEnableType::new(LocalApicEnableType::XApic);
pub trait LocalAPIC {
/// @brief 判断当前处理器是否支持这个类型的apic
///
/// @return true 当前处理器支持这个类型的apic
/// @return false 当前处理器不支持这个类型的apic
fn support() -> bool;
/// @brief 为当前处理器初始化local apic
///
/// @return true 初始化成功
/// @return false 初始化失败
fn init_current_cpu(&mut self) -> bool;
/// @brief 发送EOI信号End of interrupt
fn send_eoi(&self);
/// @brief 获取APIC版本号
fn version(&self) -> u8;
/// @brief 判断当前处理器是否支持EOI广播抑制
fn support_eoi_broadcast_suppression(&self) -> bool;
/// 获取最多支持的LVT寄存器数量
fn max_lvt_entry(&self) -> u8;
/// @brief 获取当前处理器的APIC ID
fn id(&self) -> u32;
/// @brief 设置LVT寄存器
///
/// @param register 寄存器
/// @param lvt 要被设置成的值
fn set_lvt(&mut self, lvt: LVT);
/// 读取LVT寄存器
fn read_lvt(&self, reg: LVTRegister) -> LVT;
fn mask_all_lvt(&mut self);
/// 写入ICR寄存器
fn write_icr(&self, icr: Icr);
}
/// @brief 所有LVT寄存器的枚举类型
#[allow(dead_code)]
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum LVTRegister {
/// CMCI寄存器
///
/// 如果支持CMCI功能那么当修正的机器错误超过阈值时Local APIC通过CMCI寄存器的配置
/// 向处理器核心投递中断消息
CMCI = 0x82f,
/// 定时器寄存器
///
/// 当APIC定时器产生中断信号时Local APIC通过定时器寄存器的设置向处理器投递中断消息
Timer = 0x832,
/// 温度传感器寄存器
///
/// 当处理器内部的温度传感器产生中断请求信号时Local APIC会通过温度传感器寄存器的设置
/// 向处理器投递中断消息。
Thermal = 0x833,
/// 性能监控计数器寄存器
///
/// 当性能检测计数器寄存器溢出产生中断请求时Local APIC将会根据这个寄存器的配置
/// 向处理器投递中断消息
PerformanceMonitor = 0x834,
/// 当处理器的LINT0引脚接收到中断请求信号时Local APIC会根据这个寄存器的配置
/// 向处理器投递中断消息
LINT0 = 0x835,
/// 当处理器的LINT0引脚接收到中断请求信号时Local APIC会根据这个寄存器的配置
/// 向处理器投递中断消息
LINT1 = 0x836,
/// 错误寄存器
///
/// 当APIC检测到内部错误而产生中断请求信号时它将会通过错误寄存器的设置向处理器投递中断消息
ErrorReg = 0x837,
}
impl Into<u32> for LVTRegister {
fn into(self) -> u32 {
self as u32
}
}
#[derive(Debug)]
pub struct LVT {
register: LVTRegister,
data: u32,
}
impl LVT {
/// 当第16位为1时表示屏蔽中断
pub const MASKED: u32 = 1 << 16;
pub fn new(register: LVTRegister, data: u32) -> Option<Self> {
// vector: u8, mode: DeliveryMode, status: DeliveryStatus
let mut result = Self { register, data: 0 };
result.set_vector((data & 0xFF) as u8);
match result.register {
LVTRegister::Timer | LVTRegister::ErrorReg => {}
_ => {
result
.set_delivery_mode(DeliveryMode::try_from(((data >> 8) & 0b111) as u8).ok()?)
.ok()?;
}
}
if let LVTRegister::LINT0 | LVTRegister::LINT1 = result.register {
result.set_interrupt_input_pin_polarity((data & (1 << 13)) == 0);
if data & (1 << 15) != 0 {
result.set_trigger_mode(TriggerMode::Level).ok()?;
} else {
result.set_trigger_mode(TriggerMode::Edge).ok()?;
}
}
result.set_mask((data & (1 << 16)) != 0);
if let LVTRegister::Timer = result.register {
result
.set_timer_mode(LocalApicTimerMode::try_from(((data >> 17) & 0b11) as u8).ok()?)
.ok()?;
}
return Some(result);
}
/// 获取LVT寄存器的原始值
#[allow(dead_code)]
pub fn data(&self) -> u32 {
return self.data;
}
pub fn register(&self) -> LVTRegister {
return self.register;
}
pub fn set_vector(&mut self, vector: u8) {
self.data &= !((1 << 8) - 1);
self.data |= vector as u32;
}
/// 获取中断向量号
#[allow(dead_code)]
pub fn vector(&self) -> u8 {
return (self.data & 0xFF) as u8;
}
/// 设置中断投递模式
///
/// Timer、ErrorReg寄存器不支持这个功能
///
/// ## 参数
///
/// - `mode`:投递模式
pub fn set_delivery_mode(&mut self, mode: DeliveryMode) -> Result<(), SystemError> {
match self.register {
LVTRegister::Timer | LVTRegister::ErrorReg => {
return Err(SystemError::EINVAL);
}
_ => {}
}
self.data &= 0xFFFF_F8FF;
self.data |= ((mode as u32) & 0x7) << 8;
return Ok(());
}
/// 获取中断投递模式
/// Timer、ErrorReg寄存器不支持这个功能
#[allow(dead_code)]
pub fn delivery_mode(&self) -> Option<DeliveryMode> {
if let LVTRegister::Timer | LVTRegister::ErrorReg = self.register {
return None;
}
return DeliveryMode::try_from(((self.data >> 8) & 0b111) as u8).ok();
}
/// Get the delivery status of the interrupt
#[allow(dead_code)]
pub fn delivery_status(&self) -> DeliveryStatus {
return DeliveryStatus::from(self.data);
}
/// 设置中断输入引脚的极性
///
/// ## 参数
///
/// - `high`true表示高电平有效false表示低电平有效
pub fn set_interrupt_input_pin_polarity(&mut self, high: bool) {
self.data &= 0xFFFF_DFFF;
// 0表示高电平有效1表示低电平有效
if !high {
self.data |= 1 << 13;
}
}
/// 获取中断输入引脚的极性
///
/// true表示高电平有效false表示低电平有效
#[allow(dead_code)]
pub fn interrupt_input_pin_polarity(&self) -> bool {
return (self.data & (1 << 13)) == 0;
}
/// 设置中断输入引脚的触发模式
///
/// 只有LINT0和LINT1寄存器支持这个功能
///
/// ## 参数
///
/// - `trigger_mode`:触发模式
pub fn set_trigger_mode(&mut self, trigger_mode: TriggerMode) -> Result<(), SystemError> {
match self.register {
LVTRegister::LINT0 | LVTRegister::LINT1 => {
self.data &= 0xFFFF_7FFF;
if trigger_mode == TriggerMode::Level {
self.data |= 1 << 15;
}
return Ok(());
}
_ => {
return Err(SystemError::EINVAL);
}
}
}
/// 获取中断输入引脚的触发模式
///
/// 只有LINT0和LINT1寄存器支持这个功能
#[allow(dead_code)]
pub fn trigger_mode(&self) -> Option<TriggerMode> {
match self.register {
LVTRegister::LINT0 | LVTRegister::LINT1 => {
if self.data & (1 << 15) != 0 {
return Some(TriggerMode::Level);
} else {
return Some(TriggerMode::Edge);
}
}
_ => {
return None;
}
}
}
/// 设置是否屏蔽中断
///
/// ## 参数
///
/// - `mask`true表示屏蔽中断false表示不屏蔽中断
pub fn set_mask(&mut self, mask: bool) {
self.data &= 0xFFFE_FFFF;
if mask {
self.data |= 1 << 16;
}
}
/// Check if the interrupt is masked
///
/// true表示屏蔽中断false表示不屏蔽中断
#[allow(dead_code)]
pub fn mask(&self) -> bool {
return (self.data & (1 << 16)) != 0;
}
/// 设置定时器模式
pub fn set_timer_mode(&mut self, mode: LocalApicTimerMode) -> Result<(), SystemError> {
match self.register {
LVTRegister::Timer => {
self.data &= 0xFFF9_FFFF;
match mode {
LocalApicTimerMode::Oneshot => {
self.data |= 0b00 << 17;
}
LocalApicTimerMode::Periodic => {
self.data |= 0b01 << 17;
}
LocalApicTimerMode::Deadline => {
self.data |= 0b10 << 17;
}
}
return Ok(());
}
_ => {
return Err(SystemError::EINVAL);
}
}
}
/// 获取定时器模式
#[allow(dead_code)]
pub fn timer_mode(&self) -> Option<LocalApicTimerMode> {
if let LVTRegister::Timer = self.register {
let mode = (self.data >> 17) & 0b11;
match mode {
0b00 => {
return Some(LocalApicTimerMode::Oneshot);
}
0b01 => {
return Some(LocalApicTimerMode::Periodic);
}
0b10 => {
return Some(LocalApicTimerMode::Deadline);
}
_ => {
return None;
}
}
}
return None;
}
}
/// @brief
#[allow(dead_code)]
#[derive(Debug, PartialEq)]
pub enum DeliveryMode {
/// 由LVT寄存器的向量号区域指定中断向量号
Fixed = 0b000,
/// 通过处理器的SMI信号线向处理器投递SMI中断请求。
/// 由于兼容性的原因使用此投递模式时LVT的中断向量号区域必须设置为0。
SMI = 0b010,
/// 向处理器投递不可屏蔽中断,并忽略向量号区域
NMI = 0b100,
/// 向处理器投递INIT中断请求处理器会执行初始化的过程。
/// 由于兼容性的原因使用此投递模式时LVT的中断向量号区域必须设置为0。
/// CMCI、温度传感器、性能监控计数器等寄存器均不支持INIT投递模式
INIT = 0b101,
/// 向目标处理器投递Start-Up IPI。
///
/// 这个向量通常由多核引导模块调用请参阅Intel开发手册Volume3 Section 8.4,
/// Multiple-Processor (MP) Initialization
/// 如果源APIC无法投递这个IPI它不会自动重发。如果Start-Up IPI未成功投递
/// 则交由软件决定是否在必要时重新投递SIPI
StartUp = 0b110,
/// ExtINT模式可以将类8259A中断控制器产生的中断请求投递到处理器并接收类
/// 8259A中断控制器提供的中断向量号。
/// CMCI、温度传感器、性能监控计数器等寄存器均不支持ExtINT投递模式
ExtINT = 0b111,
}
impl TryFrom<u8> for DeliveryMode {
type Error = SystemError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0b000 => {
return Ok(DeliveryMode::Fixed);
}
0b010 => {
return Ok(DeliveryMode::SMI);
}
0b100 => {
return Ok(DeliveryMode::NMI);
}
0b101 => {
return Ok(DeliveryMode::INIT);
}
0b110 => {
return Ok(DeliveryMode::StartUp);
}
0b111 => {
return Ok(DeliveryMode::ExtINT);
}
_ => {
return Err(SystemError::EINVAL);
}
}
}
}
/// @brief 投递状态
#[derive(Debug)]
#[allow(dead_code)]
pub enum DeliveryStatus {
/// 空闲态。
/// 此状态表明,当前中断源未产生中断,或者产生的中断已经投递到处理器,并被处理器处理。
Idle = 0,
/// 发送挂起状态。
/// 此状态表明,中断源产生的请求已经投递至处理器,但尚未被处理器处理。
SendPending = 1,
}
impl DeliveryStatus {
pub fn from(data: u32) -> Self {
if data & (1 << 12) == 0 {
return DeliveryStatus::Idle;
} else {
return DeliveryStatus::SendPending;
}
}
}
/// IPI Trigger Mode
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum TriggerMode {
Edge = 0,
Level = 1,
}
#[derive(Debug)]
pub struct CurrentApic;
impl CurrentApic {
/// x2apic是否启用
pub fn x2apic_enabled(&self) -> bool {
return LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic;
}
pub(self) unsafe fn write_xapic_register(&self, reg: XApicOffset, value: u32) {
current_xapic_instance().borrow_mut().as_mut().map(|xapic| {
xapic.write(reg, value);
});
}
/// 屏蔽类8259A芯片
unsafe fn mask8259a(&self) {
CurrentPortIOArch::out8(0x21, 0xff);
CurrentPortIOArch::out8(0xa1, 0xff);
// 写入8259A pic的EOI位
CurrentPortIOArch::out8(0x20, 0x20);
CurrentPortIOArch::out8(0xa0, 0x20);
kdebug!("8259A Masked.");
// enable IMCR
CurrentPortIOArch::out8(0x22, 0x70);
CurrentPortIOArch::out8(0x23, 0x01);
}
}
impl LocalAPIC for CurrentApic {
fn support() -> bool {
true
}
fn init_current_cpu(&mut self) -> bool {
let cpu_id = smp_get_processor_id();
if cpu_id == 0 {
unsafe {
self.mask8259a();
}
}
kinfo!("Initializing apic for cpu {}", cpu_id);
if X2Apic::support() && X2Apic.init_current_cpu() {
if cpu_id == 0 {
LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::X2Apic, Ordering::SeqCst);
}
kinfo!("x2APIC initialized for cpu {}", cpu_id);
} else {
kinfo!("x2APIC not supported or failed to initialize, fallback to xAPIC.");
if cpu_id == 0 {
LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::XApic, Ordering::SeqCst);
}
let apic_base =
PhysAddr::new(unsafe { x86::msr::rdmsr(IA32_APIC_BASE) as usize & 0xFFFF_0000 });
let xapic_instance = unsafe { XApic::new(apic_base) };
let mut cur = current_xapic_instance().borrow_mut();
if cur.is_none() {
*cur = Some(xapic_instance);
} else {
panic!("xapic instance already initialized.");
}
if let Some(xapic) = cur.as_mut() {
xapic.init_current_cpu();
}
kinfo!("xAPIC initialized for cpu {}", cpu_id);
}
if cpu_id == 0 {
ioapic_init();
}
kinfo!("Apic initialized.");
return true;
}
fn send_eoi(&self) {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
X2Apic.send_eoi();
} else {
current_xapic_instance().borrow().as_ref().map(|xapic| {
xapic.send_eoi();
});
}
}
fn version(&self) -> u8 {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
return X2Apic.version();
} else {
return current_xapic_instance()
.borrow()
.as_ref()
.map(|xapic| xapic.version())
.unwrap_or(0);
}
}
fn support_eoi_broadcast_suppression(&self) -> bool {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
return X2Apic.support_eoi_broadcast_suppression();
} else {
return current_xapic_instance()
.borrow()
.as_ref()
.map(|xapic| xapic.support_eoi_broadcast_suppression())
.unwrap_or(false);
}
}
fn max_lvt_entry(&self) -> u8 {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
return X2Apic.max_lvt_entry();
} else {
return current_xapic_instance()
.borrow()
.as_ref()
.map(|xapic| xapic.max_lvt_entry())
.unwrap_or(0);
}
}
fn id(&self) -> u32 {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
return X2Apic.id();
} else {
return current_xapic_instance()
.borrow()
.as_ref()
.map(|xapic| xapic.id())
.unwrap_or(0);
}
}
fn set_lvt(&mut self, lvt: LVT) {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
X2Apic.set_lvt(lvt);
} else {
current_xapic_instance().borrow_mut().as_mut().map(|xapic| {
xapic.set_lvt(lvt);
});
}
}
fn read_lvt(&self, reg: LVTRegister) -> LVT {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
return X2Apic.read_lvt(reg);
} else {
return current_xapic_instance()
.borrow()
.as_ref()
.map(|xapic| xapic.read_lvt(reg))
.expect("xapic instance not initialized.");
}
}
fn mask_all_lvt(&mut self) {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
X2Apic.mask_all_lvt();
} else {
current_xapic_instance().borrow_mut().as_mut().map(|xapic| {
xapic.mask_all_lvt();
});
}
}
fn write_icr(&self, icr: Icr) {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
X2Apic.write_icr(icr);
} else {
current_xapic_instance().borrow().as_ref().map(|xapic| {
xapic.write_icr(icr);
});
}
}
}

View File

@ -0,0 +1,125 @@
use x86::msr::{
rdmsr, wrmsr, IA32_APIC_BASE, IA32_X2APIC_APICID, IA32_X2APIC_EOI, IA32_X2APIC_SIVR,
IA32_X2APIC_VERSION,
};
use crate::{kdebug, kinfo};
use super::{LVTRegister, LocalAPIC, LVT};
#[derive(Debug)]
pub struct X2Apic;
impl LocalAPIC for X2Apic {
/// @brief 判断处理器是否支持x2APIC
fn support() -> bool {
return x86::cpuid::CpuId::new()
.get_feature_info()
.expect("Get cpu feature info failed.")
.has_x2apic();
}
/// @return true -> the function works
fn init_current_cpu(&mut self) -> bool {
unsafe {
// 设置 x2APIC 使能位
wrmsr(
IA32_APIC_BASE.into(),
rdmsr(IA32_APIC_BASE.into()) | 1 << 10,
);
assert!(
(rdmsr(IA32_APIC_BASE.into()) & 0xc00) == 0xc00,
"x2APIC enable failed."
);
// 设置Spurious-Interrupt Vector Register
{
let val = if self.support_eoi_broadcast_suppression() {
(1 << 12) | (1 << 8)
} else {
1 << 8
};
wrmsr(IA32_X2APIC_SIVR.into(), val);
assert!(
(rdmsr(IA32_X2APIC_SIVR.into()) & 0x100) == 0x100,
"x2APIC software enable failed."
);
kinfo!("x2APIC software enabled.");
if self.support_eoi_broadcast_suppression() {
assert!(
(rdmsr(IA32_X2APIC_SIVR.into()) & 0x1000) == 0x1000,
"x2APIC EOI broadcast suppression enable failed."
);
kinfo!("x2APIC EOI broadcast suppression enabled.");
}
}
kdebug!("x2apic: to mask all lvt");
self.mask_all_lvt();
kdebug!("x2apic: all lvt masked");
}
true
}
/// 发送 EOI (End Of Interrupt)
fn send_eoi(&self) {
unsafe {
wrmsr(IA32_X2APIC_EOI.into(), 0);
}
}
/// 获取 x2APIC 版本
fn version(&self) -> u8 {
unsafe { (rdmsr(IA32_X2APIC_VERSION.into()) & 0xff) as u8 }
}
fn support_eoi_broadcast_suppression(&self) -> bool {
unsafe { ((rdmsr(IA32_X2APIC_VERSION.into()) >> 24) & 1) == 1 }
}
fn max_lvt_entry(&self) -> u8 {
unsafe { ((rdmsr(IA32_X2APIC_VERSION.into()) >> 16) & 0xff) as u8 + 1 }
}
/// 获取 x2APIC 的 APIC ID
fn id(&self) -> u32 {
unsafe { rdmsr(IA32_X2APIC_APICID.into()) as u32 }
}
/// 设置 Local Vector Table (LVT) 寄存器
fn set_lvt(&mut self, lvt: LVT) {
unsafe {
wrmsr(lvt.register().into(), lvt.data as u64);
}
}
fn read_lvt(&self, reg: LVTRegister) -> LVT {
unsafe { LVT::new(reg, (rdmsr(reg.into()) & 0xffff_ffff) as u32).unwrap() }
}
fn mask_all_lvt(&mut self) {
// self.set_lvt(LVT::new(LVTRegister::CMCI, LVT::MASKED).unwrap());
let cpuid = raw_cpuid::CpuId::new();
// cpuid.get_performance_monitoring_info();
self.set_lvt(LVT::new(LVTRegister::Timer, LVT::MASKED).unwrap());
if cpuid.get_thermal_power_info().is_some() {
self.set_lvt(LVT::new(LVTRegister::Thermal, LVT::MASKED).unwrap());
}
if cpuid.get_performance_monitoring_info().is_some() {
self.set_lvt(LVT::new(LVTRegister::PerformanceMonitor, LVT::MASKED).unwrap());
}
self.set_lvt(LVT::new(LVTRegister::LINT0, LVT::MASKED).unwrap());
self.set_lvt(LVT::new(LVTRegister::LINT1, LVT::MASKED).unwrap());
self.set_lvt(LVT::new(LVTRegister::ErrorReg, LVT::MASKED).unwrap());
}
fn write_icr(&self, icr: x86::apic::Icr) {
unsafe { wrmsr(0x830, ((icr.upper() as u64) << 32) | icr.lower() as u64) };
}
}

View File

@ -0,0 +1,358 @@
use core::{
cell::RefCell,
hint::spin_loop,
ptr::{read_volatile, write_volatile},
};
use crate::{
kdebug, kerror, kinfo,
mm::{
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
percpu::PerCpu,
PhysAddr, VirtAddr,
},
smp::core::smp_get_processor_id,
};
use super::{LVTRegister, LocalAPIC, LVT};
/// per-cpu的xAPIC的MMIO空间起始地址
static mut XAPIC_INSTANCES: [RefCell<Option<XApic>>; PerCpu::MAX_CPU_NUM] =
[const { RefCell::new(None) }; PerCpu::MAX_CPU_NUM];
#[inline(always)]
pub(super) fn current_xapic_instance() -> &'static RefCell<Option<XApic>> {
unsafe { &XAPIC_INSTANCES.as_ref()[smp_get_processor_id() as usize] }
}
/// TODO统一变量
/// @brief local APIC 寄存器地址偏移量
#[derive(Debug)]
#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[repr(u32)]
pub enum XApicOffset {
// 定义各个寄存器的地址偏移量
LOCAL_APIC_OFFSET_Local_APIC_ID = 0x20,
LOCAL_APIC_OFFSET_Local_APIC_Version = 0x30,
LOCAL_APIC_OFFSET_Local_APIC_TPR = 0x80,
LOCAL_APIC_OFFSET_Local_APIC_APR = 0x90,
LOCAL_APIC_OFFSET_Local_APIC_PPR = 0xa0,
LOCAL_APIC_OFFSET_Local_APIC_EOI = 0xb0,
LOCAL_APIC_OFFSET_Local_APIC_RRD = 0xc0,
LOCAL_APIC_OFFSET_Local_APIC_LDR = 0xd0,
LOCAL_APIC_OFFSET_Local_APIC_DFR = 0xe0,
LOCAL_APIC_OFFSET_Local_APIC_SVR = 0xf0,
LOCAL_APIC_OFFSET_Local_APIC_ISR_31_0 = 0x100, // In-Service Register
LOCAL_APIC_OFFSET_Local_APIC_ISR_63_32 = 0x110,
LOCAL_APIC_OFFSET_Local_APIC_ISR_95_64 = 0x120,
LOCAL_APIC_OFFSET_Local_APIC_ISR_127_96 = 0x130,
LOCAL_APIC_OFFSET_Local_APIC_ISR_159_128 = 0x140,
LOCAL_APIC_OFFSET_Local_APIC_ISR_191_160 = 0x150,
LOCAL_APIC_OFFSET_Local_APIC_ISR_223_192 = 0x160,
LOCAL_APIC_OFFSET_Local_APIC_ISR_255_224 = 0x170,
LOCAL_APIC_OFFSET_Local_APIC_TMR_31_0 = 0x180, // Trigger Mode Register
LOCAL_APIC_OFFSET_Local_APIC_TMR_63_32 = 0x190,
LOCAL_APIC_OFFSET_Local_APIC_TMR_95_64 = 0x1a0,
LOCAL_APIC_OFFSET_Local_APIC_TMR_127_96 = 0x1b0,
LOCAL_APIC_OFFSET_Local_APIC_TMR_159_128 = 0x1c0,
LOCAL_APIC_OFFSET_Local_APIC_TMR_191_160 = 0x1d0,
LOCAL_APIC_OFFSET_Local_APIC_TMR_223_192 = 0x1e0,
LOCAL_APIC_OFFSET_Local_APIC_TMR_255_224 = 0x1f0,
LOCAL_APIC_OFFSET_Local_APIC_IRR_31_0 = 0x200, // Interrupt Request Register
LOCAL_APIC_OFFSET_Local_APIC_IRR_63_32 = 0x210,
LOCAL_APIC_OFFSET_Local_APIC_IRR_95_64 = 0x220,
LOCAL_APIC_OFFSET_Local_APIC_IRR_127_96 = 0x230,
LOCAL_APIC_OFFSET_Local_APIC_IRR_159_128 = 0x240,
LOCAL_APIC_OFFSET_Local_APIC_IRR_191_160 = 0x250,
LOCAL_APIC_OFFSET_Local_APIC_IRR_223_192 = 0x260,
LOCAL_APIC_OFFSET_Local_APIC_IRR_255_224 = 0x270,
LOCAL_APIC_OFFSET_Local_APIC_ESR = 0x280, // Error Status Register
LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI = 0x2f0, // Corrected Machine Check Interrupt Register
LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0 = 0x300, // Interrupt Command Register
LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32 = 0x310,
LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER = 0x320,
LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL = 0x330,
LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR = 0x340,
LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0 = 0x350,
LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1 = 0x360,
LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR = 0x370,
// 初始计数寄存器(定时器专用)
LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG = 0x380,
// 当前计数寄存器(定时器专用)
LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG = 0x390,
LOCAL_APIC_OFFSET_Local_APIC_CLKDIV = 0x3e0,
}
impl Into<u32> for XApicOffset {
fn into(self) -> u32 {
self as u32
}
}
impl From<LVTRegister> for XApicOffset {
fn from(lvt: LVTRegister) -> Self {
match lvt {
LVTRegister::Timer => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER,
LVTRegister::Thermal => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL,
LVTRegister::PerformanceMonitor => {
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR
}
LVTRegister::LINT0 => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0,
LVTRegister::LINT1 => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1,
LVTRegister::ErrorReg => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR,
LVTRegister::CMCI => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI,
}
}
}
#[derive(Debug)]
#[allow(dead_code)]
pub struct XApic {
/// 当前xAPIC的寄存器映射的虚拟地址。注意每个CPU都有自己的xAPIC所以这个地址是每个CPU都不一样的。
apic_vaddr: VirtAddr,
/// `apic_vaddr`与映射的空间起始位置之间的偏移量
offset: usize,
map_guard: MMIOSpaceGuard,
xapic_base: PhysAddr,
}
impl XApic {
/// 读取指定寄存器的值
#[allow(dead_code)]
pub unsafe fn read(&self, reg: XApicOffset) -> u32 {
read_volatile((self.apic_vaddr.data() + reg as usize) as *const u32)
}
/// 将指定的值写入寄存器
#[allow(dead_code)]
pub unsafe fn write(&self, reg: XApicOffset, value: u32) {
write_volatile(
(self.apic_vaddr.data() + (reg as u32) as usize) as *mut u32,
value,
);
self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID); // 等待写操作完成,通过读取进行同步
}
}
impl XApic {
/// 创建新的XAPIC实例
///
/// ## 参数
///
/// - `xapic_base` - 当前核心的xAPIC的寄存器的物理地址
pub unsafe fn new(xapic_base: PhysAddr) -> Self {
let offset = xapic_base.data() & 0xffff;
let paddr = PhysAddr::new(xapic_base.data() & !0xffff);
let g = mmio_pool()
.create_mmio(4096)
.expect("Fail to create MMIO for XAPIC");
g.map_phys(paddr, 4096).expect("Fail to map MMIO for XAPIC");
let addr = g.vaddr() + offset;
kdebug!(
"XAPIC: {:#x} -> {:#x}, offset={offset}",
xapic_base.data(),
addr.data()
);
let r = Self {
apic_vaddr: addr,
offset,
map_guard: g,
xapic_base,
};
return r;
}
}
#[allow(dead_code)]
const X1: u32 = 0x0000000B; // 将除数设置为1即不除频率
#[allow(dead_code)]
const PERIODIC: u32 = 0x00020000; // 周期性模式
#[allow(dead_code)]
const ENABLE: u32 = 0x00000100; // 单元使能
#[allow(dead_code)]
const MASKED: u32 = 0x00010000; // 中断屏蔽
const LEVEL: u32 = 0x00008000; // 电平触发
const BCAST: u32 = 0x00080000; // 发送到所有APIC包括自己
const DELIVS: u32 = 0x00001000; // 传递状态
const INIT: u32 = 0x00000500; // INIT/RESET
//中断请求
#[allow(dead_code)]
const T_IRQ0: u32 = 32; // IRQ 0 对应于 T_IRQ 中断
#[allow(dead_code)]
const IRQ_TIMER: u32 = 0;
#[allow(dead_code)]
const IRQ_KBD: u32 = 1;
#[allow(dead_code)]
const IRQ_COM1: u32 = 4;
#[allow(dead_code)]
const IRQ_IDE: u32 = 14;
#[allow(dead_code)]
const IRQ_ERROR: u32 = 19;
#[allow(dead_code)]
const IRQ_SPURIOUS: u32 = 31;
impl LocalAPIC for XApic {
/// @brief 判断处理器是否支持apic
fn support() -> bool {
return x86::cpuid::CpuId::new()
.get_feature_info()
.expect("Fail to get CPU feature.")
.has_apic();
}
/// @return true -> 函数运行成功
fn init_current_cpu(&mut self) -> bool {
unsafe {
// enable xapic
x86::msr::wrmsr(x86::msr::APIC_BASE, (self.xapic_base.data() | 0x800) as u64);
let val = x86::msr::rdmsr(x86::msr::APIC_BASE);
if val & 0x800 != 0x800 {
kerror!("xAPIC enable failed: APIC_BASE & 0x800 != 0x800");
return false;
}
// 设置 Spurious Interrupt Vector Register
let val = self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into());
self.write(
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into(),
val | ENABLE,
);
let val = self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into());
if val & ENABLE == 0 {
kerror!("xAPIC software enable failed.");
return false;
} else {
kinfo!("xAPIC software enabled.");
}
if val & 0x1000 != 0 {
kinfo!("xAPIC EOI broadcast suppression enabled.");
}
self.mask_all_lvt();
// 清除错误状态寄存器(需要连续写入两次)
self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ESR.into(), 0);
self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ESR.into(), 0);
// 确认任何未完成的中断
self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_EOI.into(), 0);
// 发送 Init Level De-Assert 信号以同步仲裁ID
self.write(
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32.into(),
0,
);
self.write(
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into(),
BCAST | INIT | LEVEL,
);
while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0
{
spin_loop();
}
}
true
}
/// 发送 EOIEnd Of Interrupt
fn send_eoi(&self) {
unsafe {
let s = self as *const Self as *mut Self;
(*s).write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_EOI.into(), 0);
}
}
/// 获取版本号
fn version(&self) -> u8 {
unsafe {
(self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) & 0xff) as u8
}
}
fn support_eoi_broadcast_suppression(&self) -> bool {
unsafe {
((self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) >> 24) & 1) == 1
}
}
fn max_lvt_entry(&self) -> u8 {
unsafe {
((self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) >> 16) & 0xff)
as u8
+ 1
}
}
/// 获取ID
fn id(&self) -> u32 {
unsafe { self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID.into()) >> 24 }
}
/// 设置LVT寄存器的值
fn set_lvt(&mut self, lvt: LVT) {
unsafe {
self.write(lvt.register().into(), lvt.data);
}
}
fn read_lvt(&self, reg: LVTRegister) -> LVT {
unsafe {
LVT::new(
reg,
self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER.into()),
)
.unwrap()
}
}
fn mask_all_lvt(&mut self) {
// self.set_lvt(LVT::new(LVTRegister::CMCI, LVT::MASKED).unwrap());
self.set_lvt(LVT::new(LVTRegister::Timer, LVT::MASKED).unwrap());
self.set_lvt(LVT::new(LVTRegister::Thermal, LVT::MASKED).unwrap());
self.set_lvt(LVT::new(LVTRegister::PerformanceMonitor, LVT::MASKED).unwrap());
self.set_lvt(LVT::new(LVTRegister::LINT0, LVT::MASKED).unwrap());
self.set_lvt(LVT::new(LVTRegister::LINT1, LVT::MASKED).unwrap());
self.set_lvt(LVT::new(LVTRegister::ErrorReg, LVT::MASKED).unwrap());
}
fn write_icr(&self, icr: x86::apic::Icr) {
unsafe {
// Wait for any previous send to finish
while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0
{
spin_loop();
}
self.write(
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32.into(),
icr.upper(),
);
self.write(
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into(),
icr.lower(),
);
// Wait for send to finish
while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0
{
spin_loop();
}
}
}
}

View File

@ -1,6 +1,6 @@
#include <common/glib.h>
#include <common/kprint.h>
#include <driver/interrupt/apic/apic.h>
#include <arch/x86_64/driver/apic/apic.h>
extern void rs_handle_hpet_irq(uint32_t timer_num);

View File

@ -1,3 +1,4 @@
pub mod apic;
mod c_adapter;
pub mod hpet;
pub mod tsc;

View File

@ -0,0 +1,15 @@
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(target_cpu)
.map(|_| 0)
.unwrap_or_else(|e| e.to_posix_errno());
}

View File

@ -1,9 +1,13 @@
use crate::exception::ipi::{IpiKind, IpiTarget};
use x86::apic::ApicId;
extern "C" {
pub fn apic_write_icr(value: u64);
pub fn apic_x2apic_enabled() -> bool;
}
use crate::{
arch::{
driver::apic::{CurrentApic, LocalAPIC},
smp::SMP_BOOT_DATA,
},
exception::ipi::{IpiKind, IpiTarget},
syscall::SystemError,
};
/// IPI的种类(架构相关,指定了向量号)
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
@ -32,7 +36,7 @@ pub enum ArchIpiTarget {
/// 除了当前CPU以外的所有CPU
Other,
/// 指定的CPU
Specified(usize),
Specified(x86::apic::ApicId),
}
impl From<IpiTarget> for ArchIpiTarget {
@ -41,7 +45,23 @@ impl From<IpiTarget> for ArchIpiTarget {
IpiTarget::Current => ArchIpiTarget::Current,
IpiTarget::All => ArchIpiTarget::All,
IpiTarget::Other => ArchIpiTarget::Other,
IpiTarget::Specified(cpu_id) => ArchIpiTarget::Specified(cpu_id),
IpiTarget::Specified(cpu_id) => {
ArchIpiTarget::Specified(Self::cpu_id_to_apic_id(cpu_id as u32))
}
}
}
}
impl Into<ApicId> for ArchIpiTarget {
fn into(self) -> ApicId {
if let ArchIpiTarget::Specified(id) = self {
return id;
} else {
if CurrentApic.x2apic_enabled() {
return x86::apic::ApicId::X2Apic(0);
} else {
return x86::apic::ApicId::XApic(0);
}
}
}
}
@ -55,6 +75,15 @@ impl ArchIpiTarget {
ArchIpiTarget::Other => 3,
}
}
#[inline(always)]
fn cpu_id_to_apic_id(cpu_id: u32) -> x86::apic::ApicId {
if CurrentApic.x2apic_enabled() {
x86::apic::ApicId::X2Apic(cpu_id as u32)
} else {
x86::apic::ApicId::XApic(cpu_id as u8)
}
}
}
impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget {
@ -68,21 +97,6 @@ impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget {
}
}
impl Into<x86::apic::ApicId> for ArchIpiTarget {
fn into(self) -> x86::apic::ApicId {
let id = match self {
ArchIpiTarget::Specified(cpu_id) => cpu_id,
_ => 0,
};
if unsafe { apic_x2apic_enabled() } {
return x86::apic::ApicId::X2Apic(id as u32);
} else {
return x86::apic::ApicId::XApic(id as u8);
}
}
}
#[inline(always)]
pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
// kdebug!("send_ipi: {:?} {:?}", kind, target);
@ -91,9 +105,9 @@ pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
let target = ArchIpiTarget::from(target);
let shorthand: x86::apic::DestinationShorthand = target.into();
let destination: x86::apic::ApicId = target.into();
if unsafe { apic_x2apic_enabled() } {
let icr = if CurrentApic.x2apic_enabled() {
// kdebug!("send_ipi: x2apic");
let icr = x86::apic::Icr::for_x2apic(
x86::apic::Icr::for_x2apic(
ipi_vec,
destination,
shorthand,
@ -102,14 +116,10 @@ pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
x86::apic::DeliveryStatus::Idle,
x86::apic::Level::Assert,
x86::apic::TriggerMode::Edge,
);
unsafe {
apic_write_icr(((icr.upper() as u64) << 32) | icr.lower() as u64);
}
)
} else {
// kdebug!("send_ipi: xapic");
let icr = x86::apic::Icr::for_xapic(
x86::apic::Icr::for_xapic(
ipi_vec,
destination,
shorthand,
@ -118,10 +128,77 @@ pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
x86::apic::DeliveryStatus::Idle,
x86::apic::Level::Assert,
x86::apic::TriggerMode::Edge,
);
)
};
unsafe {
apic_write_icr(((icr.upper() as u64) << 32) | icr.lower() as u64);
}
}
CurrentApic.write_icr(icr);
}
/// 发送smp初始化IPI
pub fn ipi_send_smp_init() -> Result<(), SystemError> {
let target = ArchIpiTarget::Other;
let icr = if CurrentApic.x2apic_enabled() {
x86::apic::Icr::for_x2apic(
0,
target.into(),
x86::apic::DestinationShorthand::AllExcludingSelf,
x86::apic::DeliveryMode::Init,
x86::apic::DestinationMode::Physical,
x86::apic::DeliveryStatus::Idle,
x86::apic::Level::Deassert,
x86::apic::TriggerMode::Edge,
)
} else {
x86::apic::Icr::for_xapic(
0,
target.into(),
x86::apic::DestinationShorthand::AllExcludingSelf,
x86::apic::DeliveryMode::Init,
x86::apic::DestinationMode::Physical,
x86::apic::DeliveryStatus::Idle,
x86::apic::Level::Deassert,
x86::apic::TriggerMode::Edge,
)
};
CurrentApic.write_icr(icr);
return Ok(());
}
/// 发送smp启动IPI
///
/// ## 参数
///
/// * `target_cpu` - 目标CPU
pub fn ipi_send_smp_startup(target_cpu: u32) -> Result<(), SystemError> {
if target_cpu as usize >= SMP_BOOT_DATA.cpu_count() {
return Err(SystemError::EINVAL);
}
let target: ArchIpiTarget = IpiTarget::Specified(target_cpu as usize).into();
let icr = if CurrentApic.x2apic_enabled() {
x86::apic::Icr::for_x2apic(
0x20,
target.into(),
x86::apic::DestinationShorthand::NoShorthand,
x86::apic::DeliveryMode::StartUp,
x86::apic::DestinationMode::Physical,
x86::apic::DeliveryStatus::Idle,
x86::apic::Level::Deassert,
x86::apic::TriggerMode::Edge,
)
} else {
x86::apic::Icr::for_xapic(
0x20,
target.into(),
x86::apic::DestinationShorthand::NoShorthand,
x86::apic::DeliveryMode::StartUp,
x86::apic::DestinationMode::Physical,
x86::apic::DeliveryStatus::Idle,
x86::apic::Level::Deassert,
x86::apic::TriggerMode::Edge,
)
};
CurrentApic.write_icr(icr);
return Ok(());
}

View File

@ -1,5 +1,6 @@
#![allow(dead_code)]
mod c_adapter;
pub mod ipi;
use core::{

View File

@ -1,4 +1,4 @@
use core::{ffi::c_void, mem::size_of};
use core::{ffi::c_void, intrinsics::unlikely, mem::size_of};
use crate::{
arch::{
@ -322,7 +322,7 @@ impl SigContext {
//TODO 引入线程后补上
// let current_thread = ProcessManager::current_pcb().thread;
let pcb = ProcessManager::current_pcb();
let mut archinfo_guard = pcb.arch_info();
let mut archinfo_guard = pcb.arch_info_irqsave();
self.oldmask = *mask;
self.frame = frame.clone();
// context.trap_num = unsafe { (*current_thread).trap_num };
@ -368,6 +368,7 @@ pub struct SigStack {
#[no_mangle]
unsafe extern "C" fn do_signal(frame: &mut TrapFrame) {
X86_64SignalArch::do_signal(frame);
return;
}
pub struct X86_64SignalArch;
@ -377,35 +378,46 @@ impl SignalArch for X86_64SignalArch {
let pcb = ProcessManager::current_pcb();
let siginfo = pcb.try_siginfo(5);
// 检查sigpending是否为0
if siginfo
.map(|s| s.sig_pending().signal().bits() == 0)
.unwrap_or(true)
|| !frame.from_user()
{
// 若没有正在等待处理的信号,或者将要返回到的是内核态,则启用中断,然后返回
CurrentIrqArch::interrupt_enable();
if unlikely(siginfo.is_none()) {
return;
}
let siginfo_read_guard = siginfo.unwrap();
// 检查sigpending是否为0
if siginfo_read_guard.sig_pending().signal().bits() == 0 || !frame.from_user() {
// 若没有正在等待处理的信号,或者将要返回到的是内核态,则返回
return;
}
// 做完上面的检查后,开中断
CurrentIrqArch::interrupt_enable();
let pcb = ProcessManager::current_pcb();
let sig_guard = pcb.sig_struct();
let mut sig_number: Signal;
let mut info: Option<SigInfo>;
let mut sigaction: Sigaction;
let reader = pcb.sig_info();
let sig_block: SigSet = reader.sig_block().clone();
drop(reader);
let sig_block: SigSet = siginfo_read_guard.sig_block().clone();
drop(siginfo_read_guard);
let sig_guard = pcb.try_sig_struct_irq(5);
if unlikely(sig_guard.is_none()) {
return;
}
let siginfo_mut = pcb.try_siginfo_mut(5);
if unlikely(siginfo_mut.is_none()) {
return;
}
let sig_guard = sig_guard.unwrap();
let mut siginfo_mut_guard = siginfo_mut.unwrap();
loop {
(sig_number, info) = pcb.sig_info_mut().dequeue_signal(&sig_block);
(sig_number, info) = siginfo_mut_guard.dequeue_signal(&sig_block);
// 如果信号非法,则直接返回
if sig_number == Signal::INVALID {
return;
}
sigaction = sig_guard.handlers[sig_number as usize - 1];
match sigaction.action() {
SigactionType::SaHandler(action_type) => match action_type {
SaHandlerType::SigError => {
@ -425,12 +437,14 @@ impl SignalArch for X86_64SignalArch {
}
// 如果当前动作是忽略这个信号,就继续循环。
}
// 所有的信号都处理完了
let reader = pcb.sig_info();
let oldset = reader.sig_block().clone();
let oldset = siginfo_mut_guard.sig_block().clone();
//避免死锁
drop(reader);
drop(siginfo_mut_guard);
drop(sig_guard);
// 做完上面的检查后,开中断
CurrentIrqArch::interrupt_enable();
let res: Result<i32, SystemError> =
handle_signal(sig_number, &mut sigaction, &info.unwrap(), &oldset, frame);
if res.is_err() {
@ -564,7 +578,8 @@ fn setup_frame(
let frame: *mut SigFrame = get_stack(&trap_frame, size_of::<SigFrame>());
// kdebug!("frame=0x{:016x}", frame as usize);
// 要求这个frame的地址位于用户空间因此进行校验
let r = UserBufferWriter::new(frame, size_of::<SigFrame>(), true);
let r: Result<UserBufferWriter<'_>, SystemError> =
UserBufferWriter::new(frame, size_of::<SigFrame>(), true);
if r.is_err() {
// 如果地址区域位于内核空间,则直接报错
// todo: 生成一个sigsegv

View File

@ -1,39 +1,5 @@
#include "x86_64_ipi.h"
#include <driver/interrupt/apic/apic.h>
void ipi_send_IPI(uint32_t dest_mode, uint32_t deliver_status, uint32_t level, uint32_t trigger,
uint32_t vector, uint32_t deliver_mode, uint32_t dest_shorthand, uint32_t destination)
{
struct INT_CMD_REG icr_entry;
icr_entry.dest_mode = dest_mode;
icr_entry.deliver_status = deliver_status;
icr_entry.res_1 = 0;
icr_entry.level = level;
icr_entry.trigger = trigger;
icr_entry.res_2 = 0;
icr_entry.res_3 = 0;
icr_entry.vector = vector;
icr_entry.deliver_mode = deliver_mode;
icr_entry.dest_shorthand = dest_shorthand;
// x2APIC下ICR寄存器地址为0x830
// xAPIC下则为0xfee00300(31-0) 0xfee00310 (63-32)
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED) // x2APIC
{
icr_entry.destination.x2apic_destination = destination;
wrmsr(0x830, *(unsigned long *)&icr_entry); // 发送ipi
}
else // xAPIC
{
icr_entry.destination.apic_destination.dest_field = destination & 0xff;
icr_entry.destination.apic_destination.res_4 = 0;
// 先向高32bit写数据然后再向低32bit写数据不能调转
*(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + 0x310) = (uint32_t)(((*(ul *)&icr_entry) >> 32) & 0xffffffff);
*(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + 0x300) = (uint32_t)((*(ul *)&icr_entry) & 0xffffffff);
}
}
#include <arch/x86_64/driver/apic/apic.h>
int ipi_regiserIPI(uint64_t irq_num, void *arg,
void (*handler)(uint64_t irq_num, uint64_t param, struct pt_regs *regs),

View File

@ -12,22 +12,7 @@
#pragma once
#include <common/kprint.h>
#include <driver/interrupt/apic/apic.h>
/**
* @brief ipi消息
*
* @param dest_mode
* @param deliver_status
* @param level
* @param trigger
* @param vector
* @param deliver_mode
* @param dest_shorthand
* @param destination
*/
void ipi_send_IPI(uint32_t dest_mode, uint32_t deliver_status, uint32_t level, uint32_t trigger,
uint32_t vector, uint32_t deliver_mode, uint32_t dest_shorthand, uint32_t destination);
#include <arch/x86_64/driver/apic/apic.h>
/**
* @brief ipi中断处理注册函数

View File

@ -8,7 +8,7 @@ ECHO:
$(kernel_common_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)"
all: $(kernel_common_subdirs)

View File

@ -1,14 +1,14 @@
CFLAGS += -I .
kernel_driver_subdirs:=interrupt pci acpi disk keyboard mouse multiboot2 timers hid
kernel_driver_subdirs:=pci acpi disk keyboard mouse multiboot2 timers hid
ECHO:
@echo "$@"
$(kernel_driver_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)"
all: $(kernel_driver_subdirs)

View File

@ -9,7 +9,7 @@ ECHO:
@echo "$@"
$(kernel_driver_hid_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)"
$(kernel_driver_hid_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o

View File

@ -1,66 +0,0 @@
#include "8259A.h"
#include <common/printk.h>
#include <common/kprint.h>
#include <exception/gate.h>
// 导出定义在irq.c中的中段门表
extern void (*interrupt_table[24])(void);
void init_8259A()
{
// 初始化中断门, 中断使用第0个ist
for(int i=32;i<=55;++i)
set_intr_gate(i, 0, interrupt_table[i-32]);
kinfo("Initializing 8259A...");
// 初始化主芯片
io_out8(0x20, 0x11); // 初始化主芯片的icw1
io_out8(0x21, 0x20); // 设置主芯片的中断向量号为0x20(0x20-0x27)
io_out8(0x21, 0x04); // 设置int2端口级联从芯片
io_out8(0x21, 0x01); // 设置为AEOI模式、FNM、无缓冲
// 初始化从芯片
io_out8(0xa0, 0x11);
io_out8(0xa1, 0x28); // 设置从芯片的中断向量号为0x28(0x28-0x2f)
io_out8(0xa1, 0x02); // 设置从芯片连接到主芯片的int2
io_out8(0xa1, 0x01);
// 设置ocw1, 允许所有中断请求
io_out8(0x21, 0x00);
io_out8(0xa1, 0x00);
sti();
kinfo("IRQ circuit 8259A initialized.");
}
/**
* @brief
*
* @param rsp
* @param number
*/
void do_IRQ(struct pt_regs *regs, ul number)
{
unsigned char x;
switch (number)
{
case 0x20: // 时钟中断信号
break;
case 0x21: // 键盘中断
x = io_in8(0x60);
printk_color(ORANGE, BLACK, "Received key irq, key code:%#018lx\n", x);
break;
default:
break;
}
if(number!=0x20)
printk_color(ORANGE, BLACK, "Received irq:%#018x\n", number);
// 向主芯片发送中断结束信号
io_out8(PIC_master, PIC_EOI);
}

View File

@ -1,33 +0,0 @@
/**
* @file 8259A.h
* @author longjin
* @brief 8259A中断芯片
* @version 0.1
* @date 2022-01-29
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#include <common/glib.h>
#include <exception/irq.h>
#define PIC_EOI 0x20
#define PIC_master 0x20 /* IO base address for master PIC */
#define PIC2_slave 0xA0 /* IO base address for slave PIC */
// 初始化8259A芯片的中断服务
void init_8259A();
/**
* @brief
*
* @param rsp
* @param number
*/
void do_IRQ(struct pt_regs* rsp, ul number);

View File

@ -1,14 +0,0 @@
all: pic.o
# 中断处理芯片的驱动程序
ifeq ($(PIC), _INTR_8259A_)
pic.o: 8259A/8259A.c
$(CC) $(CFLAGS) -c 8259A/8259A.c -o pic.o
else
pic.o: apic/apic.c apic_timer.o
$(CC) $(CFLAGS) -c apic/apic.c -o pic.o
apic_timer.o: apic/apic_timer.c
$(CC) $(CFLAGS) -c apic/apic_timer.c -o apic/apic_timer.o
endif

View File

@ -1,741 +0,0 @@
#include "apic.h"
#include "apic_timer.h"
#include <common/cpu.h>
#include <common/glib.h>
#include <common/kprint.h>
#include <common/printk.h>
#include <driver/acpi/acpi.h>
#include <exception/gate.h>
#include <exception/softirq.h>
#include <process/process.h>
#include <sched/sched.h>
#pragma GCC push_options
#pragma GCC optimize("O0")
// 导出定义在irq.c中的中段门表
extern void (*interrupt_table[26])(void);
extern uint32_t rs_current_pcb_preempt_count();
extern uint32_t rs_current_pcb_pid();
extern uint32_t rs_current_pcb_flags();
static bool flag_support_apic = false;
static bool flag_support_x2apic = false;
uint8_t __apic_enable_state = APIC_XAPIC_ENABLED;
static uint local_apic_version;
static uint local_apic_max_LVT_entries;
static struct acpi_Multiple_APIC_Description_Table_t *madt;
static struct acpi_IO_APIC_Structure_t *io_apic_ICS;
static void __local_apic_xapic_init();
static void __local_apic_x2apic_init();
static __always_inline void __send_eoi()
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
{
__asm__ __volatile__("movq $0x00, %%rdx \n\t"
"movq $0x00, %%rax \n\t"
"movq $0x80b, %%rcx \n\t"
"wrmsr \n\t" ::
: "memory");
}
else
{
io_mfence();
__write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_EOI, 0);
io_mfence();
}
}
/**
* @brief io_apic
*
*/
void apic_io_apic_init()
{
ul madt_addr;
acpi_iter_SDT(acpi_get_MADT, &madt_addr);
madt = (struct acpi_Multiple_APIC_Description_Table_t *)madt_addr;
// kdebug("MADT->local intr controller addr=%#018lx", madt->Local_Interrupt_Controller_Address);
// kdebug("MADT->length= %d bytes", madt->header.Length);
// 寻找io apic的ICS
void *ent = (void *)(madt_addr) + sizeof(struct acpi_Multiple_APIC_Description_Table_t);
struct apic_Interrupt_Controller_Structure_header_t *header =
(struct apic_Interrupt_Controller_Structure_header_t *)ent;
while (header->length > 2)
{
header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
if (header->type == 1)
{
struct acpi_IO_APIC_Structure_t *t = (struct acpi_IO_APIC_Structure_t *)ent;
// kdebug("IO apic addr = %#018lx", t->IO_APIC_Address);
io_apic_ICS = t;
break;
}
ent += header->length;
}
// kdebug("Global_System_Interrupt_Base=%d", io_apic_ICS->Global_System_Interrupt_Base);
apic_ioapic_map.addr_phys = io_apic_ICS->IO_APIC_Address;
apic_ioapic_map.virtual_index_addr = (unsigned char *)APIC_IO_APIC_VIRT_BASE_ADDR;
apic_ioapic_map.virtual_data_addr = (uint *)(APIC_IO_APIC_VIRT_BASE_ADDR + 0x10);
apic_ioapic_map.virtual_EOI_addr = (uint *)(APIC_IO_APIC_VIRT_BASE_ADDR + 0x40);
// kdebug("(ul)apic_ioapic_map.virtual_index_addr=%#018lx", (ul)apic_ioapic_map.virtual_index_addr);
// 填写页表,完成地址映射
rs_map_phys((ul)apic_ioapic_map.virtual_index_addr, apic_ioapic_map.addr_phys, PAGE_2M_SIZE,
PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
// 设置IO APIC ID 为0x0f000000
*apic_ioapic_map.virtual_index_addr = 0x00;
io_mfence();
*apic_ioapic_map.virtual_data_addr = 0x0f000000;
io_mfence();
// kdebug("I/O APIC ID:%#010x", ((*apic_ioapic_map.virtual_data_addr) >> 24) & 0xff);
io_mfence();
// 获取IO APIC Version
*apic_ioapic_map.virtual_index_addr = 0x01;
io_mfence();
kdebug("IO APIC Version=%d, Max Redirection Entries=%d", *apic_ioapic_map.virtual_data_addr & 0xff,
(((*apic_ioapic_map.virtual_data_addr) >> 16) & 0xff) + 1);
// 初始化RTE表项将所有RTE表项屏蔽
for (int i = 0x10; i < 0x40; i += 2)
{
// 以0x20为起始中断向量号初始化RTE
apic_ioapic_write_rte(i, 0x10020 + ((i - 0x10) >> 1));
}
// 不需要手动启动IO APIC只要初始化了RTE寄存器之后io apic就会自动启用了。
// 而且不是每台电脑都有RCBA寄存器因此不需要手动启用IO APIC
}
/**
* @brief AP处理器的Local apic
*
*/
void apic_init_ap_core_local_apic()
{
kinfo("Initializing AP-core's local apic...");
uint eax, edx;
// 启用xAPIC 和x2APIC
uint64_t ia32_apic_base = rdmsr(0x1b);
ia32_apic_base |= (1 << 11);
if (flag_support_x2apic) // 如果支持x2apic则启用
{
ia32_apic_base |= (1 << 10);
wrmsr(0x1b, ia32_apic_base);
}
ia32_apic_base = rdmsr(0x1b);
eax = ia32_apic_base & 0xffffffff;
// 检测是否成功启用xAPIC和x2APIC
if ((eax & 0xc00) == 0xc00)
kinfo("xAPIC & x2APIC enabled!");
else if ((eax & 0x800) == 0x800)
kinfo("Only xAPIC enabled!");
else
kerror("Both xAPIC and x2APIC are not enabled.");
// 设置SVR寄存器开启local APIC、禁止EOI广播
if (flag_support_x2apic) // 当前为x2APIC
__local_apic_x2apic_init();
else // 当前为xapic
__local_apic_xapic_init();
barrier();
kdebug("AP-core's local apic initialized.");
barrier();
}
/**
* @brief 使xapic来初始化local apic
*
*/
static void __local_apic_xapic_init()
{
__apic_enable_state = APIC_XAPIC_ENABLED;
// 设置svr的 apic软件使能位
uint64_t qword = *(uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR);
qword |= (1 << 8);
*(volatile uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR) = qword;
qword = *(volatile uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR);
if (qword & 0x100)
kinfo("APIC Software Enabled.");
if (qword & 0x1000)
kinfo("EOI-Broadcast Suppression Enabled.");
barrier();
// 从 Local APIC Version register 获取Local APIC Version
qword = *(volatile uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_Version);
qword &= 0xffffffff;
local_apic_max_LVT_entries = ((qword >> 16) & 0xff) + 1;
local_apic_version = qword & 0xff;
kdebug("local APIC Version:%#010x,Max LVT Entry:%#010x,SVR(Suppress EOI Broadcast):%#04x\t", local_apic_version,
local_apic_max_LVT_entries, (qword >> 24) & 0x1);
if ((qword & 0xff) < 0x10)
{
kdebug("82489DX discrete APIC");
}
else if (((qword & 0xff) >= 0x10) && ((qword & 0xff) <= 0x15))
kdebug("Integrated APIC.");
io_mfence();
// 如果写入这里的话,在有的机器上面会报错
// *(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI) = APIC_LVT_INT_MASKED;
io_mfence();
*(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER) = APIC_LVT_INT_MASKED;
io_mfence();
*(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL) = APIC_LVT_INT_MASKED;
io_mfence();
*(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR) =
APIC_LVT_INT_MASKED;
io_mfence();
*(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0) = APIC_LVT_INT_MASKED;
io_mfence();
*(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1) = APIC_LVT_INT_MASKED;
io_mfence();
*(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR) = APIC_LVT_INT_MASKED;
io_mfence();
kdebug("All LVT Masked");
}
/**
* @brief 使x2apic来初始化local apic
*
*/
static void __local_apic_x2apic_init()
{
__apic_enable_state = APIC_X2APIC_ENABLED;
uint32_t eax, edx;
__asm__ __volatile__("movq $0x80f, %%rcx \n\t"
"rdmsr \n\t"
"bts $8, %%rax \n\t"
// "bts $12, %%rax \n\t"
"movq $0x80f, %%rcx \n\t"
"wrmsr \n\t"
"movq $0x80f , %%rcx \n\t"
"rdmsr \n\t"
: "=a"(eax), "=d"(edx)::"memory");
if (eax & 0x100)
kinfo("APIC Software Enabled.");
if (eax & 0x1000)
kinfo("EOI-Broadcast Suppression Enabled.");
// 获取Local APIC Version
// 0x803处是 Local APIC Version register
__asm__ __volatile__("movq $0x803, %%rcx \n\t"
"rdmsr \n\t"
: "=a"(eax), "=d"(edx)::"memory");
local_apic_max_LVT_entries = ((eax >> 16) & 0xff) + 1;
local_apic_version = eax & 0xff;
kdebug("local APIC Version:%#010x,Max LVT Entry:%#010x,SVR(Suppress EOI Broadcast):%#04x\t", local_apic_version,
local_apic_max_LVT_entries, (eax >> 24) & 0x1);
if ((eax & 0xff) < 0x10)
kdebug("82489DX discrete APIC");
else if (((eax & 0xff) >= 0x10) && ((eax & 0xff) <= 0x15))
kdebug("Integrated APIC.");
// 由于尚未配置LVT对应的处理程序因此先屏蔽所有的LVT
__asm__ __volatile__( // "movq $0x82f, %%rcx \n\t" // CMCI
// "wrmsr \n\t"
"movq $0x832, %%rcx \n\t" // Timer
"wrmsr \n\t"
"movq $0x833, %%rcx \n\t" // Thermal Monitor
"wrmsr \n\t"
"movq $0x834, %%rcx \n\t" // Performance Counter
"wrmsr \n\t"
"movq $0x835, %%rcx \n\t" // LINT0
"wrmsr \n\t"
"movq $0x836, %%rcx \n\t" // LINT1
"wrmsr \n\t"
"movq $0x837, %%rcx \n\t" // Error
"wrmsr \n\t"
:
: "a"(0x10000), "d"(0x00)
: "memory");
kdebug("All LVT Masked");
}
/**
* @brief local apic
*
*/
void apic_local_apic_init()
{
uint64_t ia32_apic_base = rdmsr(0x1b);
// kdebug("apic base=%#018lx", (ia32_apic_base & 0x1FFFFFFFFFF000));
// 映射Local APIC 寄存器地址
// todo:
rs_map_phys(APIC_LOCAL_APIC_VIRT_BASE_ADDR, (ia32_apic_base & 0x1FFFFFFFFFF000), PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
uint a, b, c, d;
cpu_cpuid(1, 0, &a, &b, &c, &d);
// kdebug("CPUID 0x01, eax:%#010lx, ebx:%#010lx, ecx:%#010lx, edx:%#010lx", a, b, c, d);
// 判断是否支持APIC和xAPIC
if ((1 << 9) & d)
{
flag_support_apic = true;
kdebug("This computer support APIC&xAPIC");
}
else
{
flag_support_apic = false;
kerror("This computer does not support APIC&xAPIC");
while (1)
;
}
// 判断是否支持x2APIC
if ((1 << 21) & c)
{
flag_support_x2apic = true;
kdebug("This computer support x2APIC");
}
else
{
flag_support_x2apic = false;
kwarn("This computer does not support x2APIC");
}
uint eax, edx;
// 启用xAPIC 和x2APIC
ia32_apic_base = rdmsr(0x1b);
ia32_apic_base |= (1 << 11);
if (flag_support_x2apic) // 如果支持x2apic则启用
{
ia32_apic_base |= (1 << 10);
wrmsr(0x1b, ia32_apic_base);
}
ia32_apic_base = rdmsr(0x1b);
eax = ia32_apic_base & 0xffffffff;
// 检测是否成功启用xAPIC和x2APIC
if ((eax & 0xc00) == 0xc00)
kinfo("xAPIC & x2APIC enabled!\n");
else if ((eax & 0x800) == 0x800)
kinfo("Only xAPIC enabled!");
else
kerror("Both xAPIC and x2APIC are not enabled.");
// 设置SVR寄存器开启local APIC、禁止EOI广播
if (flag_support_x2apic) // 当前为x2APIC
__local_apic_x2apic_init();
else // 当前为xapic
__local_apic_xapic_init();
// 获取Local APIC的基础信息 参见英特尔开发手册Vol3A 10-39
// Table 10-6. Local APIC Register Address Map Supported by x2APIC
// 获取 Local APIC ID
// 0x802处是x2APIC ID 位宽32bits 的 Local APIC ID register
/*
__asm__ __volatile__("movq $0x802, %%rcx \n\t"
"rdmsr \n\t"
: "=a"(eax), "=d"(edx)::"memory");
*/
// kdebug("get Local APIC ID: edx=%#010x, eax=%#010x", edx, eax);
// kdebug("local_apic_id=%#018lx", *(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ID));
}
/**
* @brief apic控制器
*
*/
int apic_init()
{
cli();
kinfo("Initializing APIC...");
// 初始化中断门, 中断使用rsp0防止在软中断时发生嵌套然后处理器重新加载导致数据被抹掉
for (int i = 32; i <= 57; ++i)
set_intr_gate(i, 0, interrupt_table[i - 32]);
// 设置local apic中断门
for (int i = 150; i < 160; ++i)
set_intr_gate(i, 0, local_apic_interrupt_table[i - 150]);
// 屏蔽类8259A芯片
io_out8(0x21, 0xff);
io_out8(0xa1, 0xff);
// 写入8259A pic的EOI位
io_out8(0x20, 0x20);
io_out8(0xa0, 0x20);
kdebug("8259A Masked.");
// enable IMCR
io_out8(0x22, 0x70);
io_out8(0x23, 0x01);
apic_local_apic_init();
apic_io_apic_init();
// get RCBA address
io_out32(0xcf8, 0x8000f8f0);
uint32_t RCBA_phys = io_in32(0xcfc);
// 获取RCBA寄存器的地址
if (RCBA_phys > 0xfec00000 && RCBA_phys < 0xfee00000)
RCBA_vaddr = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + RCBA_phys;
else
{
RCBA_vaddr = 0;
kwarn("Cannot get RCBA address. RCBA_phys=%#010lx", RCBA_phys);
}
kinfo("APIC initialized.");
// sti();
return 0;
}
/**
* @brief
*
* @param rsp
* @param number
*/
void do_IRQ(struct pt_regs *rsp, ul number)
{
if((rsp->cs & 0x3) == 3)
{
asm volatile("swapgs":::"memory");
}
if (number < 0x80 && number >= 32) // 以0x80为界限低于0x80的是外部中断控制器高于0x80的是Local APIC
{
// ==========外部中断控制器========
irq_desc_t *irq = &interrupt_desc[number - 32];
// 执行中断上半部处理程序
if (irq != NULL && irq->handler != NULL)
irq->handler(number, irq->parameter, rsp);
else
kwarn("Intr vector [%d] does not have a handler!");
// 向中断控制器发送应答消息
if (irq->controller != NULL && irq->controller->ack != NULL)
irq->controller->ack(number);
else
__send_eoi();
}
else if (number >= 200)
{
apic_local_apic_edge_ack(number);
{
irq_desc_t *irq = &SMP_IPI_desc[number - 200];
if (irq->handler != NULL)
irq->handler(number, irq->parameter, rsp);
}
}
else if (number >= 150 && number < 200)
{
irq_desc_t *irq = &local_apic_interrupt_desc[number - 150];
// 执行中断上半部处理程序
if (irq != NULL && irq->handler != NULL)
irq->handler(number, irq->parameter, rsp);
else
kwarn("Intr vector [%d] does not have a handler!");
// 向中断控制器发送应答消息
if (irq->controller != NULL && irq->controller->ack != NULL)
irq->controller->ack(number);
else
__send_eoi(); // 向EOI寄存器写入0x00表示结束中断
}
else
{
kwarn("do IRQ receive: %d", number);
// 忽略未知中断
return;
}
// kdebug("before softirq");
// 进入软中断处理程序
rs_do_softirq();
// kdebug("after softirq");
// 检测当前进程是否持有自旋锁,若持有自旋锁,则不进行抢占式的进程调度
if (rs_current_pcb_preempt_count() > 0)
{
return;
}
else if (rs_current_pcb_preempt_count() < 0)
kBUG("current_pcb->preempt_count<0! pid=%d", rs_current_pcb_pid()); // should not be here
// 检测当前进程是否可被调度
if ((rs_current_pcb_flags() & PF_NEED_SCHED) && number == APIC_TIMER_IRQ_NUM)
{
io_mfence();
sched();
}
}
/**
* @brief RTE寄存器
* RTE位宽为64位而IO window寄存器只有32位
* @param index
* @return ul
*/
ul apic_ioapic_read_rte(unsigned char index)
{
// 由于处理器的乱序执行的问题,需要加入内存屏障以保证结果的正确性。
ul ret;
// 先读取高32bit
*apic_ioapic_map.virtual_index_addr = index + 1;
io_mfence();
ret = *apic_ioapic_map.virtual_data_addr;
ret <<= 32;
io_mfence();
// 读取低32bit
*apic_ioapic_map.virtual_index_addr = index;
io_mfence();
ret |= *apic_ioapic_map.virtual_data_addr;
io_mfence();
return ret;
}
/**
* @brief RTE寄存器
*
* @param index
* @param value
*/
void apic_ioapic_write_rte(unsigned char index, ul value)
{
// 先写入低32bit
*apic_ioapic_map.virtual_index_addr = index;
io_mfence();
*apic_ioapic_map.virtual_data_addr = value & 0xffffffff;
io_mfence();
// 再写入高32bit
value >>= 32;
io_mfence();
*apic_ioapic_map.virtual_index_addr = index + 1;
io_mfence();
*apic_ioapic_map.virtual_data_addr = value & 0xffffffff;
io_mfence();
}
// =========== 中断控制操作接口 ============
void apic_ioapic_enable(ul irq_num)
{
ul index = 0x10 + ((irq_num - 32) << 1);
ul value = apic_ioapic_read_rte(index);
value &= (~0x10000UL);
apic_ioapic_write_rte(index, value);
}
void apic_ioapic_disable(ul irq_num)
{
ul index = 0x10 + ((irq_num - 32) << 1);
ul value = apic_ioapic_read_rte(index);
value |= (0x10000UL);
apic_ioapic_write_rte(index, value);
}
ul apic_ioapic_install(ul irq_num, void *arg)
{
struct apic_IO_APIC_RTE_entry *entry = (struct apic_IO_APIC_RTE_entry *)arg;
// RTE表项值写入对应的RTE寄存器
apic_ioapic_write_rte(0x10 + ((irq_num - 32) << 1), *(ul *)entry);
return 0;
}
void apic_ioapic_uninstall(ul irq_num)
{
// 将对应的RTE表项设置为屏蔽状态
apic_ioapic_write_rte(0x10 + ((irq_num - 32) << 1), 0x10000UL);
}
void apic_ioapic_level_ack(ul irq_num) // 电平触发
{
__send_eoi();
*apic_ioapic_map.virtual_EOI_addr = irq_num;
}
void apic_ioapic_edge_ack(ul irq_num) // 边沿触发
{
// 向EOI寄存器写入0x00表示结束中断
/*
uint *eoi = (uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_EOI);
*eoi = 0x00;
*/
__send_eoi();
}
/**
* @brief local apic 沿
*
* @param irq_num
*/
void apic_local_apic_edge_ack(ul irq_num)
{
// 向EOI寄存器写入0x00表示结束中断
__send_eoi();
}
/**
* @brief Interrupt Control Structure
*
* @param type ics的类型
* @param ret_vaddr ICS的虚拟地址数组
* @param total
* @return uint
*/
uint apic_get_ics(const uint type, ul ret_vaddr[], uint *total)
{
void *ent = (void *)(madt) + sizeof(struct acpi_Multiple_APIC_Description_Table_t);
struct apic_Interrupt_Controller_Structure_header_t *header =
(struct apic_Interrupt_Controller_Structure_header_t *)ent;
bool flag = false;
uint cnt = 0;
while (header->length > 2)
{
header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
if (header->type == type)
{
ret_vaddr[cnt++] = (ul)ent;
flag = true;
}
ent += header->length;
}
*total = cnt;
if (!flag)
return APIC_E_NOTFOUND;
else
return APIC_SUCCESS;
}
/**
* @brief RTE Entry结构体
*
* @param entry
* @param vector
* @param deliver_mode
* @param dest_mode
* @param deliver_status
* @param polarity
* @param irr IRR标志位
* @param trigger
* @param mask 0 1
* @param dest_apicID apicID
*/
void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, uint8_t deliver_mode, uint8_t dest_mode,
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask,
uint8_t dest_apicID)
{
entry->vector = vector;
entry->deliver_mode = deliver_mode;
entry->dest_mode = dest_mode;
entry->deliver_status = deliver_status;
entry->polarity = polarity;
entry->remote_IRR = irr;
entry->trigger_mode = trigger;
entry->mask = mask;
entry->reserved = 0;
if (dest_mode == DEST_PHYSICAL)
{
entry->destination.physical.phy_dest = dest_apicID;
entry->destination.physical.reserved1 = 0;
entry->destination.physical.reserved2 = 0;
}
else
{
entry->destination.logical.logical_dest = dest_apicID;
entry->destination.logical.reserved1 = 0;
}
}
/**
* @brief local apic id
*
* @return uint32_t
*/
uint32_t apic_get_local_apic_id()
{
// 获取Local APIC的基础信息 参见英特尔开发手册Vol3A 10-39
// Table 10-6. Local APIC Register Address Map Supported by x2APIC
if (flag_support_x2apic)
{
// 获取 Local APIC ID
// 0x802处是x2APIC ID 位宽32bits 的 Local APIC ID register
uint32_t x = 0;
__asm__ __volatile__("movq $0x802, %%rcx \n\t"
"rdmsr \n\t"
: "=a"(x)::"memory");
return x;
}
else
{
// kdebug("get Local APIC ID: edx=%#010x, eax=%#010x", edx, eax);
// kdebug("local_apic_id=%#018lx", );
uint32_t x = *(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ID);
x = ((x >> 24) & 0xff);
return x;
}
}
/**
* icr寄存器
*
* @param value
*/
void apic_write_icr(uint64_t value)
{
if (flag_support_x2apic)
{
wrmsr(0x830, value);
}
else
{
// kdebug("to write icr: %#018lx", value);
const uint64_t PENDING = 1UL << 12;
while (*(volatile uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0) & PENDING)
;
// kdebug("write icr: %#018lx", value);
*(volatile uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32) = (value >> 32) & 0xffffffff;
*(volatile uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0) = value & 0xffffffff;
while (*(volatile uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0) & PENDING)
;
// kdebug("write icr done");
}
}
// 查询是否启用了x2APIC
bool apic_x2apic_enabled()
{
return flag_support_x2apic;
}
#pragma GCC pop_options

View File

@ -1,2 +0,0 @@
#include <common/stddef.h>
extern uint64_t ioapic_get_base_paddr();

View File

@ -1,110 +0,0 @@
#pragma once
#include <common/unistd.h>
#include "apic.h"
extern uint64_t apic_timer_ticks_result;
// 5ms产生一次中断
#define APIC_TIMER_INTERVAL 5
#define APIC_TIMER_DIVISOR 3
#define APIC_TIMER_IRQ_NUM 151
#pragma GCC push_options
#pragma GCC optimize("O0")
/**
* @brief apic定时器的分频计数
*
* @param divider
*/
static __always_inline void apic_timer_set_div(uint64_t divider)
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x83e, divider);
else
__write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CLKDIV, divider);
}
/**
* @brief apic定时器的初始计数值
*
* @param init_cnt
*/
static __always_inline void apic_timer_set_init_cnt(uint32_t init_cnt)
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x838, init_cnt);
else
__write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG, init_cnt);
}
/**
* @brief apic定时器的lvt
*
* @param vector
* @param mask 1 0
* @param mode
*/
static __always_inline void apic_timer_set_LVT(uint32_t vector, uint32_t mask, uint32_t mode)
{
register uint32_t val = (mode << 17) | vector | (mask ? (APIC_LVT_INT_MASKED) : 0);
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x832, val);
else
__write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER, val);
}
static __always_inline void apic_timer_write_LVT(uint32_t value)
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x832, value);
else
__write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER, value);
}
/**
* @brief apic定时器的LVT的值
*
*/
static __always_inline uint32_t apic_timer_get_LVT()
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
return rdmsr(0x832);
else
return __read4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER);
}
/**
* @brief apic定时器当前计数值
*
*/
static __always_inline uint32_t apic_timer_get_current()
{
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
return (uint32_t)rdmsr(0x839);
else
return __read4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG);
}
/**
* @brief apic定时器
*
*/
#define apic_timer_stop() \
do \
{ \
uint32_t val = apic_timer_get_LVT(); \
val |= APIC_LVT_INT_MASKED; \
apic_timer_write_LVT(val); \
} while (0)
/**
* @brief local APIC定时器
*
*/
void apic_timer_init();
void apic_timer_ap_core_init();
#pragma GCC pop_options

View File

@ -1,5 +1,5 @@
#include "ps2_keyboard.h"
#include <driver/interrupt/apic/apic.h>
#include <arch/x86_64/driver/apic/apic.h>
#include <mm/mm.h>
#include <mm/slab.h>
#include <common/printk.h>

View File

@ -1,5 +1,5 @@
#include "ps2_mouse.h"
#include <driver/interrupt/apic/apic.h>
#include <arch/x86_64/driver/apic/apic.h>
#include <mm/mm.h>
#include <mm/slab.h>
#include <common/printk.h>
@ -209,19 +209,19 @@ void ps2_mouse_init()
// ======== 初始化中断RTE entry ==========
ps2_mouse_entry.vector = PS2_MOUSE_INTR_VECTOR; // 设置中断向量号
ps2_mouse_entry.deliver_mode = IO_APIC_FIXED; // 投递模式:混合
ps2_mouse_entry.dest_mode = DEST_PHYSICAL; // 物理模式投递中断
ps2_mouse_entry.deliver_status = IDLE;
ps2_mouse_entry.trigger_mode = EDGE_TRIGGER; // 设置边沿触发
ps2_mouse_entry.polarity = POLARITY_HIGH; // 高电平触发
ps2_mouse_entry.remote_IRR = IRR_RESET;
ps2_mouse_entry.mask = MASKED;
ps2_mouse_entry.reserved = 0;
// ps2_mouse_entry.vector = PS2_MOUSE_INTR_VECTOR; // 设置中断向量号
// ps2_mouse_entry.deliver_mode = IO_APIC_FIXED; // 投递模式:混合
// ps2_mouse_entry.dest_mode = DEST_PHYSICAL; // 物理模式投递中断
// ps2_mouse_entry.deliver_status = IDLE;
// ps2_mouse_entry.trigger_mode = EDGE_TRIGGER; // 设置边沿触发
// ps2_mouse_entry.polarity = POLARITY_HIGH; // 高电平触发
// ps2_mouse_entry.remote_IRR = IRR_RESET;
// ps2_mouse_entry.mask = MASKED;
// ps2_mouse_entry.reserved = 0;
ps2_mouse_entry.destination.physical.reserved1 = 0;
ps2_mouse_entry.destination.physical.reserved2 = 0;
ps2_mouse_entry.destination.physical.phy_dest = 0; // 设置投递到BSP处理器
// ps2_mouse_entry.destination.physical.reserved1 = 0;
// ps2_mouse_entry.destination.physical.reserved2 = 0;
// ps2_mouse_entry.destination.physical.phy_dest = 0; // 设置投递到BSP处理器
// 注册中断处理程序
irq_register(PS2_MOUSE_INTR_VECTOR, &ps2_mouse_entry, &ps2_mouse_handler, (ul)ps2_mouse_buf_ptr, &ps2_mouse_intr_controller, "ps/2 mouse");

View File

@ -68,7 +68,7 @@ ENTRY(ret_from_intr)
// do_signal
movq %rsp, %rdi
callq do_signal
cli
__entry_ret_from_intr_before_gs_check_2:
push %rcx
@ -138,6 +138,7 @@ __entry_err_code_after_gs_check_1:
callq *%rdx // *
__entry_err_code_to_ret_from_exception:
jmp ret_from_exception

View File

@ -5,7 +5,7 @@
#if _INTR_8259A_
#include <driver/interrupt/8259A/8259A.h>
#else
#include <driver/interrupt/apic/apic.h>
#include <arch/x86_64/driver/apic/apic.h>
#endif
#include "gate.h"
@ -90,7 +90,7 @@ Build_IRQ(0x38);
Build_IRQ(0x39);
// 初始化中断数组
void (*interrupt_table[26])(void) = {
void (*interrupt_table[IRQ_NUM])(void) = {
IRQ0x20interrupt,
IRQ0x21interrupt,
IRQ0x22interrupt,

View File

@ -20,7 +20,7 @@
#define SMP_IRQ_NUM 10
#define LOCAL_APIC_IRQ_NUM 50
extern void (*interrupt_table[26])(void);
extern void (*interrupt_table[IRQ_NUM])(void);
extern void do_IRQ(struct pt_regs *regs, ul number);
@ -108,6 +108,8 @@ extern void (*local_apic_interrupt_table[LOCAL_APIC_IRQ_NUM])(void);
*/
#define APIC_TIMER_IRQ_NUM 151
typedef struct hardware_intr_type
{
// 使能中断操作接口

View File

@ -159,7 +159,6 @@ impl File {
if self.offset > self.inode.metadata()?.size as usize {
return Ok(0);
}
let len = self
.inode
.read_at(self.offset, len, buf, &mut self.private_data)?;

View File

@ -43,4 +43,4 @@
#include <driver/pci/pci_irq.h>
#include <common/errno.h>
#include <common/cpu.h>
#include <driver/interrupt/apic/apic2rust.h>
#include <exception/irq.h>

View File

@ -9,6 +9,7 @@
#![feature(core_intrinsics)]
#![feature(c_void_variant)]
#![feature(drain_filter)]
#![feature(inline_const)]
#![feature(is_some_and)]
#![feature(naked_functions)]
#![feature(panic_info_message)]

View File

@ -9,7 +9,7 @@ ECHO:
@echo "$@"
$(kernel_lib_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)"
$(kernel_lib_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o

View File

@ -0,0 +1,46 @@
use core::{cell::UnsafeCell, fmt::Debug};
/// 一个无锁的标志位
///
/// 可与bitflags配合使用以实现无锁的标志位
///
/// ## Safety
///
/// 由于标识位的修改是无锁,且不保证原子性,因此需要使用者自行在别的机制中,确保
/// 哪怕标识位的值是老的,执行动作也不会有问题(或者有状态恢复机制)。
pub struct LockFreeFlags<T> {
inner: UnsafeCell<T>,
}
impl<T> LockFreeFlags<T> {
pub unsafe fn new(inner: T) -> Self {
Self {
inner: UnsafeCell::new(inner),
}
}
pub fn get_mut(&self) -> &mut T {
unsafe { &mut *self.inner.get() }
}
pub fn get(&self) -> &T {
unsafe { &*self.inner.get() }
}
}
unsafe impl<T: Sync> Sync for LockFreeFlags<T> {}
unsafe impl<T: Send> Send for LockFreeFlags<T> {}
impl<T: Clone> Clone for LockFreeFlags<T> {
fn clone(&self) -> Self {
unsafe { Self::new(self.get().clone()) }
}
}
impl<T: Debug> Debug for LockFreeFlags<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LockFreeFlags")
.field("inner", self.get())
.finish()
}
}

View File

@ -8,6 +8,7 @@ pub mod int_like;
pub mod keyboard_parser;
pub mod lazy_init;
pub mod lib_ui;
pub mod lock_free_flags;
pub mod mutex;
pub mod notifier;
pub mod once;

View File

@ -265,6 +265,20 @@ impl<T> RwLock<T> {
return r;
}
#[allow(dead_code)]
pub fn try_upgradeable_read_irqsave(&self) -> Option<RwLockUpgradableGuard<T>> {
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
ProcessManager::preempt_disable();
let mut r = self.inner_try_upgradeable_read();
if r.is_none() {
ProcessManager::preempt_enable();
} else {
r.as_mut().unwrap().irq_guard = Some(irq_guard);
}
return r;
}
fn inner_try_upgradeable_read(&self) -> Option<RwLockUpgradableGuard<T>> {
// 获得UPGRADER守卫不需要查看读者位
// 如果获得读者锁失败,不需要撤回fetch_or的原子操作

View File

@ -28,7 +28,7 @@
#include "driver/multiboot2/multiboot2.h"
#include <time/timer.h>
#include <driver/interrupt/apic/apic_timer.h>
#include <arch/x86_64/driver/apic/apic_timer.h>
#include <virt/kvm/kvm.h>
extern int rs_driver_init();
@ -148,6 +148,7 @@ void system_initialize()
rs_pci_init();
// 这里必须加内存屏障,否则会出错
io_mfence();
smp_init();
@ -167,6 +168,7 @@ void system_initialize()
// 系统初始化到此结束,剩下的初始化功能应当放在初始内核线程中执行
apic_timer_init();
// while(1);
io_mfence();
sti();
while (1)

View File

@ -188,7 +188,7 @@ impl ProcessManager {
if clone_flags.contains(CloneFlags::CLONE_VM) {
new_pcb.flags().insert(ProcessFlags::VFORK);
}
*new_pcb.flags.lock() = ProcessManager::current_pcb().flags().clone();
*new_pcb.flags.get_mut() = ProcessManager::current_pcb().flags().clone();
return Ok(());
}

View File

@ -253,7 +253,7 @@ impl KernelThreadMechanism {
// 由于当前是pid=0的idle进程,而__inner_create要求当前是kthread,所以先临时设置为kthread
ProcessManager::current_pcb()
.flags
.lock()
.get_mut()
.insert(ProcessFlags::KTHREAD);
create_info
.set_to_mark_sleep(false)
@ -266,7 +266,7 @@ impl KernelThreadMechanism {
ProcessManager::current_pcb()
.flags
.lock()
.get_mut()
.remove(ProcessFlags::KTHREAD);
drop(irq_guard);
kinfo!("Initializing kernel thread mechanism stage1 complete");

View File

@ -34,6 +34,7 @@ use crate::{
constant::{FutexFlag, FUTEX_BITSET_MATCH_ANY},
futex::Futex,
},
lock_free_flags::LockFreeFlags,
rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableGuard, RwLockWriteGuard},
spinlock::{SpinLock, SpinLockGuard},
wait_queue::WaitQueue,
@ -182,7 +183,7 @@ impl ProcessManager {
let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
let state = pcb.sched_info().state();
if state.is_blocked() {
let mut writer = pcb.sched_info_mut();
let mut writer: RwLockWriteGuard<'_, ProcessSchedulerInfo> = pcb.sched_info_mut();
let state = writer.state();
if state.is_blocked() {
writer.set_state(ProcessState::Runnable);
@ -505,7 +506,7 @@ pub struct ProcessControlBlock {
/// 当前进程的自旋锁持有计数
preempt_count: AtomicUsize,
flags: SpinLock<ProcessFlags>,
flags: LockFreeFlags<ProcessFlags>,
worker_private: SpinLock<Option<WorkerPrivate>>,
/// 进程的内核栈
kernel_stack: RwLock<KernelStack>,
@ -571,7 +572,7 @@ impl ProcessControlBlock {
let basic_info = ProcessBasicInfo::new(Pid(0), ppid, name, cwd, None);
let preempt_count = AtomicUsize::new(0);
let flags = SpinLock::new(ProcessFlags::empty());
let flags = unsafe { LockFreeFlags::new(ProcessFlags::empty()) };
let sched_info = ProcessSchedulerInfo::new(None);
let arch_info = SpinLock::new(ArchPCBInfo::new(&kstack));
@ -662,8 +663,8 @@ impl ProcessControlBlock {
}
#[inline(always)]
pub fn flags(&self) -> SpinLockGuard<ProcessFlags> {
return self.flags.lock();
pub fn flags(&self) -> &mut ProcessFlags {
return self.flags.get_mut();
}
#[inline(always)]
@ -707,6 +708,17 @@ impl ProcessControlBlock {
return self.sched_info.read();
}
#[inline(always)]
pub fn try_sched_info(&self, times: u8) -> Option<RwLockReadGuard<ProcessSchedulerInfo>> {
for _ in 0..times {
if let Some(r) = self.sched_info.try_read() {
return Some(r);
}
}
return None;
}
#[allow(dead_code)]
#[inline(always)]
pub fn sched_info_irqsave(&self) -> RwLockReadGuard<ProcessSchedulerInfo> {
@ -714,8 +726,16 @@ impl ProcessControlBlock {
}
#[inline(always)]
pub fn sched_info_upgradeable_irqsave(&self) -> RwLockUpgradableGuard<ProcessSchedulerInfo> {
return self.sched_info.upgradeable_read();
pub fn sched_info_try_upgradeable_irqsave(
&self,
times: u8,
) -> Option<RwLockUpgradableGuard<ProcessSchedulerInfo>> {
for _ in 0..times {
if let Some(r) = self.sched_info.try_upgradeable_read_irqsave() {
return Some(r);
}
}
return None;
}
#[inline(always)]
@ -816,10 +836,30 @@ impl ProcessControlBlock {
self.sig_info.write()
}
pub fn try_siginfo_mut(&self, times: u8) -> Option<RwLockWriteGuard<ProcessSignalInfo>> {
for _ in 0..times {
if let Some(r) = self.sig_info.try_write() {
return Some(r);
}
}
return None;
}
pub fn sig_struct(&self) -> SpinLockGuard<SignalStruct> {
self.sig_struct.lock()
}
pub fn try_sig_struct_irq(&self, times: u8) -> Option<SpinLockGuard<SignalStruct>> {
for _ in 0..times {
if let Ok(r) = self.sig_struct.try_lock_irqsave() {
return Some(r);
}
}
return None;
}
pub fn sig_struct_irq(&self) -> SpinLockGuard<SignalStruct> {
self.sig_struct.lock_irqsave()
}

View File

@ -1,18 +0,0 @@
CFLAGS += -I .
kernel_sched_objs:= $(shell find ./*.c)
ECHO:
@echo "$@"
$(kernel_sched_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
all: $(kernel_sched_objs)
clean:
echo "Done."

View File

@ -9,9 +9,12 @@ use crate::{
kBUG,
libs::{
rbtree::RBTree,
rwlock::RwLockReadGuard,
spinlock::{SpinLock, SpinLockGuard},
},
process::{ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState},
process::{
ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSchedulerInfo, ProcessState,
},
smp::core::smp_get_processor_id,
};
@ -142,12 +145,25 @@ impl SchedulerCFS {
}
/// @brief 时钟中断到来时由sched的core模块中的函数调用本函数更新CFS进程的可执行时间
pub fn timer_update_jiffies(&mut self) {
pub fn timer_update_jiffies(
&mut self,
sched_info_guard: &RwLockReadGuard<'_, ProcessSchedulerInfo>,
) {
let current_cpu_queue: &mut CFSQueue = self.cpu_queue[smp_get_processor_id() as usize];
// todo: 引入调度周期以及所有进程的优先权进行计算,然后设置进程的可执行时间
let mut queue = None;
for _ in 0..10 {
if let Ok(q) = current_cpu_queue.locked_queue.try_lock() {
queue = Some(q);
break;
}
}
if queue.is_none() {
return;
}
let queue = queue.unwrap();
// 更新进程的剩余可执行时间
let queue = current_cpu_queue.locked_queue.lock();
current_cpu_queue.cpu_exec_proc_jiffies -= 1;
// 时间片耗尽,标记需要被调度
if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
@ -158,9 +174,7 @@ impl SchedulerCFS {
drop(queue);
// 更新当前进程的虚拟运行时间
ProcessManager::current_pcb()
.sched_info()
.increase_virtual_runtime(1);
sched_info_guard.increase_virtual_runtime(1);
}
/// @brief 将进程加入cpu的cfs调度队列并且重设其虚拟运行时间为当前队列的最小值

View File

@ -1,4 +1,7 @@
use core::sync::atomic::{compiler_fence, Ordering};
use core::{
intrinsics::unlikely,
sync::atomic::{compiler_fence, Ordering},
};
use alloc::{sync::Arc, vec::Vec};
@ -51,8 +54,8 @@ impl CpuExecuting {
pub fn get_cpu_loads(cpu_id: u32) -> u32 {
let cfs_scheduler = __get_cfs_scheduler();
let rt_scheduler = __get_rt_scheduler();
let len_cfs = cfs_scheduler.get_cfs_queue_len(cpu_id);
let len_rt = rt_scheduler.rt_queue_len(cpu_id);
let len_cfs = cfs_scheduler.get_cfs_queue_len(cpu_id as u32);
let len_rt = rt_scheduler.rt_queue_len(cpu_id as u32);
// let load_rt = rt_scheduler.get_load_list_len(cpu_id);
// kdebug!("this cpu_id {} is load rt {}", cpu_id, load_rt);
@ -99,7 +102,13 @@ pub fn do_sched() -> Option<Arc<ProcessControlBlock>> {
// 当前进程持有锁,不切换,避免死锁
if ProcessManager::current_pcb().preempt_count() != 0 {
let binding = ProcessManager::current_pcb();
let mut guard = binding.sched_info_upgradeable_irqsave();
let guard = binding.sched_info_try_upgradeable_irqsave(5);
if unlikely(guard.is_none()) {
return None;
}
let mut guard = guard.unwrap();
let state = guard.state();
if state.is_blocked() {
// try to upgrade
@ -118,6 +127,7 @@ pub fn do_sched() -> Option<Arc<ProcessControlBlock>> {
}
return None;
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let cfs_scheduler: &mut SchedulerCFS = __get_cfs_scheduler();
let rt_scheduler: &mut SchedulerRT = __get_rt_scheduler();
@ -189,13 +199,17 @@ pub extern "C" fn sched_init() {
/// @brief 当时钟中断到达时,更新时间片
/// 请注意,该函数只能被时钟中断处理程序调用
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn sched_update_jiffies() {
let policy = ProcessManager::current_pcb().sched_info().policy();
let binding = ProcessManager::current_pcb();
let guard = binding.try_sched_info(10);
if unlikely(guard.is_none()) {
return;
}
let guard = guard.unwrap();
let policy = guard.policy();
match policy {
SchedPolicy::CFS => {
__get_cfs_scheduler().timer_update_jiffies();
__get_cfs_scheduler().timer_update_jiffies(&guard);
}
SchedPolicy::FIFO | SchedPolicy::RR => {
__get_rt_scheduler().timer_update_jiffies();

View File

@ -17,48 +17,7 @@
#define IS_VALID_SCHED_POLICY(_policy) ((_policy) > 0 && (_policy) <= SCHED_MAX_POLICY_NUM)
// struct sched_param
// {
// int sched_priority;
// };
// struct sched_attr
// {
// uint32_t size;
// uint32_t sched_policy;
// uint64_t sched_flags;
// /* SCHED_NORMAL, SCHED_BATCH */
// int32_t sched_nice;
// /* SCHED_FIFO, SCHED_RR */
// uint32_t sched_priority;
// /* SCHED_DEADLINE */
// uint64_t sched_runtime;
// uint64_t sched_deadline;
// uint64_t sched_period;
// /* Utilization hints */
// uint32_t sched_util_min;
// uint32_t sched_util_max;
// };
// static int __sched_setscheduler(struct process_control_block *p, const struct sched_attr *attr, bool user, bool pi);
// static int _sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param,
// bool check);
// /**
// * sched_setscheduler -设置进程的调度策略
// * @param p 需要修改的pcb
// * @param policy 需要设置的policy
// * @param param structure containing the new RT priority. 目前没有用
// *
// * @return 成功返回0,否则返回对应的错误码
// *
// */
// int sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param);
// ================= Rust 实现 =============
extern void sched_update_jiffies();
extern void sched_init();
extern void sched();

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

View File

@ -39,6 +39,7 @@ pub mod user_access;
#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, Eq, Clone)]
#[allow(dead_code, non_camel_case_types)]
pub enum SystemError {
/// 操作不被允许 Operation not permitted.
EPERM = 1,
/// 没有指定的文件或目录 No such file or directory.
ENOENT = 2,
@ -490,7 +491,6 @@ impl Syscall {
let open_flags: FileMode = FileMode::from_bits_truncate(flags as u32);
Self::open(path, open_flags)
};
res
}
SYS_CLOSE => {

View File

@ -40,10 +40,10 @@ ARCH="x86_64"
# 请根据自己的需要,在-d 后方加入所需的 trace 事件
# 标准的trace events
qemu_trace_std=cpu_reset,guest_errors,exec,cpu,trace:virtio*,trace:e1000e_rx*,trace:e1000e_tx*,trace:e1000e_irq*
qemu_trace_std=cpu_reset,guest_errors,trace:virtio*,trace:e1000e_rx*,trace:e1000e_tx*,trace:e1000e_irq*
# 调试usb的trace
qemu_trace_usb=trace:usb_xhci_reset,trace:usb_xhci_run,trace:usb_xhci_stop,trace:usb_xhci_irq_msi,trace:usb_xhci_irq_msix,trace:usb_xhci_port_reset,trace:msix_write_config,trace:usb_xhci_irq_msix,trace:usb_xhci_irq_msix_use,trace:usb_xhci_irq_msix_unuse,trace:usb_xhci_irq_msi,trace:usb_xhci_*
qemu_accel=kvm
qemu_accel="kvm"
if [ $(uname) == Darwin ]; then
qemu_accel=hvf
fi
@ -58,16 +58,23 @@ QEMU_CPU_FEATURES="IvyBridge,apic,x2apic,+fpu,check,+vmx,${allflags}"
QEMU_RTC_CLOCK="clock=host,base=localtime"
QEMU_SERIAL="file:../serial_opt.txt"
QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none"
QEMU_ACCELARATE=""
# 如果qemu_accel不为空
if [ -n "${qemu_accel}" ]; then
QEMU_ACCELARATE="-machine accel=${qemu_accel} -enable-kvm "
fi
# ps: 下面这条使用tap的方式无法dhcp获取到ip暂时不知道为什么
# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -net nic,netdev=nic0 -netdev tap,id=nic0,model=virtio-net-pci,script=qemu/ifup-nat,downscript=qemu/ifdown-nat -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel} -machine q35 "
QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -device virtio-net-pci,vectors=5,netdev=hostnet0,id=net0 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel} -machine q35 "
# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -net nic,netdev=nic0 -netdev tap,id=nic0,model=virtio-net-pci,script=qemu/ifup-nat,downscript=qemu/ifdown-nat -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine q35 "
QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -device virtio-net-pci,vectors=5,netdev=hostnet0,id=net0 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine q35 "
# E1000E
# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -net nic,model=e1000e,netdev=hostnet0,id=net0 -netdev user,id=hostnet1,hostfwd=tcp::12581-:12581 -device virtio-net-pci,vectors=5,netdev=hostnet1,id=net1 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel} -machine q35 "
# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -net nic,model=e1000e,netdev=hostnet0,id=net0 -netdev user,id=hostnet1,hostfwd=tcp::12581-:12581 -device virtio-net-pci,vectors=5,netdev=hostnet1,id=net1 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine q35 "
QEMU_ARGUMENT="-d ${QEMU_DISK_IMAGE} -m ${QEMU_MEMORY} -smp ${QEMU_SMP} -boot order=d -monitor ${QEMU_MONITOR} -d ${qemu_trace_std} "
QEMU_ARGUMENT+="-s -S -enable-kvm -cpu ${QEMU_CPU_FEATURES} -rtc ${QEMU_RTC_CLOCK} -serial ${QEMU_SERIAL} -drive ${QEMU_DRIVE} ${QEMU_DEVICES}"
QEMU_ARGUMENT+="-s -S -cpu ${QEMU_CPU_FEATURES} -rtc ${QEMU_RTC_CLOCK} -serial ${QEMU_SERIAL} -drive ${QEMU_DRIVE} ${QEMU_DEVICES}"
QEMU_ARGUMENT+=" ${QEMU_ACCELARATE} "
if [ $flag_can_run -eq 1 ]; then
while true;do

View File

@ -540,7 +540,6 @@ int shell_cmd_exec(int argc, char **argv)
waitpid(pid, &retval, 0);
else
printf("[1] %d\n", pid); // 输出子进程的pid
free(argv);
}
}

View File

@ -6,7 +6,7 @@
"BuildFromSource": {
"Git": {
"url": "https://git.mirrors.dragonos.org/DragonOS-Community/relibc.git",
"revision": "f797586d73"
"revision": "3ef630632f"
}
}
},