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